* Performance enhancements: put syscalls and pthread_getspecific in
  fast path.

* Jiggle timing intervals yet again, probably completely pointless.

* Teach the scheduler that a thread in cond_timedwait is in a bounded
  wait.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@147 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c
index 855f710..b3f9de2 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -148,6 +148,9 @@
 static void do_pthread_mutex_lock ( ThreadId, Bool, 
                                     void* /* pthread_cond_t* */ );
 
+static void do_pthread_getspecific ( ThreadId,
+                                     UInt /* pthread_key_t */ );
+
 
 /* ---------------------------------------------------------------------
    Helper functions for the scheduler.
@@ -676,6 +679,10 @@
          do_pthread_mutex_lock( tid, True, (void *)(arg[1]) );
          return True;
 
+      case VG_USERREQ__PTHREAD_GETSPECIFIC:
+ 	 do_pthread_getspecific ( tid, (UInt)(arg[1]) );
+ 	 return True;
+
       default:
          /* Too hard; wimp out. */
          return False;
@@ -1057,14 +1064,16 @@
 static
 void check_for_pthread_cond_timedwait ( void )
 {
-   Int i;
+   Int i, now;
    for (i = 1; i < VG_N_THREADS; i++) {
       if (vg_threads[i].status != VgTs_WaitCV)
          continue;
       if (vg_threads[i].awaken_at == 0xFFFFFFFF /* no timeout */)
          continue;
-      if (VG_(read_millisecond_timer)() >= vg_threads[i].awaken_at)
+      now = VG_(read_millisecond_timer)();
+      if (now >= vg_threads[i].awaken_at) {
          do_pthread_cond_timedwait_TIMEOUT(i);
+      }
    }
 }
 
@@ -1076,7 +1085,7 @@
    struct vki_timespec req;
    struct vki_timespec rem;
    req.tv_sec = 0;
-   req.tv_nsec = 50 * 1000 * 1000;
+   req.tv_nsec = 20 * 1000 * 1000;
    res = VG_(nanosleep)( &req, &rem );   
    vg_assert(res == 0 /* ok */ || res == 1 /* interrupted by signal */);
 }
@@ -1096,7 +1105,7 @@
    ThreadId tid, tid_next;
    UInt     trc;
    UInt     dispatch_ctr_SAVED;
-   Int      request_code, done_this_time, n_in_fdwait_or_sleep;
+   Int      request_code, done_this_time, n_in_bounded_wait;
    Char     msg_buf[100];
    Addr     trans_addr;
    Bool     sigs_delivered;
@@ -1166,13 +1175,15 @@
 
          /* Try and find a thread (tid) to run. */
          tid_next = tid;
-         n_in_fdwait_or_sleep = 0;
+         n_in_bounded_wait = 0;
          while (True) {
             tid_next++;
             if (tid_next >= VG_N_THREADS) tid_next = 1;
             if (vg_threads[tid_next].status == VgTs_WaitFD
-                || vg_threads[tid_next].status == VgTs_Sleeping)
-               n_in_fdwait_or_sleep ++;
+                || vg_threads[tid_next].status == VgTs_Sleeping
+                || (vg_threads[tid_next].status == VgTs_WaitCV 
+                    && vg_threads[tid_next].awaken_at != 0xFFFFFFFF))
+               n_in_bounded_wait ++;
             if (vg_threads[tid_next].status == VgTs_Runnable) 
                break; /* We can run this one. */
             if (tid_next == tid) 
@@ -1188,7 +1199,7 @@
 	 }
 
          /* We didn't find a runnable thread.  Now what? */
-         if (n_in_fdwait_or_sleep == 0) {
+         if (n_in_bounded_wait == 0) {
             /* No runnable threads and no prospect of any appearing
                even if we wait for an arbitrary length of time.  In
                short, we have a deadlock. */
@@ -1278,6 +1289,16 @@
 	    }
 	 }
 
+         if (trc == VG_TRC_EBP_JMP_SYSCALL) {
+            /* Do a syscall for the vthread tid.  This could cause it
+               to become non-runnable. */
+            sched_do_syscall(tid);
+            if (vg_threads[tid].status == VgTs_Runnable)
+               continue; /* with this thread */
+            else
+               goto stage1;          
+	 }
+
 	 /* It's an event we can't quickly deal with.  Give up running
             this thread and handle things the expensive way. */
 	 break;
@@ -1330,11 +1351,13 @@
                1, whereupon the signal will be "delivered". */
 	    break;
 
+#if 0
          case VG_TRC_EBP_JMP_SYSCALL:
             /* Do a syscall for the vthread tid.  This could cause it
                to become non-runnable. */
             sched_do_syscall(tid);
             break;
+#endif
 
          case VG_TRC_EBP_JMP_CLIENTREQ: 
             /* Do a client request for the vthread tid.  Note that
@@ -2388,11 +2411,6 @@
                                  (pthread_key_t)(arg[1]) );
  	 break;
 
-      case VG_USERREQ__PTHREAD_GETSPECIFIC:
- 	 do_pthread_getspecific ( tid, 
-                                  (pthread_key_t)(arg[1]) );
- 	 break;
-
       case VG_USERREQ__PTHREAD_SETSPECIFIC:
  	 do_pthread_setspecific ( tid, 
                                   (pthread_key_t)(arg[1]),