setTimeoutの最小時間を調べたときのメモ(断片)
デスクトップの整理でファイルを廃棄するのでこっちにいれとく。
while (!mShutdown) { if (mTimers.Count() > 0) { timer = static_cast<nsTimerImpl*>(mTimers[0]); if (!TIMER_LESS_THAN(now, timer->mTimeout + mTimeoutAdjustment)) { next: timer->PostTimerEvent(); } } if (mTimers.Count() > 0) { // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer // is due now or overdue. if (!TIMER_LESS_THAN(now, timeout)) goto next; } mWaiting = PR_TRUE; PR_WaitCondVar(mCondVar, waitFor); mWaiting = PR_FALSE; }
PR_WaitCondVarは環境依存。pthreadの場合
if (timeout == PR_INTERVAL_NO_TIMEOUT) rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex); else rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
こんなかんじ。1msタイムアウト前提として考えてpt_TimedWaitの中身。数字の操作をして
rv = pthread_cond_timedwait(cv, ml, &tmo);
を呼んでる。
ここでスレッドはsleepする。pthreadの実装を見ないとわかんない。
http://ftp.gnu.org/gnu/glibc/glibc-linuxthreads-2.2.5.tar.gz/linuxthreads/
static int pthread_cond_timedwait_relative(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec * abstime) { enqueue(&cond->__c_waiting, self);
condvarのlockが解けた後で指定時間までループ?
while (1) { if (!timedsuspend(self, abstime)) { int was_on_queue; /* __pthread_lock will queue back any spurious restarts that may happen to it. */ __pthread_lock(&cond->__c_lock, self); was_on_queue = remove_from_queue(&cond->__c_waiting, self); __pthread_unlock(&cond->__c_lock); if (was_on_queue) { __pthread_set_own_extricate_if(self, 0); pthread_mutex_lock(mutex); return ETIMEDOUT; } /* Eat the outstanding restart() from the signaller */ suspend(self); } if (THREAD_GETMEM(self, p_condvar_avail) == 0 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) { /* Count resumes that don't belong to us. */ spurious_wakeup_count++; continue; } break; }
~/linuxthreads/pthread.c
int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime) { sigset_t unblock, initial_mask; int was_signalled = 0; sigjmp_buf jmpbuf; if (sigsetjmp(jmpbuf, 1) == 0) { THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); THREAD_SETMEM(self, p_signal, 0); /* Unblock the restart signal */ sigemptyset(&unblock); sigaddset(&unblock, __pthread_sig_restart); sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); while (1) { struct timeval now; struct timespec reltime; /* Compute a time offset relative to now. */ __gettimeofday (&now, NULL); reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; reltime.tv_sec = abstime->tv_sec - now.tv_sec; if (reltime.tv_nsec < 0) { reltime.tv_nsec += 1000000000; reltime.tv_sec -= 1; } /* Sleep for the required duration. If woken by a signal, resume waiting as required by Single Unix Specification. */ if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) break; }
結局こうなる。__libc_nanosleepまではちょっと追いかける気にならない...