Fixes TLS (again) for static programs
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 30 Nov 2010 22:24:44 +0000 (14:24 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:57 +0000 (17:35 -0700)
Basically just broadens the fix from def9c4d0666 to all TLS allocations,
not just vcore TLS.  Still, somewhat curious why this isn't handled by
glibc.  Perhaps we're using the wrong functions...

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

index e9fb15f..7027e4f 100644 (file)
@@ -29,6 +29,9 @@ extern "C" {
 /* Defined by glibc; Must be implemented by a user level threading library */
 extern void vcore_entry();
 
+/* Utility Functions */
+void *allocate_tls(void);
+
 /* Vcore API functions */
 int vcore_init(void);
 int vcore_id(void);
index 7a59eaa..08679df 100644 (file)
@@ -149,6 +149,7 @@ int pthread_attr_destroy(pthread_attr_t *a)
   return 0;
 }
 
+/* TODO: probably don't want to dealloc.  Considering caching */
 static void __pthread_free_tls(struct pthread_tcb *pt)
 {
        extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
@@ -160,10 +161,8 @@ static void __pthread_free_tls(struct pthread_tcb *pt)
 
 static int __pthread_allocate_tls(struct pthread_tcb *pt)
 {
-       extern void *_dl_allocate_tls (void *mem) internal_function;
-
        assert(!pt->tls_desc);
-       pt->tls_desc = _dl_allocate_tls(NULL);
+       pt->tls_desc = allocate_tls();
        if (!pt->tls_desc) {
                errno = ENOMEM;
                return -1;
index a8cecdc..dbff5dd 100644 (file)
@@ -17,6 +17,25 @@ static mcs_lock_t _vcore_lock = MCS_LOCK_INIT;
 
 extern void** vcore_thread_control_blocks;
 
+/* Get a TLS, returns 0 on failure.  Vcores have their own TLS, and any thread
+ * created by a user-level scheduler needs to create a TLS as well. */
+void *allocate_tls(void)
+{
+       extern void *_dl_allocate_tls(void *mem) internal_function;
+       void *tcb = _dl_allocate_tls(NULL);
+       if (!tcb)
+               return 0;
+       /* Make sure the TLS is set up properly - its tcb pointer points to itself.
+        * Keep this in sync with sysdeps/ros/XXX/tls.h.  For whatever reason,
+        * dynamically linked programs do not need this to be redone, but statics
+        * do. */
+       tcbhead_t *head = (tcbhead_t*)tcb;
+       head->tcb = tcb;
+       head->self = tcb;
+       return tcb;
+}
+
+/* TODO: probably don't want to dealloc.  Considering caching */
 static void free_transition_tls(int id)
 {
        extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
@@ -29,24 +48,19 @@ static void free_transition_tls(int id)
 
 static int allocate_transition_tls(int id)
 {
-       extern void *_dl_allocate_tls(void *mem) internal_function;
        /* We want to free and then reallocate the tls rather than simply 
-        * reinitializing it because its size may have changed */
+        * reinitializing it because its size may have changed.  TODO: not sure if
+        * this is right.  0-ing is one thing, but freeing and reallocating can be
+        * expensive, esp if syscalls are involved.  Check out glibc's
+        * allocatestack.c for what might work. */
        free_transition_tls(id);
 
-       void *tcb = _dl_allocate_tls(NULL);
+       void *tcb = allocate_tls();
 
        if ((vcore_thread_control_blocks[id] = tcb) == NULL) {
                errno = ENOMEM;
                return -1;
        }
-       /* Make sure the TLS is set up properly - its tcb pointer points to itself.
-        * Keep this in sync with sysdeps/ros/XXX/tls.h.  For whatever reason,
-        * dynamically linked programs do not need this to be redone, but statics
-        * do. */
-       tcbhead_t *head = (tcbhead_t*)tcb;
-       head->tcb = tcb;
-       head->self = tcb;
        return 0;
 }