Redesign of our initialization path for libs (XCC)
authorKevin Klues <klueska@cs.berkeley.edu>
Thu, 25 Jun 2015 22:32:04 +0000 (15:32 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Fri, 26 Jun 2015 04:36:28 +0000 (21:36 -0700)
Previously there was a big mismatch of how we performed various
initialization for our various libraries, such as vcores, uthreads,
pthreads, etc.

We now do initialization based on libc *constructors* functions as
defined with an __attribute__((constructor)) attribute.  Doing
initalizaton this way makes things more consistent, as well as ensures
that evertything we want to have initialized gets initialized early on in
the lifetime of an application, while at the same time allowing us to
easily add per-library initialization simply by linking in some extra
libraries.

We previously had a hodgepodge of workarounds to essentially try and
give us this functionality, none of which worked very well (mostly based
on overwriting weak symbols and/or calling certain functions (i.e.
vcore_event_init()) in places that made following the logic of
initialization confusing).  Now all startup initialization occurs via
*constructor* functions with the name '*_lib_init()' and depenencies are
preserved using 'init_once_racy()' calls as the very first call in each
of these functions, followed by calls to the specific *_lib_init()
functions they depend on. Following this discipline, all *_lib_init()
functions will be called *exactly* once, and all of them will be called
in the proper order (even if they get called multiple times, they will
only execute once due to the init_once_racy() call). The hacky call to
vcore_event_init() in _start is now completely eliminated with this
design.

As part of this redesign, a few modifications were also made to separate
out what it really means to "initailize" a uthread and "initialize" a
pthread vs. both intitializing these constructs as well as transitioning
into an MCP. Previously, initializing the uthread library implicitly
turned you into an MCP.  Now there is an explicit call for
uthread_mcp_init() (which is also wrapped by pthread_mcp_init()), who's
sole purpose is to transition a process into an MCP that is
uthread/pthread ready. It is this functionality that we *actually*
needed to ensure was executed whenever we first call pthread_create()
and friends, not the simple initialization of thread0 to become a
uthread/pthread (that now happens inside our new constructor
functions at startup time).  Moreover, the old uthread_lib_init() is now
called uthread_2ls_init() in order to accommodate the new naming
convention, and it does essentially the same thing it did before (minus
the automatic transition into an MCP).

Because of this change in semantics, all tests that were previously
calling pthread_lib_init() explicitly (rather than relying on
pthread_create() to call it implicitly) must now call pthread_mcs_init()
instead.  This is actually more intuitive, given what its purpose is.

24 files changed:
tests/lock_test.c
tests/mcp_halt.c
tests/mhello.c
tests/old/condvar_test.c
tests/old/fpperf.cc
tests/old/syscall.c
tests/pthread_barrier_test.c
tests/pthread_switch.c
tests/pthread_test.c
tests/vmm/virtioconsole.c
tests/vmm/virtiopiocons.c
tests/vmm/virtiostress.c
tests/vmm/vmmcp.c
tests/vmm/vmmcpkernel.c
tests/vmm/vmrunkernel.c
tests/vmm/vmrunkernelmmap.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/start.c
user/parlib/include/uthread.h
user/parlib/include/vcore.h
user/parlib/uthread.c
user/parlib/vcore.c
user/pthread/pthread.c
user/pthread/pthread.h
user/utest/pvcalarm.c

index 9e59ce9..de0ffa0 100644 (file)
@@ -734,7 +734,7 @@ static void os_prep_work(pthread_t *worker_threads, int nr_threads)
        atomic_init(&indir_cnt, 0);
        pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
        pthread_need_tls(FALSE);
-       pthread_lib_init();                                     /* gives us one vcore */
+       pthread_mcp_init();                                     /* gives us one vcore */
        register_ev_handler(EV_VCORE_PREEMPT, trace_preempt, 0);
        register_ev_handler(EV_CHECK_MSGS, trace_indir, 0);
        if (pargs.fake_vc_ctx) {
index f994f60..ee234e6 100644 (file)
@@ -42,7 +42,8 @@ int main(int argc, char** argv)
        /* Inits a thread for us, though we won't use it.  Just a hack to get into
         * _M mode.  Note this requests one vcore for us */
        struct uthread dummy = {0};
-       uthread_lib_init(&dummy);
+       uthread_2ls_init(&dummy);
+       uthread_mcp_init();
 
        /* Reset the blockon to be the spinner...  This is really shitty.  Any
         * blocking calls after we become an MCP and before this will fail.  This is
index 863c17f..e9940a6 100644 (file)
@@ -80,7 +80,8 @@ int main(int argc, char** argv)
        /* Inits a thread for us, though we won't use it.  Just a hack to get into
         * _M mode.  Note this requests one vcore for us */
        struct uthread dummy = {0};
-       uthread_lib_init(&dummy);
+       uthread_2ls_init(&dummy);
+       uthread_mcp_init();
        /* Reset the blockon to be the spinner...  This is really shitty.  Any
         * blocking calls after we become an MCP and before this will fail.  This is
         * just mhello showing its warts due to trying to work outside uthread.c */
index 8e6f4d8..89bcab1 100644 (file)
@@ -62,7 +62,7 @@ void *__test_pthread_cond_waiter_t3(void *arg)
 int main(void)
 {
        int nr_msgs;
-       pthread_lib_init();
+       pthread_mcp_init();
        pthread_cond_init(cv, 0);
        pthread_mutex_init(pth_m, 0);
 
index f0b3dc6..55b0f29 100644 (file)
@@ -73,7 +73,7 @@ int main(int argc, char **argv)
        # ifdef __ros__
        if (argc == 4) {
                pthread_can_vcore_request(FALSE);
-               pthread_lib_init();                             
+               pthread_mcp_init();
                printf("Vcore %d mapped to pcore %d\n", 0, __procinfo.vcoremap[0].pcoreid);
        }
        # endif
index 2e047e0..1572a45 100644 (file)
@@ -57,7 +57,8 @@ int main(int argc, char** argv)
        /* Inits a thread for us, though we won't use it.  Just a hack to get into
         * _M mode.  Note this requests one vcore for us */
        struct uthread dummy = {0};
-       uthread_lib_init(&dummy);
+       uthread_2ls_init(&dummy);
+       uthread_mcs_init();
        /* Need to save our floating point state somewhere (like in the
         * user_thread_tcb so it can be restarted too */
        enable_notifs(0);
index 62c1a32..339fc20 100644 (file)
@@ -47,7 +47,7 @@ int main(int argc, char** argv)
        if (nr_vcores) {
                /* Only do the vcore trickery if requested */
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_vcores - 1);           /* ghetto incremental interface */
                for (int i = 0; i < nr_vcores; i++) {
                        printd("Vcore %d mapped to pcore %d\n", i,
index ffca972..3093c79 100644 (file)
@@ -70,7 +70,7 @@ int main(int argc, char** argv)
 
        pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
        pthread_need_tls(FALSE);
-       pthread_lib_init();                                     /* gives us one vcore */
+       pthread_mcp_init();                                     /* gives us one vcore */
 
        /* each is passed the other's pthread_t.  th1 starts the switching. */
        if (pthread_create(&th1, NULL, &switch_thread, &th2))
index 7bf1f15..45bc45c 100644 (file)
@@ -84,7 +84,7 @@ int main(int argc, char** argv)
                /* Only do the vcore trickery if requested */
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
                pthread_need_tls(FALSE);
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_vcores - 1);           /* ghetto incremental interface */
                for (int i = 0; i < nr_vcores; i++) {
                        printf_safe("Vcore %d mapped to pcore %d\n", i,
index 656ee4c..af422bf 100644 (file)
@@ -172,7 +172,7 @@ int main(int argc, char **argv)
        if (!(my_retvals && my_threads))
                perror("Init threads/malloc");
 
-       pthread_lib_init();     /* gives us one vcore */
+       pthread_mcp_init();     /* gives us one vcore */
        vcore_request(nr_threads - 1);  /* ghetto incremental interface */
        for (int i = 0; i < nr_threads; i++) {
                x = __procinfo.vcoremap;
index e1e60db..69d4dc3 100644 (file)
@@ -98,7 +98,7 @@ int main(int argc, char **argv)
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
                pthread_need_tls(FALSE);
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_threads - 1);          /* ghetto incremental interface */
                for (int i = 0; i < nr_threads; i++) {
                        x = __procinfo.vcoremap;
index 2fac3a8..34b8622 100644 (file)
@@ -254,7 +254,7 @@ int main(int argc, char **argv)
        if (!(my_retvals && my_threads))
                perror("Init threads/malloc");
 
-       pthread_lib_init();     /* gives us one vcore */
+       pthread_mcp_init();     /* gives us one vcore */
        vcore_request(nr_threads - 1);  /* ghetto incremental interface */
        for (int i = 0; i < nr_threads; i++) {
                x = __procinfo.vcoremap;
index f192a4d..3ff0964 100644 (file)
@@ -87,7 +87,7 @@ int main(int argc, char **argv)
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
                pthread_need_tls(FALSE);
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_threads - 1);          /* ghetto incremental interface */
                for (int i = 0; i < nr_threads; i++) {
                        x = __procinfo.vcoremap;
index 31165dc..aff6126 100644 (file)
@@ -103,7 +103,7 @@ int main(int argc, char **argv)
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
                pthread_need_tls(FALSE);
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_threads - 1);          /* ghetto incremental interface */
                for (int i = 0; i < nr_threads; i++) {
                        x = __procinfo.vcoremap;
index a64f996..0983a4f 100644 (file)
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
                pthread_need_tls(FALSE);
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_threads - 1);          /* ghetto incremental interface */
                for (int i = 0; i < nr_threads; i++) {
                        x = __procinfo.vcoremap;
index 27c40d7..4bc9cc7 100644 (file)
@@ -82,7 +82,7 @@ int main(int argc, char **argv)
 
                pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
                pthread_need_tls(FALSE);
-               pthread_lib_init();                                     /* gives us one vcore */
+               pthread_mcp_init();                                     /* gives us one vcore */
                vcore_request(nr_threads - 1);          /* ghetto incremental interface */
                for (int i = 0; i < nr_threads; i++) {
                        x = __procinfo.vcoremap;
index c5b846f..0e4dfba 100644 (file)
@@ -31,23 +31,8 @@ void __vcore_entry(void)
 }
 weak_alias(__vcore_entry, vcore_entry)
 
-void __vcore_event_init(void)
-{
-       fputs("Build your application with -lparlib\n", stderr);
-       abort();
-}
-weak_alias(__vcore_event_init, vcore_event_init)
-
 #define failmsg(str) write(2,str"\n",sizeof(str"\n")-1)
 
-void __ros_libc_csu_init(int argc, char **argv, char **envp)
-{
-       vcore_event_init();
-       // Note that we want the ctors to be called after vcore_event_init.
-       // (They are invoked by the next line.)
-       __libc_csu_init(argc, argv, envp);
-}
-
 void
 _start(void)
 {
@@ -112,7 +97,7 @@ _start(void)
        extern char** _environ;
        _environ = argv+argc+1;
 
-       __libc_start_main(&main, argc, argv, &__ros_libc_csu_init, &__libc_csu_fini,
+       __libc_start_main(&main, argc, argv, &__libc_csu_init, &__libc_csu_fini,
                          0, 0);
 
        failmsg("why did main() return?");
index e8be2b7..cfd2fbb 100644 (file)
@@ -55,9 +55,13 @@ struct schedule_ops {
 };
 extern struct schedule_ops *sched_ops;
 
+/* Low-level _S code calls this for basic uthreading without a 2LS */
+void uthread_lib_init(void);
 /* Call this, passing it a uthread representing thread0, from your 2LS init
  * routines.  When it returns, you're in _M mode (thread0 on vcore0) */
-void uthread_lib_init(struct uthread *uthread);
+void uthread_2ls_init(struct uthread *uthread);
+/* Call this to become an mcp capable of worling with uthreads. */
+void uthread_mcp_init(void);
 
 /* Functions to make/manage uthreads.  Can be called by functions such as
  * pthread_create(), which can wrap these with their own stuff (like attrs,
@@ -70,8 +74,6 @@ struct uth_thread_attr {
        bool want_tls;          /* default, no */
 };
 void uthread_init(struct uthread *new_thread, struct uth_thread_attr *attr);
-/* Low-level _S code calls this for basic uthreading without a 2LS */
-void uthread_slim_init(void);
 /* Call this when you are done with a uthread, forever, but before you free it */
 void uthread_cleanup(struct uthread *uthread);
 void uthread_runnable(struct uthread *uthread);
index f4aeacc..64742e1 100644 (file)
@@ -54,7 +54,6 @@ static inline void set_vcpd_tls_desc(uint32_t vcoreid, void *tls_desc);
 static inline uint64_t vcore_account_resume_nsec(uint32_t vcoreid);
 static inline uint64_t vcore_account_total_nsec(uint32_t vcoreid);
 void vcore_lib_init(void);
-void vcore_event_init(void);
 void vcore_change_to_m(void);
 int vcore_request(long nr_new_vcores);
 void vcore_yield(bool preempt_pending);
index 21afc63..ff196a3 100644 (file)
@@ -35,8 +35,8 @@ static void __ros_mcp_syscall_blockon(struct syscall *sysc);
 
 /* Helper, make the uthread code manage thread0.  This sets up uthread such
  * that the calling code and its TLS are tracked by the uthread struct, and
- * vcore0 thinks the uthread is running there.  Called only by slim_init (early
- * _S code) and lib_init.
+ * vcore0 thinks the uthread is running there.  Called only by lib_init (early
+ * _S code) and 2ls_init (when initializing thread0 for use in a 2LS).
  *
  * Whether or not uthreads have TLS, thread0 has TLS, given to it by glibc.
  * This TLS will get set whenever we use thread0, regardless of whether or not
@@ -64,18 +64,18 @@ static void uthread_manage_thread0(struct uthread *uthread)
         * its TLS vars. */
        set_tls_desc(get_vcpd_tls_desc(0), 0);
        begin_safe_access_tls_vars();
-       /* We might have a basic uthread already installed (from slim_init), so
+       /* We might have a basic uthread already installed (from lib_init), so
         * free it before installing the new one. */
        if (current_uthread)
                free(current_uthread);
        current_uthread = uthread;
-       /* We could consider setting __vcore_context = TRUE here, since this is
-        * probably the first time we're initializing vcore 0's TLS.  However, when
-        * we actually turn into an MCP, VC 0 will come up and set __vcore_context.
-        * I actually want it cleared until then, so that various asserts will catch
-        * if we call other uthread functions before the 2LS is set up (before we're
-        * an MCP).  For example, if someone calls uthread_yield from thread0 (which
-        * has TLS), we'll panic since VC 0's TLS doesn't know it's a VC yet. */
+       /* We may not be an MCP at this point (and thus not really working with
+        * vcores), but there is still the notion of something vcore_context-like
+        * even when running as an SCP (i.e. its more of a scheduler_context than a
+        * vcore_context).  Threfore we need to set __vcore_context to TRUE here to
+        * represent this (otherwise we will hit some asserts of not being in
+        * vcore_context when running in scheduler_context for the SCP. */
+       __vcore_context = TRUE;
        end_safe_access_tls_vars();
        set_tls_desc(uthread->tls_desc, 0);
        begin_safe_access_tls_vars();
@@ -84,14 +84,13 @@ static void uthread_manage_thread0(struct uthread *uthread)
        end_safe_access_tls_vars();
 }
 
-/* The real 2LS calls this, passing in a uthread representing thread0.  When it
+/* The real 2LS calls this to transition us into mcp mode.  When it
  * returns, you're in _M mode, still running thread0, on vcore0 */
-void uthread_lib_init(struct uthread *uthread)
+void uthread_mcp_init()
 {
+       /* Prevent this from happening more than once. */
        init_once_racy(return);
-       vcore_lib_init();
-       uthread_manage_thread0(uthread);
-       register_ev_handler(EV_EVENT, handle_ev_ev, 0);
+
        /* Receive preemption events.  Note that this merely tells the kernel how to
         * send the messages, and does not necessarily provide storage space for the
         * messages.  What we're doing is saying that all PREEMPT and CHECK_MSGS
@@ -117,6 +116,16 @@ void uthread_lib_init(struct uthread *uthread)
        vcore_change_to_m();
 }
 
+/* The real 2LS calls this, passing in a uthread representing thread0. */
+void uthread_2ls_init(struct uthread *uthread)
+{
+       /* All we need to do is set up thread0 to run with our new 2LS specific
+        * uthread pointer. Under the hood, this function will free any previously
+        * allocated uthread structs representing thread0 (e.g. the one set up by
+        * uthread_lib_init() previously). */
+       uthread_manage_thread0(uthread);
+}
+
 /* Helper: tells the kernel our SCP is capable of going into vcore context on
  * vcore 0.  Pairs with k/s/process.c scp_is_vcctx_ready(). */
 static void scp_vcctx_ready(void)
@@ -153,18 +162,22 @@ static char *__ros_errstr_loc(void)
                return current_uthread->err_str;
 }
 
-/* Slim-init - sets up basic uthreading for when we are in _S mode and before
- * we set up the 2LS.  Some apps may not have a 2LS and thus never do the full
+/* Sets up basic uthreading for when we are in _S mode and before we set up the
+ * 2LS.  Some apps may not have a 2LS and thus never do the full
  * vcore/2LS/uthread init. */
-void uthread_slim_init(void)
+void __attribute__((constructor)) uthread_lib_init(void)
 {
        struct uthread *uthread;
-       int ret = posix_memalign((void**)&uthread, __alignof__(struct uthread),
+       int ret;
+
+       /* Only run once, but make sure that vcore_lib_init() has run already. */
+       init_once_racy(return);
+       vcore_lib_init();
+
+       ret = posix_memalign((void**)&uthread, __alignof__(struct uthread),
                                 sizeof(struct uthread));
        assert(!ret);
        memset(uthread, 0, sizeof(struct uthread));     /* aggressively 0 for bugs */
-       /* TODO: consider a vcore_init_vc0 call. */
-       vcore_lib_init();
        uthread_manage_thread0(uthread);
        scp_vcctx_ready();
        init_posix_signals();
@@ -177,6 +190,7 @@ void uthread_slim_init(void)
         * errno.c for more info. */
        ros_errno_loc = __ros_errno_loc;
        ros_errstr_loc = __ros_errstr_loc;
+       register_ev_handler(EV_EVENT, handle_ev_ev, 0);
 }
 
 /* 2LSs shouldn't call uthread_vcore_entry directly */
index ba92019..8ab4686 100644 (file)
@@ -78,10 +78,25 @@ static int allocate_transition_stack(int id)
        return 0;
 }
 
-void vcore_lib_init(void)
+/* This gets called in glibc before calling the programs 'main'.  Need to set
+ * ourselves up so that thread0 is a uthread, and then register basic signals to
+ * go to vcore 0. */
+static void vcore_libc_init(void)
+{
+       register_printf_specifier('r', printf_errstr, printf_errstr_info);
+       /* TODO: register for other kevents/signals and whatnot (can probably reuse
+        * the simple ev_q).  Could also do this via explicit functions from the
+        * program. */
+}
+
+void __attribute__((constructor)) vcore_lib_init(void)
 {
        uintptr_t mmap_block;
-       /* Note this is racy, but okay.  The first time through, we are _S */
+
+       /* Note this is racy, but okay.  The first time through, we are _S.
+        * Also, this is the "lowest" level constructor for now, so we don't need
+        * to call any other init functions after our run_once() call. This may
+        * change in the future. */
        init_once_racy(return);
 
        /* Need to alloc vcore0's transition stuff here (technically, just the TLS)
@@ -111,6 +126,7 @@ void vcore_lib_init(void)
        }
        atomic_init(&vc_req_being_handled, 0);
        assert(!in_vcore_context());
+       vcore_libc_init();
        /* no longer need to enable notifs on vcore 0, it is set like that by
         * default (so you drop into vcore context immediately on transtioning to
         * _M) */
@@ -140,19 +156,6 @@ void vcore_reenter(void (*entry_func)(void))
   __vcore_reenter();
 }
 
-/* This gets called in glibc before calling the programs 'main'.  Need to set
- * ourselves up so that thread0 is a uthread, and then register basic signals to
- * go to vcore 0. */
-void vcore_event_init(void)
-{
-       register_printf_specifier('r', printf_errstr, printf_errstr_info);
-       /* set up our thread0 as a uthread */
-       uthread_slim_init();
-       /* TODO: register for other kevents/signals and whatnot (can probably reuse
-        * the simple ev_q).  Could also do this via explicit functions from the
-        * program. */
-}
-
 /* Helper, picks some sane defaults and changes the process into an MCP */
 void vcore_change_to_m(void)
 {
index f73229c..e994357 100644 (file)
@@ -587,14 +587,18 @@ int pthread_getattr_np(pthread_t __th, pthread_attr_t *__attr)
        return 0;
 }
 
-/* Do whatever init you want.  At some point call uthread_lib_init() and pass it
+/* Do whatever init you want.  At some point call uthread_2ls_init() and pass it
  * a uthread representing thread0 (int main()) */
-void pthread_lib_init(void)
+void __attribute__((constructor)) pthread_lib_init(void)
 {
        uintptr_t mmap_block;
        struct pthread_tcb *t;
        int ret;
 
+       /* Only run once, but make sure that uthread_lib_init() has run already. */
+       init_once_racy(return);
+       uthread_lib_init();
+
        /* Publish our sched_ops and signal_ops, overriding the defaults */
        sched_ops = &pthread_sched_ops;
        signal_ops = &pthread_signal_ops;
@@ -602,7 +606,6 @@ void pthread_lib_init(void)
        /* Some testing code might call this more than once (once for a slimmed down
         * pth 2LS, and another from pthread_create().  Also, this is racy, but the
         * first time through we are an SCP. */
-       init_once_racy(return);
        assert(!in_multi_mode());
        mcs_pdr_init(&queue_lock);
        /* Create a pthread_tcb for the main thread */
@@ -676,26 +679,38 @@ void pthread_lib_init(void)
                sysc_mgmt[i].ev_q->ev_mbox = sysc_mbox;
        }
 #endif
-       /* Initialize the uthread code (we're in _M mode after this).  Doing this
-        * last so that all the event stuff is ready when we're in _M mode.  Not a
-        * big deal one way or the other.  Note that vcore_lib_init() probably has
-        * happened, but don't rely on this.  Careful if your 2LS somehow wants to
-        * have its init stuff use things like vcore stacks or TLSs, we'll need to
-        * change this. */
-       uthread_lib_init((struct uthread*)t);
+       uthread_2ls_init((struct uthread*)t);
        atomic_init(&threads_total, 1);                 /* one for thread0 */
 }
 
+/* Make sure our scheduler runs inside an MCP rather than an SCP. */
+void pthread_mcp_init()
+{
+       /* Prevent this from happening more than once. */
+       init_once_racy(return);
+
+       uthread_mcp_init();
+       /* From here forward we are an MCP running on vcore 0. Could consider doing
+        * other pthread specific initialization based on knowing we are an mcp
+        * after this point. */
+}
+
 int __pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                      void *(*start_routine)(void *), void *arg)
 {
        struct uth_thread_attr uth_attr = {0};
-       run_once(pthread_lib_init());
-       /* Create the actual thread */
-       struct pthread_tcb *parent = (struct pthread_tcb*)current_uthread;
+       struct pthread_tcb *parent;
        struct pthread_tcb *pthread;
-       int ret = posix_memalign((void**)&pthread, __alignof__(struct pthread_tcb),
-                                sizeof(struct pthread_tcb));
+       int ret;
+
+       /* For now, unconditionally become an mcp when creating a pthread (if not
+        * one already). This may change in the future once we support 2LSs in an
+        * SCP. */
+       pthread_mcp_init();
+
+       parent = (struct pthread_tcb*)current_uthread;
+       ret = posix_memalign((void**)&pthread, __alignof__(struct pthread_tcb),
+                            sizeof(struct pthread_tcb));
        assert(!ret);
        memset(pthread, 0, sizeof(struct pthread_tcb)); /* aggressively 0 for bugs*/
        pthread->stacksize = PTHREAD_STACK_SIZE;        /* default */
@@ -849,7 +864,7 @@ 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_mcs_init();
        pthread->retval = ret;
        destroy_dtls();
        uthread_yield(FALSE, __pth_exit_cb, 0);
index 173afc6..d8004d5 100644 (file)
@@ -149,6 +149,7 @@ typedef dtls_key_t pthread_key_t;
 void pthread_can_vcore_request(bool can);      /* default is TRUE */
 void pthread_need_tls(bool need);                      /* default is TRUE */
 void pthread_lib_init(void);
+void pthread_mcp_init(void);
 void __pthread_generic_yield(struct pthread_tcb *pthread);
 
 /* Profiling alarms for pthreads.  (profalarm.c) */
index ffd777c..09e0eaa 100644 (file)
@@ -14,8 +14,8 @@ bool test_pvcalarms(void) {
                __sync_fetch_and_add(&count[vcore_id()], 1);
        }
 
-       pthread_lib_init();
        pthread_can_vcore_request(FALSE);
+       pthread_mcp_init();
        vcore_request(max_vcores() - num_vcores());
        for (int i=0; i<max_vcores(); i++)
                count[i] = 0;