Implement pthread_yield.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@308 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/arch/x86-linux/vg_libpthread.c b/coregrind/arch/x86-linux/vg_libpthread.c
index 572f33a..46d1c65 100644
--- a/coregrind/arch/x86-linux/vg_libpthread.c
+++ b/coregrind/arch/x86-linux/vg_libpthread.c
@@ -259,6 +259,17 @@
    THREADs
    ------------------------------------------------ */
 
+__attribute__((weak))
+int pthread_yield ( void )
+{
+   int res;
+   ensure_valgrind("pthread_yield");
+   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+                           VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
+   return 0;
+}
+
+
 int pthread_equal(pthread_t thread1, pthread_t thread2)
 {
    return thread1 == thread2 ? 1 : 0;
diff --git a/coregrind/arch/x86-linux/vg_libpthread_unimp.c b/coregrind/arch/x86-linux/vg_libpthread_unimp.c
index 01c299e..1458dc2 100644
--- a/coregrind/arch/x86-linux/vg_libpthread_unimp.c
+++ b/coregrind/arch/x86-linux/vg_libpthread_unimp.c
@@ -252,8 +252,6 @@
                       { vgPlain_unimp("pthread_spin_trylock"); }
 __attribute__((weak)) void pthread_spin_unlock ( void )
                       { vgPlain_unimp("pthread_spin_unlock"); }
-__attribute__((weak)) void pthread_yield ( void )
-                      { vgPlain_unimp("pthread_yield"); }
 
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h
index cdcd1ca..692a48c 100644
--- a/coregrind/vg_include.h
+++ b/coregrind/vg_include.h
@@ -436,6 +436,7 @@
 #define VG_USERREQ__PTHREAD_SIGMASK         0x3012
 #define VG_USERREQ__SIGWAIT                 0x3013
 #define VG_USERREQ__PTHREAD_KILL            0x3014
+#define VG_USERREQ__PTHREAD_YIELD           0x3015
 
 /* Cosmetic ... */
 #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101
diff --git a/coregrind/vg_libpthread.c b/coregrind/vg_libpthread.c
index 572f33a..46d1c65 100644
--- a/coregrind/vg_libpthread.c
+++ b/coregrind/vg_libpthread.c
@@ -259,6 +259,17 @@
    THREADs
    ------------------------------------------------ */
 
+__attribute__((weak))
+int pthread_yield ( void )
+{
+   int res;
+   ensure_valgrind("pthread_yield");
+   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+                           VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
+   return 0;
+}
+
+
 int pthread_equal(pthread_t thread1, pthread_t thread2)
 {
    return thread1 == thread2 ? 1 : 0;
diff --git a/coregrind/vg_libpthread_unimp.c b/coregrind/vg_libpthread_unimp.c
index 01c299e..1458dc2 100644
--- a/coregrind/vg_libpthread_unimp.c
+++ b/coregrind/vg_libpthread_unimp.c
@@ -252,8 +252,6 @@
                       { vgPlain_unimp("pthread_spin_trylock"); }
 __attribute__((weak)) void pthread_spin_unlock ( void )
                       { vgPlain_unimp("pthread_spin_unlock"); }
-__attribute__((weak)) void pthread_yield ( void )
-                      { vgPlain_unimp("pthread_yield"); }
 
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c
index 57d687d..1c6dfed 100644
--- a/coregrind/vg_scheduler.c
+++ b/coregrind/vg_scheduler.c
@@ -1543,6 +1543,20 @@
 
 
 static
+void do_pthread_yield ( ThreadId tid )
+{
+   Char msg_buf[100];
+   vg_assert(VG_(is_valid_tid)(tid));
+
+   if (VG_(clo_trace_sched)) {
+      VG_(sprintf)(msg_buf, "yield");
+      print_sched_event(tid, msg_buf);
+   }
+   SET_EDX(tid, 0);
+}
+
+
+static
 void do_pthread_cancel ( ThreadId  tid,
                          pthread_t tid_cancellee )
 {
@@ -2672,6 +2686,12 @@
          do_pthread_kill ( tid, arg[1], arg[2] );
 	 break;
 
+      case VG_USERREQ__PTHREAD_YIELD:
+         do_pthread_yield ( tid );
+         /* because this is classified as a non-trivial client
+            request, the scheduler should now select a new thread to
+            run. */
+	 break;
 
       case VG_USERREQ__MAKE_NOACCESS:
       case VG_USERREQ__MAKE_WRITABLE:
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 93a79cf..796a033 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -28,4 +28,4 @@
 	bt_everything.c bt_literal.c \
 	pth_threadpool.c pth_specific.c pth_mutexspeed.c malloc3.c \
 	pth_once.c weirdioctl.c pth_signal1.c pth_signal2.c \
-	discard.c pth_semaphore1.c new_override.cpp
+	discard.c pth_semaphore1.c new_override.cpp pth_yield.c
diff --git a/tests/pth_yield.c b/tests/pth_yield.c
new file mode 100644
index 0000000..0b708ba
--- /dev/null
+++ b/tests/pth_yield.c
@@ -0,0 +1,44 @@
+
+#include <stdio.h>
+#include <assert.h>
+
+#define __USE_GNU
+#include <pthread.h>
+
+void do_one_thing ( void* v )
+{
+  int i, j, res;
+  for (i = 0; i < 10; i++) {
+    for (j = 0; j < 10; j++) {
+       printf("a "); fflush(stdout);
+    }
+    printf("\naaaaaaa-yielding\n");
+    res = pthread_yield();
+    assert(res == 0);
+  }
+}
+
+void do_another_thing ( void* v )
+{
+  int i, j, res;
+  for (i = 0; i < 10; i++) {
+    for (j = 0; j < 10; j++) {
+       printf("b "); fflush(stdout);
+    }
+    printf("\nbbbbbbb-yielding\n");
+    res = pthread_yield();
+    assert(res == 0);
+  }
+}
+
+
+int main ( void )
+{
+  pthread_t t1, t2;
+  pthread_create( &t1, NULL, (void*)do_one_thing, NULL );
+  pthread_create( &t2, NULL, (void*)do_another_thing, NULL );
+  pthread_join(t1, NULL);
+  pthread_join(t2, NULL);
+  printf("bye!\n");
+  return 0;
+}
diff --git a/vg_include.h b/vg_include.h
index cdcd1ca..692a48c 100644
--- a/vg_include.h
+++ b/vg_include.h
@@ -436,6 +436,7 @@
 #define VG_USERREQ__PTHREAD_SIGMASK         0x3012
 #define VG_USERREQ__SIGWAIT                 0x3013
 #define VG_USERREQ__PTHREAD_KILL            0x3014
+#define VG_USERREQ__PTHREAD_YIELD           0x3015
 
 /* Cosmetic ... */
 #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101
diff --git a/vg_libpthread.c b/vg_libpthread.c
index 572f33a..46d1c65 100644
--- a/vg_libpthread.c
+++ b/vg_libpthread.c
@@ -259,6 +259,17 @@
    THREADs
    ------------------------------------------------ */
 
+__attribute__((weak))
+int pthread_yield ( void )
+{
+   int res;
+   ensure_valgrind("pthread_yield");
+   VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
+                           VG_USERREQ__PTHREAD_YIELD, 0, 0, 0, 0);
+   return 0;
+}
+
+
 int pthread_equal(pthread_t thread1, pthread_t thread2)
 {
    return thread1 == thread2 ? 1 : 0;
diff --git a/vg_libpthread_unimp.c b/vg_libpthread_unimp.c
index 01c299e..1458dc2 100644
--- a/vg_libpthread_unimp.c
+++ b/vg_libpthread_unimp.c
@@ -252,8 +252,6 @@
                       { vgPlain_unimp("pthread_spin_trylock"); }
 __attribute__((weak)) void pthread_spin_unlock ( void )
                       { vgPlain_unimp("pthread_spin_unlock"); }
-__attribute__((weak)) void pthread_yield ( void )
-                      { vgPlain_unimp("pthread_yield"); }
 
 
 /*--------------------------------------------------------------------*/
diff --git a/vg_scheduler.c b/vg_scheduler.c
index 57d687d..1c6dfed 100644
--- a/vg_scheduler.c
+++ b/vg_scheduler.c
@@ -1543,6 +1543,20 @@
 
 
 static
+void do_pthread_yield ( ThreadId tid )
+{
+   Char msg_buf[100];
+   vg_assert(VG_(is_valid_tid)(tid));
+
+   if (VG_(clo_trace_sched)) {
+      VG_(sprintf)(msg_buf, "yield");
+      print_sched_event(tid, msg_buf);
+   }
+   SET_EDX(tid, 0);
+}
+
+
+static
 void do_pthread_cancel ( ThreadId  tid,
                          pthread_t tid_cancellee )
 {
@@ -2672,6 +2686,12 @@
          do_pthread_kill ( tid, arg[1], arg[2] );
 	 break;
 
+      case VG_USERREQ__PTHREAD_YIELD:
+         do_pthread_yield ( tid );
+         /* because this is classified as a non-trivial client
+            request, the scheduler should now select a new thread to
+            run. */
+	 break;
 
       case VG_USERREQ__MAKE_NOACCESS:
       case VG_USERREQ__MAKE_WRITABLE: