Skip to content

Commit

Permalink
Replicate EEXIST epoll_ctl behavior in kqueue
Browse files Browse the repository at this point in the history
* In the epoll implementation, you get an EEXIST if you try to register the same event for the same fd more than once for a particular epoll instance

* Otherwise kevent will just override the previous event registration, and if multiple threads listen on the same fd only the last one to register will ever finish, the others are stuck

* This approach will lead to native threads getting created, similar to the epoll implementation. This is not ideal, but it fixes certain test cases for now, like test/socket/test_tcp.rb#test_accept_multithread
  • Loading branch information
jpcamara authored and ko1 committed Dec 23, 2023
1 parent fadda88 commit a2ebf9c
Showing 1 changed file with 19 additions and 0 deletions.
19 changes: 19 additions & 0 deletions thread_pthread_mn.c
Expand Up @@ -616,6 +616,21 @@ kqueue_unregister_waiting(int fd, enum thread_sched_waiting_flag flags)
}
}

static bool
kqueue_already_registered(int fd)
{
rb_thread_t *wth, *found_wth = NULL;
ccan_list_for_each(&timer_th.waiting, wth, sched.waiting_reason.node) {
// Similar to EEXIST in epoll_ctl, but more strict because it checks fd rather than flags
// for simplicity
if (wth->sched.waiting_reason.flags && wth->sched.waiting_reason.data.fd == fd) {
found_wth = wth;
break;
}
}
return found_wth != NULL;
}

#endif // HAVE_SYS_EVENT_H

// return false if the fd is not waitable or not need to wait.
Expand Down Expand Up @@ -645,6 +660,10 @@ timer_thread_register_waiting(rb_thread_t *th, int fd, enum thread_sched_waiting
#if HAVE_SYS_EVENT_H
struct kevent ke[2];
int num_events = 0;

if (kqueue_already_registered(fd)) {
return false;
}
#else
uint32_t epoll_events = 0;
#endif
Expand Down

0 comments on commit a2ebf9c

Please sign in to comment.