1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
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
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
47 /* This is missing from unistd.h */
51 #ifndef DONT_HAVE_SYS_TYPES_H
52 #include <sys/types.h>
64 #include <net/socket.h>
67 #include "myselect.h" /* Also includes mytime.h */
72 static PyObject
*SelectError
;
74 /* list of Python objects and their file descriptor */
76 PyObject
*obj
; /* owned reference */
78 int sentinel
; /* -1 == sentinel */
83 pylist fd2obj
[FD_SETSIZE
+ 3];
86 for (i
= 0; i
< FD_SETSIZE
+ 3 && fd2obj
[i
].sentinel
>= 0; i
++) {
87 Py_XDECREF(fd2obj
[i
].obj
);
90 fd2obj
[0].sentinel
= -1;
94 /* returns -1 and sets the Python exception if an error occurred, otherwise
98 list2set(list
, set
, fd2obj
)
101 pylist fd2obj
[FD_SETSIZE
+ 3];
106 int len
= PyList_Size(list
);
109 fd2obj
[0].obj
= (PyObject
*)0; /* set list to zero size */
112 for (i
= 0; i
< len
; i
++) {
116 /* any intervening fileno() calls could decr this refcnt */
117 if (!(o
= PyList_GetItem(list
, i
)))
122 if (PyInt_Check(o
)) {
125 else if ((meth
= PyObject_GetAttrString(o
, "fileno")) != NULL
)
127 PyObject
*fno
= PyEval_CallObject(meth
, NULL
);
132 if (!PyInt_Check(fno
)) {
133 PyErr_SetString(PyExc_TypeError
,
134 "fileno method returned a non-integer");
138 v
= PyInt_AsLong(fno
);
142 PyErr_SetString(PyExc_TypeError
,
143 "argument must be an int, or have a fileno() method.");
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()");
156 #endif /* _MSC_VER */
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()");
165 fd2obj
[index
].obj
= o
;
166 fd2obj
[index
].fd
= v
;
167 fd2obj
[index
].sentinel
= 0;
168 fd2obj
[++index
].sentinel
= -1;
177 /* returns NULL and sets the Python exception if an error occurred */
179 set2list(set
, fd2obj
)
181 pylist fd2obj
[FD_SETSIZE
+ 3];
187 for (j
= 0; fd2obj
[j
].sentinel
>= 0; j
++) {
188 if (FD_ISSET(fd2obj
[j
].fd
, set
))
191 list
= PyList_New(count
);
196 for (j
= 0; fd2obj
[j
].sentinel
>= 0; j
++) {
198 if (FD_ISSET(fd
, set
)) {
200 if (fd
> FD_SETSIZE
) {
201 PyErr_SetString(PyExc_SystemError
,
202 "filedescriptor out of range returned in select()");
207 fd2obj
[j
].obj
= NULL
;
208 /* transfer ownership */
209 if (PyList_SetItem(list
, i
, o
) < 0)
223 select_select(self
, args
)
228 /* This would be an awful lot of stack space on Windows! */
229 pylist
*rfd2obj
, *wfd2obj
, *efd2obj
;
231 pylist rfd2obj
[FD_SETSIZE
+ 3];
232 pylist wfd2obj
[FD_SETSIZE
+ 3];
233 pylist efd2obj
[FD_SETSIZE
+ 3];
235 PyObject
*ifdlist
, *ofdlist
, *efdlist
;
236 PyObject
*ret
= NULL
;
237 PyObject
*tout
= Py_None
;
238 fd_set ifdset
, ofdset
, efdset
;
240 struct timeval tv
, *tvp
;
242 int imax
, omax
, emax
, max
;
245 /* convert arguments */
246 if (!PyArg_ParseTuple(args
, "OOO|O",
247 &ifdlist
, &ofdlist
, &efdlist
, &tout
))
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");
258 seconds
= (int)timeout
;
259 timeout
= timeout
- (double)seconds
;
261 tv
.tv_usec
= (int)(timeout
*1000000.0);
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");
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
) {
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)
295 if ((omax
=list2set(ofdlist
, &ofdset
, wfd2obj
)) < 0)
297 if ((emax
=list2set(efdlist
, &efdset
, efd2obj
)) < 0)
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
);
308 PyErr_SetFromErrno(SelectError
);
312 ifdlist
= PyList_New(0);
314 ret
= Py_BuildValue("OOO", ifdlist
, ifdlist
, ifdlist
);
319 /* any of these three calls can raise an exception. it's more
320 convenient to test for this after all three calls... but
323 ifdlist
= set2list(&ifdset
, rfd2obj
);
324 ofdlist
= set2list(&ofdset
, wfd2obj
);
325 efdlist
= set2list(&efdset
, efd2obj
);
326 if (PyErr_Occurred())
329 ret
= Py_BuildValue("OOO", ifdlist
, ofdlist
, efdlist
);
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\
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.";
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
);