[前][次][番号順一覧][スレッド一覧]

ruby-changes:19417

From: kosaki <ko1@a...>
Date: Sat, 7 May 2011 03:17:22 +0900 (JST)
Subject: [ruby-changes:19417] Ruby:r31457 (trunk): sleep_cond use monotonic time if possible.

kosaki	2011-05-07 03:17:14 +0900 (Sat, 07 May 2011)

  New Revision: 31457

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=31457

  Log:
    sleep_cond use monotonic time if possible.
    
    * thread_pthread.c (native_thread_init): change sleep_cond
      attribute to monotonic.
    * thread_pthread.c (native_sleep): use native_cond_timeout().
    
    * thread_pthread.c (native_cond_timeout): add overflow care.
    * thread_win32.c (native_cond_timeout): ditto.

  Modified files:
    trunk/ChangeLog
    trunk/thread_pthread.c
    trunk/thread_win32.c

Index: thread_win32.c
===================================================================
--- thread_win32.c	(revision 31456)
+++ thread_win32.c	(revision 31457)
@@ -491,29 +491,49 @@
     return __cond_timedwait(cond, mutex, timeout_ms);
 }
 
+#if SIZEOF_TIME_T == SIZEOF_LONG
+typedef unsigned long unsigned_time_t;
+#elif SIZEOF_TIME_T == SIZEOF_INT
+typedef unsigned int unsigned_time_t;
+#elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
+typedef unsigned LONG_LONG unsigned_time_t;
+#else
+# error cannot find integer type which size is same as time_t.
+#endif
+
+#define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
+
 static struct timespec
 native_cond_timeout(rb_thread_cond_t *cond, struct timespec timeout_rel)
 {
     int ret;
     struct timeval tv;
     struct timespec timeout;
+    struct timespec now;
 
     ret = gettimeofday(&tv, 0);
     if (ret != 0)
 	rb_sys_fail(0);
-    timeout.tv_sec = tv.tv_sec;
-    timeout.tv_nsec = tv.tv_usec * 1000;
+    now.tv_sec = tv.tv_sec;
+    now.tv_nsec = tv.tv_usec * 1000;
 
+  out:
+    timeout.tv_sec = now.tv_sec;
+    timeout.tv_nsec = now.tv_nsec;
     timeout.tv_sec += timeout_rel.tv_sec;
     timeout.tv_nsec += timeout_rel.tv_nsec;
+
     if (timeout.tv_nsec >= 1000*1000*1000) {
 	timeout.tv_sec++;
 	timeout.tv_nsec -= 1000*1000*1000;
     }
+
+    if (timeout.tv_sec < now.tv_sec)
+	timeout.tv_sec = TIMET_MAX;
+
     return timeout;
 }
 
-
 static void
 native_cond_initialize(rb_thread_cond_t *cond, int flags)
 {
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 31456)
+++ ChangeLog	(revision 31457)
@@ -1,3 +1,14 @@
+Sat May  7 03:14:13 2011  KOSAKI Motohiro  <kosaki.motohiro@g...>
+
+	sleep_cond use monotonic time if possible.
+
+	* thread_pthread.c (native_thread_init): change sleep_cond
+	  attribute to monotonic.
+	* thread_pthread.c (native_sleep): use native_cond_timeout().
+
+	* thread_pthread.c (native_cond_timeout): add overflow care.
+	* thread_win32.c (native_cond_timeout): ditto.
+
 Sat May  7 02:49:12 2011  KOSAKI Motohiro  <kosaki.motohiro@g...>
 	  fix win32 compile error.
 
Index: thread_pthread.c
===================================================================
--- thread_pthread.c	(revision 31456)
+++ thread_pthread.c	(revision 31457)
@@ -296,16 +296,29 @@
     return r;
 }
 
+#if SIZEOF_TIME_T == SIZEOF_LONG
+typedef unsigned long unsigned_time_t;
+#elif SIZEOF_TIME_T == SIZEOF_INT
+typedef unsigned int unsigned_time_t;
+#elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
+typedef unsigned LONG_LONG unsigned_time_t;
+#else
+# error cannot find integer type which size is same as time_t.
+#endif
+
+#define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
+
 static struct timespec
 native_cond_timeout(rb_thread_cond_t *cond, struct timespec timeout_rel)
 {
     int ret;
     struct timeval tv;
     struct timespec timeout;
+    struct timespec now;
 
 #if USE_MONOTONIC_COND
     if (cond->clockid == CLOCK_MONOTONIC) {
-	ret = clock_gettime(cond->clockid, &timeout);
+	ret = clock_gettime(cond->clockid, &now);
 	if (ret != 0)
 	    rb_sys_fail("clock_gettime()");
 	goto out;
@@ -318,16 +331,23 @@
     ret = gettimeofday(&tv, 0);
     if (ret != 0)
 	rb_sys_fail(0);
-    timeout.tv_sec = tv.tv_sec;
-    timeout.tv_nsec = tv.tv_usec * 1000;
+    now.tv_sec = tv.tv_sec;
+    now.tv_nsec = tv.tv_usec * 1000;
 
   out:
+    timeout.tv_sec = now.tv_sec;
+    timeout.tv_nsec = now.tv_nsec;
     timeout.tv_sec += timeout_rel.tv_sec;
     timeout.tv_nsec += timeout_rel.tv_nsec;
+
     if (timeout.tv_nsec >= 1000*1000*1000) {
 	timeout.tv_sec++;
 	timeout.tv_nsec -= 1000*1000*1000;
     }
+
+    if (timeout.tv_sec < now.tv_sec)
+	timeout.tv_sec = TIMET_MAX;
+
     return timeout;
 }
 
@@ -383,7 +403,7 @@
 static void
 native_thread_init(rb_thread_t *th)
 {
-    native_cond_initialize(&th->native_thread_data.sleep_cond, 0);
+    native_cond_initialize(&th->native_thread_data.sleep_cond, RB_CONDATTR_CLOCK_MONOTONIC);
     native_cond_initialize(&th->native_thread_data.gvl_cond, 0);
     ruby_thread_set_native(th);
 }
@@ -809,25 +829,25 @@
 #define PER_NANO 1000000000
 
 static void
-native_sleep(rb_thread_t *th, struct timeval *tv)
+native_sleep(rb_thread_t *th, struct timeval *timeout_tv)
 {
-    struct timespec ts;
+    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 (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;
-	}
+    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);
     }
 
-    thread_debug("native_sleep %ld\n", (long)(tv ? tv->tv_sec : -1));
     GVL_UNLOCK_BEGIN();
     {
-	pthread_mutex_lock(&th->interrupt_lock);
+	pthread_mutex_lock(lock);
 	th->unblock.func = ubf_pthread_cond_signal;
 	th->unblock.arg = th;
 
@@ -836,27 +856,15 @@
 	    thread_debug("native_sleep: interrupted before sleep\n");
 	}
 	else {
-	    if (tv == 0 || ts.tv_sec < tvn.tv_sec /* overflow */ ) {
-		thread_debug("native_sleep: pthread_cond_wait start\n");
-		native_cond_wait(&th->native_thread_data.sleep_cond,
-				 &th->interrupt_lock);
-		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 = native_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);
-	    }
+	    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(&th->interrupt_lock);
+	pthread_mutex_unlock(lock);
     }
     GVL_UNLOCK_END();
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]