Added 'list_only' option (and modified 'run()' to respect it).
[python/dscho.git] / Modules / selectmodule.c
blobc18d979828ebb7e75314085eb0bc6e1e358ef1f3
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 #ifndef DONT_HAVE_SYS_TYPES_H
52 #include <sys/types.h>
53 #endif
55 #if defined(PYOS_OS2)
56 #include <sys/time.h>
57 #include <utils.h>
58 #endif
60 #ifdef MS_WINDOWS
61 #include <winsock.h>
62 #else
63 #ifdef __BEOS__
64 #include <net/socket.h>
65 #define SOCKET int
66 #else
67 #include "myselect.h" /* Also includes mytime.h */
68 #define SOCKET int
69 #endif
70 #endif
72 static PyObject *SelectError;
74 /* list of Python objects and their file descriptor */
75 typedef struct {
76 PyObject *obj; /* owned reference */
77 SOCKET fd;
78 int sentinel; /* -1 == sentinel */
79 } pylist;
81 static void
82 reap_obj(fd2obj)
83 pylist fd2obj[FD_SETSIZE + 3];
85 int i;
86 for (i = 0; i < FD_SETSIZE + 3 && fd2obj[i].sentinel >= 0; i++) {
87 Py_XDECREF(fd2obj[i].obj);
88 fd2obj[i].obj = NULL;
90 fd2obj[0].sentinel = -1;
94 /* returns -1 and sets the Python exception if an error occurred, otherwise
95 returns a number >= 0
97 static int
98 list2set(list, set, fd2obj)
99 PyObject *list;
100 fd_set *set;
101 pylist fd2obj[FD_SETSIZE + 3];
103 int i;
104 int max = -1;
105 int index = 0;
106 int len = PyList_Size(list);
107 PyObject* o = NULL;
109 fd2obj[0].obj = (PyObject*)0; /* set list to zero size */
110 FD_ZERO(set);
112 for (i = 0; i < len; i++) {
113 PyObject *meth;
114 SOCKET v;
116 /* any intervening fileno() calls could decr this refcnt */
117 if (!(o = PyList_GetItem(list, i)))
118 return -1;
120 Py_INCREF(o);
122 if (PyInt_Check(o)) {
123 v = PyInt_AsLong(o);
125 else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL)
127 PyObject *fno = PyEval_CallObject(meth, NULL);
128 Py_DECREF(meth);
129 if (fno == NULL)
130 goto finally;
132 if (!PyInt_Check(fno)) {
133 PyErr_SetString(PyExc_TypeError,
134 "fileno method returned a non-integer");
135 Py_DECREF(fno);
136 goto finally;
138 v = PyInt_AsLong(fno);
139 Py_DECREF(fno);
141 else {
142 PyErr_SetString(PyExc_TypeError,
143 "argument must be an int, or have a fileno() method.");
144 goto finally;
146 #if defined(_MSC_VER) || defined(__BEOS__)
147 max = 0; /* not used for Win32 */
148 #else /* !_MSC_VER */
149 if (v < 0 || v >= FD_SETSIZE) {
150 PyErr_SetString(PyExc_ValueError,
151 "filedescriptor out of range in select()");
152 goto finally;
154 if (v > max)
155 max = v;
156 #endif /* _MSC_VER */
157 FD_SET(v, set);
159 /* add object and its file descriptor to the list */
160 if (index >= FD_SETSIZE) {
161 PyErr_SetString(PyExc_ValueError,
162 "too many file descriptors in select()");
163 goto finally;
165 fd2obj[index].obj = o;
166 fd2obj[index].fd = v;
167 fd2obj[index].sentinel = 0;
168 fd2obj[++index].sentinel = -1;
170 return max+1;
172 finally:
173 Py_XDECREF(o);
174 return -1;
177 /* returns NULL and sets the Python exception if an error occurred */
178 static PyObject *
179 set2list(set, fd2obj)
180 fd_set *set;
181 pylist fd2obj[FD_SETSIZE + 3];
183 int i, j, count=0;
184 PyObject *list, *o;
185 SOCKET fd;
187 for (j = 0; fd2obj[j].sentinel >= 0; j++) {
188 if (FD_ISSET(fd2obj[j].fd, set))
189 count++;
191 list = PyList_New(count);
192 if (!list)
193 return NULL;
195 i = 0;
196 for (j = 0; fd2obj[j].sentinel >= 0; j++) {
197 fd = fd2obj[j].fd;
198 if (FD_ISSET(fd, set)) {
199 #ifndef _MSC_VER
200 if (fd > FD_SETSIZE) {
201 PyErr_SetString(PyExc_SystemError,
202 "filedescriptor out of range returned in select()");
203 goto finally;
205 #endif
206 o = fd2obj[j].obj;
207 fd2obj[j].obj = NULL;
208 /* transfer ownership */
209 if (PyList_SetItem(list, i, o) < 0)
210 goto finally;
212 i++;
215 return list;
216 finally:
217 Py_DECREF(list);
218 return NULL;
222 static PyObject *
223 select_select(self, args)
224 PyObject *self;
225 PyObject *args;
227 #ifdef MS_WINDOWS
228 /* This would be an awful lot of stack space on Windows! */
229 pylist *rfd2obj, *wfd2obj, *efd2obj;
230 #else
231 pylist rfd2obj[FD_SETSIZE + 3];
232 pylist wfd2obj[FD_SETSIZE + 3];
233 pylist efd2obj[FD_SETSIZE + 3];
234 #endif
235 PyObject *ifdlist, *ofdlist, *efdlist;
236 PyObject *ret = NULL;
237 PyObject *tout = Py_None;
238 fd_set ifdset, ofdset, efdset;
239 double timeout;
240 struct timeval tv, *tvp;
241 int seconds;
242 int imax, omax, emax, max;
243 int n;
245 /* convert arguments */
246 if (!PyArg_ParseTuple(args, "OOO|O",
247 &ifdlist, &ofdlist, &efdlist, &tout))
248 return NULL;
250 if (tout == Py_None)
251 tvp = (struct timeval *)0;
252 else if (!PyArg_Parse(tout, "d", &timeout)) {
253 PyErr_SetString(PyExc_TypeError,
254 "timeout must be a float or None");
255 return NULL;
257 else {
258 seconds = (int)timeout;
259 timeout = timeout - (double)seconds;
260 tv.tv_sec = seconds;
261 tv.tv_usec = (int)(timeout*1000000.0);
262 tvp = &tv;
265 /* sanity check first three arguments */
266 if (!PyList_Check(ifdlist) ||
267 !PyList_Check(ofdlist) ||
268 !PyList_Check(efdlist))
270 PyErr_SetString(PyExc_TypeError,
271 "arguments 1-3 must be lists");
272 return NULL;
275 #ifdef MS_WINDOWS
276 /* Allocate memory for the lists */
277 rfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 3);
278 wfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 3);
279 efd2obj = PyMem_NEW(pylist, FD_SETSIZE + 3);
280 if (rfd2obj == NULL || wfd2obj == NULL || efd2obj == NULL) {
281 PyMem_XDEL(rfd2obj);
282 PyMem_XDEL(wfd2obj);
283 PyMem_XDEL(efd2obj);
284 return NULL;
286 #endif
287 /* Convert lists to fd_sets, and get maximum fd number
288 * propagates the Python exception set in list2set()
290 rfd2obj[0].sentinel = -1;
291 wfd2obj[0].sentinel = -1;
292 efd2obj[0].sentinel = -1;
293 if ((imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0)
294 goto finally;
295 if ((omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0)
296 goto finally;
297 if ((emax=list2set(efdlist, &efdset, efd2obj)) < 0)
298 goto finally;
299 max = imax;
300 if (omax > max) max = omax;
301 if (emax > max) max = emax;
303 Py_BEGIN_ALLOW_THREADS
304 n = select(max, &ifdset, &ofdset, &efdset, tvp);
305 Py_END_ALLOW_THREADS
307 if (n < 0) {
308 PyErr_SetFromErrno(SelectError);
310 else if (n == 0) {
311 /* optimization */
312 ifdlist = PyList_New(0);
313 if (ifdlist) {
314 ret = Py_BuildValue("OOO", ifdlist, ifdlist, ifdlist);
315 Py_DECREF(ifdlist);
318 else {
319 /* any of these three calls can raise an exception. it's more
320 convenient to test for this after all three calls... but
321 is that acceptable?
323 ifdlist = set2list(&ifdset, rfd2obj);
324 ofdlist = set2list(&ofdset, wfd2obj);
325 efdlist = set2list(&efdset, efd2obj);
326 if (PyErr_Occurred())
327 ret = NULL;
328 else
329 ret = Py_BuildValue("OOO", ifdlist, ofdlist, efdlist);
331 Py_DECREF(ifdlist);
332 Py_DECREF(ofdlist);
333 Py_DECREF(efdlist);
336 finally:
337 reap_obj(rfd2obj);
338 reap_obj(wfd2obj);
339 reap_obj(efd2obj);
340 #ifdef MS_WINDOWS
341 PyMem_DEL(rfd2obj);
342 PyMem_DEL(wfd2obj);
343 PyMem_DEL(efd2obj);
344 #endif
345 return ret;
348 static char select_doc[] =
349 "select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)\n\
351 Wait until one or more file descriptors are ready for some kind of I/O.\n\
352 The first three arguments are lists of file descriptors to be waited for:\n\
353 rlist -- wait until ready for reading\n\
354 wlist -- wait until ready for writing\n\
355 xlist -- wait for an ``exceptional condition''\n\
356 If only one kind of condition is required, pass [] for the other lists.\n\
357 A file descriptor is either a socket or file object, or a small integer\n\
358 gotten from a fileno() method call on one of those.\n\
360 The optional 4th argument specifies a timeout in seconds; it may be\n\
361 a floating point number to specify fractions of seconds. If it is absent\n\
362 or None, the call will never time out.\n\
364 The return value is a tuple of three lists corresponding to the first three\n\
365 arguments; each contains the subset of the corresponding file descriptors\n\
366 that are ready.\n\
368 *** IMPORTANT NOTICE ***\n\
369 On Windows, only sockets are supported; on Unix, all file descriptors.";
372 static PyMethodDef select_methods[] = {
373 {"select", select_select, 1, select_doc},
374 {0, 0}, /* sentinel */
377 static char module_doc[] =
378 "This module supports asynchronous I/O on multiple file descriptors.\n\
380 *** IMPORTANT NOTICE ***\n\
381 On Windows, only sockets are supported; on Unix, all file descriptors.";
383 DL_EXPORT(void)
384 initselect()
386 PyObject *m, *d;
387 m = Py_InitModule3("select", select_methods, module_doc);
388 d = PyModule_GetDict(m);
389 SelectError = PyErr_NewException("select.error", NULL, NULL);
390 PyDict_SetItemString(d, "error", SelectError);