/* * call-seq: * io.wait_writable -> IO * io.wait_writable(timeout) -> IO or nil * * Waits until IO writable is available or times out and returns self or * nil when EOF is reached. */ static VALUE io_wait_writable(int argc, VALUE *argv, VALUE io) { rb_io_t *fptr; int i; VALUE timeout; struct timeval timerec; struct timeval *tv; GetOpenFile(io, fptr); rb_io_check_writable(fptr); rb_scan_args(argc, argv, "01", &timeout); if (NIL_P(timeout)) { tv = NULL; } else { timerec = rb_time_interval(timeout); tv = &timerec; } i = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_OUT, tv); if (i < 0) rb_sys_fail(0); rb_io_check_closed(fptr); if (i & RB_WAITFD_OUT) return io; return Qnil; }
static int kgio_timedwait(VALUE self, VALUE timeout, int write_p) { struct timeval tv = rb_time_interval(timeout); int events = write_p ? RB_WAITFD_OUT : RB_WAITFD_IN; return rb_wait_for_single_fd(my_fileno(self), events, &tv); }
static VALUE io_wait_readable(int argc, VALUE *argv, VALUE io) { rb_io_t *fptr; int i; ioctl_arg n; VALUE timeout; struct timeval timerec; struct timeval *tv; GetOpenFile(io, fptr); rb_io_check_readable(fptr); rb_scan_args(argc, argv, "01", &timeout); if (NIL_P(timeout)) { tv = NULL; } else { timerec = rb_time_interval(timeout); tv = &timerec; } if (rb_io_read_pending(fptr)) return Qtrue; if (!FIONREAD_POSSIBLE_P(fptr->fd)) return Qfalse; i = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_IN, tv); if (i < 0) rb_sys_fail(0); rb_io_check_closed(fptr); if (ioctl(fptr->fd, FIONREAD, &n)) rb_sys_fail(0); if (n > 0) return io; return Qnil; }
static VALUE thread_runnable_sleep(VALUE thread, VALUE timeout) { struct timeval timeval; if (NIL_P(timeout)) { rb_raise(rb_eArgError, "timeout must be non nil"); } timeval = rb_time_interval(timeout); rb_thread_call_without_gvl(native_sleep_callback, &timeval, RUBY_UBF_IO, NULL); return thread; }
VALUE rb_mutex_sleep(VALUE self, VALUE timeout) { time_t beg, end; struct timeval t; if (!NIL_P(timeout)) { t = rb_time_interval(timeout); } rb_mutex_unlock(self); beg = time(0); if (NIL_P(timeout)) { rb_ensure(rb_mutex_sleep_forever, Qnil, rb_mutex_lock, self); } else { rb_ensure(rb_mutex_wait_for, (VALUE)&t, rb_mutex_lock, self); } end = time(0) - beg; return INT2FIX(end); }
static VALUE mutex_sleep(VALUE self, SEL sel, int argc, VALUE *argv) { VALUE timeout; rb_scan_args(argc, argv, "01", &timeout); rb_mutex_unlock(self, 0); time_t beg, end; beg = time(0); if (timeout == Qnil) { rb_thread_sleep_forever(); } else { struct timeval t = rb_time_interval(timeout); rb_thread_wait_for(t); } end = time(0) - beg; return INT2FIX(end); }
static VALUE thread_join_m(VALUE self, SEL sel, int argc, VALUE *argv) { VALUE timeout; rb_scan_args(argc, argv, "01", &timeout); rb_vm_thread_t *t = GetThreadPtr(self); if (t->status != THREAD_DEAD) { if (timeout == Qnil) { // No timeout given: block until the thread finishes. pthread_assert(pthread_join(t->thread, NULL)); } else { // Timeout given: sleep then check if the thread is dead. // TODO do multiple sleeps instead of only one. struct timeval tv = rb_time_interval(timeout); struct timespec ts; ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; while (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; } nanosleep(&ts, NULL); if (t->status != THREAD_DEAD) { return Qnil; } } } // If the thread was terminated because of an exception, we need to // propagate it. if (t->exception != Qnil) { rb_exc_raise(t->exception); } return self; }
static VALUE thread_join_m(VALUE self, SEL sel, int argc, VALUE *argv) { VALUE timeout; rb_scan_args(argc, argv, "01", &timeout); rb_vm_thread_t *t = GetThreadPtr(self); if (t->status != THREAD_DEAD) { if (timeout == Qnil) { // No timeout given: block until the thread finishes. //pthread_assert(pthread_join(t->thread, NULL)); struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 10000000; while (t->status != THREAD_DEAD) { nanosleep(&ts, NULL); pthread_yield_np(); if (t->status == THREAD_KILLED && t->wait_for_mutex_lock) { goto dead; } } } else { // Timeout given: sleep and check if the thread is dead. struct timeval tv = rb_time_interval(timeout); struct timespec ts; ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; while (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; } while (ts.tv_sec > 0 || ts.tv_nsec > 0) { struct timespec its; again: if (ts.tv_nsec > 100000000) { ts.tv_nsec -= 100000000; its.tv_sec = 0; its.tv_nsec = 100000000; } else if (ts.tv_sec > 0) { ts.tv_sec -= 1; ts.tv_nsec += 1000000000; goto again; } else { its = ts; ts.tv_sec = ts.tv_nsec = 0; } nanosleep(&its, NULL); if (t->status == THREAD_DEAD) { goto dead; } if (t->status == THREAD_KILLED && t->wait_for_mutex_lock) { goto dead; } } return Qnil; } } dead: // If the thread was terminated because of an exception, we need to // propagate it. if (t->exception != Qnil) { t->joined_on_exception = true; rb_exc_raise(t->exception); } return self; }