summaryrefslogtreecommitdiff
path: root/thread_pthread.c
diff options
context:
space:
mode:
authorJP Camara <[email protected]>2023-12-06 20:01:14 -0500
committerKoichi Sasada <[email protected]>2023-12-20 16:23:38 +0900
commit8782e02138e6fe18b6c0dcc29bb877d6cdae57e5 (patch)
treeb77e899dc4cd1ac14c496bc0fdcf034261451667 /thread_pthread.c
parent7ef90b3978dad057ad6360a94d2d64e8ca5e9c38 (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.c24
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;