about summary refs log tree commit homepage
path: root/ext/sleepy_penguin/epoll.c
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2013-12-27 23:02:48 +0000
committerEric Wong <normalperson@yhbt.net>2013-12-27 23:03:53 +0000
commit45ce6646ab7cc62ad30ec0bf9c68719f9c467866 (patch)
tree809dc13cfe7b82875a52a6761a4834475fe32c86 /ext/sleepy_penguin/epoll.c
parenta00b3766fa4c498a65f5742e161a382717db3041 (diff)
downloadsleepy_penguin-45ce6646ab7cc62ad30ec0bf9c68719f9c467866.tar.gz
Storing heap-allocated memory in __thread is not feasible for a
library since it provides no automatic resource de-allocation.

This oversight caused rare applications which use short-lived
threads for epoll_wait, kevent, or inotify read to leak memory over
time.  So we refactor everything to use pthread_* thread-local
storage APIs instead.

While we're at it, we can safely use a common, generic buffer for
inotify, epoll, and kevent to avoid running into PTHREAD_KEYS_MAX
limitations.

These leaks only affected sleepy_penguin v3.2.0 and later, and
only applications which use short-lived threads to call epoll_wait,
kevent and inotify read.
Diffstat (limited to 'ext/sleepy_penguin/epoll.c')
-rw-r--r--ext/sleepy_penguin/epoll.c17
1 files changed, 2 insertions, 15 deletions
diff --git a/ext/sleepy_penguin/epoll.c b/ext/sleepy_penguin/epoll.c
index 5e5cb20..423ed69 100644
--- a/ext/sleepy_penguin/epoll.c
+++ b/ext/sleepy_penguin/epoll.c
@@ -1,7 +1,6 @@
 #include "sleepy_penguin.h"
 #ifdef HAVE_SYS_EPOLL_H
 #include <sys/epoll.h>
-#include <unistd.h>
 #include <time.h>
 #include "missing_clock_gettime.h"
 #include "missing_epoll.h"
@@ -52,10 +51,8 @@ static int ep_fd_check(struct ep_per_thread *ept)
 
 static struct ep_per_thread *ept_get(VALUE self, int maxevents)
 {
-        static __thread struct ep_per_thread *ept;
+        struct ep_per_thread *ept;
         size_t size;
-        int err;
-        void *ptr;
 
         /* error check here to prevent OOM from posix_memalign */
         if (maxevents <= 0) {
@@ -63,21 +60,11 @@ static struct ep_per_thread *ept_get(VALUE self, int maxevents)
                 rb_sys_fail("epoll_wait maxevents <= 0");
         }
 
-        if (ept && ept->capa >= maxevents)
-                goto out;
-
         size = sizeof(struct ep_per_thread) +
                sizeof(struct epoll_event) * maxevents;
 
-        free(ept); /* free(NULL) is POSIX and works on glibc */
-        err = posix_memalign(&ptr, rb_sp_l1_cache_line_size, size);
-        if (err) {
-                errno = err;
-                rb_memerror();
-        }
-        ept = ptr;
+        ept = rb_sp_gettlsbuf(&size);
         ept->capa = maxevents;
-out:
         ept->maxevents = maxevents;
         ept->io = self;
         ept->fd = rb_sp_fileno(ept->io);