Allows uthread_init() to be called repeatedly
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 22 Aug 2011 23:53:50 +0000 (16:53 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:06 +0000 (17:36 -0700)
So a 2LS can repurpose a thread, getting a fresh TLS, etc.  There's an
assertion that could trip (the flags and sysc check), though no one
should have a uthread with an old sysc.  'flags' could go either way,
but for now we want to catch "DONT_MIGRATE" being turned on.

user/parlib/uthread.c
user/parlib/vcore.c

index 0498c49..11671b9 100644 (file)
@@ -14,6 +14,7 @@ __thread struct uthread *current_uthread = 0;
 
 /* static helpers: */
 static int __uthread_allocate_tls(struct uthread *uthread);
+static int __uthread_reinit_tls(struct uthread *uthread);
 static void __uthread_free_tls(struct uthread *uthread);
 
 /* The real 2LS calls this, passing in a uthread representing thread0.  When it
@@ -87,8 +88,11 @@ void uthread_init(struct uthread *new_thread)
        new_thread->state = UT_CREATED;
        /* They should have zero'd the uthread.  Let's check critical things: */
        assert(!new_thread->flags && !new_thread->sysc);
-       /* Get a TLS */
-       assert(!__uthread_allocate_tls(new_thread));
+       /* Get a TLS.  If we already have one, reallocate/refresh it */
+       if (new_thread->tls_desc)
+               assert(!__uthread_reinit_tls(new_thread));
+       else
+               assert(!__uthread_allocate_tls(new_thread));
        /* Switch into the new guys TLS and let it know who it is */
        struct uthread *caller = current_uthread;
        assert(caller);
@@ -109,7 +113,7 @@ void uthread_init(struct uthread *new_thread)
        set_tls_desc(caller->tls_desc, vcoreid);
        /* Okay to migrate now, and enable interrupts/notifs.  This could be called
         * from vcore context, so only enable if we're in _M and in vcore context. */
-       if (!in_vcore_context() && num_vcores() > 0)
+       if (!in_vcore_context() && in_multi_mode())
                enable_notifs(vcoreid);
        wmb();
        caller->flags &= ~UTHREAD_DONT_MIGRATE;
@@ -369,6 +373,16 @@ static int __uthread_allocate_tls(struct uthread *uthread)
        return 0;
 }
 
+static int __uthread_reinit_tls(struct uthread *uthread)
+{
+       uthread->tls_desc = reinit_tls(uthread->tls_desc);
+       if (!uthread->tls_desc) {
+               errno = ENOMEM;
+               return -1;
+       }
+       return 0;
+}
+
 static void __uthread_free_tls(struct uthread *uthread)
 {
        free_tls(uthread->tls_desc);
index e052a8d..b521fdf 100644 (file)
@@ -47,6 +47,17 @@ void free_tls(void *tcb)
        _dl_deallocate_tls(tcb, TRUE);
 }
 
+/* Reinitialize / reset / refresh a TLS to its initial values.  This doesn't do
+ * it properly yet, it merely frees and re-allocates the TLS, which is why we're
+ * slightly ghetto and return the pointer you should use for the TCB. */
+void *reinit_tls(void *tcb)
+{
+       /* TODO: keep this in sync with the methods used in
+        * allocate_transition_tls() */
+       free_tls(tcb);
+       return allocate_tls();
+}
+
 /* TODO: probably don't want to dealloc.  Considering caching */
 static void free_transition_tls(int id)
 {