diff options
Diffstat (limited to 'Modules/selectmodule.c')
-rw-r--r-- | Modules/selectmodule.c | 575 |
1 files changed, 497 insertions, 78 deletions
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 7863aaa4bb..952a0919d4 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -7,6 +7,14 @@ #include "Python.h" #include <structmember.h> +#ifdef HAVE_SYS_DEVPOLL_H +#include <sys/resource.h> +#include <sys/devpoll.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#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. @@ -54,8 +62,6 @@ extern void bzero(void *, int); # endif #endif -static PyObject *SelectError; - /* list of Python objects and their file descriptor */ typedef struct { PyObject *obj; /* owned reference */ @@ -68,8 +74,7 @@ reap_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; + Py_CLEAR(fd2obj[i].obj); } fd2obj[0].sentinel = -1; } @@ -198,9 +203,7 @@ select_select(PyObject *self, PyObject *args) 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; @@ -217,18 +220,31 @@ select_select(PyObject *self, PyObject *args) return NULL; } else { - timeout = PyFloat_AsDouble(tout); - if (timeout == -1 && PyErr_Occurred()) +#ifdef MS_WINDOWS + time_t sec; + if (_PyTime_ObjectToTimeval(tout, &sec, &tv.tv_usec) == -1) return NULL; - if (timeout > (double)LONG_MAX) { + assert(sizeof(tv.tv_sec) == sizeof(long)); +#if SIZEOF_TIME_T > SIZEOF_LONG + if (sec > LONG_MAX) { PyErr_SetString(PyExc_OverflowError, - "timeout period too long"); + "timeout is too large"); + return NULL; + } +#endif + tv.tv_sec = (long)sec; +#else + /* 64-bit OS X has struct timeval.tv_usec as an int (and thus still 4 + bytes as required), but no longer defined by a long. */ + long tv_usec; + if (_PyTime_ObjectToTimeval(tout, &tv.tv_sec, &tv_usec) == -1) + return NULL; + tv.tv_usec = tv_usec; +#endif + if (tv.tv_sec < 0) { + PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); return NULL; } - seconds = (long)timeout; - timeout = timeout - (double)seconds; - tv.tv_sec = seconds; - tv.tv_usec = (long)(timeout * 1E6); tvp = &tv; } @@ -267,11 +283,11 @@ select_select(PyObject *self, PyObject *args) #ifdef MS_WINDOWS if (n == SOCKET_ERROR) { - PyErr_SetExcFromWindowsErr(SelectError, WSAGetLastError()); + PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); } #else if (n < 0) { - PyErr_SetFromErrno(SelectError); + PyErr_SetFromErrno(PyExc_OSError); } #endif else { @@ -315,6 +331,7 @@ typedef struct { int ufd_uptodate; int ufd_len; struct pollfd *ufds; + int poll_running; } pollObject; static PyTypeObject poll_Type; @@ -343,7 +360,7 @@ update_ufd_array(pollObject *self) assert(i < self->ufd_len); /* Never overflow */ self->ufds[i].fd = (int)PyLong_AsLong(key); - self->ufds[i].events = (short)PyLong_AsLong(value); + self->ufds[i].events = (short)(unsigned short)PyLong_AsLong(value); i++; } assert(i == self->ufd_len); @@ -351,6 +368,24 @@ update_ufd_array(pollObject *self) return 1; } +static int +ushort_converter(PyObject *obj, void *ptr) +{ + unsigned long uval; + + uval = PyLong_AsUnsignedLong(obj); + if (uval == (unsigned long)-1 && PyErr_Occurred()) + return 0; + if (uval > USHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large for C unsigned short"); + return 0; + } + + *(unsigned short *)ptr = Py_SAFE_DOWNCAST(uval, unsigned long, unsigned short); + return 1; +} + PyDoc_STRVAR(poll_register_doc, "register(fd [, eventmask] ) -> None\n\n\ Register a file descriptor with the polling object.\n\ @@ -363,12 +398,11 @@ poll_register(pollObject *self, PyObject *args) { PyObject *o, *key, *value; int fd; - short events = POLLIN | POLLPRI | POLLOUT; + unsigned short events = POLLIN | POLLPRI | POLLOUT; int err; - if (!PyArg_ParseTuple(args, "O|h:register", &o, &events)) { + if (!PyArg_ParseTuple(args, "O|O&:register", &o, ushort_converter, &events)) return NULL; - } fd = PyObject_AsFileDescriptor(o); if (fd == -1) return NULL; @@ -406,12 +440,12 @@ static PyObject * poll_modify(pollObject *self, PyObject *args) { PyObject *o, *key, *value; - int fd, events; + int fd; + unsigned short events; int err; - if (!PyArg_ParseTuple(args, "Oi:modify", &o, &events)) { + if (!PyArg_ParseTuple(args, "OO&:modify", &o, ushort_converter, &events)) return NULL; - } fd = PyObject_AsFileDescriptor(o); if (fd == -1) return NULL; @@ -422,7 +456,7 @@ poll_modify(pollObject *self, PyObject *args) return NULL; if (PyDict_GetItem(self->dict, key) == NULL) { errno = ENOENT; - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); Py_DECREF(key); return NULL; } @@ -511,18 +545,29 @@ poll_poll(pollObject *self, PyObject *args) return NULL; } + /* Avoid concurrent poll() invocation, issue 8865 */ + if (self->poll_running) { + PyErr_SetString(PyExc_RuntimeError, + "concurrent poll() invocation"); + return NULL; + } + /* Ensure the ufd array is up to date */ if (!self->ufd_uptodate) if (update_ufd_array(self) == 0) return NULL; + self->poll_running = 1; + /* call poll() */ Py_BEGIN_ALLOW_THREADS poll_result = poll(self->ufds, self->ufd_len, timeout); Py_END_ALLOW_THREADS + self->poll_running = 0; + if (poll_result < 0) { - PyErr_SetFromErrno(SelectError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -597,6 +642,7 @@ newPollObject(void) array pointed to by ufds matches the contents of the dictionary. */ self->ufd_uptodate = 0; self->ufds = NULL; + self->poll_running = 0; self->dict = PyDict_New(); if (self->dict == NULL) { Py_DECREF(self); @@ -648,6 +694,339 @@ static PyTypeObject poll_Type = { poll_methods, /*tp_methods*/ }; +#ifdef HAVE_SYS_DEVPOLL_H +typedef struct { + PyObject_HEAD + int fd_devpoll; + int max_n_fds; + int n_fds; + struct pollfd *fds; +} 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; + + Py_BEGIN_ALLOW_THREADS + n = write(self->fd_devpoll, self->fds, size); + Py_END_ALLOW_THREADS + + if (n == -1 ) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + if (n < size) { + /* + ** Data writed to /dev/poll is a binary data structure. It is not + ** clear what to do if a partial write occurred. For now, raise + ** an exception and see if we actually found this problem in + ** the wild. + ** See http://bugs.python.org/issue6397. + */ + PyErr_Format(PyExc_IOError, "failed to write all pollfds. " + "Please, report at http://bugs.python.org/. " + "Data to report: Size tried: %d, actual size written: %d.", + size, n); + return -1; + } + return 0; +} + +static PyObject * +internal_devpoll_register(devpollObject *self, PyObject *args, int remove) +{ + PyObject *o; + int fd; + unsigned short events = POLLIN | POLLPRI | POLLOUT; + + if (!PyArg_ParseTuple(args, "O|O&:register", &o, ushort_converter, &events)) + return NULL; + + fd = PyObject_AsFileDescriptor(o); + if (fd == -1) return NULL; + + if (remove) { + self->fds[self->n_fds].fd = fd; + self->fds[self->n_fds].events = POLLREMOVE; + + if (++self->n_fds == self->max_n_fds) { + if (devpoll_flush(self)) + return NULL; + } + } + + self->fds[self->n_fds].fd = fd; + self->fds[self->n_fds].events = (signed short)events; + + if (++self->n_fds == self->max_n_fds) { + if (devpoll_flush(self)) + return NULL; + } + + Py_RETURN_NONE; +} + +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) +{ + return internal_devpoll_register(self, args, 0); +} + +PyDoc_STRVAR(devpoll_modify_doc, +"modify(fd[, eventmask]) -> None\n\n\ +Modify a possible 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 internal_devpoll_register(self, args, 1); +} + + +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 == self->max_n_fds) { + if (devpoll_flush(self)) + return NULL; + } + + Py_RETURN_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 poll_result, i; + long timeout; + PyObject *value, *num1, *num2; + + 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; + } + + if ((timeout < -1) || (timeout > INT_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "timeout is out of range"); + return NULL; + } + + if (devpoll_flush(self)) + return NULL; + + dvp.dp_fds = self->fds; + dvp.dp_nfds = self->max_n_fds; + 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++) { + num1 = PyLong_FromLong(self->fds[i].fd); + num2 = PyLong_FromLong(self->fds[i].revents); + if ((num1 == NULL) || (num2 == NULL)) { + Py_XDECREF(num1); + Py_XDECREF(num2); + goto error; + } + value = PyTuple_Pack(2, num1, num2); + Py_DECREF(num1); + Py_DECREF(num2); + if (value == NULL) + goto error; + 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, limit_result; + struct pollfd *fds; + struct rlimit limit; + + Py_BEGIN_ALLOW_THREADS + /* + ** If we try to process more that getrlimit() + ** fds, the kernel will give an error, so + ** we set the limit here. It is a dynamic + ** value, because we can change rlimit() anytime. + */ + limit_result = getrlimit(RLIMIT_NOFILE, &limit); + if (limit_result != -1) + fd_devpoll = open("/dev/poll", O_RDWR); + Py_END_ALLOW_THREADS + + if (limit_result == -1) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + if (fd_devpoll == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, "/dev/poll"); + return NULL; + } + + fds = PyMem_NEW(struct pollfd, limit.rlim_cur); + if (fds == NULL) { + close(fd_devpoll); + PyErr_NoMemory(); + return NULL; + } + + self = PyObject_New(devpollObject, &devpoll_Type); + if (self == NULL) { + close(fd_devpoll); + PyMem_DEL(fds); + return NULL; + } + self->fd_devpoll = fd_devpoll; + self->max_n_fds = limit.rlim_cur; + self->n_fds = 0; + self->fds = fds; + + return self; +} + +static void +devpoll_dealloc(devpollObject *self) +{ + Py_BEGIN_ALLOW_THREADS + close(self->fd_devpoll); + Py_END_ALLOW_THREADS + + PyMem_DEL(self->fds); + + 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."); @@ -658,6 +1037,19 @@ select_poll(PyObject *self, PyObject *unused) return (PyObject *)newPollObject(); } +#ifdef HAVE_SYS_DEVPOLL_H +PyDoc_STRVAR(devpoll_doc, +"Returns a polling object, which supports registering and\n\ +unregistering file descriptors, and then polling them for I/O events."); + +static PyObject * +select_devpoll(PyObject *self, PyObject *unused) +{ + return (PyObject *)newDevPollObject(); +} +#endif + + #ifdef __APPLE__ /* * On some systems poll() sets errno on invalid file descriptors. We test @@ -733,20 +1125,10 @@ pyepoll_internal_close(pyEpoll_Object *self) } static PyObject * -newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd) +newPyEpoll_Object(PyTypeObject *type, int sizehint, int flags, SOCKET fd) { pyEpoll_Object *self; - if (sizehint == -1) { - sizehint = FD_SETSIZE-1; - } - else if (sizehint < 1) { - PyErr_Format(PyExc_ValueError, - "sizehint must be greater zero, got %d", - sizehint); - return NULL; - } - assert(type != NULL && type->tp_alloc != NULL); self = (pyEpoll_Object *) type->tp_alloc(type, 0); if (self == NULL) @@ -754,6 +1136,11 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd) if (fd == -1) { Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_EPOLL_CREATE1 + if (flags) + self->epfd = epoll_create1(flags); + else +#endif self->epfd = epoll_create(sizehint); Py_END_ALLOW_THREADS } @@ -762,7 +1149,7 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd) } if (self->epfd < 0) { Py_DECREF(self); - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } return (PyObject *)self; @@ -772,14 +1159,18 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd) static PyObject * pyepoll_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - int sizehint = -1; - static char *kwlist[] = {"sizehint", NULL}; + int flags = 0, sizehint = FD_SETSIZE - 1; + static char *kwlist[] = {"sizehint", "flags", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:epoll", kwlist, - &sizehint)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:epoll", kwlist, + &sizehint, &flags)) return NULL; + if (sizehint < 0) { + PyErr_SetString(PyExc_ValueError, "negative sizehint"); + return NULL; + } - return newPyEpoll_Object(type, sizehint, -1); + return newPyEpoll_Object(type, sizehint, flags, -1); } @@ -795,7 +1186,7 @@ pyepoll_close(pyEpoll_Object *self) { errno = pyepoll_internal_close(self); if (errno < 0) { - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; @@ -837,7 +1228,7 @@ pyepoll_fromfd(PyObject *cls, PyObject *args) if (!PyArg_ParseTuple(args, "i:fromfd", &fd)) return NULL; - return newPyEpoll_Object((PyTypeObject*)cls, -1, fd); + return newPyEpoll_Object((PyTypeObject*)cls, FD_SETSIZE - 1, 0, fd); } PyDoc_STRVAR(pyepoll_fromfd_doc, @@ -888,7 +1279,7 @@ pyepoll_internal_ctl(int epfd, int op, PyObject *pfd, unsigned int events) } if (result < 0) { - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; @@ -912,7 +1303,7 @@ pyepoll_register(pyEpoll_Object *self, PyObject *args, PyObject *kwds) PyDoc_STRVAR(pyepoll_register_doc, "register(fd[, eventmask]) -> None\n\ \n\ -Registers a new fd or raises an IOError if the fd is already registered.\n\ +Registers a new fd or raises an OSError if the fd is already registered.\n\ fd is the target file descriptor of the operation.\n\ events is a bit set composed of the various EPOLL constants; the default\n\ is EPOLL_IN | EPOLL_OUT | EPOLL_PRI.\n\ @@ -1011,7 +1402,7 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds) nfds = epoll_wait(self->epfd, evs, maxevents, timeout); Py_END_ALLOW_THREADS if (nfds < 0) { - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); goto error; } @@ -1066,7 +1457,7 @@ static PyGetSetDef pyepoll_getsetlist[] = { }; PyDoc_STRVAR(pyepoll_doc, -"select.epoll([sizehint=-1])\n\ +"select.epoll(sizehint=-1, flags=0)\n\ \n\ Returns an epolling object\n\ \n\ @@ -1209,6 +1600,23 @@ static PyTypeObject kqueue_queue_Type; # error uintptr_t does not match int, long, or long long! #endif +/* + * kevent is not standard and its members vary across BSDs. + */ +#if !defined(__OpenBSD__) +# define IDENT_TYPE T_UINTPTRT +# define IDENT_CAST Py_intptr_t +# define DATA_TYPE T_INTPTRT +# define DATA_FMT_UNIT INTPTRT_FMT_UNIT +# define IDENT_AsType PyLong_AsUintptr_t +#else +# define IDENT_TYPE T_UINT +# define IDENT_CAST int +# define DATA_TYPE T_INT +# define DATA_FMT_UNIT "i" +# define IDENT_AsType PyLong_AsUnsignedLong +#endif + /* Unfortunately, we can't store python objects in udata, because * kevents in the kernel can be removed without warning, which would * forever lose the refcount on the object stored with it. @@ -1216,11 +1624,11 @@ static PyTypeObject kqueue_queue_Type; #define KQ_OFF(x) offsetof(kqueue_event_Object, x) static struct PyMemberDef kqueue_event_members[] = { - {"ident", T_UINTPTRT, KQ_OFF(e.ident)}, + {"ident", IDENT_TYPE, KQ_OFF(e.ident)}, {"filter", T_SHORT, KQ_OFF(e.filter)}, {"flags", T_USHORT, KQ_OFF(e.flags)}, {"fflags", T_UINT, KQ_OFF(e.fflags)}, - {"data", T_INTPTRT, KQ_OFF(e.data)}, + {"data", DATA_TYPE, KQ_OFF(e.data)}, {"udata", T_UINTPTRT, KQ_OFF(e.udata)}, {NULL} /* Sentinel */ }; @@ -1246,7 +1654,7 @@ kqueue_event_init(kqueue_event_Object *self, PyObject *args, PyObject *kwds) PyObject *pfd; static char *kwlist[] = {"ident", "filter", "flags", "fflags", "data", "udata", NULL}; - static char *fmt = "O|hhi" INTPTRT_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; + static char *fmt = "O|hHI" DATA_FMT_UNIT UINTPTRT_FMT_UNIT ":kevent"; EV_SET(&(self->e), 0, EVFILT_READ, EV_ADD, 0, 0, 0); /* defaults */ @@ -1256,8 +1664,12 @@ kqueue_event_init(kqueue_event_Object *self, PyObject *args, PyObject *kwds) return -1; } - if (PyLong_Check(pfd)) { - self->e.ident = PyLong_AsUintptr_t(pfd); + if (PyLong_Check(pfd) +#if IDENT_TYPE == T_UINT + && PyLong_AsUnsignedLong(pfd) <= UINT_MAX +#endif + ) { + self->e.ident = IDENT_AsType(pfd); } else { self->e.ident = PyObject_AsFileDescriptor(pfd); @@ -1285,10 +1697,10 @@ kqueue_event_richcompare(kqueue_event_Object *s, kqueue_event_Object *o, Py_TYPE(s)->tp_name, Py_TYPE(o)->tp_name); return NULL; } - if (((result = s->e.ident - o->e.ident) == 0) && + if (((result = (IDENT_CAST)(s->e.ident - o->e.ident)) == 0) && ((result = s->e.filter - o->e.filter) == 0) && ((result = s->e.flags - o->e.flags) == 0) && - ((result = s->e.fflags - o->e.fflags) == 0) && + ((result = (int)(s->e.fflags - o->e.fflags)) == 0) && ((result = s->e.data - o->e.data) == 0) && ((result = s->e.udata - o->e.udata) == 0) ) { @@ -1402,7 +1814,7 @@ newKqueue_Object(PyTypeObject *type, SOCKET fd) } if (self->kqfd < 0) { Py_DECREF(self); - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } return (PyObject *)self; @@ -1434,7 +1846,7 @@ kqueue_queue_close(kqueue_queue_Object *self) { errno = kqueue_queue_internal_close(self); if (errno < 0) { - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; @@ -1497,7 +1909,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) PyObject *result = NULL; struct kevent *evl = NULL; struct kevent *chl = NULL; - struct timespec timeoutspec; + struct timespec timeout; struct timespec *ptimeoutspec; if (self->kqfd < 0) @@ -1517,28 +1929,16 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) ptimeoutspec = NULL; } else if (PyNumber_Check(otimeout)) { - double timeout; - long seconds; - - timeout = PyFloat_AsDouble(otimeout); - if (timeout == -1 && PyErr_Occurred()) + if (_PyTime_ObjectToTimespec(otimeout, + &timeout.tv_sec, &timeout.tv_nsec) == -1) return NULL; - if (timeout > (double)LONG_MAX) { - PyErr_SetString(PyExc_OverflowError, - "timeout period too long"); - return NULL; - } - if (timeout < 0) { + + if (timeout.tv_sec < 0) { PyErr_SetString(PyExc_ValueError, "timeout must be positive or None"); return NULL; } - - seconds = (long)timeout; - timeout = timeout - (double)seconds; - timeoutspec.tv_sec = seconds; - timeoutspec.tv_nsec = (long)(timeout * 1E9); - ptimeoutspec = &timeoutspec; + ptimeoutspec = &timeout; } else { PyErr_Format(PyExc_TypeError, @@ -1715,6 +2115,11 @@ static PyTypeObject kqueue_queue_Type = { }; #endif /* HAVE_KQUEUE */ + + + + + /* ************************************************************************ */ PyDoc_STRVAR(select_doc, @@ -1746,6 +2151,9 @@ static PyMethodDef select_methods[] = { #if defined(HAVE_POLL) && !defined(HAVE_BROKEN_POLL) {"poll", select_poll, METH_NOARGS, poll_doc}, #endif /* HAVE_POLL */ +#ifdef HAVE_SYS_DEVPOLL_H + {"devpoll", select_devpoll, METH_NOARGS, devpoll_doc}, +#endif {0, 0}, /* sentinel */ }; @@ -1768,6 +2176,9 @@ static struct PyModuleDef selectmodule = { NULL }; + + + PyMODINIT_FUNC PyInit_select(void) { @@ -1776,9 +2187,8 @@ PyInit_select(void) if (m == NULL) return NULL; - SelectError = PyErr_NewException("select.error", NULL, NULL); - Py_INCREF(SelectError); - PyModule_AddObject(m, "error", SelectError); + Py_INCREF(PyExc_OSError); + PyModule_AddObject(m, "error", PyExc_OSError); #ifdef PIPE_BUF #ifdef HAVE_BROKEN_PIPE_BUF @@ -1825,6 +2235,11 @@ PyInit_select(void) } #endif /* HAVE_POLL */ +#ifdef HAVE_SYS_DEVPOLL_H + if (PyType_Ready(&devpoll_Type) < 0) + return NULL; +#endif + #ifdef HAVE_EPOLL Py_TYPE(&pyEpoll_Type) = &PyType_Type; if (PyType_Ready(&pyEpoll_Type) < 0) @@ -1849,6 +2264,10 @@ PyInit_select(void) PyModule_AddIntConstant(m, "EPOLLWRNORM", EPOLLWRNORM); PyModule_AddIntConstant(m, "EPOLLWRBAND", EPOLLWRBAND); PyModule_AddIntConstant(m, "EPOLLMSG", EPOLLMSG); + +#ifdef EPOLL_CLOEXEC + PyModule_AddIntConstant(m, "EPOLL_CLOEXEC", EPOLL_CLOEXEC); +#endif #endif /* HAVE_EPOLL */ #ifdef HAVE_KQUEUE |