[Python-checkins] CVS: python/dist/src/Modules selectmodule.c,2.42,2.43
A.M. Kuchling
python-dev@python.org
Thu, 24 Aug 2000 18:15:37 -0700
Update of /cvsroot/python/python/dist/src/Modules
In directory slayer.i.sourceforge.net:/tmp/cvs-serv13765
Modified Files:
selectmodule.c
Log Message:
Add interface to poll() system call (SF patch #100852)
Index: selectmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/selectmodule.c,v
retrieving revision 2.42
retrieving revision 2.43
diff -C2 -r2.42 -r2.43
*** selectmodule.c 2000/07/31 15:28:04 2.42
--- selectmodule.c 2000/08/25 01:15:33 2.43
***************
*** 25,28 ****
--- 25,31 ----
#include <limits.h>
#endif
+ #ifdef HAVE_POLL_H
+ #include <poll.h>
+ #endif
#ifdef __sgi
***************
*** 300,303 ****
--- 303,584 ----
}
+ #ifdef HAVE_POLL
+ /*
+ * poll() support
+ */
+
+ typedef struct {
+ PyObject_HEAD
+ PyObject *dict;
+ int ufd_uptodate;
+ int ufd_len;
+ struct pollfd *ufds;
+ } pollObject;
+
+ staticforward 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 int
+ update_ufd_array(pollObject *self)
+ {
+ int i, j, 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 ((j = PyDict_Next(self->dict, &pos, &key, &value))) {
+ self->ufds[i].fd = PyInt_AsLong(key);
+ self->ufds[i].events = PyInt_AsLong(value);
+ i++;
+ }
+ self->ufd_uptodate = 1;
+ return 1;
+ }
+
+ static char 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 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;
+
+ if (!PyArg_ParseTuple(args, "O|i", &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. */
+ if ( (NULL == (key = PyInt_FromLong(fd))) ||
+ (NULL == (value = PyInt_FromLong(events))) ||
+ (PyDict_SetItem(self->dict, key, value)) == -1) {
+ return NULL;
+ }
+ self->ufd_uptodate = 0;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ static char 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 *args)
+ {
+ PyObject *o, *key;
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "O", &o)) {
+ return NULL;
+ }
+
+ 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;
+ }
+
+ static char 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_ParseTuple(args, "|O", &tout)) {
+ return NULL;
+ }
+
+ /* Check values for timeout */
+ if (tout == NULL || tout == Py_None)
+ timeout = -1;
+ else if (!PyArg_Parse(tout, "i", &timeout)) {
+ PyErr_SetString(PyExc_TypeError,
+ "timeout must be an integer or None");
+ 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 {
+ for (i = 0, j = 0; j < poll_result; j++) {
+ /* skip to the next fired descriptor */
+ while (!self->ufds[i].revents) {
+ i++;
+ }
+ /* if we hit a NULL return, set value to NULL
+ and break out of loop; code at end will
+ clean up result_list */
+ value = PyTuple_New(2);
+ if (value == NULL)
+ goto error;
+ num = PyInt_FromLong(self->ufds[i].fd);
+ if (num == NULL) {
+ Py_DECREF(value);
+ goto error;
+ }
+ PyTuple_SET_ITEM(value, 0, num);
+
+ num = PyInt_FromLong(self->ufds[i].revents);
+ if (num == NULL) {
+ Py_DECREF(value);
+ goto error;
+ }
+ PyTuple_SET_ITEM(value, 1, num);
+ if ((PyList_SetItem(result_list, j, value)) == -1) {
+ Py_DECREF(value);
+ goto error;
+ }
+ i++;
+ }
+ }
+ return result_list;
+
+ error:
+ Py_DECREF(result_list);
+ return NULL;
+ }
+
+ static PyMethodDef poll_methods[] = {
+ {"register", (PyCFunction)poll_register,
+ METH_VARARGS, poll_register_doc},
+ {"unregister", (PyCFunction)poll_unregister,
+ METH_VARARGS, poll_unregister_doc},
+ {"poll", (PyCFunction)poll_poll,
+ METH_VARARGS, poll_poll_doc},
+ {NULL, NULL} /* sentinel */
+ };
+
+ static pollObject *
+ newPollObject()
+ {
+ pollObject *self;
+ self = PyObject_New(pollObject, &poll_Type);
+ if (self == NULL)
+ return NULL;
+ /* ufd_uptodate is a Boolean, denoting whether the
+ array pointed to by ufds matches the contents of the dictionary. */
+ self->ufd_uptodate = 0;
+ self->ufds = NULL;
+ self->dict = PyDict_New();
+ if (self->dict == NULL) {
+ Py_DECREF(self);
+ return NULL;
+ }
+ return self;
+ }
+
+ static void
+ poll_dealloc(pollObject *self)
+ {
+ if (self->ufds != NULL)
+ PyMem_DEL(self->ufds);
+ Py_XDECREF(self->dict);
+ PyObject_Del(self);
+ }
+
+ static PyObject *
+ poll_getattr(pollObject *self, char *name)
+ {
+ return Py_FindMethod(poll_methods, (PyObject *)self, name);
+ }
+
+ statichere PyTypeObject poll_Type = {
+ /* The ob_type field must be initialized in the module init function
+ * to be portable to Windows without using C++. */
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "poll", /*tp_name*/
+ sizeof(pollObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)poll_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ (getattrfunc)poll_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ };
+
+ static char poll_doc[] =
+ "Returns a polling object, which supports registering and\n\
+ unregistering file descriptors, and then polling them for I/O events.";
+
+ static PyObject *
+ select_poll(PyObject *self, PyObject *args)
+ {
+ pollObject *rv;
+
+ if (!PyArg_ParseTuple(args, ":poll"))
+ return NULL;
+ rv = newPollObject();
+ if ( rv == NULL )
+ return NULL;
+ return (PyObject *)rv;
+ }
+ #endif /* HAVE_POLL */
+
static char select_doc[] =
"select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)\n\
***************
*** 323,329 ****
On Windows, only sockets are supported; on Unix, all file descriptors.";
-
static PyMethodDef select_methods[] = {
! {"select", select_select, 1, select_doc},
{0, 0}, /* sentinel */
};
--- 604,612 ----
On Windows, only sockets are supported; on Unix, all file descriptors.";
static PyMethodDef select_methods[] = {
! {"select", select_select, METH_VARARGS, select_doc},
! #ifdef HAVE_POLL
! {"poll", select_poll, METH_VARARGS, poll_doc},
! #endif /* HAVE_POLL */
{0, 0}, /* sentinel */
};
***************
*** 335,338 ****
--- 618,640 ----
On Windows, only sockets are supported; on Unix, all file descriptors.";
+ /*
+ * Convenience routine to export an integer value.
+ * For simplicity, errors (which are unlikely anyway) are ignored.
+ */
+
+ static void
+ insint(PyObject *d, char *name, int value)
+ {
+ PyObject *v = PyInt_FromLong((long) value);
+ if (v == NULL) {
+ /* Don't bother reporting this error */
+ PyErr_Clear();
+ }
+ else {
+ PyDict_SetItemString(d, name, v);
+ Py_DECREF(v);
+ }
+ }
+
DL_EXPORT(void)
initselect(void)
***************
*** 343,345 ****
--- 645,662 ----
SelectError = PyErr_NewException("select.error", NULL, NULL);
PyDict_SetItemString(d, "error", SelectError);
+ #ifdef HAVE_POLL
+ poll_Type.ob_type = &PyType_Type;
+ insint(d, "POLLIN", POLLIN);
+ insint(d, "POLLPRI", POLLPRI);
+ insint(d, "POLLOUT", POLLOUT);
+ insint(d, "POLLERR", POLLERR);
+ insint(d, "POLLHUP", POLLHUP);
+ insint(d, "POLLNVAL", POLLNVAL);
+
+ insint(d, "POLLRDNORM", POLLRDNORM);
+ insint(d, "POLLRDBAND", POLLRDBAND);
+ insint(d, "POLLWRNORM", POLLWRNORM);
+ insint(d, "POLLWRBAND", POLLWRBAND);
+ insint(d, "POLLMSG", POLLMSG);
+ #endif /* HAVE_POLL */
}