summaryrefslogtreecommitdiffstats
path: root/Modules/selectmodule.c
diff options
context:
space:
mode:
authorCharles-François Natali <neologix@free.fr>2013-01-09 18:00:26 (GMT)
committerCharles-François Natali <neologix@free.fr>2013-01-09 18:00:26 (GMT)
commitf424f3856da382e0d430692e09a0da07e7d8d02a (patch)
tree922d9b90ee1ccac9ef78a27c1214d6dfac083bb9 /Modules/selectmodule.c
parent0b32a480bd0ddd25d0a2f511861c160590296ce2 (diff)
downloadcpython-f424f3856da382e0d430692e09a0da07e7d8d02a.zip
cpython-f424f3856da382e0d430692e09a0da07e7d8d02a.tar.gz
cpython-f424f3856da382e0d430692e09a0da07e7d8d02a.tar.bz2
Issue #16876: Optimize epoll.poll() by keeping a per-instance epoll events
buffer instead of allocating a new one at each poll().
Diffstat (limited to 'Modules/selectmodule.c')
-rw-r--r--Modules/selectmodule.c45
1 files changed, 32 insertions, 13 deletions
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 52be4d8..466f980 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -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;
}