mirror of https://github.com/python/cpython
Issue #6397: Support '/dev/poll' polling objects in select module, under Solaris & derivatives.
This commit is contained in:
parent
d5d4406c8e
commit
d8b9ae6e8f
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
|
|
||||||
This module provides access to the :c:func:`select` and :c:func:`poll` functions
|
This module provides access to the :c:func:`select` and :c:func:`poll` functions
|
||||||
available in most operating systems, :c:func:`epoll` available on Linux 2.5+ and
|
available in most operating systems, :c:func:`devpoll` available on
|
||||||
|
Solaris and derivatives, :c:func:`epoll` available on Linux 2.5+ and
|
||||||
:c:func:`kqueue` available on most BSD.
|
:c:func:`kqueue` available on most BSD.
|
||||||
Note that on Windows, it only works for sockets; on other operating systems,
|
Note that on Windows, it only works for sockets; on other operating systems,
|
||||||
it also works for other file types (in particular, on Unix, it works on pipes).
|
it also works for other file types (in particular, on Unix, it works on pipes).
|
||||||
|
@ -24,6 +25,19 @@ The module defines the following:
|
||||||
Following :pep:`3151`, this class was made an alias of :exc:`OSError`.
|
Following :pep:`3151`, this class was made an alias of :exc:`OSError`.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: devpoll()
|
||||||
|
(Only supported on Solaris and derivatives.) Returns a ``/dev/poll``
|
||||||
|
polling object; see section :ref:`devpoll-objects` below for the
|
||||||
|
methods supported by devpoll objects.
|
||||||
|
|
||||||
|
:c:func:`devpoll` objects are linked to the number of file
|
||||||
|
descriptors allowed at the time of instantiation. If your program
|
||||||
|
reduces this value, :c:func:`devpoll` will fail. If your program
|
||||||
|
increases this value, c:func:`devpoll` may return an
|
||||||
|
incomplete list of active file descriptors.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
.. function:: epoll(sizehint=-1)
|
.. function:: epoll(sizehint=-1)
|
||||||
|
|
||||||
(Only supported on Linux 2.5.44 and newer.) Returns an edge polling object,
|
(Only supported on Linux 2.5.44 and newer.) Returns an edge polling object,
|
||||||
|
@ -107,6 +121,74 @@ The module defines the following:
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
||||||
|
.. _devpoll-objects:
|
||||||
|
|
||||||
|
``/dev/poll`` Polling Objects
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
http://developers.sun.com/solaris/articles/using_devpoll.html
|
||||||
|
http://developers.sun.com/solaris/articles/polling_efficient.html
|
||||||
|
|
||||||
|
Solaris and derivatives have ``/dev/poll``. While :c:func:`select` is
|
||||||
|
O(highest file descriptor) and :c:func:`poll` is O(number of file
|
||||||
|
descriptors), ``/dev/poll`` is O(active file descriptors).
|
||||||
|
|
||||||
|
``/dev/poll`` behaviour is very close to the standard :c:func:`poll`
|
||||||
|
object.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: devpoll.register(fd[, eventmask])
|
||||||
|
|
||||||
|
Register a file descriptor with the polling object. Future calls to the
|
||||||
|
:meth:`poll` method will then check whether the file descriptor has any pending
|
||||||
|
I/O events. *fd* can be either an integer, or an object with a :meth:`fileno`
|
||||||
|
method that returns an integer. File objects implement :meth:`fileno`, so they
|
||||||
|
can also be used as the argument.
|
||||||
|
|
||||||
|
*eventmask* is an optional bitmask describing the type of events you want to
|
||||||
|
check for. The constants are the same that with :c:func:`poll`
|
||||||
|
object. The default value is a combination of the constants :const:`POLLIN`,
|
||||||
|
:const:`POLLPRI`, and :const:`POLLOUT`.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Registering a file descriptor that's already registered is not an
|
||||||
|
error, but the result is undefined. The appropiate action is to
|
||||||
|
unregister or modify it first. This is an important difference
|
||||||
|
compared with :c:func:`poll`.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: devpoll.modify(fd[, eventmask])
|
||||||
|
|
||||||
|
This method does an :meth:`unregister` followed by a
|
||||||
|
:meth:`register`. It is (a bit) more efficient that doing the same
|
||||||
|
explicitly.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: devpoll.unregister(fd)
|
||||||
|
|
||||||
|
Remove a file descriptor being tracked by a polling object. Just like the
|
||||||
|
:meth:`register` method, *fd* can be an integer or an object with a
|
||||||
|
:meth:`fileno` method that returns an integer.
|
||||||
|
|
||||||
|
Attempting to remove a file descriptor that was never registered is
|
||||||
|
safely ignored.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: devpoll.poll([timeout])
|
||||||
|
|
||||||
|
Polls the set of registered file descriptors, and returns a possibly-empty list
|
||||||
|
containing ``(fd, event)`` 2-tuples for the descriptors that have events or
|
||||||
|
errors to report. *fd* is the file descriptor, and *event* is a bitmask with
|
||||||
|
bits set for the reported events for that descriptor --- :const:`POLLIN` for
|
||||||
|
waiting input, :const:`POLLOUT` to indicate that the descriptor can be written
|
||||||
|
to, and so forth. An empty list indicates that the call timed out and no file
|
||||||
|
descriptors had any events to report. If *timeout* is given, it specifies the
|
||||||
|
length of time in milliseconds which the system will wait for events before
|
||||||
|
returning. If *timeout* is omitted, -1, or :const:`None`, the call will
|
||||||
|
block until there is an event for this poll object.
|
||||||
|
|
||||||
|
|
||||||
.. _epoll-objects:
|
.. _epoll-objects:
|
||||||
|
|
||||||
Edge and Level Trigger Polling (epoll) Objects
|
Edge and Level Trigger Polling (epoll) Objects
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
# Test case for the select.devpoll() function
|
||||||
|
|
||||||
|
# Initial tests are copied as is from "test_poll.py"
|
||||||
|
|
||||||
|
import os, select, random, unittest, sys
|
||||||
|
from test.support import TESTFN, run_unittest
|
||||||
|
|
||||||
|
try:
|
||||||
|
select.devpoll
|
||||||
|
except AttributeError:
|
||||||
|
raise unittest.SkipTest("select.devpoll not defined -- skipping test_devpoll")
|
||||||
|
|
||||||
|
|
||||||
|
def find_ready_matching(ready, flag):
|
||||||
|
match = []
|
||||||
|
for fd, mode in ready:
|
||||||
|
if mode & flag:
|
||||||
|
match.append(fd)
|
||||||
|
return match
|
||||||
|
|
||||||
|
class DevPollTests(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_devpoll1(self):
|
||||||
|
# Basic functional test of poll object
|
||||||
|
# Create a bunch of pipe and test that poll works with them.
|
||||||
|
|
||||||
|
p = select.devpoll()
|
||||||
|
|
||||||
|
NUM_PIPES = 12
|
||||||
|
MSG = b" This is a test."
|
||||||
|
MSG_LEN = len(MSG)
|
||||||
|
readers = []
|
||||||
|
writers = []
|
||||||
|
r2w = {}
|
||||||
|
w2r = {}
|
||||||
|
|
||||||
|
for i in range(NUM_PIPES):
|
||||||
|
rd, wr = os.pipe()
|
||||||
|
p.register(rd)
|
||||||
|
p.modify(rd, select.POLLIN)
|
||||||
|
p.register(wr, select.POLLOUT)
|
||||||
|
readers.append(rd)
|
||||||
|
writers.append(wr)
|
||||||
|
r2w[rd] = wr
|
||||||
|
w2r[wr] = rd
|
||||||
|
|
||||||
|
bufs = []
|
||||||
|
|
||||||
|
while writers:
|
||||||
|
ready = p.poll()
|
||||||
|
ready_writers = find_ready_matching(ready, select.POLLOUT)
|
||||||
|
if not ready_writers:
|
||||||
|
self.fail("no pipes ready for writing")
|
||||||
|
wr = random.choice(ready_writers)
|
||||||
|
os.write(wr, MSG)
|
||||||
|
|
||||||
|
ready = p.poll()
|
||||||
|
ready_readers = find_ready_matching(ready, select.POLLIN)
|
||||||
|
if not ready_readers:
|
||||||
|
self.fail("no pipes ready for reading")
|
||||||
|
self.assertEqual([w2r[wr]], ready_readers)
|
||||||
|
rd = ready_readers[0]
|
||||||
|
buf = os.read(rd, MSG_LEN)
|
||||||
|
self.assertEqual(len(buf), MSG_LEN)
|
||||||
|
bufs.append(buf)
|
||||||
|
os.close(r2w[rd]) ; os.close(rd)
|
||||||
|
p.unregister(r2w[rd])
|
||||||
|
p.unregister(rd)
|
||||||
|
writers.remove(r2w[rd])
|
||||||
|
|
||||||
|
self.assertEqual(bufs, [MSG] * NUM_PIPES)
|
||||||
|
|
||||||
|
def test_timeout_overflow(self):
|
||||||
|
pollster = select.devpoll()
|
||||||
|
w, r = os.pipe()
|
||||||
|
pollster.register(w)
|
||||||
|
|
||||||
|
pollster.poll(-1)
|
||||||
|
self.assertRaises(OverflowError, pollster.poll, -2)
|
||||||
|
self.assertRaises(OverflowError, pollster.poll, -1 << 31)
|
||||||
|
self.assertRaises(OverflowError, pollster.poll, -1 << 64)
|
||||||
|
|
||||||
|
pollster.poll(0)
|
||||||
|
pollster.poll(1)
|
||||||
|
pollster.poll(1 << 30)
|
||||||
|
self.assertRaises(OverflowError, pollster.poll, 1 << 31)
|
||||||
|
self.assertRaises(OverflowError, pollster.poll, 1 << 63)
|
||||||
|
self.assertRaises(OverflowError, pollster.poll, 1 << 64)
|
||||||
|
|
||||||
|
def test_main():
|
||||||
|
run_unittest(DevPollTests)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_main()
|
|
@ -365,6 +365,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6397: Support "/dev/poll" polling objects in select module,
|
||||||
|
under Solaris & derivatives.
|
||||||
|
|
||||||
- Issues #1745761, #755670, #13357, #12629, #1200313: HTMLParser now correctly
|
- Issues #1745761, #755670, #13357, #12629, #1200313: HTMLParser now correctly
|
||||||
handles non-valid attributes, including adjacent and unquoted attributes.
|
handles non-valid attributes, including adjacent and unquoted attributes.
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,14 @@
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include <structmember.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__
|
#ifdef __APPLE__
|
||||||
/* Perform runtime testing for a broken poll on OSX to make it easier
|
/* Perform runtime testing for a broken poll on OSX to make it easier
|
||||||
* to use the same binary on multiple releases of the OS.
|
* to use the same binary on multiple releases of the OS.
|
||||||
|
@ -648,6 +656,339 @@ static PyTypeObject poll_Type = {
|
||||||
poll_methods, /*tp_methods*/
|
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, events = POLLIN | POLLPRI | POLLOUT;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O|i:register", &o, &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 = 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,
|
PyDoc_STRVAR(poll_doc,
|
||||||
"Returns a polling object, which supports registering and\n\
|
"Returns a polling object, which supports registering and\n\
|
||||||
unregistering file descriptors, and then polling them for I/O events.");
|
unregistering file descriptors, and then polling them for I/O events.");
|
||||||
|
@ -658,6 +999,19 @@ select_poll(PyObject *self, PyObject *unused)
|
||||||
return (PyObject *)newPollObject();
|
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__
|
#ifdef __APPLE__
|
||||||
/*
|
/*
|
||||||
* On some systems poll() sets errno on invalid file descriptors. We test
|
* On some systems poll() sets errno on invalid file descriptors. We test
|
||||||
|
@ -1715,6 +2069,11 @@ static PyTypeObject kqueue_queue_Type = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HAVE_KQUEUE */
|
#endif /* HAVE_KQUEUE */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ************************************************************************ */
|
/* ************************************************************************ */
|
||||||
|
|
||||||
PyDoc_STRVAR(select_doc,
|
PyDoc_STRVAR(select_doc,
|
||||||
|
@ -1746,6 +2105,9 @@ static PyMethodDef select_methods[] = {
|
||||||
#ifdef HAVE_POLL
|
#ifdef HAVE_POLL
|
||||||
{"poll", select_poll, METH_NOARGS, poll_doc},
|
{"poll", select_poll, METH_NOARGS, poll_doc},
|
||||||
#endif /* HAVE_POLL */
|
#endif /* HAVE_POLL */
|
||||||
|
#ifdef HAVE_SYS_DEVPOLL_H
|
||||||
|
{"devpoll", select_devpoll, METH_NOARGS, devpoll_doc},
|
||||||
|
#endif
|
||||||
{0, 0}, /* sentinel */
|
{0, 0}, /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1768,6 +2130,9 @@ static struct PyModuleDef selectmodule = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit_select(void)
|
PyInit_select(void)
|
||||||
{
|
{
|
||||||
|
@ -1824,6 +2189,11 @@ PyInit_select(void)
|
||||||
}
|
}
|
||||||
#endif /* HAVE_POLL */
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_DEVPOLL_H
|
||||||
|
if (PyType_Ready(&devpoll_Type) < 0)
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_EPOLL
|
#ifdef HAVE_EPOLL
|
||||||
Py_TYPE(&pyEpoll_Type) = &PyType_Type;
|
Py_TYPE(&pyEpoll_Type) = &PyType_Type;
|
||||||
if (PyType_Ready(&pyEpoll_Type) < 0)
|
if (PyType_Ready(&pyEpoll_Type) < 0)
|
||||||
|
|
|
@ -6139,12 +6139,13 @@ fi
|
||||||
|
|
||||||
for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
|
for ac_header in asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
|
||||||
fcntl.h grp.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 \
|
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
|
||||||
unistd.h utime.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/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/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 \
|
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 \
|
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
|
||||||
|
|
|
@ -1329,12 +1329,13 @@ dnl AC_MSG_RESULT($cpp_type)
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS(asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
|
AC_CHECK_HEADERS(asm/types.h conio.h curses.h direct.h dlfcn.h errno.h \
|
||||||
fcntl.h grp.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 \
|
sched.h shadow.h signal.h stdint.h stropts.h termios.h \
|
||||||
unistd.h utime.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/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/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 \
|
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 \
|
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
|
||||||
|
|
|
@ -883,6 +883,9 @@
|
||||||
/* Define to 1 if you have the <sys/bsdtty.h> header file. */
|
/* Define to 1 if you have the <sys/bsdtty.h> header file. */
|
||||||
#undef HAVE_SYS_BSDTTY_H
|
#undef HAVE_SYS_BSDTTY_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/devpoll.h> header file. */
|
||||||
|
#undef HAVE_SYS_DEVPOLL_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||||
*/
|
*/
|
||||||
#undef HAVE_SYS_DIR_H
|
#undef HAVE_SYS_DIR_H
|
||||||
|
|
Loading…
Reference in New Issue