//wait method implementation //// static IDATA latch_wait_impl(hylatch_t latch, I_64 ms, IDATA nano, IDATA interruptable) { IDATA status; status = port_mutex_lock(&latch->mutex); if (status != TM_ERROR_NONE) { return status; } while (latch->count) { status = condvar_wait_impl(&latch->condition, &latch->mutex, ms, nano, interruptable); //check interruption and other problems if (status != TM_ERROR_NONE) { port_mutex_unlock(&latch->mutex); return status; } if (ms || nano) break; } status = port_mutex_unlock(&latch->mutex); return status; }
IDATA monitor_wait_impl(hythread_monitor_t mon_ptr, I_64 ms, IDATA nano, IDATA interruptable) { IDATA status; int saved_recursion; //int saved_disable_count; hythread_t self = tm_self_tls; if (mon_ptr->owner != self) { return TM_ERROR_ILLEGAL_STATE; } saved_recursion = mon_ptr->recursion_count; assert(saved_recursion>=0); mon_ptr->owner = NULL; mon_ptr->recursion_count =0; mon_ptr->wait_count++; port_mutex_lock(&self->mutex); self->state |= TM_THREAD_STATE_IN_MONITOR_WAIT; self->waited_monitor = mon_ptr; port_mutex_unlock(&self->mutex); do { apr_time_t start; assert(mon_ptr->notify_count >= 0); assert(mon_ptr->notify_count < mon_ptr->wait_count); start = apr_time_now(); status = condvar_wait_impl(&mon_ptr->condition, &mon_ptr->mutex, ms, nano, interruptable); if (status != TM_ERROR_NONE || mon_ptr->notify_count) { break; } // we should not change ms and nano if both are 0 (meaning "no timeout") if (ms || nano) { apr_interval_time_t elapsed; elapsed = apr_time_now() - start; // microseconds nano -= (IDATA)((elapsed % 1000) * 1000); if (nano < 0) { ms -= elapsed/1000 + 1; nano += 1000000; } else { ms -= elapsed/1000; } if (ms < 0) { assert(status == TM_ERROR_NONE); status = TM_ERROR_TIMEOUT; break; } assert(0 <= nano && nano < 1000000); } } while (1); // consume the notify_count unless we got an error (or were interrupted) if (mon_ptr->notify_count > 0 && (status == TM_ERROR_NONE || mon_ptr->notify_count == mon_ptr->wait_count)) { mon_ptr->notify_count--; } port_mutex_lock(&self->mutex); self->state &= ~TM_THREAD_STATE_IN_MONITOR_WAIT; self->waited_monitor = NULL; port_mutex_unlock(&self->mutex); mon_ptr->wait_count--; assert(mon_ptr->notify_count <= mon_ptr->wait_count); if (self->request) { int save_count; port_mutex_unlock(&mon_ptr->mutex); hythread_safe_point(); hythread_exception_safe_point(); save_count = hythread_reset_suspend_disable(); port_mutex_lock(&mon_ptr->mutex); hythread_set_suspend_disable(save_count); } mon_ptr->recursion_count = saved_recursion; mon_ptr->owner = self; assert(mon_ptr->owner); return status; }
IDATA thread_sleep_impl(I_64 millis, IDATA nanos, IDATA interruptable) { IDATA status; IDATA result; hythread_t self; hythread_monitor_t mon; if (nanos == 0 && millis == 0) { hythread_yield(); return TM_ERROR_NONE; } if (!(self = hythread_self())) { // Report error in case current thread is not attached return TM_ERROR_UNATTACHED_THREAD; } // Grab thread monitor mon = self->monitor; status = hythread_monitor_enter(mon); assert(status == TM_ERROR_NONE); assert(mon->recursion_count == 0); mon->owner = NULL; mon->wait_count++; // Set thread state status = port_mutex_lock(&self->mutex); assert(status == TM_ERROR_NONE); self->waited_monitor = mon; self->state |= TM_THREAD_STATE_SLEEPING; status = port_mutex_unlock(&self->mutex); assert(status == TM_ERROR_NONE); do { apr_time_t start; assert(mon->notify_count >= 0); assert(mon->notify_count < mon->wait_count); start = apr_time_now(); result = condvar_wait_impl(&mon->condition, &mon->mutex, millis, nanos, interruptable); if (result != TM_ERROR_NONE) { break; } // we should not change millis and nanos if both are 0 (meaning "no timeout") if (millis || nanos) { apr_interval_time_t elapsed = apr_time_now() - start; nanos -= (IDATA)((elapsed % 1000) * 1000); if (nanos < 0) { millis -= elapsed/1000 + 1; nanos += 1000000; } else { millis -= elapsed/1000; } if (millis < 0) { assert(status == TM_ERROR_NONE); status = TM_ERROR_TIMEOUT; break; } assert(0 <= nanos && nanos < 1000000); } } while(1); // Restore thread state status = port_mutex_lock(&self->mutex); assert(status == TM_ERROR_NONE); self->state &= ~TM_THREAD_STATE_SLEEPING; self->waited_monitor = NULL; status = port_mutex_unlock(&self->mutex); assert(status == TM_ERROR_NONE); // Release thread monitor mon->wait_count--; mon->owner = self; assert(mon->notify_count <= mon->wait_count); status = hythread_monitor_exit(mon); assert(status == TM_ERROR_NONE); if (self->request) { hythread_safe_point(); hythread_exception_safe_point(); } return (result == TM_ERROR_INTERRUPT && interruptable) ? TM_ERROR_INTERRUPT : TM_ERROR_NONE; }
/** * Instructs the current thread to wait until signaled to wake up or * the specified timeout is elapsed. * * @param[in] cond the condition variable on which to block. * @param[in] mutex the mutex that must be locked upon entering this function * @param[in] ms amount of time in milliseconds to wait * @param[in] nano amount of time in nanoseconds to wait * @sa apr_thread_cond_timedwait() * @return * TM_NO_ERROR on success */ IDATA VMCALL hycond_wait_timed(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { return condvar_wait_impl(cond, mutex, ms, nano, WAIT_NONINTERRUPTABLE); }
/** * Instructs the current thread to wait until it is signaled to wake up. * * @param[in] cond the condition variable on which to block * @param[in] mutex the mutex that must be locked upon entering this function * @sa apr_thread_cond_wait() * @return * TM_NO_ERROR on success */ IDATA VMCALL hycond_wait(hycond_t *cond, osmutex_t *mutex) { return condvar_wait_impl(cond, mutex, 0, 0, WAIT_NONINTERRUPTABLE); }
/** * Instructs the current thread to wait until signaled to wake up or * the specified timeout is elapsed. * * @param[in] cond the condition variable on which to block. * @param[in] mutex the mutex that must be locked upon entering this function * @param[in] ms amount of time in milliseconds to wait * @param[in] nano amount of time in nanoseconds to wait * @sa apr_thread_cond_timedwait() * @return * TM_NO_ERROR on success * TM_THREAD_INTERRUPTED in case thread was interrupted during wait. */ IDATA VMCALL hycond_wait_interruptable(hycond_t *cond, osmutex_t *mutex, I_64 ms, IDATA nano) { return condvar_wait_impl(cond, mutex, ms, nano, WAIT_INTERRUPTABLE); }