Added calls neessary to get lithe running on ROS
authorKevin Klues <klueska@cs.berkeley.edu>
Tue, 10 Apr 2012 01:13:22 +0000 (18:13 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Tue, 10 Apr 2012 01:13:22 +0000 (18:13 -0700)
This also includes some nice helper macros for accessing
and modifying TLS variables in other contexts without
having to remember the entire sequence of things you need
to do to make this happen.

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

index 4c35135..db10e82 100644 (file)
@@ -26,6 +26,7 @@ struct uthread {
        struct syscall *sysc;   /* syscall we're blocking on, if any */
        int state;
 };
+typedef struct uthread uthread_t;
 extern __thread struct uthread *current_uthread;
 
 /* 2L-Scheduler operations.  Can be 0.  Examples in pthread.c. */
@@ -70,7 +71,32 @@ bool register_evq(struct syscall *sysc, struct event_queue *ev_q);
 void deregister_evq(struct syscall *sysc);
 
 /* Helpers, which sched_entry() can call */
+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)
+{
+  init_user_tf(&uth->utf, (long)entry, (long)(stack_bottom));
+}
+
+#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_get_tls_var(uthread, name)                               \
+({                                                                       \
+      typeof(name) val;                                                  \
+      begin_access_tls_vars(((uthread_t*)(uthread))->tls_desc);          \
+      val = name;                                                        \
+      end_access_tls_vars();                                             \
+      val;                                                               \
+})
+
 #endif /* _UTHREAD_H */
index 126490c..62844d1 100644 (file)
@@ -143,6 +143,107 @@ static inline bool __preempt_is_pending(uint32_t vcoreid)
        return __procinfo.vcoremap[vcoreid].preempt_pending;
 }
 
+
+#ifndef __PIC__
+
+#define begin_safe_access_tls_vars()
+
+#define end_safe_access_tls_vars()
+
+#else
+
+#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("");                                                            \
+
+#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 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();                                                        \
+}
+
+#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 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;                                                      \
+})
+
 #ifdef __cplusplus
 }
 #endif
index 9287b92..98c592c 100644 (file)
@@ -403,6 +403,22 @@ static void __run_cur_uthread(void)
        }
 }
 
+/* Simply sets current uthread to be whatever the value of uthread is.  This
+ * can be called from outside of sched_entry() to highjack the current context,
+ * and make sure that the new uthread struct is used to store this context upon
+ * yielding, etc. USE WITH EXTREME CAUTION!
+*/
+void highjack_current_uthread(struct uthread *uthread)
+{
+       assert(uthread != current_uthread);
+       assert(uthread->tls_desc);
+
+       current_uthread->state = UT_RUNNABLE;
+       uthread->state = UT_RUNNING;
+       vcore_set_tls_var(current_uthread, uthread);
+       set_tls_desc(uthread->tls_desc, vcore_id());
+}
+
 /* Runs whatever thread is vcore's current_uthread.  This is nothing but a
  * couple checks, then the real run_cur_uth. */
 void run_current_uthread(void)