static void native_sleep(rb_thread_t *th, struct timeval *tv) { struct timespec ts; struct timeval tvn; if (tv) { gettimeofday(&tvn, NULL); ts.tv_sec = tvn.tv_sec + tv->tv_sec; ts.tv_nsec = (tvn.tv_usec + tv->tv_usec) * 1000; if (ts.tv_nsec >= PER_NANO){ ts.tv_sec += 1; ts.tv_nsec -= PER_NANO; } } thread_debug("native_sleep %ld\n", (long)(tv ? tv->tv_sec : -1)); GVL_UNLOCK_BEGIN(); { pthread_mutex_lock(&th->interrupt_lock); th->unblock.func = ubf_pthread_cond_signal; th->unblock.arg = th; if (RUBY_VM_INTERRUPTED(th)) { /* interrupted. return immediate */ thread_debug("native_sleep: interrupted before sleep\n"); } else { if (tv == 0 || ts.tv_sec < tvn.tv_sec /* overflow */ ) { int r; thread_debug("native_sleep: pthread_cond_wait start\n"); r = pthread_cond_wait(&th->native_thread_data.sleep_cond, &th->interrupt_lock); if (r) rb_bug_errno("pthread_cond_wait", r); thread_debug("native_sleep: pthread_cond_wait end\n"); } else { int r; thread_debug("native_sleep: pthread_cond_timedwait start (%ld, %ld)\n", (unsigned long)ts.tv_sec, ts.tv_nsec); r = pthread_cond_timedwait(&th->native_thread_data.sleep_cond, &th->interrupt_lock, &ts); if (r && r != ETIMEDOUT) rb_bug_errno("pthread_cond_timedwait", r); thread_debug("native_sleep: pthread_cond_timedwait end (%d)\n", r); } } th->unblock.func = 0; th->unblock.arg = 0; pthread_mutex_unlock(&th->interrupt_lock); } GVL_UNLOCK_END(); thread_debug("native_sleep done\n"); }
static void native_sleep(rb_thread_t *th, struct timeval *timeout_tv) { struct timespec timeout; rb_nativethread_lock_t *lock = &th->interrupt_lock; rb_nativethread_cond_t *cond = &th->native_thread_data.sleep_cond; if (timeout_tv) { struct timespec timeout_rel; timeout_rel.tv_sec = timeout_tv->tv_sec; timeout_rel.tv_nsec = timeout_tv->tv_usec * 1000; /* Solaris cond_timedwait() return EINVAL if an argument is greater than * current_time + 100,000,000. So cut up to 100,000,000. This is * considered as a kind of spurious wakeup. The caller to native_sleep * should care about spurious wakeup. * * See also [Bug #1341] [ruby-core:29702] * http://download.oracle.com/docs/cd/E19683-01/816-0216/6m6ngupgv/index.html */ if (timeout_rel.tv_sec > 100000000) { timeout_rel.tv_sec = 100000000; timeout_rel.tv_nsec = 0; } timeout = native_cond_timeout(cond, timeout_rel); } GVL_UNLOCK_BEGIN(); { native_mutex_lock(lock); th->unblock.func = ubf_pthread_cond_signal; th->unblock.arg = th; if (RUBY_VM_INTERRUPTED(th)) { /* interrupted. return immediate */ thread_debug("native_sleep: interrupted before sleep\n"); } else { if (!timeout_tv) native_cond_wait(cond, lock); else native_cond_timedwait(cond, lock, &timeout); } th->unblock.func = 0; th->unblock.arg = 0; native_mutex_unlock(lock); } GVL_UNLOCK_END(); thread_debug("native_sleep done\n"); }
static int w32_wait_events(HANDLE *events, int count, DWORD timeout, rb_thread_t *th) { HANDLE *targets = events; HANDLE intr; DWORD ret; thread_debug(" w32_wait_events events:%p, count:%d, timeout:%ld, th:%p\n", events, count, timeout, th); if (th && (intr = th->native_thread_data.interrupt_event)) { native_mutex_lock(&th->vm->global_vm_lock); if (intr == th->native_thread_data.interrupt_event) { w32_reset_event(intr); if (RUBY_VM_INTERRUPTED(th)) { w32_set_event(intr); } targets = ALLOCA_N(HANDLE, count + 1); memcpy(targets, events, sizeof(HANDLE) * count); targets[count++] = intr; thread_debug(" * handle: %p (count: %d, intr)\n", intr, count); } native_mutex_unlock(&th->vm->global_vm_lock); } thread_debug(" WaitForMultipleObjects start (count: %d)\n", count); ret = WaitForMultipleObjects(count, targets, FALSE, timeout); thread_debug(" WaitForMultipleObjects end (ret: %lu)\n", ret); if (ret == WAIT_OBJECT_0 + count - 1 && th) { errno = EINTR; } if (ret == -1 && THREAD_DEBUG) { int i; DWORD dmy; for (i = 0; i < count; i++) { thread_debug(" * error handle %d - %s\n", i, GetHandleInformation(targets[i], &dmy) ? "OK" : "NG"); } } return ret; }
static void native_sleep(rb_thread_t *th, struct timeval *timeout_tv) { struct timespec timeout; struct timeval tvn; pthread_mutex_t *lock = &th->interrupt_lock; rb_thread_cond_t *cond = &th->native_thread_data.sleep_cond; if (timeout_tv) { struct timespec timeout_rel; timeout_rel.tv_sec = timeout_tv->tv_sec; timeout_rel.tv_nsec = timeout_tv->tv_usec; timeout = native_cond_timeout(cond, timeout_rel); } GVL_UNLOCK_BEGIN(); { pthread_mutex_lock(lock); th->unblock.func = ubf_pthread_cond_signal; th->unblock.arg = th; if (RUBY_VM_INTERRUPTED(th)) { /* interrupted. return immediate */ thread_debug("native_sleep: interrupted before sleep\n"); } else { if (!timeout_tv) native_cond_wait(cond, lock); else native_cond_timedwait(cond, lock, &timeout); } th->unblock.func = 0; th->unblock.arg = 0; pthread_mutex_unlock(lock); } GVL_UNLOCK_END(); thread_debug("native_sleep done\n"); }
static int lock_func(rb_thread_t *th, rb_mutex_t *mutex, int timeout_ms) { int interrupted = 0; int err = 0; mutex->cond_waiting++; for (;;) { if (!mutex->th) { mutex->th = th; break; } if (RUBY_VM_INTERRUPTED(th)) { interrupted = 1; break; } if (err == ETIMEDOUT) { interrupted = 2; break; } if (timeout_ms) { struct timespec timeout_rel; struct timespec timeout; timeout_rel.tv_sec = 0; timeout_rel.tv_nsec = timeout_ms * 1000 * 1000; timeout = native_cond_timeout(&mutex->cond, timeout_rel); err = native_cond_timedwait(&mutex->cond, &mutex->lock, &timeout); } else { native_cond_wait(&mutex->cond, &mutex->lock); err = 0; } } mutex->cond_waiting--; return interrupted; }
static void native_sleep(rb_thread_t *th, struct timeval *tv) { DWORD msec; if (tv) { msec = tv->tv_sec * 1000 + tv->tv_usec / 1000; } else { msec = INFINITE; } GVL_UNLOCK_BEGIN(); { DWORD ret; native_mutex_lock(&th->interrupt_lock); th->unblock.func = ubf_handle; th->unblock.arg = th; native_mutex_unlock(&th->interrupt_lock); if (RUBY_VM_INTERRUPTED(th)) { /* interrupted. return immediate */ } else { thread_debug("native_sleep start (%lu)\n", msec); ret = w32_wait_events(0, 0, msec, th); thread_debug("native_sleep done (%lu)\n", ret); } native_mutex_lock(&th->interrupt_lock); th->unblock.func = 0; th->unblock.arg = 0; native_mutex_unlock(&th->interrupt_lock); } GVL_UNLOCK_END(); }
static void native_sleep(rb_thread_t *th, struct timeval *tv) { DWORD msec; if (tv) { msec = tv->tv_sec * 1000 + tv->tv_usec / 1000; } else { msec = INFINITE; } GVL_UNLOCK_BEGIN(); { DWORD ret; int status = th->status; th->status = THREAD_STOPPED; th->unblock_function = ubf_handle; th->unblock_function_arg = th; if (RUBY_VM_INTERRUPTED(th)) { /* interrupted. return immediate */ } else { thread_debug("native_sleep start (%d)\n", (int)msec); ret = w32_wait_events(0, 0, msec, th); thread_debug("native_sleep done (%d)\n", ret); } th->unblock_function = 0; th->unblock_function_arg = 0; th->status = status; } GVL_UNLOCK_END(); RUBY_VM_CHECK_INTS(); }