Kaydet (Commit) e4ac0aa6 authored tarafından Barry Warsaw's avatar Barry Warsaw

Several changes... Guido *please* take a look!

1. Renamed

2. Several coding styles were being used here, owing to the multiple
   contributors.  I tried to convert everything to standard "python"
   coding style for indentation, paren and brace placement, etc.

3. There were several potential error conditions that were never being
   checked, and where I saw them, I added checks of return values,
   etc.  I'm pretty sure I got them all.

4. There were some old-style (pre PyArg_ParseTuple) argument
   extraction and these were converted to use PyArg_ParseTuple.

All changes compile and run with the new test_select.py module, at
least on my Solaris/Sparc box.
üst 792c94a3
...@@ -30,14 +30,12 @@ PERFORMANCE OF THIS SOFTWARE. ...@@ -30,14 +30,12 @@ PERFORMANCE OF THIS SOFTWARE.
******************************************************************/ ******************************************************************/
/* select - Module containing unix select(2) call. /* select - Module containing unix select(2) call.
Under Unix, the file descriptors are small integers. Under Unix, the file descriptors are small integers.
Under Win32, select only exists for sockets, and sockets may Under Win32, select only exists for sockets, and sockets may
have any value except INVALID_SOCKET. have any value except INVALID_SOCKET.
*/ */
#include "allobjects.h" #include "Python.h"
#include "modsupport.h"
#include "ceval.h"
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
...@@ -57,196 +55,236 @@ extern void bzero(); ...@@ -57,196 +55,236 @@ extern void bzero();
#define SOCKET int #define SOCKET int
#endif #endif
static object *SelectError; static PyObject *SelectError;
typedef struct { /* list of Python objects and their file descriptor */ typedef struct { /* list of Python objects and their file descriptor */
object *obj; PyObject *obj;
SOCKET fd; SOCKET fd;
} pylist; } pylist;
/* returns -1 and sets the Python exception if an error occurred, otherwise
returns a number >= 0
*/
static int static int
list2set(list, set, fd2obj) list2set(list, set, fd2obj)
object *list; PyObject *list;
fd_set *set; fd_set *set;
pylist fd2obj[FD_SETSIZE + 3]; pylist fd2obj[FD_SETSIZE + 3];
{ {
int i, len, index, max = -1; int i, len, index, max = -1;
object *o, *filenomethod, *fno; PyObject *o, *fno;
SOCKET v; PyObject *meth;
SOCKET v;
index = 0; index = 0;
fd2obj[0].obj = (object*)0; /* set list to zero size */ fd2obj[0].obj = (PyObject*)0; /* set list to zero size */
FD_ZERO(set); FD_ZERO(set);
len = getlistsize(list); len = PyList_Size(list);
for( i=0; i<len; i++ ) { for (i=0; i<len; i++) {
o = getlistitem(list, i); o = PyList_GetItem(list, i);
if ( is_intobject(o) ) { if (PyInt_Check(o)) {
v = getintvalue(o); v = PyInt_AsLong(o);
} else if ( (filenomethod = getattr(o, "fileno")) != NULL ) { }
fno = call_object(filenomethod, NULL); else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL)
DECREF(filenomethod); {
if ( fno == NULL ) fno = PyEval_CallObject(meth, NULL);
return -1; Py_DECREF(meth);
if ( !is_intobject(fno) ) { if (fno == NULL)
err_badarg(); return -1;
DECREF(fno); if (!PyInt_Check(fno)) {
return -1; PyErr_SetString(PyExc_TypeError,
} "fileno method returned a non-integer");
v = getintvalue(fno); Py_DECREF(fno);
DECREF(fno); return -1;
} else { }
err_badarg(); v = PyInt_AsLong(fno);
return -1; Py_DECREF(fno);
} }
else {
PyErr_SetString(PyExc_TypeError,
"argument must be an int, or have a fileno() method."
);
return -1;
}
#ifdef _MSC_VER #ifdef _MSC_VER
max = 0; /* not used for Win32 */ max = 0; /* not used for Win32 */
#else #else
if ( v < 0 || v >= FD_SETSIZE ) { if (v < 0 || v >= FD_SETSIZE) {
err_setstr(ValueError, "filedescriptor out of range in select()"); PyErr_SetString(
return -1; PyExc_ValueError,
} "filedescriptor out of range in select()");
if ( v > max ) max = v; return -1;
}
if (v > max)
max = v;
#endif #endif
FD_SET(v, set); FD_SET(v, set);
/* add object and its file descriptor to the list */ /* add object and its file descriptor to the list */
if ( index >= FD_SETSIZE ) { if (index >= FD_SETSIZE) {
err_setstr(ValueError, "too many file descriptors in select()"); PyErr_SetString(
return -1; PyExc_ValueError,
"too many file descriptors in select()");
return -1;
}
fd2obj[index].obj = o;
fd2obj[index].fd = v;
fd2obj[++index].obj = (PyObject *)0; /* sentinel */
} }
fd2obj[index].obj = o; return max+1;
fd2obj[index].fd = v;
fd2obj[++index].obj = (object *)0; /* sentinel */
}
return max+1;
} }
static object * /* returns NULL and sets the Python exception if an error occurred */
static PyObject *
set2list(set, fd2obj) set2list(set, fd2obj)
fd_set *set; fd_set *set;
pylist fd2obj[FD_SETSIZE + 3]; pylist fd2obj[FD_SETSIZE + 3];
{ {
int j, num=0; int j, num=0;
object *list, *o; PyObject *list, *o;
SOCKET fd; SOCKET fd;
for(j=0; fd2obj[j].obj; j++) for (j=0; fd2obj[j].obj; j++)
if ( FD_ISSET(fd2obj[j].fd, set) ) if (FD_ISSET(fd2obj[j].fd, set))
num++; num++;
list = newlistobject(num);
num = 0; list = PyList_New(num);
for(j=0; fd2obj[j].obj; j++) { if (!list)
fd = fd2obj[j].fd; return NULL;
if ( FD_ISSET(fd, set) ) {
num = 0;
for (j=0; fd2obj[j].obj; j++) {
fd = fd2obj[j].fd;
if (FD_ISSET(fd, set)) {
#ifndef _MSC_VER #ifndef _MSC_VER
if ( fd > FD_SETSIZE ) { if (fd > FD_SETSIZE) {
err_setstr(SystemError, PyErr_SetString(PyExc_SystemError,
"filedescriptor out of range returned in select()"); "filedescriptor out of range returned in select()");
return NULL; return NULL;
} }
#endif #endif
o = fd2obj[j].obj; o = fd2obj[j].obj;
INCREF(o); Py_INCREF(o);
setlistitem(list, num, o); if (PyList_SetItem(list, num, o) < 0) {
num++; Py_DECREF(list);
} return NULL;
} }
return list; num++;
}
}
return list;
} }
static object * static PyObject *
select_select(self, args) select_select(self, args)
object *self; PyObject *self;
object *args; PyObject *args;
{ {
pylist rfd2obj[FD_SETSIZE + 3], wfd2obj[FD_SETSIZE + 3], efd2obj[FD_SETSIZE + 3]; pylist rfd2obj[FD_SETSIZE + 3];
object *ifdlist, *ofdlist, *efdlist; pylist wfd2obj[FD_SETSIZE + 3];
object *ret, *tout; pylist efd2obj[FD_SETSIZE + 3];
fd_set ifdset, ofdset, efdset; PyObject *ifdlist, *ofdlist, *efdlist;
double timeout; PyObject *ret;
struct timeval tv, *tvp; PyObject *tout = Py_None;
int seconds; fd_set ifdset, ofdset, efdset;
int imax, omax, emax, max; double timeout;
int n; struct timeval tv, *tvp;
int seconds;
int imax, omax, emax, max;
/* Get args. Looks funny because of optional timeout argument */ int n;
if ( getargs(args, "(OOOO)", &ifdlist, &ofdlist, &efdlist, &tout) ) {
if (tout == None) /* convert arguments */
tvp = (struct timeval *)0; if (!PyArg_ParseTuple(args, "OOO|O",
&ifdlist, &ofdlist, &efdlist, &tout))
return NULL;
if (tout == Py_None)
tvp = (struct timeval *)0;
else if (!PyArg_Parse(tout, "d;timeout must be float or None",
&timeout))
return NULL;
else { else {
if (!getargs(tout, "d;timeout must be float or None", &timeout)) seconds = (int)timeout;
return NULL; timeout = timeout - (double)seconds;
seconds = (int)timeout; tv.tv_sec = seconds;
timeout = timeout - (double)seconds; tv.tv_usec = (int)(timeout*1000000.0);
tv.tv_sec = seconds; tvp = &tv;
tv.tv_usec = (int)(timeout*1000000.0);
tvp = &tv;
} }
} else {
/* Doesn't have 4 args, that means no timeout */ /* sanity check first three arguments */
err_clear(); if (!PyList_Check(ifdlist) ||
if (!getargs(args, "(OOO)", &ifdlist, &ofdlist, &efdlist) ) !PyList_Check(ofdlist) ||
return 0; !PyList_Check(efdlist))
tvp = (struct timeval *)0; {
} PyErr_SetString(PyExc_TypeError,
if ( !is_listobject(ifdlist) || !is_listobject(ofdlist) || "arguments 1-3 must be lists");
!is_listobject(efdlist) ) { return NULL;
err_badarg(); }
return 0;
} /* Convert lists to fd_sets, and get maximum fd number
* propagates the Python exception set in list2set()
/* Convert lists to fd_sets, and get maximum fd number */ */
if( (imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0 ) if ((imax=list2set(ifdlist, &ifdset, rfd2obj)) < 0)
return 0; return NULL;
if( (omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0 ) if ((omax=list2set(ofdlist, &ofdset, wfd2obj)) < 0)
return 0; return NULL;
if( (emax=list2set(efdlist, &efdset, efd2obj)) < 0 ) if ((emax=list2set(efdlist, &efdset, efd2obj)) < 0)
return 0; return NULL;
max = imax; max = imax;
if ( omax > max ) max = omax; if (omax > max) max = omax;
if ( emax > max ) max = emax; if (emax > max) max = emax;
BGN_SAVE Py_BEGIN_ALLOW_THREADS
n = select(max, &ifdset, &ofdset, &efdset, tvp); n = select(max, &ifdset, &ofdset, &efdset, tvp);
END_SAVE Py_END_ALLOW_THREADS
if ( n < 0 ) { if (n < 0) {
err_errno(SelectError); PyErr_SetFromErrno(SelectError);
return 0; return NULL;
} }
if ( n == 0 ) { /* Speedup hack */ if (n == 0) { /* Speedup hack */
ifdlist = newlistobject(0); ifdlist = PyList_New(0);
ret = mkvalue("OOO", ifdlist, ifdlist, ifdlist); if (!ifdlist)
XDECREF(ifdlist); return NULL;
return ret; ret = Py_BuildValue("OOO", ifdlist, ifdlist, ifdlist);
} Py_XDECREF(ifdlist);
return ret;
ifdlist = set2list(&ifdset, rfd2obj); }
ofdlist = set2list(&ofdset, wfd2obj);
efdlist = set2list(&efdset, efd2obj); /* any of these three calls can raise an exception. it's more
ret = mkvalue("OOO", ifdlist, ofdlist, efdlist); convenient to test for this after all three calls... but is that
XDECREF(ifdlist); acceptable?
XDECREF(ofdlist); */
XDECREF(efdlist); ifdlist = set2list(&ifdset, rfd2obj);
return ret; ofdlist = set2list(&ofdset, wfd2obj);
efdlist = set2list(&efdset, efd2obj);
if (PyErr_Occurred())
ret = NULL;
else
ret = Py_BuildValue("OOO", ifdlist, ofdlist, efdlist);
Py_DECREF(ifdlist);
Py_DECREF(ofdlist);
Py_DECREF(efdlist);
return ret;
} }
static struct methodlist select_methods[] = { static PyMethodDef select_methods[] = {
{ "select", select_select }, {"select", select_select, 1},
{ 0, 0 }, {0, 0}, /* sentinel */
}; };
void void
initselect() initselect()
{ {
object *m, *d; PyObject *m, *d;
m = initmodule("select", select_methods); m = Py_InitModule("select", select_methods);
d = getmoduledict(m); d = PyModule_GetDict(m);
SelectError = newstringobject("select.error"); SelectError = PyString_FromString("select.error");
if ( SelectError == NULL || dictinsert(d, "error", SelectError) ) PyDict_SetItemString(d, "error", SelectError);
fatal("Cannot define select.error"); if (PyErr_Occurred())
Py_FatalError("Cannot initialize select module");
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment