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:
parent
baaf3ba189
commit
863e24b2b1
3 changed files with 70 additions and 1 deletions
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue