Initial pthreads library on top of vcores
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 16 Apr 2010 00:50:51 +0000 (17:50 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:42 +0000 (17:35 -0700)
The old pthreads is now bthreads.  The current pthreads library can
handle restarting vcore0 after a transition, but other than that it
doesn't do anything.

kern/src/Makefrag
kern/src/kfs.c
kern/src/manager.c
tests/pthread_test.c
user/include/bthread.h [new file with mode: 0644]
user/include/pthread.h
user/parlib/Makefrag
user/parlib/bthread.c [new file with mode: 0644]
user/parlib/pthread.c
user/parlib/vcore.c

index 0311fb8..1ae8dac 100644 (file)
@@ -61,7 +61,8 @@ KERN_APPFILES += \
                  $(TESTS_DIR)/draw_nanwan \
                  $(TESTS_DIR)/hello \
                  $(TESTS_DIR)/mhello \
-                 $(TESTS_DIR)/manycore_test
+                 $(TESTS_DIR)/manycore_test \
+                 $(TESTS_DIR)/pthread_test
 endif
 
 KERN_LDFLAGS   := $(KERN_LDFLAGS) -L$(OBJDIR)/$(KERN_DIR) \
index 3ed134b..dbd79b0 100644 (file)
@@ -49,6 +49,7 @@ DECL_PROG(draw_nanwan);
 DECL_PROG(hello);
 DECL_PROG(mhello);
 DECL_PROG(manycore_test);
+DECL_PROG(pthread_test);
 DECL_FILE(kfs_test_txt);
 DECL_FILE(hello_txt);
 #endif
@@ -65,6 +66,7 @@ struct kfs_entry kfs[MAX_KFS_FILES] = {
        KFS_PENTRY(hello)
        KFS_PENTRY(mhello)
        KFS_PENTRY(manycore_test)
+       KFS_PENTRY(pthread_test)
        KFS_FENTRY(kfs_test_txt)
        KFS_FENTRY(hello_txt)
 #endif
index 6743f63..0ff709d 100644 (file)
@@ -65,7 +65,8 @@ void manager_brho(void)
        switch (progress++) {
                case 0:
                        // TODO: need to store the pid for future manager runs, not the *p
-                       p = kfs_proc_create(kfs_lookup_path("mhello"));
+                       p = kfs_proc_create(kfs_lookup_path("pthread_test"));
+                       //p = kfs_proc_create(kfs_lookup_path("mhello"));
                        //p = kfs_proc_create(kfs_lookup_path("roslib_mhello"));
                        //p = kfs_proc_create(kfs_lookup_path("roslib_mproctests"));
                        //p = kfs_proc_create(kfs_lookup_path("roslib_spawn"));
index 2229f12..76e548a 100644 (file)
@@ -24,15 +24,18 @@ int main(int argc, char** argv)
        thread_num = 0;
        printf_safe("About to create thread 0\n");
        pthread_create(&t0, NULL, &thread, NULL);
-       printf_safe("About to create thread 1\n");
-       pthread_create(&t1, NULL, &thread, NULL);
-       printf_safe("About to create thread 2\n");
-       pthread_create(&t2, NULL, &thread, NULL);
+       printf("returned from creating him, spinning\n");
+       while(1);
+
+//     printf_safe("About to create thread 1\n");
+//     pthread_create(&t1, NULL, &thread, NULL);
+//     printf_safe("About to create thread 2\n");
+//     pthread_create(&t2, NULL, &thread, NULL);
 
        printf_safe("About to join on thread 0\n");
        pthread_join(t0, NULL);
-       printf_safe("About to join on thread 1\n");
-       pthread_join(t1, NULL);
-       printf_safe("About to join on thread 2\n");
-       pthread_join(t2, NULL);
+//     printf_safe("About to join on thread 1\n");
+//     pthread_join(t1, NULL);
+//     printf_safe("About to join on thread 2\n");
+//     pthread_join(t2, NULL);
 } 
diff --git a/user/include/bthread.h b/user/include/bthread.h
new file mode 100644 (file)
index 0000000..47c35f0
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef _BTHREAD_H
+#define _BTHREAD_H
+
+#include <vcore.h>
+#include <mcs.h>
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/* Detach state.  */
+enum
+{
+  BTHREAD_CREATE_JOINABLE,
+#define BTHREAD_CREATE_JOINABLE        BTHREAD_CREATE_JOINABLE
+  BTHREAD_CREATE_DETACHED
+#define BTHREAD_CREATE_DETACHED        BTHREAD_CREATE_DETACHED
+};
+
+struct bthread_wqt
+{
+  void* (*start_routine)(void*);
+  void* arg;
+  int finished;
+  int detached;
+  struct bthread_wqt* next;
+};
+
+typedef struct
+{
+  int type;
+} bthread_mutexattr_t;
+
+typedef struct
+{
+  const bthread_mutexattr_t* attr;
+  int lock;
+} bthread_mutex_t;
+
+typedef struct
+{
+  int local_sense[32*MAX_VCORES];
+  volatile int sense;
+  int count;
+  int nprocs;
+  mcs_lock_t lock;
+} bthread_barrier_t;
+
+typedef struct
+{
+  int pshared;
+} bthread_condattr_t;
+
+typedef struct
+{
+  const bthread_condattr_t* attr;
+  int waiters[MAX_VCORES];
+} bthread_cond_t;
+
+typedef struct bthread_wqt work_queue_t;
+typedef work_queue_t* bthread_t;
+typedef int bthread_attr_t;
+typedef int bthread_barrierattr_t;
+typedef int bthread_once_t;
+typedef void** bthread_key_t;
+
+#define BTHREAD_ONCE_INIT 0
+#define BTHREAD_BARRIER_SERIAL_THREAD 12345
+#define BTHREAD_MUTEX_INITIALIZER {0}
+#define BTHREAD_MUTEX_NORMAL 0
+#define BTHREAD_MUTEX_DEFAULT BTHREAD_MUTEX_NORMAL
+#define BTHREAD_COND_INITIALIZER {0}
+#define BTHREAD_PROCESS_PRIVATE 0
+
+int bthread_attr_init(bthread_attr_t *);
+int bthread_attr_destroy(bthread_attr_t *);
+int bthread_create(bthread_t *, const bthread_attr_t *,
+                   void *(*)(void *), void *);
+int bthread_join(bthread_t, void **);
+
+int bthread_attr_setdetachstate(bthread_attr_t *__attr,int __detachstate);
+
+int bthread_mutex_destroy(bthread_mutex_t *);
+int bthread_mutex_init(bthread_mutex_t *, const bthread_mutexattr_t *);
+int bthread_mutex_lock(bthread_mutex_t *);
+int bthread_mutex_trylock(bthread_mutex_t *);
+int bthread_mutex_unlock(bthread_mutex_t *);
+int bthread_mutex_destroy(bthread_mutex_t *);
+
+int bthread_mutexattr_init(bthread_mutexattr_t *);
+int bthread_mutexattr_destroy(bthread_mutexattr_t *);
+int bthread_mutexattr_gettype(const bthread_mutexattr_t *, int *);
+int bthread_mutexattr_settype(bthread_mutexattr_t *, int);
+
+int bthread_cond_init(bthread_cond_t *, const bthread_condattr_t *);
+int bthread_cond_destroy(bthread_cond_t *);
+int bthread_cond_broadcast(bthread_cond_t *);
+int bthread_cond_signal(bthread_cond_t *);
+int bthread_cond_wait(bthread_cond_t *, bthread_mutex_t *);
+
+int bthread_condattr_init(bthread_condattr_t *);
+int bthread_condattr_destroy(bthread_condattr_t *);
+int bthread_condattr_setpshared(bthread_condattr_t *, int);
+int bthread_condattr_getpshared(bthread_condattr_t *, int *);
+
+#define bthread_rwlock_t bthread_mutex_t
+#define bthread_rwlockattr_t bthread_mutexattr_t
+#define bthread_rwlock_destroy bthread_mutex_destroy
+#define bthread_rwlock_init bthread_mutex_init
+#define bthread_rwlock_unlock bthread_mutex_unlock
+#define bthread_rwlock_rdlock bthread_mutex_lock
+#define bthread_rwlock_wrlock bthread_mutex_lock
+#define bthread_rwlock_tryrdlock bthread_mutex_trylock
+#define bthread_rwlock_trywrlock bthread_mutex_trylock
+
+bthread_t bthread_self();
+int bthread_equal(bthread_t t1, bthread_t t2);
+void bthread_exit(void* ret);
+int bthread_once(bthread_once_t* once_control, void (*init_routine)(void));
+
+int bthread_barrier_init(bthread_barrier_t* b, const bthread_barrierattr_t* a, int count);
+int bthread_barrier_wait(bthread_barrier_t* b);
+int bthread_barrier_destroy(bthread_barrier_t* b);
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index f9136e2..b45a478 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _PTHREAD_H
 #define _PTHREAD_H
 
+#include <sys/queue.h>
 #include <vcore.h>
 #include <mcs.h>
 
@@ -8,7 +9,25 @@
   extern "C" {
 #endif
 
-/* Detach state.  */
+/* Our internal types for pthread management */
+struct pthread_tcb {
+       TAILQ_ENTRY(pthread_tcb) next;
+       void* (*start_routine)(void*);
+       void* arg;
+
+       struct user_trapframe utf;
+       struct ancillary_state as;
+       void *tls_desc;
+       uint32_t vcoreid;
+       uint32_t pthreadid;
+
+       int finished;
+       int detached;
+};
+typedef struct pthread_tcb* pthread_t;
+TAILQ_HEAD(pthread_queue, pthread_tcb);
+
+/* For compatibility with the existing pthread library */
 enum
 {
   PTHREAD_CREATE_JOINABLE,
@@ -17,14 +36,13 @@ enum
 #define PTHREAD_CREATE_DETACHED        PTHREAD_CREATE_DETACHED
 };
 
-struct pthread_wqt
-{
-  void* (*start_routine)(void*);
-  void* arg;
-  int finished;
-  int detached;
-  struct pthread_wqt* next;
-};
+#define PTHREAD_ONCE_INIT 0
+#define PTHREAD_BARRIER_SERIAL_THREAD 12345
+#define PTHREAD_MUTEX_INITIALIZER {0}
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+#define PTHREAD_COND_INITIALIZER {0}
+#define PTHREAD_PROCESS_PRIVATE 0
 
 typedef struct
 {
@@ -57,21 +75,12 @@ typedef struct
   int waiters[MAX_VCORES];
 } pthread_cond_t;
 
-typedef struct pthread_wqt work_queue_t;
-typedef work_queue_t* pthread_t;
 typedef int pthread_attr_t;
 typedef int pthread_barrierattr_t;
 typedef int pthread_once_t;
 typedef void** pthread_key_t;
 
-#define PTHREAD_ONCE_INIT 0
-#define PTHREAD_BARRIER_SERIAL_THREAD 12345
-#define PTHREAD_MUTEX_INITIALIZER {0}
-#define PTHREAD_MUTEX_NORMAL 0
-#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
-#define PTHREAD_COND_INITIALIZER {0}
-#define PTHREAD_PROCESS_PRIVATE 0
-
+/* The pthreads API */
 int pthread_attr_init(pthread_attr_t *);
 int pthread_attr_destroy(pthread_attr_t *);
 int pthread_create(pthread_t *, const pthread_attr_t *,
index 145f33e..384c751 100644 (file)
@@ -11,6 +11,7 @@ ROS_USER_LIBS += $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a
 
 USER_PARLIB_SRCFILES := \
                  $(USER_PARLIB_DIR)/pthread.c \
+                 $(USER_PARLIB_DIR)/bthread.c \
                  $(USER_PARLIB_DIR)/vcore.c \
                  $(USER_PARLIB_DIR)/mcs.c \
                  $(USER_PARLIB_DIR)/panic.c \
diff --git a/user/parlib/bthread.c b/user/parlib/bthread.c
new file mode 100644 (file)
index 0000000..ab20bf5
--- /dev/null
@@ -0,0 +1,309 @@
+#include <bthread.h>
+#include <vcore.h>
+#include <mcs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <rstdio.h>
+#include <errno.h>
+#include <arch/atomic.h>
+
+int threads_active = 1;
+mcs_lock_t work_queue_lock = MCS_LOCK_INIT;
+bthread_t work_queue_head = 0;
+bthread_t work_queue_tail = 0;
+bthread_once_t init_once = BTHREAD_ONCE_INIT;
+bthread_t active_threads[MAX_VCORES] = {0};
+
+void queue_insert(bthread_t* head, bthread_t* tail, bthread_t node)
+{
+  node->next = 0;
+  if(*head == 0)
+    *head = node;
+  else
+    (*tail)->next = node;
+  *tail = node;
+}
+
+bthread_t queue_remove(bthread_t* head, bthread_t* tail)
+{
+  bthread_t node = *head;
+  *head = (*head)->next;
+  if(*head == 0)
+    *tail = 0;
+  node->next = 0;
+  return node;
+}
+
+void vcore_entry()
+{
+  bthread_t node = NULL;
+  while(1)
+  {
+    mcs_lock_lock(&work_queue_lock);
+    if(work_queue_head)
+      node = queue_remove(&work_queue_head,&work_queue_tail);
+    mcs_lock_unlock(&work_queue_lock);
+
+    if(node)
+      break;
+    cpu_relax();
+  }
+
+  active_threads[vcore_id()] = node;
+
+  bthread_exit(node->start_routine(node->arg));
+}
+
+void _bthread_init()
+{
+  // if we allocated active_threads dynamically, we'd do so here
+}
+
+int bthread_attr_init(bthread_attr_t *a)
+{
+  return 0;
+}
+
+int bthread_attr_destroy(bthread_attr_t *a)
+{
+  return 0;
+}
+
+int bthread_create(bthread_t* thread, const bthread_attr_t* attr,
+                   void *(*start_routine)(void *), void* arg)
+{
+  bthread_once(&init_once,&_bthread_init);
+
+  *thread = (bthread_t)malloc(sizeof(work_queue_t));
+  (*thread)->start_routine = start_routine;
+  (*thread)->arg = arg;
+  (*thread)->next = 0;
+  (*thread)->finished = 0;
+  (*thread)->detached = 0;
+  mcs_lock_lock(&work_queue_lock);
+  {
+    threads_active++;
+    queue_insert(&work_queue_head,&work_queue_tail,*thread);
+    // don't return until we get a vcore
+    while(threads_active > num_vcores() && vcore_request(1));
+  }
+  mcs_lock_unlock(&work_queue_lock);
+
+  return 0;
+}
+
+int bthread_join(bthread_t t, void** arg)
+{
+  volatile bthread_t thread = t;
+  while(!thread->finished);
+  if(arg) *arg = thread->arg;
+  free(thread);
+  return 0;
+}
+
+int bthread_mutexattr_init(bthread_mutexattr_t* attr)
+{
+  attr->type = BTHREAD_MUTEX_DEFAULT;
+  return 0;
+}
+
+int bthread_mutexattr_destroy(bthread_mutexattr_t* attr)
+{
+  return 0;
+}
+
+
+int bthread_attr_setdetachstate(bthread_attr_t *__attr,int __detachstate) {
+       *__attr = __detachstate;
+       return 0;
+}
+
+int bthread_mutexattr_gettype(const bthread_mutexattr_t* attr, int* type)
+{
+  *type = attr ? attr->type : BTHREAD_MUTEX_DEFAULT;
+  return 0;
+}
+
+int bthread_mutexattr_settype(bthread_mutexattr_t* attr, int type)
+{
+  if(type != BTHREAD_MUTEX_NORMAL)
+    return EINVAL;
+  attr->type = type;
+  return 0;
+}
+
+int bthread_mutex_init(bthread_mutex_t* m, const bthread_mutexattr_t* attr)
+{
+  m->attr = attr;
+  m->lock = 0;
+  return 0;
+}
+
+int bthread_mutex_lock(bthread_mutex_t* m)
+{
+  while(bthread_mutex_trylock(m))
+    while(*(volatile size_t*)&m->lock);
+  return 0;
+}
+
+int bthread_mutex_trylock(bthread_mutex_t* m)
+{
+  return atomic_swap(&m->lock,1) == 0 ? 0 : EBUSY;
+}
+
+int bthread_mutex_unlock(bthread_mutex_t* m)
+{
+  m->lock = 0;
+  return 0;
+}
+
+int bthread_mutex_destroy(bthread_mutex_t* m)
+{
+  return 0;
+}
+
+int bthread_cond_init(bthread_cond_t *c, const bthread_condattr_t *a)
+{
+  c->attr = a;
+  memset(c->waiters,0,sizeof(c->waiters));
+  return 0;
+}
+
+int bthread_cond_destroy(bthread_cond_t *c)
+{
+  return 0;
+}
+
+int bthread_cond_broadcast(bthread_cond_t *c)
+{
+  memset(c->waiters,0,sizeof(c->waiters));
+  return 0;
+}
+
+int bthread_cond_signal(bthread_cond_t *c)
+{
+  int i;
+  for(i = 0; i < max_vcores(); i++)
+  {
+    if(c->waiters[i])
+    {
+      c->waiters[i] = 0;
+      break;
+    }
+  }
+  return 0;
+}
+
+int bthread_cond_wait(bthread_cond_t *c, bthread_mutex_t *m)
+{
+  c->waiters[vcore_id()] = 1;
+  bthread_mutex_unlock(m);
+
+  volatile int* poll = &c->waiters[vcore_id()];
+  while(*poll);
+
+  bthread_mutex_lock(m);
+
+  return 0;
+}
+
+int bthread_condattr_init(bthread_condattr_t *a)
+{
+  a = BTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int bthread_condattr_destroy(bthread_condattr_t *a)
+{
+  return 0;
+}
+
+int bthread_condattr_setpshared(bthread_condattr_t *a, int s)
+{
+  a->pshared = s;
+  return 0;
+}
+
+int bthread_condattr_getpshared(bthread_condattr_t *a, int *s)
+{
+  *s = a->pshared;
+  return 0;
+}
+
+bthread_t bthread_self()
+{
+  return active_threads[vcore_id()];
+}
+
+int bthread_equal(bthread_t t1, bthread_t t2)
+{
+  return t1 == t2;
+}
+
+void bthread_exit(void* ret)
+{
+  bthread_once(&init_once,&_bthread_init);
+
+  bthread_t t = bthread_self();
+
+  mcs_lock_lock(&work_queue_lock);
+  threads_active--;
+  if(threads_active == 0)
+    exit(0);
+  mcs_lock_unlock(&work_queue_lock);
+
+  if(t)
+  {
+    t->arg = ret;
+    t->finished = 1;
+    if(t->detached)
+      free(t);
+  }
+
+  vcore_entry();
+}
+
+int bthread_once(bthread_once_t* once_control, void (*init_routine)(void))
+{
+  if(atomic_swap(once_control,1) == 0)
+    init_routine();
+  return 0;
+}
+
+int bthread_barrier_init(bthread_barrier_t* b, const bthread_barrierattr_t* a, int count)
+{
+  memset(b->local_sense,0,sizeof(b->local_sense));
+
+  b->sense = 0;
+  b->nprocs = b->count = count;
+  mcs_lock_init(&b->lock);
+  return 0;
+}
+
+int bthread_barrier_wait(bthread_barrier_t* b)
+{
+  int id = vcore_id();
+  int ls = b->local_sense[32*id] = 1 - b->local_sense[32*id];
+
+  mcs_lock_lock(&b->lock);
+  int count = --b->count;
+  mcs_lock_unlock(&b->lock);
+
+  if(count == 0)
+  {
+    b->count = b->nprocs;
+    b->sense = ls;
+    return BTHREAD_BARRIER_SERIAL_THREAD;
+  }
+  else
+  {
+    while(b->sense != ls);
+    return 0;
+  }
+}
+
+int bthread_barrier_destroy(bthread_barrier_t* b)
+{
+  return 0;
+}
index 621e79f..e25c4e7 100644 (file)
@@ -6,58 +6,98 @@
 #include <assert.h>
 #include <rstdio.h>
 #include <errno.h>
+#include <ros/notification.h>
 #include <arch/atomic.h>
+#include <sys/queue.h>
+#include <assert.h>
 
-int threads_active = 1;
-mcs_lock_t work_queue_lock = MCS_LOCK_INIT;
-pthread_t work_queue_head = 0;
-pthread_t work_queue_tail = 0;
+struct pthread_queue ready_queue = TAILQ_HEAD_INITIALIZER(ready_queue);
+struct pthread_queue active_queue = TAILQ_HEAD_INITIALIZER(active_queue);
+mcs_lock_t queue_lock = MCS_LOCK_INIT;
 pthread_once_t init_once = PTHREAD_ONCE_INIT;
-pthread_t active_threads[MAX_VCORES] = {0};
+int threads_ready = 0;
 
-void queue_insert(pthread_t* head, pthread_t* tail, pthread_t node)
-{
-  node->next = 0;
-  if(*head == 0)
-    *head = node;
-  else
-    (*tail)->next = node;
-  *tail = node;
-}
+__thread struct pthread_tcb *current_thread = 0;
 
-pthread_t queue_remove(pthread_t* head, pthread_t* tail)
+void _pthread_init()
 {
-  pthread_t node = *head;
-  *head = (*head)->next;
-  if(*head == 0)
-    *tail = 0;
-  node->next = 0;
-  return node;
+       if (vcore_init())
+               printf("vcore_init() failed, we're fucked!\n");
+       
+       assert(vcore_id() == 0);
+
+       /* tell the kernel where and how we want to receive notifications */
+       struct notif_method *nm;
+       for (int i = 0; i < MAX_NR_NOTIF; i++) {
+               nm = &__procdata.notif_methods[i];
+               nm->flags |= NOTIF_WANTED | NOTIF_MSG | NOTIF_IPI;
+               nm->vcoreid = i % 2; // vcore0 or 1, keepin' it fresh.
+       }
+
+       /* Create a pthread_tcb for the main thread */
+       pthread_t t = (pthread_t)calloc(sizeof(struct pthread_tcb), 1);
+       t->pthreadid = 0; // The main thread gets id 0
+       
+       /* Save a pointer to the newly created threads tls region into its tcb */
+       t->tls_desc = get_tls_desc(0);
+
+       /* Change temporarily to vcore0s tls region so we can save the newly created
+        * tcb into its current_thread variable and then restore it.  One minor
+        * issue is that vcore0's transition-TLS isn't TLS_INITed yet.  Until it is
+        * (right before vcore_entry(), don't try and take the address of any of
+        * its TLS vars. */
+       extern void** vcore_thread_control_blocks;
+       set_tls_desc(vcore_thread_control_blocks[0], 0);
+       current_thread = t;
+       set_tls_desc(t->tls_desc, 0);
+
+       // TODO: consider replacing this when we have an interface allowing
+       // requesting absolute num vcores, and moving it to pthread_create and
+       // asking for 2
+       vcore_request(1);
 }
 
 void vcore_entry()
 {
-  pthread_t node = NULL;
-  while(1)
-  {
-    mcs_lock_lock(&work_queue_lock);
-    if(work_queue_head)
-      node = queue_remove(&work_queue_head,&work_queue_tail);
-    mcs_lock_unlock(&work_queue_lock);
+       uint32_t vcoreid = vcore_id();
+       printf("Hi entering vcore entry on vcore %d!!\n", vcoreid);
 
-    if(node)
-      break;
-    cpu_relax();
-  }
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       struct vcore *vc = &__procinfo.vcoremap[vcoreid];
 
-  active_threads[vcore_id()] = node;
+       /* Put this in the loop that deals with notifications.  It will return if
+        * there is no preempt pending. */ 
+       if (vc->preempt_pending)
+               sys_yield(TRUE);
 
-  pthread_exit(node->start_routine(node->arg));
-}
+       if (current_thread) {
+               /* Do one last check for notifs before clearing pending */
+               vcpd->notif_pending = 0;
+               set_tls_desc(current_thread->tls_desc, 0);
 
-void _pthread_init()
-{
-  // if we allocated active_threads dynamically, we'd do so here
+               /* Load silly state (Floating point) too, though not for a restart -
+                * only for a fresh pthread */
+       
+               /* Pop the user trap frame */
+               pop_ros_tf(&vcpd->notif_tf, vcoreid);
+               assert(0);
+       }
+       while(1);
+
+#if 0
+       pthread_t node = NULL;
+       mcs_lock_lock(&queue_lock);
+       if(ready_queue)
+               node = queue_remove(&work_queue_head,&work_queue_tail);
+mcs_lock_unlock(&work_queue_lock);
+
+if(node)
+  break;
+cpu_relax();
+active_threads[vcore_id()] = node;
+
+pthread_exit(node->start_routine(node->arg));
+#endif
 }
 
 int pthread_attr_init(pthread_attr_t *a)
@@ -70,27 +110,36 @@ int pthread_attr_destroy(pthread_attr_t *a)
   return 0;
 }
 
+void __pthread_create(pthread_t* thread, const pthread_attr_t* attr,
+                   void *(*start_routine)(void *), void* arg) 
+{
+}
+
 int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
                    void *(*start_routine)(void *), void* arg)
 {
-  pthread_once(&init_once,&_pthread_init);
-
-  *thread = (pthread_t)malloc(sizeof(work_queue_t));
-  (*thread)->start_routine = start_routine;
-  (*thread)->arg = arg;
-  (*thread)->next = 0;
-  (*thread)->finished = 0;
-  (*thread)->detached = 0;
-  mcs_lock_lock(&work_queue_lock);
-  {
-    threads_active++;
-    queue_insert(&work_queue_head,&work_queue_tail,*thread);
-    // don't return until we get a vcore
-    while(threads_active > num_vcores() && vcore_request(1));
-  }
-  mcs_lock_unlock(&work_queue_lock);
-
-  return 0;
+       pthread_once(&init_once,&_pthread_init);
+       // Most fields already zeroed out by the calloc below...
+       *thread = (pthread_t)calloc(sizeof(struct pthread_tcb), 1);
+       (*thread)->start_routine = start_routine;
+       (*thread)->arg = arg;
+       (*thread)->pthreadid = 3413; // TODO
+       
+       // TODO: Allocate pthread tls regions and stacks
+       
+       // Insert the newly created thread into the ready queue of threads.
+       // It will be removed from this queue later when vcore_entry() comes up
+       mcs_lock_lock(&queue_lock);
+       {
+               TAILQ_INSERT_TAIL(&ready_queue, *thread, next);
+               threads_ready++;
+       }
+       mcs_lock_unlock(&queue_lock);
+
+       // Attempt to request a new core, may or may not get it...
+       vcore_request(1);
+       
+       return 0;
 }
 
 int pthread_join(pthread_t t, void** arg)
@@ -233,7 +282,8 @@ int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
 
 pthread_t pthread_self()
 {
-  return active_threads[vcore_id()];
+  //return active_threads[vcore_id()];
+  return 0; // TODO
 }
 
 int pthread_equal(pthread_t t1, pthread_t t2)
@@ -243,15 +293,14 @@ int pthread_equal(pthread_t t1, pthread_t t2)
 
 void pthread_exit(void* ret)
 {
-  pthread_once(&init_once,&_pthread_init);
-
   pthread_t t = pthread_self();
 
-  mcs_lock_lock(&work_queue_lock);
+#if 0
+  mcs_lock_lock(&queue_lock);
   threads_active--;
   if(threads_active == 0)
     exit(0);
-  mcs_lock_unlock(&work_queue_lock);
+  mcs_lock_unlock(&queue_lock);
 
   if(t)
   {
@@ -262,6 +311,7 @@ void pthread_exit(void* ret)
   }
 
   vcore_entry();
+#endif
 }
 
 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
index d4db153..0289451 100644 (file)
@@ -17,7 +17,8 @@
 #  define internal_function
 # endif
 
-static size_t _max_vcores_ever_wanted = 0;
+/* starting with 1 since we alloc vcore0's stacks and TLS in vcore_init(). */
+static size_t _max_vcores_ever_wanted = 1;
 static mcs_lock_t _vcore_lock = MCS_LOCK_INIT;
 
 extern void** vcore_thread_control_blocks;
@@ -84,9 +85,17 @@ int vcore_init()
        if(!vcore_thread_control_blocks)
                goto vcore_init_fail;
 
+       /* Need to alloc vcore0's transition stuff here (technically, just the TLS)
+        * so that schedulers can use vcore0's transition TLS before it comes up in
+        * vcore_entry() */
+       if(allocate_transition_stack(0) || allocate_transition_tls(0))
+               goto vcore_init_tls_fail;
+
        initialized = 1;
        return 0;
 
+vcore_init_tls_fail:
+       free(vcore_thread_control_blocks);
 vcore_init_fail:
        errno = ENOMEM;
        return -1;