Thread0 can call pthread_exit()
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 9 Aug 2013 23:41:11 +0000 (16:41 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 9 Aug 2013 23:41:11 +0000 (16:41 -0700)
Needed to not free thread0's TLS (it was never malloc'd), and needed to
trigger exit() when the last pthread (including thread0) exits.

user/parlib/include/uthread.h
user/parlib/uthread.c
user/pthread/pthread.c

index 4a1d2cd..cdd2fbc 100644 (file)
@@ -7,6 +7,7 @@
 #define UTHREAD_DONT_MIGRATE           0x001 /* don't move to another vcore */
 #define UTHREAD_SAVED                          0x002 /* uthread's state is in utf */
 #define UTHREAD_FPSAVED                                0x004 /* uthread's FP state is in uth->as */
+#define UTHREAD_IS_THREAD0                     0x008 /* thread0: glibc's main() thread */
 
 /* Thread States */
 #define UT_RUNNING             1
index a0945d0..81e6b26 100644 (file)
@@ -48,6 +48,8 @@ static void uthread_manage_thread0(struct uthread *uthread)
        uthread->state = UT_RUNNING;
        /* utf/as doesn't represent the state of the uthread (we are running) */
        uthread->flags &= ~(UTHREAD_SAVED | UTHREAD_FPSAVED);
+       /* need to track thread0 for TLS deallocation */
+       uthread->flags |= UTHREAD_IS_THREAD0;
        /* Change temporarily to vcore0s tls region so we can save the newly created
         * tcb into its current_uthread variable and then restore it.  One minor
         * issue is that vcore0's transition-TLS isn't TLS_INITed yet.  Until it is
@@ -368,8 +370,9 @@ yield_return_path:
 void uthread_cleanup(struct uthread *uthread)
 {
        printd("[U] thread %08p on vcore %d is DYING!\n", uthread, vcore_id());
-       /* we alloc and manage the TLS, so lets get rid of it */
-       if (__uthread_has_tls(uthread))
+       /* we alloc and manage the TLS, so lets get rid of it, except for thread0.
+        * glibc owns it.  might need to keep it around for a full exit() */
+       if (__uthread_has_tls(uthread) && !(uthread->flags & UTHREAD_IS_THREAD0))
                __uthread_free_tls(uthread);
 }
 
index bec5098..af378f9 100644 (file)
@@ -21,6 +21,7 @@ struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
 struct mcs_pdr_lock queue_lock;
 int threads_ready = 0;
 int threads_active = 0;
+atomic_t threads_total;
 bool can_adjust_vcores = TRUE;
 bool need_tls = TRUE;
 
@@ -415,6 +416,7 @@ void pthread_lib_init(void)
         * have its init stuff use things like vcore stacks or TLSs, we'll need to
         * change this. */
        uthread_lib_init((struct uthread*)t);
+       atomic_init(&threads_total, 1);                 /* one for thread0 */
 }
 
 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
@@ -456,6 +458,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
        uthread_init((struct uthread*)pthread, &uth_attr);
        pth_thread_runnable((struct uthread*)pthread);
        *thread = pthread;
+       atomic_inc(&threads_total);
        return 0;
 }
 
@@ -549,11 +552,19 @@ static void __pth_exit_cb(struct uthread *uthread, void *junk)
                        pth_thread_runnable((struct uthread*)temp_pth);
                }
        }
+       /* If we were the last pthread, we exit for the whole process.  Keep in mind
+        * that thread0 is counted in this, so this will only happen if that thread
+        * calls pthread_exit(). */
+       if ((atomic_fetch_and_add(&threads_total, -1) == 1))
+               exit(0);
 }
 
 void pthread_exit(void *ret)
 {
        struct pthread_tcb *pthread = pthread_self();
+       /* Some apps could call pthread_exit before initing.  This will slow down
+        * our pthread exits slightly. */
+       pthread_lib_init();
        pthread->retval = ret;
        destroy_dtls();
        uthread_yield(FALSE, __pth_exit_cb, 0);