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 #include <sys/types.h>
62 #include <net/socket.h>
65 #include "myselect.h" /* Also includes mytime.h */
70 static PyObject
*SelectError
;
72 /* list of Python objects and their file descriptor */
74 PyObject
*obj
; /* owned reference */
76 int sentinel
; /* -1 == sentinel */
81 pylist fd2obj
[FD_SETSIZE
+ 3];
84 for (i
= 0; i
< FD_SETSIZE
+ 3 && fd2obj
[i
].sentinel
>= 0; i
++) {
85 Py_XDECREF(fd2obj
[i
].obj
);
88 fd2obj
[0].sentinel
= -1;
92 /* returns -1 and sets the Python exception if an error occurred, otherwise
96 list2set(list
, set
, fd2obj
)
99 pylist fd2obj
[FD_SETSIZE
+ 3];
104 int len
= PyList_Size(list
);
107 fd2obj
[0].obj
= (PyObject
*)0; /* set list to zero size */
110 for (i
= 0; i
< len
; i
++) {
114 /* any intervening fileno() calls could decr this refcnt */
115 if (!(o
= PyList_GetItem(list
, i
)))
120 if (PyInt_Check(o
)) {
123 else if ((meth
= PyObject_GetAttrString(o
, "fileno")) != NULL
)
125 PyObject
*fno
= PyEval_CallObject(meth
, NULL
);
130 if (!PyInt_Check(fno
)) {
131 PyErr_SetString(PyExc_TypeError
,
132 "fileno method returned a non-integer");
136 v
= PyInt_AsLong(fno
);
140 PyErr_SetString(PyExc_TypeError
,
141 "argument must be an int, or have a fileno() method.");
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()");
154 #endif /* _MSC_VER */
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()");
163 fd2obj
[index
].obj
= o
;
164 fd2obj
[index
].fd
= v
;
165 fd2obj
[index
].sentinel
= 0;
166 fd2obj
[++index
].sentinel
= -1;
175 /* returns NULL and sets the Python exception if an error occurred */
177 set2list(set
, fd2obj
)
179 pylist fd2obj
[FD_SETSIZE
+ 3];
185 for (j
= 0; fd2obj
[j
].sentinel
>= 0; j
++) {
186 if (FD_ISSET(fd2obj
[j
].fd
, set
))
189 list
= PyList_New(count
);
194 for (j
= 0; fd2obj
[j
].sentinel
>= 0; j
++) {
196 if (FD_ISSET(fd
, set
)) {
198 if (fd
> FD_SETSIZE
) {
199 PyErr_SetString(PyExc_SystemError
,
200 "filedescriptor out of range returned in select()");
205 fd2obj
[j
].obj
= NULL
;
206 /* transfer ownership */
207 if (PyList_SetItem(list
, i
, o
) < 0)
221 select_select(self
, args
)
226 /* This would be an awful lot of stack space on Windows! */
227 pylist
*rfd2obj
, *wfd2obj
, *efd2obj
;
229 pylist rfd2obj
[FD_SETSIZE
+ 3];
230 pylist wfd2obj
[FD_SETSIZE
+ 3];
231 pylist efd2obj
[FD_SETSIZE
+ 3];
233 PyObject
*ifdlist
, *ofdlist
, *efdlist
;
234 PyObject
*ret
= NULL
;
235 PyObject
*tout
= Py_None
;
236 fd_set ifdset
, ofdset
, efdset
;
238 struct timeval tv
, *tvp
;
240 int imax
, omax
, emax
, max
;
243 /* convert arguments */
244 if (!PyArg_ParseTuple(args
, "OOO|O",
245 &ifdlist
, &ofdlist
, &efdlist
, &tout
))
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");
256 seconds
= (int)timeout
;
257 timeout
= timeout
- (double)seconds
;
259 tv
.tv_usec
= (int)(timeout
*1000000.0);
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");
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
) {
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)
293 if ((omax
=list2set(ofdlist
, &ofdset
, wfd2obj
)) < 0)
295 if ((emax
=list2set(efdlist
, &efdset
, efd2obj
)) < 0)
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
);
306 PyErr_SetFromErrno(SelectError
);
310 ifdlist
= PyList_New(0);
312 ret
= Py_BuildValue("OOO", ifdlist
, ifdlist
, ifdlist
);
317 /* any of these three calls can raise an exception. it's more
318 convenient to test for this after all three calls... but
321 ifdlist
= set2list(&ifdset
, rfd2obj
);
322 ofdlist
= set2list(&ofdset
, wfd2obj
);
323 efdlist
= set2list(&efdset
, efd2obj
);
324 if (PyErr_Occurred())
327 ret
= Py_BuildValue("OOO", ifdlist
, ofdlist
, efdlist
);
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\
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.";
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
);