From 863e24b2b1a1b946c89d32575c2814b564a1bf95 Mon Sep 17 00:00:00 2001 From: normal Date: Mon, 14 May 2018 23:51:35 +0000 Subject: test_wait_for_single_fd: ensure this works with kqueue Regardless of future features, this needs to work with kqueue descriptors across platforms. Today this will be useful for 3rd-party libraries using kqueue. In the future, Ruby may use kqueue natively and we shall ensure we can wait on it. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63421 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/-test-/wait_for_single_fd/extconf.rb | 2 + ext/-test-/wait_for_single_fd/wait_for_single_fd.c | 64 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) (limited to 'ext') diff --git a/ext/-test-/wait_for_single_fd/extconf.rb b/ext/-test-/wait_for_single_fd/extconf.rb index 931662c040..2a976c8f4b 100644 --- a/ext/-test-/wait_for_single_fd/extconf.rb +++ b/ext/-test-/wait_for_single_fd/extconf.rb @@ -1,2 +1,4 @@ # frozen_string_literal: false +headers = %w(sys/types.h sys/time.h sys/event.h).select { |h| have_header(h) } +have_func('kqueue', headers) create_makefile("-test-/wait_for_single_fd") diff --git a/ext/-test-/wait_for_single_fd/wait_for_single_fd.c b/ext/-test-/wait_for_single_fd/wait_for_single_fd.c index d406724a3f..6eaeff1e5e 100644 --- a/ext/-test-/wait_for_single_fd/wait_for_single_fd.c +++ b/ext/-test-/wait_for_single_fd/wait_for_single_fd.c @@ -19,6 +19,67 @@ wait_for_single_fd(VALUE ign, VALUE fd, VALUE events, VALUE timeout) return INT2NUM(rc); } +#ifdef HAVE_KQUEUE +/* ensure rb_wait_for_single_fd works on kqueue descriptors */ +#include +#include +#include +static VALUE +kqueue_test_wait(VALUE klass) +{ + int kqfd = -1; + int p[2] = { -1, -1 }; + struct timeval tv = { 0, 0 }; + const struct timespec ts = { 1, 0 }; + struct kevent kev; + const char *msg; + VALUE ret = Qfalse; + int e = 0; + int n; + + msg = "pipe"; + if (rb_cloexec_pipe(p) < 0) goto err; + + msg = "kqueue"; + kqfd = kqueue(); + if (kqfd < 0) goto err; + + n = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN, &tv); + if (n != 0) { + msg = "spurious wakeup"; + errno = 0; + goto err; + } + + msg = "write"; + if (write(p[1], "", 1) < 0) goto err; + + EV_SET(&kev, p[0], EVFILT_READ, EV_ADD, 0, 0, 0); + + msg = "kevent"; + n = kevent(kqfd, &kev, 1, &kev, 1, &ts); + if (n < 0) goto err; + msg = NULL; + if (n == 1) { + n = rb_wait_for_single_fd(kqfd, RB_WAITFD_IN, &tv); + ret = INT2NUM(n); + } + else { + rb_warn("kevent did not return readiness"); + } +err: + if (msg) e = errno; + if (p[0] >= 0) close(p[0]); + if (p[1] >= 0) close(p[1]); + if (kqfd >= 0) close(kqfd); + if (msg) { + if (e) rb_syserr_fail(e, msg); + rb_raise(rb_eRuntimeError, msg); + } + return ret; +} +#endif /* HAVE_KQUEUE */ + void Init_wait_for_single_fd(void) { @@ -27,4 +88,7 @@ Init_wait_for_single_fd(void) rb_define_const(rb_cObject, "RB_WAITFD_PRI", INT2NUM(RB_WAITFD_PRI)); rb_define_singleton_method(rb_cIO, "wait_for_single_fd", wait_for_single_fd, 3); +#ifdef HAVE_KQUEUE + rb_define_singleton_method(rb_cIO, "kqueue_test_wait", kqueue_test_wait, 0); +#endif } -- cgit v1.2.3