parlib: Don't run ctors in "fake parlib"
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 29 Jan 2017 22:36:41 +0000 (17:36 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 9 Feb 2017 17:31:09 +0000 (12:31 -0500)
Due to how we force gcc to link parlib with every binary, our shared
objects (e.g. libelf.so) have a copy of parlib and its ctors.  These
ctors run when the shared obj is loaded.  Additionally, the ctors run
again when the binary is loaded.  This means we've been running the
ctors multiple times (for perf and vmrunkernel), and haven't been
noticing it.  Yikes!

We can check the _start symbol to see if we're in the actual program or a
shared library (the fake parlib).  We need to run only one of them, and it
must be the programs.  Briefly, I tried letting the library's version run.
That registers the fake parlib's vcore_entry with the kernel.  So the
kernel would call into fake parlib, with its copy of data structures like
2LS ops and __in_vcore_context.  And the program would call into its copy.
Those structures would differ, and madness ensued.

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

index c0be1de..8cbf213 100644 (file)
@@ -53,6 +53,7 @@ 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);
+bool __in_fake_parlib(void);
 void vcore_change_to_m(void);
 void vcore_request_more(long nr_new_vcores);
 void vcore_request_total(long nr_vcores_wanted);
index c9a706b..b86a7ea 100644 (file)
@@ -234,6 +234,10 @@ void __attribute__((constructor)) uthread_lib_init(void)
                                           unsigned int ev_type, void *data);
        int ret;
 
+       /* Surprise!  Parlib's ctors also run in shared objects.  We can't have
+        * multiple versions of parlib (with multiple data structures). */
+       if (__in_fake_parlib())
+               return;
        /* Only run once, but make sure that vcore_lib_init() has run already. */
        init_once_racy(return);
        vcore_lib_init();
index 0380de6..1f8c59a 100644 (file)
@@ -35,6 +35,16 @@ void __attribute__((noreturn)) __vcore_entry(void)
 }
 void vcore_entry(void) __attribute__((weak, alias ("__vcore_entry")));
 
+static void __fake_start(void)
+{
+}
+void _start(void) __attribute__((weak, alias ("__fake_start")));
+
+bool __in_fake_parlib(void)
+{
+       return _start == __fake_start;
+}
+
 /* TODO: probably don't want to dealloc.  Considering caching */
 static void free_transition_tls(int id)
 {
@@ -168,6 +178,8 @@ static void vcore_libc_init(void)
 
 void __attribute__((constructor)) vcore_lib_init(void)
 {
+       if (__in_fake_parlib())
+               return;
        /* 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