Issue #16876: Optimize epoll.poll() by keeping a per-instance epoll events
buffer instead of allocating a new one at each poll().
This commit is contained in:
parent
0b32a480bd
commit
f424f3856d
|
@ -212,6 +212,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #16876: Optimize epoll.poll() by keeping a per-instance epoll events
|
||||
buffer instead of allocating a new one at each poll().
|
||||
|
||||
- Issue #16491: IDLE now prints chained exception tracebacks.
|
||||
|
||||
- fcntl: add F_DUPFD_CLOEXEC constant, available on Linux 2.6.24+.
|
||||
|
|
|
@ -1056,9 +1056,14 @@ static int select_have_broken_poll(void)
|
|||
#include <sys/epoll.h>
|
||||
#endif
|
||||
|
||||
/* default maximum number of events returned by epoll_wait() */
|
||||
#define EPOLL_DEFAULT_MAXEVENTS (FD_SETSIZE)
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
SOCKET epfd; /* epoll control file descriptor */
|
||||
SOCKET epfd; /* epoll control file descriptor */
|
||||
int maxevents; /* maximum number of epoll events */
|
||||
struct epoll_event *evs; /* epoll events buffer */
|
||||
} pyEpoll_Object;
|
||||
|
||||
static PyTypeObject pyEpoll_Type;
|
||||
|
@ -1114,6 +1119,15 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, int flags, SOCKET fd)
|
|||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self->maxevents = EPOLL_DEFAULT_MAXEVENTS;
|
||||
self->evs = PyMem_New(struct epoll_event, self->maxevents);
|
||||
if (!self->evs) {
|
||||
Py_DECREF(self);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
|
@ -1140,6 +1154,10 @@ static void
|
|||
pyepoll_dealloc(pyEpoll_Object *self)
|
||||
{
|
||||
(void)pyepoll_internal_close(self);
|
||||
if (self->evs) {
|
||||
PyMem_Free(self->evs);
|
||||
self->evs = NULL;
|
||||
}
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
|
@ -1320,7 +1338,6 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
|
|||
int maxevents = -1;
|
||||
int nfds, i;
|
||||
PyObject *elist = NULL, *etuple = NULL;
|
||||
struct epoll_event *evs = NULL;
|
||||
static char *kwlist[] = {"timeout", "maxevents", NULL};
|
||||
|
||||
if (self->epfd < 0)
|
||||
|
@ -1344,24 +1361,27 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
|
||||
if (maxevents == -1) {
|
||||
maxevents = FD_SETSIZE-1;
|
||||
}
|
||||
else if (maxevents < 1) {
|
||||
maxevents = EPOLL_DEFAULT_MAXEVENTS;
|
||||
} else if (maxevents < 1) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"maxevents must be greater than 0, got %d",
|
||||
maxevents);
|
||||
return NULL;
|
||||
}
|
||||
if (maxevents > self->maxevents) {
|
||||
struct epoll_event *orig_evs = self->evs;
|
||||
|
||||
evs = PyMem_New(struct epoll_event, maxevents);
|
||||
if (evs == NULL) {
|
||||
Py_DECREF(self);
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
PyMem_RESIZE(self->evs, struct epoll_event, maxevents);
|
||||
if (!self->evs) {
|
||||
self->evs = orig_evs;
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
self->maxevents = maxevents;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
nfds = epoll_wait(self->epfd, evs, maxevents, timeout);
|
||||
nfds = epoll_wait(self->epfd, self->evs, self->maxevents, timeout);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (nfds < 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
@ -1374,7 +1394,7 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
etuple = Py_BuildValue("iI", evs[i].data.fd, evs[i].events);
|
||||
etuple = Py_BuildValue("iI", self->evs[i].data.fd, self->evs[i].events);
|
||||
if (etuple == NULL) {
|
||||
Py_CLEAR(elist);
|
||||
goto error;
|
||||
|
@ -1383,7 +1403,6 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
|
||||
error:
|
||||
PyMem_Free(evs);
|
||||
return elist;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue