blob: a1e3cf0deacb79c7604d5c54476060e95d76bcad [file] [log] [blame]
Guido van Rossumed233a51992-06-23 09:07:03 +00001/***********************************************************
Guido van Rossum524b5881995-01-04 19:10:35 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossumed233a51992-06-23 09:07:03 +00004
5 All Rights Reserved
6
Guido van Rossumd266eb41996-10-25 14:44:06 +00007Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
Guido van Rossumed233a51992-06-23 09:07:03 +00009provided that the above copyright notice appear in all copies and that
Guido van Rossumd266eb41996-10-25 14:44:06 +000010both that copyright notice and this permission notice appear in
Guido van Rossumed233a51992-06-23 09:07:03 +000011supporting documentation, and that the names of Stichting Mathematisch
Guido van Rossumd266eb41996-10-25 14:44:06 +000012Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
Guido van Rossumed233a51992-06-23 09:07:03 +000016
Guido van Rossumd266eb41996-10-25 14:44:06 +000017While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
Guido van Rossumed233a51992-06-23 09:07:03 +000029
30******************************************************************/
31
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000032/* select - Module containing unix select(2) call.
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000033 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.
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000036*/
Guido van Rossumed233a51992-06-23 09:07:03 +000037
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000038#include "Python.h"
Guido van Rossumed233a51992-06-23 09:07:03 +000039
Guido van Rossuma376cc51996-12-05 23:43:35 +000040#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43
Guido van Rossum37273171996-12-09 18:47:43 +000044#ifdef __sgi
45/* This is missing from unistd.h */
46extern void bzero();
47#endif
48
Guido van Rossumb6775db1994-08-01 11:34:53 +000049#include <sys/types.h>
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000050
Guido van Rossum6f489d91996-06-28 20:15:15 +000051#ifdef MS_WINDOWS
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000052#include <winsock.h>
53#else
Guido van Rossumb6775db1994-08-01 11:34:53 +000054#include "myselect.h" /* Also includes mytime.h */
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000055#define SOCKET int
56#endif
Guido van Rossumed233a51992-06-23 09:07:03 +000057
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000058static PyObject *SelectError;
Guido van Rossumed233a51992-06-23 09:07:03 +000059
Barry Warsawc1cb3601996-12-12 22:16:21 +000060/* list of Python objects and their file descriptor */
61typedef struct {
62 PyObject *obj; /* owned reference */
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000063 SOCKET fd;
Barry Warsawc1cb3601996-12-12 22:16:21 +000064 int sentinel; /* -1 == sentinel */
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000065} pylist;
66
Barry Warsawc1cb3601996-12-12 22:16:21 +000067static void
68reap_obj(fd2obj)
69 pylist fd2obj[FD_SETSIZE + 3];
70{
71 int i;
72 for (i = 0; i < FD_SETSIZE + 3 && fd2obj[i].sentinel >= 0; i++) {
73 Py_XDECREF(fd2obj[i].obj);
74 fd2obj[i].obj = NULL;
75 }
76 fd2obj[0].sentinel = -1;
77}
78
79
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000080/* returns -1 and sets the Python exception if an error occurred, otherwise
81 returns a number >= 0
82*/
Guido van Rossum4f0fbf81996-06-12 04:22:53 +000083static int
Guido van Rossum4fbf7981992-08-04 09:13:45 +000084list2set(list, set, fd2obj)
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000085 PyObject *list;
86 fd_set *set;
87 pylist fd2obj[FD_SETSIZE + 3];
Guido van Rossumed233a51992-06-23 09:07:03 +000088{
Barry Warsawc1cb3601996-12-12 22:16:21 +000089 int i;
90 int max = -1;
91 int index = 0;
92 int len = PyList_Size(list);
93 PyObject* o = NULL;
Guido van Rossum07432c01995-03-29 16:47:45 +000094
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000095 fd2obj[0].obj = (PyObject*)0; /* set list to zero size */
Barry Warsawe4ac0aa1996-12-12 00:04:35 +000096 FD_ZERO(set);
Barry Warsawc1cb3601996-12-12 22:16:21 +000097
98 for (i = 0; i < len; i++) {
99 PyObject *meth;
100 SOCKET v;
101
102 /* any intervening fileno() calls could decr this refcnt */
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000103 o = PyList_GetItem(list, i);
Barry Warsawc1cb3601996-12-12 22:16:21 +0000104 Py_INCREF(o);
105
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000106 if (PyInt_Check(o)) {
107 v = PyInt_AsLong(o);
108 }
109 else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL)
110 {
Barry Warsawc1cb3601996-12-12 22:16:21 +0000111 PyObject *fno = PyEval_CallObject(meth, NULL);
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000112 Py_DECREF(meth);
113 if (fno == NULL)
Barry Warsawc1cb3601996-12-12 22:16:21 +0000114 goto finally;
115
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000116 if (!PyInt_Check(fno)) {
Barry Warsawc1cb3601996-12-12 22:16:21 +0000117 PyErr_SetString(PyExc_TypeError,
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000118 "fileno method returned a non-integer");
Barry Warsawc1cb3601996-12-12 22:16:21 +0000119 Py_DECREF(fno);
120 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000121 }
122 v = PyInt_AsLong(fno);
123 Py_DECREF(fno);
124 }
125 else {
126 PyErr_SetString(PyExc_TypeError,
Barry Warsawc1cb3601996-12-12 22:16:21 +0000127 "argument must be an int, or have a fileno() method.");
128 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000129 }
Guido van Rossum4f0fbf81996-06-12 04:22:53 +0000130#ifdef _MSC_VER
Barry Warsawc1cb3601996-12-12 22:16:21 +0000131 max = 0; /* not used for Win32 */
132#else /* !_MSC_VER */
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000133 if (v < 0 || v >= FD_SETSIZE) {
Barry Warsawc1cb3601996-12-12 22:16:21 +0000134 PyErr_SetString(PyExc_ValueError,
135 "filedescriptor out of range in select()");
136 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000137 }
138 if (v > max)
139 max = v;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000140#endif /* _MSC_VER */
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000141 FD_SET(v, set);
Barry Warsawc1cb3601996-12-12 22:16:21 +0000142
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000143 /* add object and its file descriptor to the list */
144 if (index >= FD_SETSIZE) {
Barry Warsawc1cb3601996-12-12 22:16:21 +0000145 PyErr_SetString(PyExc_ValueError,
146 "too many file descriptors in select()");
147 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000148 }
149 fd2obj[index].obj = o;
150 fd2obj[index].fd = v;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000151 fd2obj[index].sentinel = 0;
152 fd2obj[++index].sentinel = -1;
Guido van Rossum4f0fbf81996-06-12 04:22:53 +0000153 }
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000154 return max+1;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000155
156 finally:
157 Py_XDECREF(o);
158 return -1;
Guido van Rossumed233a51992-06-23 09:07:03 +0000159}
160
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000161/* returns NULL and sets the Python exception if an error occurred */
162static PyObject *
Guido van Rossum4f0fbf81996-06-12 04:22:53 +0000163set2list(set, fd2obj)
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000164 fd_set *set;
165 pylist fd2obj[FD_SETSIZE + 3];
Guido van Rossumed233a51992-06-23 09:07:03 +0000166{
Barry Warsawc1cb3601996-12-12 22:16:21 +0000167 int i, j, count=0;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000168 PyObject *list, *o;
169 SOCKET fd;
Guido van Rossumed233a51992-06-23 09:07:03 +0000170
Barry Warsawc1cb3601996-12-12 22:16:21 +0000171 for (j = 0; fd2obj[j].sentinel >= 0; j++) {
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000172 if (FD_ISSET(fd2obj[j].fd, set))
Barry Warsawc1cb3601996-12-12 22:16:21 +0000173 count++;
174 }
175 list = PyList_New(count);
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000176 if (!list)
177 return NULL;
178
Barry Warsawc1cb3601996-12-12 22:16:21 +0000179 i = 0;
180 for (j = 0; fd2obj[j].sentinel >= 0; j++) {
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000181 fd = fd2obj[j].fd;
182 if (FD_ISSET(fd, set)) {
Guido van Rossum4f0fbf81996-06-12 04:22:53 +0000183#ifndef _MSC_VER
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000184 if (fd > FD_SETSIZE) {
185 PyErr_SetString(PyExc_SystemError,
186 "filedescriptor out of range returned in select()");
Barry Warsawc1cb3601996-12-12 22:16:21 +0000187 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000188 }
Guido van Rossum4f0fbf81996-06-12 04:22:53 +0000189#endif
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000190 o = fd2obj[j].obj;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000191 fd2obj[j].obj = NULL;
192 /* transfer ownership */
193 if (PyList_SetItem(list, i, o) < 0)
194 goto finally;
195
196 i++;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000197 }
198 }
199 return list;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000200 finally:
201 Py_DECREF(list);
202 return NULL;
Guido van Rossumed233a51992-06-23 09:07:03 +0000203}
Barry Warsawc1cb3601996-12-12 22:16:21 +0000204
Guido van Rossumed233a51992-06-23 09:07:03 +0000205
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000206static PyObject *
Guido van Rossumed233a51992-06-23 09:07:03 +0000207select_select(self, args)
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000208 PyObject *self;
209 PyObject *args;
Guido van Rossumed233a51992-06-23 09:07:03 +0000210{
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000211 pylist rfd2obj[FD_SETSIZE + 3];
212 pylist wfd2obj[FD_SETSIZE + 3];
213 pylist efd2obj[FD_SETSIZE + 3];
214 PyObject *ifdlist, *ofdlist, *efdlist;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000215 PyObject *ret = NULL;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000216 PyObject *tout = Py_None;
217 fd_set ifdset, ofdset, efdset;
218 double timeout;
219 struct timeval tv, *tvp;
220 int seconds;
221 int imax, omax, emax, max;
222 int n;
Guido van Rossumed233a51992-06-23 09:07:03 +0000223
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000224 /* convert arguments */
225 if (!PyArg_ParseTuple(args, "OOO|O",
226 &ifdlist, &ofdlist, &efdlist, &tout))
227 return NULL;
Guido van Rossumed233a51992-06-23 09:07:03 +0000228
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000229 if (tout == Py_None)
230 tvp = (struct timeval *)0;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000231 else if (!PyArg_Parse(tout, "d", &timeout)) {
232 PyErr_SetString(PyExc_TypeError,
233 "timeout must be a float or None");
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000234 return NULL;
Barry Warsawc1cb3601996-12-12 22:16:21 +0000235 }
Guido van Rossumc7a22701993-11-01 16:27:16 +0000236 else {
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000237 seconds = (int)timeout;
238 timeout = timeout - (double)seconds;
239 tv.tv_sec = seconds;
240 tv.tv_usec = (int)(timeout*1000000.0);
241 tvp = &tv;
Guido van Rossumc7a22701993-11-01 16:27:16 +0000242 }
Guido van Rossumed233a51992-06-23 09:07:03 +0000243
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000244 /* sanity check first three arguments */
245 if (!PyList_Check(ifdlist) ||
246 !PyList_Check(ofdlist) ||
247 !PyList_Check(efdlist))
248 {
249 PyErr_SetString(PyExc_TypeError,
250 "arguments 1-3 must be lists");
251 return NULL;
252 }
Guido van Rossumed233a51992-06-23 09:07:03 +0000253
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000254 /* Convert lists to fd_sets, and get maximum fd number
255 * propagates the Python exception set in list2set()
256 */
Barry Warsawc1cb3601996-12-12 22:16:21 +0000257 rfd2obj[0].sentinel = -1;
258 wfd2obj[0].sentinel = -1;
259 efd2obj[0].sentinel = -1;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000260 if ((imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0)
Barry Warsawc1cb3601996-12-12 22:16:21 +0000261 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000262 if ((omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0)
Barry Warsawc1cb3601996-12-12 22:16:21 +0000263 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000264 if ((emax=list2set(efdlist, &efdset, efd2obj)) < 0)
Barry Warsawc1cb3601996-12-12 22:16:21 +0000265 goto finally;
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000266 max = imax;
267 if (omax > max) max = omax;
268 if (emax > max) max = emax;
Guido van Rossumed233a51992-06-23 09:07:03 +0000269
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000270 Py_BEGIN_ALLOW_THREADS
271 n = select(max, &ifdset, &ofdset, &efdset, tvp);
272 Py_END_ALLOW_THREADS
Guido van Rossumed233a51992-06-23 09:07:03 +0000273
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000274 if (n < 0) {
275 PyErr_SetFromErrno(SelectError);
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000276 }
Barry Warsawc1cb3601996-12-12 22:16:21 +0000277 else if (n == 0) {
278 /* optimization */
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000279 ifdlist = PyList_New(0);
Barry Warsawc1cb3601996-12-12 22:16:21 +0000280 if (ifdlist) {
281 ret = Py_BuildValue("OOO", ifdlist, ifdlist, ifdlist);
282 Py_DECREF(ifdlist);
283 }
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000284 }
Barry Warsawc1cb3601996-12-12 22:16:21 +0000285 else {
286 /* any of these three calls can raise an exception. it's more
287 convenient to test for this after all three calls... but
288 is that acceptable?
289 */
290 ifdlist = set2list(&ifdset, rfd2obj);
291 ofdlist = set2list(&ofdset, wfd2obj);
292 efdlist = set2list(&efdset, efd2obj);
293 if (PyErr_Occurred())
294 ret = NULL;
295 else
296 ret = Py_BuildValue("OOO", ifdlist, ofdlist, efdlist);
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000297
Barry Warsawc1cb3601996-12-12 22:16:21 +0000298 Py_DECREF(ifdlist);
299 Py_DECREF(ofdlist);
300 Py_DECREF(efdlist);
301 }
302
303 finally:
304 reap_obj(rfd2obj);
305 reap_obj(wfd2obj);
306 reap_obj(efd2obj);
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000307 return ret;
Guido van Rossumed233a51992-06-23 09:07:03 +0000308}
309
310
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000311static PyMethodDef select_methods[] = {
312 {"select", select_select, 1},
313 {0, 0}, /* sentinel */
Guido van Rossumed233a51992-06-23 09:07:03 +0000314};
315
316
317void
318initselect()
319{
Barry Warsawe4ac0aa1996-12-12 00:04:35 +0000320 PyObject *m, *d;
321 m = Py_InitModule("select", select_methods);
322 d = PyModule_GetDict(m);
323 SelectError = PyString_FromString("select.error");
324 PyDict_SetItemString(d, "error", SelectError);
325 if (PyErr_Occurred())
326 Py_FatalError("Cannot initialize select module");
Guido van Rossumed233a51992-06-23 09:07:03 +0000327}