Cleans up TLS access macros (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 5 Sep 2012 20:58:58 +0000 (13:58 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 5 Sep 2012 20:58:58 +0000 (13:58 -0700)
Documents and cleans up the TLS access macros.  A bunch of the comments
were lost a few commits back.

Since I was changing things, I fixed up the whitespace and formatting
too.  If you want to review this, ignore whitespace.

You need to rebuild glibc, though not because of this patch.  Some of
the previous ones changed a few things (esp 716debe).  I needed to
completely rebuild glibc (delete glibc-XXX directory, the i686
files/directories, etc).

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

index be0c1a1..6ec9d07 100644 (file)
@@ -78,28 +78,29 @@ void highjack_current_uthread(struct uthread *uthread);
 void run_current_uthread(void);
 void run_uthread(struct uthread *uthread);
 
-static inline void
-init_uthread_tf(uthread_t *uth, void (*entry)(void),
-                void *stack_bottom, uint32_t size)
+/* Asking for trouble with this API, when we just want stacktop (or whatever
+ * the SP will be). */
+static inline void init_uthread_tf(struct uthread *uth, void (*entry)(void),
+                                   void *stack_bottom, uint32_t size)
 {
-  init_user_tf(&uth->utf, (long)entry, (long)(stack_bottom) + size);
+       init_user_tf(&uth->utf, (long)entry, (long)(stack_bottom) + size);
 }
 
-#define uthread_set_tls_var(uthread, name, val)                          \
-{                                                                        \
-      typeof(val) __val = val;                                           \
-      begin_access_tls_vars(((uthread_t*)(uthread))->tls_desc);          \
-      name = __val;                                                      \
-      end_access_tls_vars();                                             \
-}
+#define uthread_set_tls_var(uth, name, val)                                    \
+({                                                                             \
+       typeof(val) __val = val;                                                   \
+       begin_access_tls_vars(((struct uthread*)(uth))->tls_desc);                 \
+       name = __val;                                                              \
+       end_access_tls_vars();                                                     \
+})
 
-#define uthread_get_tls_var(uthread, name)                               \
-({                                                                       \
-      typeof(name) val;                                                  \
-      begin_access_tls_vars(((uthread_t*)(uthread))->tls_desc);          \
-      val = name;                                                        \
-      end_access_tls_vars();                                             \
-      val;                                                               \
+#define uthread_get_tls_var(uth, name)                                         \
+({                                                                             \
+       typeof(name) val;                                                          \
+       begin_access_tls_vars(((struct uthread*)(uth))->tls_desc);                 \
+       val = name;                                                                \
+       end_access_tls_vars();                                                     \
+       val;                                                                       \
 })
 
 #endif /* _UTHREAD_H */
index 0bbce22..df7c021 100644 (file)
@@ -151,93 +151,110 @@ static inline bool __preempt_is_pending(uint32_t vcoreid)
 #include <features.h>
 #if __GNUC_PREREQ(4,4)
 
-#define begin_safe_access_tls_vars()                                    \
-  void __attribute__((noinline, optimize("O0")))                        \
-  safe_access_tls_var_internal() {                                      \
-    asm("");                                                            \
+/* These macro acrobatics trick the compiler into not caching the (linear)
+ * address of TLS variables across loads/stores of the TLS descriptor, in lieu
+ * of a "TLS cmb()". */
+#define begin_safe_access_tls_vars()                                           \
+       void __attribute__((noinline, optimize("O0")))                             \
+       safe_access_tls_var_internal() {                                           \
+               asm("");                                                               \
 
-#define end_safe_access_tls_vars()                                      \
-  } safe_access_tls_var_internal();                                     \
+#define end_safe_access_tls_vars()                                             \
+       } safe_access_tls_var_internal();                                          \
 
 #else
 
-#define begin_safe_access_tls_vars()                                                   \
-  printf("ERROR: For PIC you must be using gcc 4.4 or above for tls support!\n");      \
-  printf("ERROR: As a quick fix, try recompiling your application with -static...\n"); \
-  exit(2);
+#define begin_safe_access_tls_vars()                                           \
+       printf("ERROR: For PIC use gcc 4.4 or above for tls support!\n");          \
+       printf("ERROR: As a quick fix, recompile your app with -static...\n");     \
+       exit(2);
 
-#define end_safe_access_tls_vars()                                         \
-  printf("Will never be called because we abort above!");                  \
-  exit(2);
+#define end_safe_access_tls_vars()                                             \
+       printf("Will never be called because we abort above!");                    \
+       exit(2);
 
 #endif //__GNUC_PREREQ
 #endif // __PIC__
 
-#define begin_access_tls_vars(tls_desc)                               \
-{                                                                     \
-       uthread_t *caller;                                            \
-        int invcore = in_vcore_context();                             \
-        if(!invcore) {                                                \
-          caller = current_uthread;                                   \
-         assert(caller);                                             \
-         caller->flags |= UTHREAD_DONT_MIGRATE;                      \
-        }                                                             \
-                                                                      \
-       cmb();                                                        \
-       int vcoreid = vcore_id();                                     \
-        void *temp_tls_desc = get_tls_desc(vcoreid);                  \
-                                                                      \
-        if(!invcore)                                                  \
-         disable_notifs(vcoreid);                                    \
-                                                                      \
-        set_tls_desc(tls_desc, vcoreid);                              \
-        begin_safe_access_tls_vars();
-
-#define end_access_tls_vars()                                         \
-        end_safe_access_tls_vars();                                   \
-        set_tls_desc(temp_tls_desc, vcoreid);                         \
-                                                                      \
-        if(!invcore) {                                                \
-         caller->flags &= ~UTHREAD_DONT_MIGRATE;                     \
-          cmb();                                                      \
-         if(in_multi_mode())                                         \
-            enable_notifs(vcoreid);                                   \
-        }                                                             \
-       cmb();                                                        \
+/* Switches into the TLS 'tls_desc'.  Capable of being called from either
+ * uthread or vcore context.  Pairs with end_access_tls_vars(). */
+#define begin_access_tls_vars(tls_desc)                                        \
+{                                                                              \
+       struct uthread *caller;                                                    \
+       uint32_t vcoreid;                                                          \
+       void *temp_tls_desc;                                                       \
+       bool invcore = in_vcore_context();                                         \
+       if (!invcore) {                                                            \
+               caller = current_uthread;                                              \
+               /* If you have no current_uthread, you might be called too early in the
+                * process's lifetime.  Make sure something like uthread_slim_init() has
+                * been run. */                                                        \
+               assert(caller);                                                        \
+               /* We need to disable notifs here (in addition to not migrating), since
+                * we could get interrupted when we're in the other TLS, and when the
+                * vcore restarts us, it will put us in our old TLS, not the one we were
+                * in when we were interrupted.  We need to not migrate, since once we
+                * know the vcoreid, we depend on being on the same vcore throughout.*/\
+               caller->flags |= UTHREAD_DONT_MIGRATE;                                 \
+               /* Not concerned about cross-core memory ordering, so no CPU mbs needed.
+                * The cmb is to prevent the compiler from issuing the vcore read before
+                * the DONT_MIGRATE write. */                                          \
+               cmb();                                                                 \
+               vcoreid = vcore_id();                                                  \
+               disable_notifs(vcoreid);                                               \
+       } else { /* vcore context */                                               \
+               vcoreid = vcore_id();                                                  \
+       }                                                                          \
+       temp_tls_desc = get_tls_desc(vcoreid);                                     \
+       set_tls_desc(tls_desc, vcoreid);                                           \
+       begin_safe_access_tls_vars();
+
+#define end_access_tls_vars()                                                  \
+       end_safe_access_tls_vars();                                                \
+       set_tls_desc(temp_tls_desc, vcoreid);                                      \
+       if (!invcore) {                                                            \
+               /* Note we reenable migration before enabling notifs, which is reverse
+                * from how we disabled notifs.  We must enabling migration before
+                * enabling notifs.  See 6c7fb12 and 5e4825eb4 for details. */         \
+               caller->flags &= ~UTHREAD_DONT_MIGRATE;                                \
+               cmb();  /* turn off DONT_MIGRATE before enabling notifs */             \
+               if (in_multi_mode())                                                   \
+                       enable_notifs(vcoreid);                                            \
+       }                                                                          \
 }
 
-#define safe_set_tls_var(name, val)                                   \
-({                                                                    \
-        begin_safe_access_tls_vars();                                 \
-        name = val;                                                   \
-        end_safe_access_tls_vars();                                   \
+#define safe_set_tls_var(name, val)                                            \
+({                                                                             \
+       begin_safe_access_tls_vars();                                              \
+       name = val;                                                                \
+       end_safe_access_tls_vars();                                                \
 })
 
-#define safe_get_tls_var(name)                                        \
-({                                                                    \
-        typeof(name) __val;                                           \
-        begin_safe_access_tls_vars();                                 \
-        __val = name;                                                 \
-        end_safe_access_tls_vars();                                   \
-        __val;                                                        \
+#define safe_get_tls_var(name)                                                 \
+({                                                                             \
+       typeof(name) __val;                                                        \
+       begin_safe_access_tls_vars();                                              \
+       __val = name;                                                              \
+       end_safe_access_tls_vars();                                                \
+       __val;                                                                     \
 })
 
-#define vcore_set_tls_var(name, val)                                     \
-{                                                                        \
-      extern void** vcore_thread_control_blocks;                         \
-      typeof(val) __val = val;                                           \
-      begin_access_tls_vars(vcore_thread_control_blocks[vcoreid]);       \
-      name = __val;                                                      \
-      end_access_tls_vars();                                             \
-}
+#define vcore_set_tls_var(name, val)                                           \
+({                                                                             \
+       extern void** vcore_thread_control_blocks;                                 \
+       typeof(val) __val = val;                                                   \
+       begin_access_tls_vars(vcore_thread_control_blocks[vcoreid]);               \
+       name = __val;                                                              \
+       end_access_tls_vars();                                                     \
+})
 
-#define vcore_get_tls_var(name)                                 \
-({                                                              \
-      typeof(name) val;                                         \
-      begin_access_tls_vars(vcore_tls_descs[vcoreid]);          \
-      val = name;                                               \
-      end_access_tls_vars();                                    \
-      val;                                                      \
+#define vcore_get_tls_var(name)                                                \
+({                                                                             \
+       typeof(name) val;                                                          \
+       begin_access_tls_vars(vcore_tls_descs[vcoreid]);                           \
+       val = name;                                                                \
+       end_access_tls_vars();                                                     \
+       val;                                                                       \
 })
 
 #ifdef __cplusplus
index b4cbb58..2ac9e00 100644 (file)
@@ -166,10 +166,6 @@ void __attribute__((noreturn)) uthread_vcore_entry(void)
  * this whenever you are "starting over" with a thread. */
 void uthread_init(struct uthread *new_thread)
 {
-       /* don't remove this assert without dealing with 'caller' below.  if we want
-        * to call this while in vcore context, we'll need to handle the TLS
-        * swapping a little differently */
-       uint32_t vcoreid;
        assert(new_thread);
        new_thread->state = UT_NOT_RUNNING;
        /* They should have zero'd the uthread.  Let's check critical things: */