diff options
author | JP Camara <[email protected]> | 2023-12-06 20:01:14 -0500 |
---|---|---|
committer | Koichi Sasada <[email protected]> | 2023-12-20 16:23:38 +0900 |
commit | 8782e02138e6fe18b6c0dcc29bb877d6cdae57e5 (patch) | |
tree | b77e899dc4cd1ac14c496bc0fdcf034261451667 /thread_pthread.c | |
parent | 7ef90b3978dad057ad6360a94d2d64e8ca5e9c38 (diff) |
KQueue support for M:N threads
* Allows macOS users to use M:N threads (and technically FreeBSD, though it has not been verified on FreeBSD)
* Include sys/event.h header check for macros, and include sys/event.h when present
* Rename epoll_fd to more generic kq_fd (Kernel event Queue) for use by both epoll and kqueue
* MAP_STACK is not available on macOS so conditionall apply it to mmap flags
* Set fd to close on exec
* Log debug messages specific to kqueue and epoll on creation
* close_invalidate raises an error for the kqueue fd on child process fork. It's unclear rn if that's a bug, or if it's kqueue specific behavior
Use kq with rb_thread_wait_for_single_fd
* Only platforms with `USE_POLL` (linux) had changes applied to take advantage of kernel event queues. It needed to be applied to the `select` so that kqueue could be properly applied
* Clean up kqueue specific code and make sure only flags that were actually set are removed (or an error is raised)
* Also handle kevent specific errnos, since most don't apply from epoll to kqueue
* Use the more platform standard close-on-exec approach of `fcntl` and `FD_CLOEXEC`. The io-event gem uses `ioctl`, but fcntl seems to be the recommended choice. It is also what Go, Bun, and Libuv use
* We're making changes in this file anyways - may as well fix a couple spelling mistakes while here
Make sure FD_CLOEXEC carries over in dup
* Otherwise the kqueue descriptor should have FD_CLOEXEC, but doesn't and fails in assert_close_on_exec
Diffstat (limited to 'thread_pthread.c')
-rw-r--r-- | thread_pthread.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/thread_pthread.c b/thread_pthread.c index e7e827793b..d8ca403be6 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -62,6 +62,10 @@ static const void *const condattr_monotonic = NULL; #include COROUTINE_H +#ifndef HAVE_SYS_EVENT_H +#define HAVE_SYS_EVENT_H 0 +#endif + #ifndef HAVE_SYS_EPOLL_H #define HAVE_SYS_EPOLL_H 0 #else @@ -78,6 +82,9 @@ static const void *const condattr_monotonic = NULL; #elif HAVE_SYS_EPOLL_H #include <sys/epoll.h> #define USE_MN_THREADS 1 + #elif HAVE_SYS_EVENT_H + #include <sys/event.h> + #define USE_MN_THREADS 1 #else #define USE_MN_THREADS 0 #endif @@ -2799,10 +2806,15 @@ static struct { int comm_fds[2]; // r, w +#if (HAVE_SYS_EPOLL_H || HAVE_SYS_EVENT_H) && USE_MN_THREADS + int event_fd; // kernel event queue fd (epoll/kqueue) +#endif #if HAVE_SYS_EPOLL_H && USE_MN_THREADS #define EPOLL_EVENTS_MAX 0x10 - int epoll_fd; struct epoll_event finished_events[EPOLL_EVENTS_MAX]; +#elif HAVE_SYS_EVENT_H && USE_MN_THREADS +#define KQUEUE_EVENTS_MAX 0x10 + struct kevent finished_events[KQUEUE_EVENTS_MAX]; #endif // waiting threads list @@ -3088,7 +3100,7 @@ rb_thread_create_timer_thread(void) CLOSE_INVALIDATE_PAIR(timer_th.comm_fds); #if HAVE_SYS_EPOLL_H && USE_MN_THREADS - close_invalidate(&timer_th.epoll_fd, "close epoll_fd"); + close_invalidate(&timer_th.event_fd, "close event_fd"); #endif rb_native_mutex_destroy(&timer_th.waiting_lock); } @@ -3099,8 +3111,8 @@ rb_thread_create_timer_thread(void) // open communication channel setup_communication_pipe_internal(timer_th.comm_fds); - // open epoll fd - timer_thread_setup_nm(); + // open event fd + timer_thread_setup_mn(); } pthread_create(&timer_th.pthread_id, NULL, timer_thread_func, GET_VM()); @@ -3181,8 +3193,8 @@ rb_reserved_fd_p(int fd) if (fd == timer_th.comm_fds[0] || fd == timer_th.comm_fds[1] -#if HAVE_SYS_EPOLL_H && USE_MN_THREADS - || fd == timer_th.epoll_fd +#if (HAVE_SYS_EPOLL_H || HAVE_SYS_EVENT_H) && USE_MN_THREADS + || fd == timer_th.event_fd #endif ) { goto check_fork_gen; |