Class around PixMap objects that allows more python-like access. By Joe Strout.
[python/dscho.git] / Modules / selectmodule.c
blob11f72f5aa27e4b5c0d5ae76626da4248c0c220bf
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
15 permission.
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* select - Module containing unix select(2) call.
33 Under Unix, the file descriptors are small integers.
34 Under Win32, select only exists for sockets, and sockets may
35 have any value except INVALID_SOCKET.
36 Under BeOS, we suffer the same dichotomy as Win32; sockets can be anything
37 >= 0.
40 #include "Python.h"
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
46 #ifdef __sgi
47 /* This is missing from unistd.h */
48 extern void bzero();
49 #endif
51 #include <sys/types.h>
53 #if defined(PYOS_OS2)
54 #include <sys/time.h>
55 #include <utils.h>
56 #endif
58 #ifdef MS_WINDOWS
59 #include <winsock.h>
60 #else
61 #ifdef __BEOS__
62 #include <net/socket.h>
63 #define SOCKET int
64 #else
65 #include "myselect.h" /* Also includes mytime.h */
66 #define SOCKET int
67 #endif
68 #endif
70 static PyObject *SelectError;
72 /* list of Python objects and their file descriptor */
73 typedef struct {
74 PyObject *obj; /* owned reference */
75 SOCKET fd;
76 int sentinel; /* -1 == sentinel */
77 } pylist;
79 static void
80 reap_obj(fd2obj)
81 pylist fd2obj[FD_SETSIZE + 3];
83 int i;
84 for (i = 0; i < FD_SETSIZE + 3 && fd2obj[i].sentinel >= 0; i++) {
85 Py_XDECREF(fd2obj[i].obj);
86 fd2obj[i].obj = NULL;
88 fd2obj[0].sentinel = -1;
92 /* returns -1 and sets the Python exception if an error occurred, otherwise
93 returns a number >= 0
95 static int
96 list2set(list, set, fd2obj)
97 PyObject *list;
98 fd_set *set;
99 pylist fd2obj[FD_SETSIZE + 3];
101 int i;
102 int max = -1;
103 int index = 0;
104 int len = PyList_Size(list);
105 PyObject* o = NULL;
107 fd2obj[0].obj = (PyObject*)0; /* set list to zero size */
108 FD_ZERO(set);
110 for (i = 0; i < len; i++) {
111 PyObject *meth;
112 SOCKET v;
114 /* any intervening fileno() calls could decr this refcnt */
115 if (!(o = PyList_GetItem(list, i)))
116 return -1;
118 Py_INCREF(o);
120 if (PyInt_Check(o)) {
121 v = PyInt_AsLong(o);
123 else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL)
125 PyObject *fno = PyEval_CallObject(meth, NULL);
126 Py_DECREF(meth);
127 if (fno == NULL)
128 goto finally;
130 if (!PyInt_Check(fno)) {
131 PyErr_SetString(PyExc_TypeError,
132 "fileno method returned a non-integer");
133 Py_DECREF(fno);
134 goto finally;
136 v = PyInt_AsLong(fno);
137 Py_DECREF(fno);
139 else {
140 PyErr_SetString(PyExc_TypeError,
141 "argument must be an int, or have a fileno() method.");
142 goto finally;
144 #if defined(_MSC_VER) || defined(__BEOS__)
145 max = 0; /* not used for Win32 */
146 #else /* !_MSC_VER */
147 if (v < 0 || v >= FD_SETSIZE) {
148 PyErr_SetString(PyExc_ValueError,
149 "filedescriptor out of range in select()");
150 goto finally;
152 if (v > max)
153 max = v;
154 #endif /* _MSC_VER */
155 FD_SET(v, set);
157 /* add object and its file descriptor to the list */
158 if (index >= FD_SETSIZE) {
159 PyErr_SetString(PyExc_ValueError,
160 "too many file descriptors in select()");
161 goto finally;
163 fd2obj[index].obj = o;
164 fd2obj[index].fd = v;
165 fd2obj[index].sentinel = 0;
166 fd2obj[++index].sentinel = -1;
168 return max+1;
170 finally:
171 Py_XDECREF(o);
172 return -1;
175 /* returns NULL and sets the Python exception if an error occurred */
176 static PyObject *
177 set2list(set, fd2obj)
178 fd_set *set;
179 pylist fd2obj[FD_SETSIZE + 3];
181 int i, j, count=0;
182 PyObject *list, *o;
183 SOCKET fd;
185 for (j = 0; fd2obj[j].sentinel >= 0; j++) {
186 if (FD_ISSET(fd2obj[j].fd, set))
187 count++;
189 list = PyList_New(count);
190 if (!list)
191 return NULL;
193 i = 0;
194 for (j = 0; fd2obj[j].sentinel >= 0; j++) {
195 fd = fd2obj[j].fd;
196 if (FD_ISSET(fd, set)) {
197 #ifndef _MSC_VER
198 if (fd > FD_SETSIZE) {
199 PyErr_SetString(PyExc_SystemError,
200 "filedescriptor out of range returned in select()");
201 goto finally;
203 #endif
204 o = fd2obj[j].obj;
205 fd2obj[j].obj = NULL;
206 /* transfer ownership */
207 if (PyList_SetItem(list, i, o) < 0)
208 goto finally;
210 i++;
213 return list;
214 finally:
215 Py_DECREF(list);
216 return NULL;
220 static PyObject *
221 select_select(self, args)
222 PyObject *self;
223 PyObject *args;
225 #ifdef MS_WINDOWS
226 /* This would be an awful lot of stack space on Windows! */
227 pylist *rfd2obj, *wfd2obj, *efd2obj;
228 #else
229 pylist rfd2obj[FD_SETSIZE + 3];
230 pylist wfd2obj[FD_SETSIZE + 3];
231 pylist efd2obj[FD_SETSIZE + 3];
232 #endif
233 PyObject *ifdlist, *ofdlist, *efdlist;
234 PyObject *ret = NULL;
235 PyObject *tout = Py_None;
236 fd_set ifdset, ofdset, efdset;
237 double timeout;
238 struct timeval tv, *tvp;
239 int seconds;
240 int imax, omax, emax, max;
241 int n;
243 /* convert arguments */
244 if (!PyArg_ParseTuple(args, "OOO|O",
245 &ifdlist, &ofdlist, &efdlist, &tout))
246 return NULL;
248 if (tout == Py_None)
249 tvp = (struct timeval *)0;
250 else if (!PyArg_Parse(tout, "d", &timeout)) {
251 PyErr_SetString(PyExc_TypeError,
252 "timeout must be a float or None");
253 return NULL;
255 else {
256 seconds = (int)timeout;
257 timeout = timeout - (double)seconds;
258 tv.tv_sec = seconds;
259 tv.tv_usec = (int)(timeout*1000000.0);
260 tvp = &tv;
263 /* sanity check first three arguments */
264 if (!PyList_Check(ifdlist) ||
265 !PyList_Check(ofdlist) ||
266 !PyList_Check(efdlist))
268 PyErr_SetString(PyExc_TypeError,
269 "arguments 1-3 must be lists");
270 return NULL;
273 #ifdef MS_WINDOWS
274 /* Allocate memory for the lists */
275 rfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 3);
276 wfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 3);
277 efd2obj = PyMem_NEW(pylist, FD_SETSIZE + 3);
278 if (rfd2obj == NULL || wfd2obj == NULL || efd2obj == NULL) {
279 PyMem_XDEL(rfd2obj);
280 PyMem_XDEL(wfd2obj);
281 PyMem_XDEL(efd2obj);
282 return NULL;
284 #endif
285 /* Convert lists to fd_sets, and get maximum fd number
286 * propagates the Python exception set in list2set()
288 rfd2obj[0].sentinel = -1;
289 wfd2obj[0].sentinel = -1;
290 efd2obj[0].sentinel = -1;
291 if ((imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0)
292 goto finally;
293 if ((omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0)
294 goto finally;
295 if ((emax=list2set(efdlist, &efdset, efd2obj)) < 0)
296 goto finally;
297 max = imax;
298 if (omax > max) max = omax;
299 if (emax > max) max = emax;
301 Py_BEGIN_ALLOW_THREADS
302 n = select(max, &ifdset, &ofdset, &efdset, tvp);
303 Py_END_ALLOW_THREADS
305 if (n < 0) {
306 PyErr_SetFromErrno(SelectError);
308 else if (n == 0) {
309 /* optimization */
310 ifdlist = PyList_New(0);
311 if (ifdlist) {
312 ret = Py_BuildValue("OOO", ifdlist, ifdlist, ifdlist);
313 Py_DECREF(ifdlist);
316 else {
317 /* any of these three calls can raise an exception. it's more
318 convenient to test for this after all three calls... but
319 is that acceptable?
321 ifdlist = set2list(&ifdset, rfd2obj);
322 ofdlist = set2list(&ofdset, wfd2obj);
323 efdlist = set2list(&efdset, efd2obj);
324 if (PyErr_Occurred())
325 ret = NULL;
326 else
327 ret = Py_BuildValue("OOO", ifdlist, ofdlist, efdlist);
329 Py_DECREF(ifdlist);
330 Py_DECREF(ofdlist);
331 Py_DECREF(efdlist);
334 finally:
335 reap_obj(rfd2obj);
336 reap_obj(wfd2obj);
337 reap_obj(efd2obj);
338 #ifdef MS_WINDOWS
339 PyMem_DEL(rfd2obj);
340 PyMem_DEL(wfd2obj);
341 PyMem_DEL(efd2obj);
342 #endif
343 return ret;
346 static char select_doc[] =
347 "select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)\n\
349 Wait until one or more file descriptors are ready for some kind of I/O.\n\
350 The first three arguments are lists of file descriptors to be waited for:\n\
351 rlist -- wait until ready for reading\n\
352 wlist -- wait until ready for writing\n\
353 xlist -- wait for an ``exceptional condition''\n\
354 If only one kind of condition is required, pass [] for the other lists.\n\
355 A file descriptor is either a socket or file object, or a small integer\n\
356 gotten from a fileno() method call on one of those.\n\
358 The optional 4th argument specifies a timeout in seconds; it may be\n\
359 a floating point number to specify fractions of seconds. If it is absent\n\
360 or None, the call will never time out.\n\
362 The return value is a tuple of three lists corresponding to the first three\n\
363 arguments; each contains the subset of the corresponding file descriptors\n\
364 that are ready.\n\
366 *** IMPORTANT NOTICE ***\n\
367 On Windows, only sockets are supported; on Unix, all file descriptors.";
370 static PyMethodDef select_methods[] = {
371 {"select", select_select, 1, select_doc},
372 {0, 0}, /* sentinel */
375 static char module_doc[] =
376 "This module supports asynchronous I/O on multiple file descriptors.\n\
378 *** IMPORTANT NOTICE ***\n\
379 On Windows, only sockets are supported; on Unix, all file descriptors.";
381 DL_EXPORT(void)
382 initselect()
384 PyObject *m, *d;
385 m = Py_InitModule3("select", select_methods, module_doc);
386 d = PyModule_GetDict(m);
387 SelectError = PyErr_NewException("select.error", NULL, NULL);
388 PyDict_SetItemString(d, "error", SelectError);