Made pthreads work with our hack to never yield the last core
authorKevin Klues <klueska@parcad.millennium.berkeley.edu>
Sat, 24 Apr 2010 00:11:59 +0000 (17:11 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:44 +0000 (17:35 -0700)
Need a while loop, since sys_yield() may now return instead of
actually yielding.

tests/pthread_test.c
user/parlib/pthread.c

index 46f5bc5..9e243b2 100644 (file)
@@ -1,5 +1,8 @@
 #include <rstdio.h>
 #include <pthread.h>
+#include <stdlib.h>
+#include <parlib.h>
+#include <unistd.h>
 
 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 #define printf_safe(...) \
@@ -11,8 +14,10 @@ pthread_t t1;
 pthread_t t2;
 pthread_t t3;
 
-pthread_t my_threads[10];
-void *my_retvals[10];
+#define NUM_TEST_THREADS 10
+
+pthread_t my_threads[NUM_TEST_THREADS];
+void *my_retvals[NUM_TEST_THREADS];
 
 __thread int my_id;
 void *yield_thread(void* arg)
@@ -36,16 +41,15 @@ int main(int argc, char** argv)
 {
        void *retval1 = 0;
        void *retval2 = 0;
+       void *retval3 = 0;
 
        /* yield test */
        printf_safe("[A] About to create thread 1\n");
        pthread_create(&t1, NULL, &yield_thread, NULL);
        printf_safe("[A] About to create thread 2\n");
        pthread_create(&t2, NULL, &yield_thread, NULL);
-       printf_safe("About to create thread 3\n");
+       printf_safe("[A] About to create thread 3\n");
        pthread_create(&t3, NULL, &yield_thread, NULL);
-       while(1);
-       #if 0
        /* join on them */
        printf_safe("[A] About to join on thread 1\n");
        pthread_join(t1, &retval1);
@@ -53,21 +57,23 @@ int main(int argc, char** argv)
        printf_safe("[A] About to join on thread 2\n");
        pthread_join(t2, &retval2);
        printf_safe("[A] Successfully joined on thread 2 (retval: %p)\n", retval2);
-       printf_safe("About to join on thread 3\n");
+       printf_safe("[A] About to join on thread 3\n");
        pthread_join(t3, NULL);
-       #endif
+       printf_safe("[A] Successfully joined on thread 3 (retval: %p)\n", retval3);
 
        /* create and join on hellos */
-       while (1) {
-               for (int i = 1; i < 10; i++) {
+               for (int i = 1; i < NUM_TEST_THREADS; i++) {
                        printf_safe("[A] About to create thread %d\n", i);
                        pthread_create(&my_threads[i], NULL, &hello_thread, NULL);
                }
-               for (int i = 1; i < 10; i++) {
+               for (int i = 1; i < NUM_TEST_THREADS; i++) {
                        printf_safe("[A] About to join on thread %d\n", i);
                        pthread_join(my_threads[i], &my_retvals[i]);
                        printf_safe("[A] Successfully joined on thread %d (retval: %p)\n", i,
                                    my_retvals[i]);
                }
-       }
+       // Hack for now to make this process exit cleanly
+       // For some reason, libc decided to call sys_yield() while we 
+       // are exiting, which breaks our model in multicore mode...
+       sys_proc_destroy(getpid(),0);
 } 
index 9322bab..a9f44bf 100644 (file)
@@ -103,19 +103,31 @@ void __attribute__((noreturn)) vcore_entry()
        }
 
        /* no one currently running, so lets get someone from the ready queue */
-       mcs_lock_lock(&queue_lock);
-       struct pthread_tcb *new_thread = TAILQ_FIRST(&ready_queue);
-       if (new_thread) {
-               TAILQ_REMOVE(&ready_queue, new_thread, next);
-               TAILQ_INSERT_TAIL(&active_queue, new_thread, next);
-               threads_active++;
-               threads_ready--;
-       }
-       mcs_lock_unlock(&queue_lock);
-       if (!new_thread) {
-               printd("[P] No threads, vcore %d is yielding\n", vcoreid);
-               sys_yield(0);
+       struct pthread_tcb *new_thread = NULL;
+#ifdef __CONFIG_OSDI__
+       // Added so that we will return back to here if there is no new thread
+       // instead of at the top of this function.  Related to the fact that
+       // the kernel level scheduler can't yet handle scheduling manycore 
+       // processed yet when there are no more jobs left (i.e. sys_yield() will
+       // return instead of actually yielding...).
+       while(!new_thread) {
+#endif
+               mcs_lock_lock(&queue_lock);
+               new_thread = TAILQ_FIRST(&ready_queue);
+               if (new_thread) {
+                       TAILQ_REMOVE(&ready_queue, new_thread, next);
+                       TAILQ_INSERT_TAIL(&active_queue, new_thread, next);
+                       threads_active++;
+                       threads_ready--;
+               }
+               mcs_lock_unlock(&queue_lock);
+               if (!new_thread) {
+                       printd("[P] No threads, vcore %d is yielding\n", vcoreid);
+                       sys_yield(0);
+               }
+#ifdef __CONFIG_OSDI__
        }
+#endif
        /* Save a ptr to the pthread running in the transition context's TLS */
        current_thread = new_thread;
        printd("[P] Vcore %d is starting pthread %d\n", vcoreid, new_thread->id);