@@ -10569,6 +10569,12 @@ rb_thread_remove(th)
10569
10569
rb_thread_die (th );
10570
10570
th -> prev -> next = th -> next ;
10571
10571
th -> next -> prev = th -> prev ;
10572
+ #if defined(_THREAD_SAFE ) || defined(HAVE_SETITIMER )
10573
+ /* if this is the last ruby thread, stop timer signals */
10574
+ if (th -> next == th -> prev && th -> next == main_thread ) {
10575
+ rb_thread_stop_timer ();
10576
+ }
10577
+ #endif
10572
10578
}
10573
10579
10574
10580
static int
@@ -11955,58 +11961,98 @@ catch_timer(sig)
11955
11961
/* cause EINTR */
11956
11962
}
11957
11963
11958
- static int time_thread_alive_p = 0 ;
11959
- static pthread_t time_thread ;
11964
+ #define PER_NANO 1000000000
11965
+
11966
+ static struct timespec *
11967
+ get_ts (struct timespec * to , long ns )
11968
+ {
11969
+ struct timeval tv ;
11970
+
11971
+ #ifdef CLOCK_MONOTONIC
11972
+ if (clock_gettime (CLOCK_MONOTONIC , to ) != 0 )
11973
+ #endif
11974
+ {
11975
+ gettimeofday (& tv , NULL );
11976
+ to -> tv_sec = tv .tv_sec ;
11977
+ to -> tv_nsec = tv .tv_usec * 1000 ;
11978
+ }
11979
+ if ((to -> tv_nsec += ns ) >= PER_NANO ) {
11980
+ to -> tv_sec += to -> tv_nsec / PER_NANO ;
11981
+ to -> tv_nsec %= PER_NANO ;
11982
+ }
11983
+ return to ;
11984
+ }
11985
+
11986
+ static struct timer_thread {
11987
+ pthread_cond_t cond ;
11988
+ pthread_mutex_t lock ;
11989
+ pthread_t thread ;
11990
+ } time_thread = {PTHREAD_COND_INITIALIZER , PTHREAD_MUTEX_INITIALIZER };
11991
+
11992
+ #define safe_mutex_lock (lock ) \
11993
+ (pthread_mutex_lock(lock), \
11994
+ pthread_cleanup_push((void (*)_((void *)))pthread_mutex_unlock, lock))
11960
11995
11961
11996
static void *
11962
11997
thread_timer (dummy )
11963
11998
void * dummy ;
11964
11999
{
11965
- #ifdef _THREAD_SAFE
11966
- #define test_cancel () pthread_testcancel()
11967
- #else
11968
- #define test_cancel () /* void */
11969
- #endif
12000
+ struct timer_thread * running = ((void * * )dummy )[0 ];
12001
+ pthread_cond_t * start = ((void * * )dummy )[1 ];
12002
+ struct timespec to ;
12003
+ int err ;
11970
12004
11971
12005
sigset_t all_signals ;
11972
12006
11973
12007
sigfillset (& all_signals );
11974
12008
pthread_sigmask (SIG_BLOCK , & all_signals , 0 );
11975
12009
11976
- for (;;) {
11977
- #ifdef HAVE_NANOSLEEP
11978
- struct timespec req , rem ;
12010
+ safe_mutex_lock (& running -> lock );
12011
+ pthread_cond_signal (start );
11979
12012
11980
- test_cancel ();
11981
- req .tv_sec = 0 ;
11982
- req .tv_nsec = 10000000 ;
11983
- nanosleep (& req , & rem );
11984
- #else
11985
- struct timeval tv ;
11986
-
11987
- test_cancel ();
11988
- tv .tv_sec = 0 ;
11989
- tv .tv_usec = 10000 ;
11990
- select (0 , NULL , NULL , NULL , & tv );
11991
- #endif
12013
+ #define WAIT_FOR_10MS () \
12014
+ pthread_cond_timedwait(&running->cond, &running->lock, get_ts(&to, PER_NANO/100))
12015
+ while ((err = WAIT_FOR_10MS ()) == EINTR || err == ETIMEDOUT ) {
11992
12016
if (!rb_thread_critical ) {
11993
12017
rb_thread_pending = 1 ;
11994
12018
if (rb_trap_immediate ) {
11995
12019
pthread_kill (ruby_thid , SIGVTALRM );
11996
12020
}
11997
12021
}
11998
12022
}
11999
- #undef test_cancel
12023
+
12024
+ pthread_cleanup_pop (1 );
12025
+
12026
+ return NULL ;
12000
12027
}
12001
12028
12002
12029
void
12003
12030
rb_thread_start_timer ()
12004
12031
{
12032
+ void * args [2 ];
12033
+ static pthread_cond_t start = PTHREAD_COND_INITIALIZER ;
12034
+
12035
+ if (!thread_init ) return ;
12036
+ args [0 ] = & time_thread ;
12037
+ args [1 ] = & start ;
12038
+ safe_mutex_lock (& time_thread .lock );
12039
+ if (pthread_create (& time_thread .thread , 0 , thread_timer , args ) == 0 ) {
12040
+ thread_init = 1 ;
12041
+ pthread_atfork (0 , 0 , rb_thread_stop_timer );
12042
+ pthread_cond_wait (& start , & time_thread .lock );
12043
+ }
12044
+ pthread_cleanup_pop (1 );
12005
12045
}
12006
12046
12007
12047
void
12008
12048
rb_thread_stop_timer ()
12009
12049
{
12050
+ if (!thread_init ) return ;
12051
+ safe_mutex_lock (& time_thread .lock );
12052
+ pthread_cond_signal (& time_thread .cond );
12053
+ pthread_cleanup_pop (1 );
12054
+ pthread_join (time_thread .thread , NULL );
12055
+ thread_init = 0 ;
12010
12056
}
12011
12057
12012
12058
void
@@ -12047,11 +12093,12 @@ rb_thread_start_timer()
12047
12093
{
12048
12094
struct itimerval tval ;
12049
12095
12050
- if (! thread_init ) return ;
12096
+ if (thread_init ) return ;
12051
12097
tval .it_interval .tv_sec = 0 ;
12052
12098
tval .it_interval .tv_usec = 10000 ;
12053
12099
tval .it_value = tval .it_interval ;
12054
12100
setitimer (ITIMER_VIRTUAL , & tval , NULL );
12101
+ thread_init = 1 ;
12055
12102
}
12056
12103
12057
12104
void
@@ -12064,6 +12111,7 @@ rb_thread_stop_timer()
12064
12111
tval .it_interval .tv_usec = 0 ;
12065
12112
tval .it_value = tval .it_interval ;
12066
12113
setitimer (ITIMER_VIRTUAL , & tval , NULL );
12114
+ thread_init = 0 ;
12067
12115
}
12068
12116
12069
12117
void
@@ -12098,21 +12146,14 @@ rb_thread_start_0(fn, arg, th)
12098
12146
}
12099
12147
12100
12148
if (!thread_init ) {
12101
- thread_init = 1 ;
12102
12149
#if defined(HAVE_SETITIMER ) || defined(_THREAD_SAFE )
12103
12150
#if defined(POSIX_SIGNAL )
12104
12151
posix_signal (SIGVTALRM , catch_timer );
12105
12152
#else
12106
12153
signal (SIGVTALRM , catch_timer );
12107
12154
#endif
12108
12155
12109
- #ifdef _THREAD_SAFE
12110
- pthread_create (& time_thread , 0 , thread_timer , 0 );
12111
- time_thread_alive_p = 1 ;
12112
- pthread_atfork (0 , 0 , rb_child_atfork );
12113
- #else
12114
12156
rb_thread_start_timer ();
12115
- #endif
12116
12157
#endif
12117
12158
}
12118
12159
0 commit comments