diff -r 26f6d8cc2749 Modules/selectmodule.c --- a/Modules/selectmodule.c Thu Jan 28 15:44:10 2016 +0100 +++ b/Modules/selectmodule.c Thu Jan 28 16:47:57 2016 +0100 @@ -1220,6 +1220,11 @@ static int select_have_broken_poll(void) typedef struct { PyObject_HEAD SOCKET epfd; /* epoll control file descriptor */ + + /* Buffer used by pyepoll_poll() to avoid calling + * PyMem_Malloc()/PyMem_Free() for each time poll. */ + Py_ssize_t allocated; + struct epoll_event *buffer; } pyEpoll_Object; static PyTypeObject pyEpoll_Type; @@ -1236,6 +1241,11 @@ static int pyepoll_internal_close(pyEpoll_Object *self) { int save_errno = 0; + if (self->buffer) { + PyMem_Free(self->buffer); + self->allocated = 0; + self->buffer = NULL; + } if (self->epfd >= 0) { int epfd = self->epfd; self->epfd = -1; @@ -1284,6 +1294,9 @@ newPyEpoll_Object(PyTypeObject *type, in } #endif + self->allocated = 0; + self->buffer = NULL; + return (PyObject *)self; } @@ -1492,6 +1505,8 @@ pyepoll_poll(pyEpoll_Object *self, PyObj PyObject *elist = NULL, *etuple = NULL; struct epoll_event *evs = NULL; _PyTime_t timeout, ms, deadline; + Py_ssize_t allocated; + struct epoll_event *buffer; if (self->epfd < 0) return pyepoll_err_closed(); @@ -1536,13 +1551,39 @@ pyepoll_poll(pyEpoll_Object *self, PyObj maxevents); return NULL; } - - evs = PyMem_New(struct epoll_event, maxevents); - if (evs == NULL) { + if (maxevents > PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(struct epoll_event)) { PyErr_NoMemory(); return NULL; } + /* steal the buffer (the GIL ensures that the exchange is atomic) */ + allocated = self->allocated; + buffer = self->buffer; + self->allocated = 0; + self->buffer = NULL; + + if (allocated < maxevents) { + Py_ssize_t size; + + size = maxevents; + if (allocated && size < PY_SSIZE_T_MAX - maxevents / 2) { + /* if resize, overallocate by 50% */ + size += maxevents / 2; + } + + size *= sizeof(struct epoll_event); + evs = (struct epoll_event *)PyMem_Realloc(buffer, size); + if (evs == NULL) { + PyErr_NoMemory(); + goto error; + } + allocated = maxevents; + buffer = evs; + } + else { + evs = buffer; + } + do { Py_BEGIN_ALLOW_THREADS errno = 0; @@ -1586,8 +1627,19 @@ pyepoll_poll(pyEpoll_Object *self, PyObj PyList_SET_ITEM(elist, i, etuple); } - error: - PyMem_Free(evs); +error: + /* always keep the largest buffer */ + if (self->allocated < allocated) { + /* if another thread allocated a smaller buffer, release it */ + PyMem_Free(self->buffer); + self->allocated = allocated; + self->buffer = buffer; + } + else { + /* another thread allocated a larger buffer, + * release the small buffer */ + PyMem_Free(buffer); + } return elist; }