1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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
This commit is contained in:
normal 2018-05-14 23:51:35 +00:00
parent baaf3ba189
commit 863e24b2b1
3 changed files with 70 additions and 1 deletions

View file

@ -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")

View file

@ -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 <sys/types.h>
#include <sys/time.h>
#include <sys/event.h>
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
}

View file

@ -52,5 +52,8 @@ class TestWaitForSingleFD < Test::Unit::TestCase
end
end
def test_wait_for_kqueue
skip 'no kqueue' unless IO.respond_to?(:kqueue_test_wait)
assert_equal RB_WAITFD_IN, IO.kqueue_test_wait
end
end