From: Nobuyoshi Nakada Date: 2007-03-20T02:03:56+09:00 Subject: [ruby-dev:30646] Re: [ruby-core:10580] Thread後のexecでENOTSUPPエラー対応 なかだです。 At Wed, 14 Mar 2007 21:26:31 +0900, H.Holon wrote in [ruby-dev:30581]: > +#ifdef _THREAD_SAFE > + pthread_testcancel(); > +#endif > #ifdef HAVE_NANOSLEEP > struct timespec req, rem; この位置だと変数宣言よりも前に実行文を追加することになるのでま ずいです。 もう一点、この方法ではtestcancelに入るまで中断させることができ ません。nanosleepやselectとの組合せよりも、cancel pointである pthread_cond_timedwait()あたりを使ったほうがよくはないでしょう か。 eval.cの分だけ。 Index: eval.c =================================================================== --- eval.c (revision 12059) +++ eval.c (working copy) @@ -11737,5 +11737,9 @@ catch_timer(sig) } -static pthread_t time_thread; +static struct { + pthread_t thid; + pthread_mutex_t lock; + pthread_cond_t cond; +} timer; static void* @@ -11743,17 +11747,41 @@ thread_timer(dummy) void *dummy; { - for (;;) { -#ifdef HAVE_NANOSLEEP - struct timespec req, rem; +#define PER_NANO 1000000000 - req.tv_sec = 0; - req.tv_nsec = 10000000; - nanosleep(&req, &rem); -#else - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10000; - select(0, NULL, NULL, NULL, &tv); -#endif +#define cleanup_start(v, t, i, d) \ + pthread_cleanup_push((void (*)_((void *)))pthread_##t##_##d, v);\ + pthread_##t##_##i +#define cleanup_end() pthread_cleanup_pop(1) + + struct timespec to; + struct timeval tv; + + /* count from the thread creation */ + gettimeofday(&tv, NULL); + to.tv_sec = tv.tv_sec; + to.tv_nsec = tv.tv_usec * 1000; + + cleanup_start(&timer.cond, cond, init, destroy)(&timer.cond, NULL); + cleanup_start(&timer.lock, mutex, init, destroy)(&timer.lock, NULL); + cleanup_start(&timer.lock, mutex, lock, unlock)(&timer.lock); + + for (;;) { + /* 0.01sec future */ + if ((to.tv_nsec += PER_NANO / 100) >= PER_NANO) { + to.tv_sec += to.tv_nsec / PER_NANO; + to.tv_nsec %= PER_NANO; + } + gettimeofday(&tv, NULL); + if ((tv.tv_sec < to.tv_sec) || + (tv.tv_sec == to.tv_sec && tv.tv_usec <= to.tv_nsec * 1000)) { + /* has past already */ + to.tv_sec = tv.tv_sec; + to.tv_nsec = tv.tv_usec * 1000; + continue; + } + if (!pthread_cond_timedwait(&timer.cond, &timer.lock, &to)) { + /* cancel request */ + break; + } if (!rb_thread_critical) { rb_thread_pending = 1; @@ -11763,4 +11791,8 @@ thread_timer(dummy) } } + + cleanup_end(); + cleanup_end(); + cleanup_end(); } @@ -11774,4 +11806,14 @@ rb_thread_stop_timer() { } + +void +rb_thread_cancel_timer() +{ + if (!thread_init) return; + pthread_mutex_lock(&timer.lock); + pthread_cond_signal(&timer.cond); + pthread_mutex_unlock(&timer.lock); + thread_init = 0; +} #elif defined(HAVE_SETITIMER) static void @@ -11811,4 +11853,10 @@ rb_thread_stop_timer() setitimer(ITIMER_VIRTUAL, &tval, NULL); } + +void +rb_thread_cancel_timer() +{ + thread_init = 0; +} #else /* !(_THREAD_SAFE || HAVE_SETITIMER) */ int rb_thread_tick = THREAD_TICK; -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦