734 lines · 17.5 KB · C
RawDownload
/* select - Module containing unix select(2) call.   Under Unix, the file descriptors are small integers.   Under Win32, select only exists for sockets, and sockets may   have any value except INVALID_SOCKET.   Under BeOS, we suffer the same dichotomy as Win32; sockets can be anything   >= 0.*/ #include "Python.h" #ifdef __APPLE__    /* Perform runtime testing for a broken poll on OSX to make it easier     * to use the same binary on multiple releases of the OS.     */#undef HAVE_BROKEN_POLL#endif /* Windows #defines FD_SETSIZE to 64 if FD_SETSIZE isn't already defined.   64 is too small (too many people have bumped into that limit).   Here we boost it.   Users who want even more than the boosted limit should #define   FD_SETSIZE higher before this; e.g., via compiler /D switch.*/#if defined(MS_WINDOWS) && !defined(FD_SETSIZE)#define FD_SETSIZE 512#endif  #if defined(HAVE_POLL_H)#include <poll.h>#elif defined(HAVE_SYS_POLL_H)#include <sys/poll.h>#endif #ifdef __sgi/* This is missing from unistd.h */extern void bzero(void *, int);#endif #ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif #if defined(PYOS_OS2) && !defined(PYCC_GCC)#include <sys/time.h>#include <utils.h>#endif #ifdef MS_WINDOWS#  include <winsock.h>#else#  define SOCKET int#  ifdef __BEOS__#    include <net/socket.h>#  elif defined(__VMS)#    include <socket.h>#  endif#endif  static PyObject *SelectError; /* list of Python objects and their file descriptor */typedef struct {	PyObject *obj;			     /* owned reference */	SOCKET fd;	int sentinel;			     /* -1 == sentinel */} pylist; static voidreap_obj(pylist fd2obj[FD_SETSIZE + 1]){	int i;	for (i = 0; i < FD_SETSIZE + 1 && fd2obj[i].sentinel >= 0; i++) {		Py_XDECREF(fd2obj[i].obj);		fd2obj[i].obj = NULL;	}	fd2obj[0].sentinel = -1;}  /* returns -1 and sets the Python exception if an error occurred, otherwise   returns a number >= 0*/static intseq2set(PyObject *seq, fd_set *set, pylist fd2obj[FD_SETSIZE + 1]){	int i;	int max = -1;	int index = 0;        int len = -1;        PyObject* fast_seq = NULL;	PyObject* o = NULL; 	fd2obj[0].obj = (PyObject*)0;	     /* set list to zero size */	FD_ZERO(set);         fast_seq=PySequence_Fast(seq, "arguments 1-3 must be sequences");        if (!fast_seq)            return -1;         len = PySequence_Fast_GET_SIZE(fast_seq); 	for (i = 0; i < len; i++)  {		SOCKET v; 		/* any intervening fileno() calls could decr this refcnt */		if (!(o = PySequence_Fast_GET_ITEM(fast_seq, i)))                    return -1; 		Py_INCREF(o);		v = PyObject_AsFileDescriptor( o );		if (v == -1) goto finally; #if defined(_MSC_VER)		max = 0;		     /* not used for Win32 */#else  /* !_MSC_VER */		if (v < 0 || v >= FD_SETSIZE) {			PyErr_SetString(PyExc_ValueError,				    "filedescriptor out of range in select()");			goto finally;		}		if (v > max)			max = v;#endif /* _MSC_VER */		FD_SET(v, set); 		/* add object and its file descriptor to the list */		if (index >= FD_SETSIZE) {			PyErr_SetString(PyExc_ValueError,				      "too many file descriptors in select()");			goto finally;		}		fd2obj[index].obj = o;		fd2obj[index].fd = v;		fd2obj[index].sentinel = 0;		fd2obj[++index].sentinel = -1;	}        Py_DECREF(fast_seq);	return max+1;   finally:	Py_XDECREF(o);        Py_DECREF(fast_seq);	return -1;} /* returns NULL and sets the Python exception if an error occurred */static PyObject *set2list(fd_set *set, pylist fd2obj[FD_SETSIZE + 1]){	int i, j, count=0;	PyObject *list, *o;	SOCKET fd; 	for (j = 0; fd2obj[j].sentinel >= 0; j++) {		if (FD_ISSET(fd2obj[j].fd, set))			count++;	}	list = PyList_New(count);	if (!list)		return NULL; 	i = 0;	for (j = 0; fd2obj[j].sentinel >= 0; j++) {		fd = fd2obj[j].fd;		if (FD_ISSET(fd, set)) {#ifndef _MSC_VER			if (fd > FD_SETSIZE) {				PyErr_SetString(PyExc_SystemError,			   "filedescriptor out of range returned in select()");				goto finally;			}#endif			o = fd2obj[j].obj;			fd2obj[j].obj = NULL;			/* transfer ownership */			if (PyList_SetItem(list, i, o) < 0)				goto finally; 			i++;		}	}	return list;  finally:	Py_DECREF(list);	return NULL;} #undef SELECT_USES_HEAP#if FD_SETSIZE > 1024#define SELECT_USES_HEAP#endif /* FD_SETSIZE > 1024 */ static PyObject *select_select(PyObject *self, PyObject *args){#ifdef SELECT_USES_HEAP	pylist *rfd2obj, *wfd2obj, *efd2obj;#else  /* !SELECT_USES_HEAP */	/* XXX: All this should probably be implemented as follows:	 * - find the highest descriptor we're interested in	 * - add one	 * - that's the size	 * See: Stevens, APitUE, $12.5.1	 */	pylist rfd2obj[FD_SETSIZE + 1];	pylist wfd2obj[FD_SETSIZE + 1];	pylist efd2obj[FD_SETSIZE + 1];#endif /* SELECT_USES_HEAP */	PyObject *ifdlist, *ofdlist, *efdlist;	PyObject *ret = NULL;	PyObject *tout = Py_None;	fd_set ifdset, ofdset, efdset;	double timeout;	struct timeval tv, *tvp;	long seconds;	int imax, omax, emax, max;	int n; 	/* convert arguments */	if (!PyArg_UnpackTuple(args, "select", 3, 4,			      &ifdlist, &ofdlist, &efdlist, &tout))		return NULL; 	if (tout == Py_None)		tvp = (struct timeval *)0;	else if (!PyNumber_Check(tout)) {		PyErr_SetString(PyExc_TypeError,				"timeout must be a float or None");		return NULL;	}	else {		timeout = PyFloat_AsDouble(tout);		if (timeout == -1 && PyErr_Occurred())			return NULL;		if (timeout > (double)LONG_MAX) {			PyErr_SetString(PyExc_OverflowError,					"timeout period too long");			return NULL;		}		seconds = (long)timeout;		timeout = timeout - (double)seconds;		tv.tv_sec = seconds;		tv.tv_usec = (long)(timeout*1000000.0);		tvp = &tv;	}  #ifdef SELECT_USES_HEAP	/* Allocate memory for the lists */	rfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1);	wfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1);	efd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1);	if (rfd2obj == NULL || wfd2obj == NULL || efd2obj == NULL) {		if (rfd2obj) PyMem_DEL(rfd2obj);		if (wfd2obj) PyMem_DEL(wfd2obj);		if (efd2obj) PyMem_DEL(efd2obj);		return PyErr_NoMemory();	}#endif /* SELECT_USES_HEAP */	/* Convert sequences to fd_sets, and get maximum fd number	 * propagates the Python exception set in seq2set()	 */	rfd2obj[0].sentinel = -1;	wfd2obj[0].sentinel = -1;	efd2obj[0].sentinel = -1;	if ((imax=seq2set(ifdlist, &ifdset, rfd2obj)) < 0) 		goto finally;	if ((omax=seq2set(ofdlist, &ofdset, wfd2obj)) < 0) 		goto finally;	if ((emax=seq2set(efdlist, &efdset, efd2obj)) < 0) 		goto finally;	max = imax;	if (omax > max) max = omax;	if (emax > max) max = emax; 	Py_BEGIN_ALLOW_THREADS	n = select(max, &ifdset, &ofdset, &efdset, tvp);	Py_END_ALLOW_THREADS #ifdef MS_WINDOWS	if (n == SOCKET_ERROR) {		PyErr_SetExcFromWindowsErr(SelectError, WSAGetLastError());	}#else	if (n < 0) {		PyErr_SetFromErrno(SelectError);	}#endif	else if (n == 0) {                /* optimization */		ifdlist = PyList_New(0);		if (ifdlist) {			ret = PyTuple_Pack(3, ifdlist, ifdlist, ifdlist);			Py_DECREF(ifdlist);		}	}	else {		/* any of these three calls can raise an exception.  it's more		   convenient to test for this after all three calls... but		   is that acceptable?		*/		ifdlist = set2list(&ifdset, rfd2obj);		ofdlist = set2list(&ofdset, wfd2obj);		efdlist = set2list(&efdset, efd2obj);		if (PyErr_Occurred())			ret = NULL;		else			ret = PyTuple_Pack(3, ifdlist, ofdlist, efdlist); 		Py_DECREF(ifdlist);		Py_DECREF(ofdlist);		Py_DECREF(efdlist);	}	  finally:	reap_obj(rfd2obj);	reap_obj(wfd2obj);	reap_obj(efd2obj);#ifdef SELECT_USES_HEAP	PyMem_DEL(rfd2obj);	PyMem_DEL(wfd2obj);	PyMem_DEL(efd2obj);#endif /* SELECT_USES_HEAP */	return ret;} #if defined(HAVE_POLL) && !defined(HAVE_BROKEN_POLL)/*  * poll() support */ typedef struct {	PyObject_HEAD	PyObject *dict;	int ufd_uptodate; 	int ufd_len;        struct pollfd *ufds;} pollObject; static PyTypeObject poll_Type; /* Update the malloc'ed array of pollfds to match the dictionary    contained within a pollObject.  Return 1 on success, 0 on an error.*/ static intupdate_ufd_array(pollObject *self){	Py_ssize_t i, pos;	PyObject *key, *value; 	self->ufd_len = PyDict_Size(self->dict);	PyMem_Resize(self->ufds, struct pollfd, self->ufd_len);	if (self->ufds == NULL) {		PyErr_NoMemory();		return 0;	} 	i = pos = 0;	while (PyDict_Next(self->dict, &pos, &key, &value)) {		self->ufds[i].fd = PyInt_AsLong(key);		self->ufds[i].events = (short)PyInt_AsLong(value);		i++;	}	self->ufd_uptodate = 1;	return 1;} PyDoc_STRVAR(poll_register_doc,"register(fd [, eventmask] ) -> None\n\n\Register a file descriptor with the polling object.\n\fd -- either an integer, or an object with a fileno() method returning an\n\      int.\n\events -- an optional bitmask describing the type of events to check for"); static PyObject *poll_register(pollObject *self, PyObject *args) {	PyObject *o, *key, *value;	int fd, events = POLLIN | POLLPRI | POLLOUT;	int err; 	if (!PyArg_ParseTuple(args, "O|i:register", &o, &events)) {		return NULL;	}  	fd = PyObject_AsFileDescriptor(o);	if (fd == -1) return NULL; 	/* Add entry to the internal dictionary: the key is the 	   file descriptor, and the value is the event mask. */	key = PyInt_FromLong(fd);	if (key == NULL)		return NULL;	value = PyInt_FromLong(events);	if (value == NULL) {		Py_DECREF(key);		return NULL;	}	err = PyDict_SetItem(self->dict, key, value);	Py_DECREF(key);	Py_DECREF(value);	if (err < 0)		return NULL; 	self->ufd_uptodate = 0;		       	Py_INCREF(Py_None);	return Py_None;} PyDoc_STRVAR(poll_unregister_doc,"unregister(fd) -> None\n\n\Remove a file descriptor being tracked by the polling object."); static PyObject *poll_unregister(pollObject *self, PyObject *o) {	PyObject *key;	int fd; 	fd = PyObject_AsFileDescriptor( o );	if (fd == -1) 		return NULL; 	/* Check whether the fd is already in the array */	key = PyInt_FromLong(fd);	if (key == NULL) 		return NULL; 	if (PyDict_DelItem(self->dict, key) == -1) {		Py_DECREF(key);		/* This will simply raise the KeyError set by PyDict_DelItem		   if the file descriptor isn't registered. */		return NULL;	} 	Py_DECREF(key);	self->ufd_uptodate = 0; 	Py_INCREF(Py_None);	return Py_None;} PyDoc_STRVAR(poll_poll_doc,"poll( [timeout] ) -> list of (fd, event) 2-tuples\n\n\Polls the set of registered file descriptors, returning a list containing \n\any descriptors that have events or errors to report."); static PyObject *poll_poll(pollObject *self, PyObject *args) {	PyObject *result_list = NULL, *tout = NULL;	int timeout = 0, poll_result, i, j;	PyObject *value = NULL, *num = NULL; 	if (!PyArg_UnpackTuple(args, "poll", 0, 1, &tout)) {		return NULL;	} 	/* Check values for timeout */	if (tout == NULL || tout == Py_None)		timeout = -1;	else if (!PyNumber_Check(tout)) {		PyErr_SetString(PyExc_TypeError,				"timeout must be an integer or None");		return NULL;	}	else {		tout = PyNumber_Int(tout);		if (!tout)			return NULL;		timeout = PyInt_AsLong(tout);		Py_DECREF(tout);		if (timeout == -1 && PyErr_Occurred())			return NULL;	} 	/* Ensure the ufd array is up to date */	if (!self->ufd_uptodate) 		if (update_ufd_array(self) == 0)			return NULL; 	/* call poll() */	Py_BEGIN_ALLOW_THREADS;	poll_result = poll(self->ufds, self->ufd_len, timeout);	Py_END_ALLOW_THREADS; 	if (poll_result < 0) {		PyErr_SetFromErrno(SelectError);		return NULL;	}        	/* build the result list */  	result_list = PyList_New(poll_result);	if (!result_list) 		return NULL;	else {

Lines 1–500 of 734.