diff -r fbba3ecc92dc -r 0ee4386d8f51 Modules/selectmodule.c --- a/Modules/selectmodule.c Wed Oct 26 01:42:30 2011 +0200 +++ b/Modules/selectmodule.c Wed Oct 26 19:04:49 2011 +0200 @@ -7,6 +7,13 @@ #include "Python.h" #include +#ifdef HAVE_SYS_DEVPOLL_H +#include +#include +#include +#include +#endif + #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. @@ -648,6 +655,280 @@ poll_methods, /*tp_methods*/ }; +#ifdef HAVE_SYS_DEVPOLL_H +#define SIZE_DEVPOLL 32 +typedef struct { + PyObject_HEAD + PyObject *dict; + int fd_devpoll; + int n_fds; + struct pollfd fds[SIZE_DEVPOLL]; +} devpollObject; + +static PyTypeObject devpoll_Type; + +static int devpoll_flush(devpollObject *self) +{ + int size, n; + + if (!self->n_fds) return 0; + + size = sizeof(struct pollfd)*self->n_fds; + self->n_fds = 0; + n = write(self->fd_devpoll, &(self->fds), size); + if (n == -1 ) { + PyErr_SetFromErrno(PyExc_IOError); + return !0; + } + if (n < size) { + PyErr_SetString(PyExc_IOError, "failed to write all pollfds"); + return !0; + } + return 0; +} + +PyDoc_STRVAR(devpoll_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 * +devpoll_register(devpollObject *self, PyObject *args) +{ + PyObject *o; + int fd, events = POLLIN | POLLPRI | POLLOUT; + + if (!PyArg_ParseTuple(args, "O|i:register", &o, &events)) { + return NULL; + } + + fd = PyObject_AsFileDescriptor(o); + if (fd == -1) return NULL; + + /* First we remove because the implicit *OR* (man poll(7d)) */ + self->fds[self->n_fds].fd = fd; + self->fds[self->n_fds].events = POLLREMOVE; + + if (++self->n_fds == SIZE_DEVPOLL) { + if (devpoll_flush(self)) + return NULL; + } + + self->fds[self->n_fds].fd = fd; + self->fds[self->n_fds].events = events; + + if (++self->n_fds == SIZE_DEVPOLL) { + if (devpoll_flush(self)) + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(devpoll_modify_doc, +"modify(fd, eventmask) -> None\n\n\ +Modify an already registered file descriptor.\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 * +devpoll_modify(devpollObject *self, PyObject *args) +{ + return devpoll_register(self, args); +} + + +PyDoc_STRVAR(devpoll_unregister_doc, +"unregister(fd) -> None\n\n\ +Remove a file descriptor being tracked by the polling object."); + +static PyObject * +devpoll_unregister(devpollObject *self, PyObject *o) +{ + int fd; + + fd = PyObject_AsFileDescriptor( o ); + if (fd == -1) + return NULL; + + self->fds[self->n_fds].fd = fd; + self->fds[self->n_fds].events = POLLREMOVE; + + if (++self->n_fds == SIZE_DEVPOLL) { + if (devpoll_flush(self)) + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(devpoll_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 * +devpoll_poll(devpollObject *self, PyObject *args) +{ + struct dvpoll dvp; + PyObject *result_list = NULL, *tout = NULL; + int timeout = 0, poll_result, i; + PyObject *value = NULL, *num = NULL; + + if (devpoll_flush(self)) + return 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_Long(tout); + if (!tout) + return NULL; + timeout = PyLong_AsLong(tout); + Py_DECREF(tout); + if (timeout == -1 && PyErr_Occurred()) + return NULL; + } + + dvp.dp_fds = &(self->fds[0]); + dvp.dp_nfds = SIZE_DEVPOLL; + dvp.dp_timeout = timeout; + + /* call devpoll() */ + Py_BEGIN_ALLOW_THREADS + poll_result = ioctl(self->fd_devpoll, DP_POLL, &dvp); + Py_END_ALLOW_THREADS + + if (poll_result < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + /* build the result list */ + + result_list = PyList_New(poll_result); + if (!result_list) + return NULL; + else { + for (i = 0; i < poll_result; i++) { + value = PyTuple_New(2); + if (value == NULL) + goto error; + num = PyLong_FromLong(self->fds[i].fd); + if (num == NULL) { + Py_DECREF(value); + goto error; + } + PyTuple_SET_ITEM(value, 0, num); + num = PyLong_FromLong(self->fds[i].revents); + if (num == NULL) { + Py_DECREF(value); + goto error; + } + PyTuple_SET_ITEM(value, 1, num); + if ((PyList_SetItem(result_list, i, value)) == -1) { + Py_DECREF(value); + goto error; + } + } + } + return result_list; + + error: + Py_DECREF(result_list); + return NULL; +} + +static PyMethodDef devpoll_methods[] = { + {"register", (PyCFunction)devpoll_register, + METH_VARARGS, devpoll_register_doc}, + {"modify", (PyCFunction)devpoll_modify, + METH_VARARGS, devpoll_modify_doc}, + {"unregister", (PyCFunction)devpoll_unregister, + METH_O, devpoll_unregister_doc}, + {"poll", (PyCFunction)devpoll_poll, + METH_VARARGS, devpoll_poll_doc}, + {NULL, NULL} /* sentinel */ +}; + +static devpollObject * +newDevPollObject(void) +{ + devpollObject *self; + int fd_devpoll; + + fd_devpoll = open("/dev/poll", O_RDWR); + if (fd_devpoll == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, "/dev/poll"); + return NULL; + } + self = PyObject_New(devpollObject, &devpoll_Type); + if (self == NULL) + return NULL; + self->fd_devpoll = fd_devpoll; + self->n_fds = 0; + return self; +} + +static void +devpoll_dealloc(devpollObject *self) +{ + close(self->fd_devpoll); + PyObject_Del(self); +} + +static PyTypeObject devpoll_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyVarObject_HEAD_INIT(NULL, 0) + "select.devpoll", /*tp_name*/ + sizeof(devpollObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)devpoll_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + devpoll_methods, /*tp_methods*/ +}; +#endif /* HAVE_SYS_DEVPOLL_H */ + + + PyDoc_STRVAR(poll_doc, "Returns a polling object, which supports registering and\n\ unregistering file descriptors, and then polling them for I/O events."); @@ -655,7 +936,11 @@ static PyObject * select_poll(PyObject *self, PyObject *unused) { +#ifdef HAVE_SYS_DEVPOLL_H + return (PyObject *)newDevPollObject(); +#else return (PyObject *)newPollObject(); +#endif } #ifdef __APPLE__ @@ -1715,6 +2000,11 @@ }; #endif /* HAVE_KQUEUE */ + + + + + /* ************************************************************************ */ PyDoc_STRVAR(select_doc, @@ -1768,6 +2058,9 @@ NULL }; + + + PyMODINIT_FUNC PyInit_select(void) { @@ -1821,6 +2114,17 @@ #ifdef POLLMSG PyModule_AddIntConstant(m, "POLLMSG", POLLMSG); #endif + +#ifdef HAVE_SYS_DEVPOLL_H + if (PyType_Ready(&devpoll_Type) < 0) + return NULL; + + Py_INCREF(Py_True); + PyModule_AddObject(m, "isdevpoll", Py_True); +#else + Py_INCREF(Py_False); + PyModule_AddObject(m, "isdevpoll", Py_False); +#endif /* HAVE_SYS_DEVPOLL_H */ } #endif /* HAVE_POLL */ diff -r fbba3ecc92dc -r 0ee4386d8f51 configure --- a/configure Wed Oct 26 01:42:30 2011 +0200 +++ b/configure Wed Oct 26 19:04:49 2011 +0200 @@ -6139,12 +6139,13 @@ for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \ fcntl.h grp.h \ -ieeefp.h io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \ +ieeefp.h io.h langinfo.h libintl.h ncurses.h process.h pthread.h \ sched.h shadow.h signal.h stdint.h stropts.h termios.h \ unistd.h utime.h \ -sys/audioio.h sys/xattr.h sys/bsdtty.h sys/epoll.h sys/event.h sys/file.h sys/loadavg.h \ +poll.h sys/devpoll.h sys/epoll.h sys/poll.h \ +sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/loadavg.h \ sys/lock.h sys/mkdev.h sys/modem.h \ -sys/param.h sys/poll.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ +sys/param.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/termio.h sys/time.h \ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ diff -r fbba3ecc92dc -r 0ee4386d8f51 configure.in --- a/configure.in Wed Oct 26 01:42:30 2011 +0200 +++ b/configure.in Wed Oct 26 19:04:49 2011 +0200 @@ -1329,12 +1329,13 @@ AC_HEADER_STDC AC_CHECK_HEADERS(asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \ fcntl.h grp.h \ -ieeefp.h io.h langinfo.h libintl.h ncurses.h poll.h process.h pthread.h \ +ieeefp.h io.h langinfo.h libintl.h ncurses.h process.h pthread.h \ sched.h shadow.h signal.h stdint.h stropts.h termios.h \ unistd.h utime.h \ -sys/audioio.h sys/xattr.h sys/bsdtty.h sys/epoll.h sys/event.h sys/file.h sys/loadavg.h \ +poll.h sys/devpoll.h sys/epoll.h sys/poll.h \ +sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/loadavg.h \ sys/lock.h sys/mkdev.h sys/modem.h \ -sys/param.h sys/poll.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ +sys/param.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/termio.h sys/time.h \ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ diff -r fbba3ecc92dc -r 0ee4386d8f51 pyconfig.h.in --- a/pyconfig.h.in Wed Oct 26 01:42:30 2011 +0200 +++ b/pyconfig.h.in Wed Oct 26 19:04:49 2011 +0200 @@ -587,6 +587,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_DEVPOLL_H + /* Define to 1 if you have the `posix_fadvise' function. */ #undef HAVE_POSIX_FADVISE