parlib: Add uthread_sched_yield()
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 12 Apr 2017 17:29:00 +0000 (13:29 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 3 May 2017 16:13:02 +0000 (12:13 -0400)
Like pthread_yield(), but it works for all 2LSs.  It can also handle if you
are a single-threaded process (no 2LS and also an SCP).  When you have
multiple threads, you yield in favor of those other threads.  Otherwise,
you yield in favor of other processes.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/parlib/include/parlib/uthread.h
user/parlib/uthread.c
user/pthread/pthread.c

index eb96f79..0e09db1 100644 (file)
@@ -23,7 +23,8 @@ __BEGIN_DECLS
 /* Externally blocked thread reasons (for uthread_has_blocked()) */
 #define UTH_EXT_BLK_MUTEX                      1
 #define UTH_EXT_BLK_EVENTQ                     2
-#define UTH_EXT_BLK_JUSTICE                    3       /* whatever.  might need more options */
+#define UTH_EXT_BLK_YIELD                      3
+#define UTH_EXT_BLK_JUSTICE                    4       /* whatever.  might need more options */
 
 /* One per joiner, usually kept on the stack. */
 struct uth_join_kicker {
@@ -147,6 +148,7 @@ struct uthread *uthread_create(void *(*func)(void *), void *arg);
 void uthread_detach(struct uthread *uth);
 void uthread_join(struct uthread *uth, void **retval_loc);
 void uthread_join_arr(struct uth_join_request reqs[], size_t nr_req);
+void uthread_sched_yield(void);
 
 /* Call this when you are done with a uthread, forever, but before you free it */
 void uthread_cleanup(struct uthread *uthread);
index 70ef9b4..7f1d484 100644 (file)
@@ -1379,3 +1379,20 @@ void uthread_join(struct uthread *uth, void **retval_loc)
        req->retval_loc = retval_loc;
        uthread_join_arr(req, 1);
 }
+
+static void __uth_sched_yield_cb(struct uthread *uth, void *arg)
+{
+       uthread_has_blocked(uth, NULL, UTH_EXT_BLK_YIELD);
+       uthread_runnable(uth);
+}
+
+void uthread_sched_yield(void)
+{
+       if (!uth_2ls_is_multithreaded()) {
+               /* We're an SCP with no other threads, so we want to yield to other
+                * processes.  For SCPs, this will yield to the OS/other procs. */
+               syscall(SYS_proc_yield, TRUE);
+               return;
+       }
+       uthread_yield(TRUE, __uth_sched_yield_cb, NULL);
+}
index 5a548ac..61a8486 100644 (file)
@@ -252,11 +252,17 @@ static void pth_thread_has_blocked(struct uthread *uthread, uth_sync_t sync_obj,
        struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
 
        __pthread_generic_yield(pthread);
-       /* could imagine doing something with the flags.  For now, we just treat all
-        * externally blocked reasons as 'MUTEX'.  Whatever we do here, we are
+       /* Could imagine doing something with the flags.  For now, we just treat
+        * most externally blocked reasons as 'MUTEX'.  Whatever we do here, we are
         * mostly communicating to our future selves in pth_thread_runnable(), which
         * gets called by whoever triggered this callback */
-       pthread->state = PTH_BLK_MUTEX;
+       switch (flags) {
+       case UTH_EXT_BLK_YIELD:
+               pthread->state = PTH_BLK_YIELDING;
+               break;
+       default:
+               pthread->state = PTH_BLK_MUTEX;
+       };
        if (sync_obj)
                __uth_default_sync_enqueue(uthread, sync_obj);
 }
@@ -665,22 +671,10 @@ void pthread_exit(void *ret)
        pthread_exit_no_cleanup(ret);
 }
 
-/* Callback/bottom half of yield.  For those writing these pth callbacks, the
- * minimum is call generic, set state (communicate with runnable), then do
- * something that causes it to be runnable in the future (or right now). */
-static void __pth_yield_cb(struct uthread *uthread, void *junk)
-{
-       struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
-       __pthread_generic_yield(pthread);
-       pthread->state = PTH_BLK_YIELDING;
-       /* just immediately restart it */
-       pth_thread_runnable(uthread);
-}
-
 /* Cooperative yielding of the processor, to allow other threads to run */
 int pthread_yield(void)
 {
-       uthread_yield(TRUE, __pth_yield_cb, 0);
+       uthread_sched_yield();
        return 0;
 }