Avoid locking in sbrk during early SCP (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 19 Sep 2016 16:39:31 +0000 (12:39 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 19 Sep 2016 18:45:55 +0000 (14:45 -0400)
This is related to replacing glibc's LLLs with PDR locks.

If, for whatever reason I don't fully understand, a binary links against
the real PDR locks (and not the internal ones in glibc for ld.so), then it
might try to use them before TLS is initialized.  Then it'll die when
checking in_vcore_context(), since the TLS descriptor is 0.

For future reference, here was the backtrace:

uth_disable_notifs+0x4
spin_pdr_lock+0x11
sbrk+0x3a
__libc_setup_tls+0xa9
__libc_start_main+0x11e
_start+0x29

Perhaps setup_tls doesn't always sbrk?  Or the linkage with parlib caused
the spin_pdr_symbol to be overridden?

Either way, we can ignore locking during early SCP context, so this change
should be safe.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sbrk.c

index d60831f..f41e6d8 100644 (file)
 #include <ros/syscall.h>
 #include <ros/memlayout.h>
 #include <ros/procinfo.h>
+#include <ros/procdata.h>
 #include <sys/mman.h>
 
-__libc_lock_define_initialized(static, brk_lock);
 static uintptr_t curbrk = 0;
+__libc_lock_define_initialized(static, __brk_lock);
+
+static bool is_early_scp(void)
+{
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
+
+       return (uintptr_t)vcpd->flags & VC_SCP_NOVCCTX;
+}
+
+/* Early SCP context doesn't need the locks, since we're single threaded, and we
+ * can't grab the PDR locks in some cases.  Specifically, we might not have a
+ * TLS for thread 0 yet, so we can't do things like check in_vcore_context(). */
+static void brk_lock(void)
+{
+       if (is_early_scp)
+               return;
+       __libc_lock_lock(__brk_lock);
+}
+
+static void brk_unlock(void)
+{
+       if (is_early_scp)
+               return;
+       __libc_lock_unlock(__brk_lock);
+}
 
 static uintptr_t
 __internal_getbrk (void)
@@ -75,9 +100,9 @@ __brk (void* addr)
   if(addr == 0)
     return 0;
 
-  __libc_lock_lock(brk_lock);
+  brk_lock();
   int ret = __internal_setbrk((uintptr_t)addr);
-  __libc_lock_unlock(brk_lock);
+  brk_unlock();
 
   return ret;
 }
@@ -89,7 +114,7 @@ weak_alias (__brk, brk)
 void *
 __sbrk (intptr_t increment)
 {
-  __libc_lock_lock(brk_lock);
+  brk_lock();
 
   uintptr_t oldbrk = __internal_getbrk();
   if ((increment > 0
@@ -98,7 +123,7 @@ __sbrk (intptr_t increment)
       || __internal_setbrk (oldbrk + increment) < 0)
     oldbrk = -1;
 
-  __libc_lock_unlock(brk_lock);
+  brk_unlock();
 
   return (void*)oldbrk;
 }