Moved pthreads into parlib
authorAndrew Waterman <waterman@r53.millennium.berkeley.edu>
Thu, 29 Oct 2009 07:33:45 +0000 (00:33 -0700)
committerAndrew Waterman <waterman@r53.millennium.berkeley.edu>
Thu, 29 Oct 2009 07:33:45 +0000 (00:33 -0700)
kern/src/manager.c
user/apps/parlib/Makefrag
user/apps/parlib/pthread/Makefrag
user/parlib/Makefrag
user/parlib/inc/pthread.h [new file with mode: 0644]
user/parlib/src/Makefrag
user/parlib/src/pthread.c [new file with mode: 0644]

index b929386..735dd66 100644 (file)
@@ -259,12 +259,13 @@ void manager_waterman()
                case 4:
                        RUN_APP("parlib_pthread_blackscholes",3,"blackscholes",itoa(num_cpus>1?num_cpus-1:1,buf0,10),itoa(256,buf1,10));
                        break;
-               case 5:
-                       while(*(volatile uint32_t*)&envs[4]->state != ENV_FREE);
-                       reboot();
-                       break;
 
-               case 10:
+               //case 5:
+               //      //while(*(volatile uint32_t*)&envs[4]->state != ENV_FREE);
+               //      //reboot();
+               //      break;
+
+               case 5:
                        RUN_APP("parlib_matrix",0);
                        break;
        }
index c05e870..2866ced 100644 (file)
@@ -2,9 +2,8 @@ USER_APPS_PARLIB_DIR = $(USER_APPS_DIR)/parlib
 OBJDIRS += $(USER_APPS_PARLIB_DIR)
 
 USER_APPS_PARLIB_CFLAGS    := $(USER_CFLAGS)  \
-                              -I$(USER_PARLIB_PTHREAD_DIR)/include \
-                              -I$(USER_PARLIB_NEWLIB_DIR)/include \
-                              -I$(USER_PARLIB_DIR)/inc
+                              -I$(USER_PARLIB_DIR)/inc \
+                              -I$(USER_PARLIB_NEWLIB_DIR)/include
 ifeq ($(COMPILER),IVY)
        PATCHFILE = $(OBJDIR)/$(USER_PARLIB_DIR)/libc_patch.i
        USER_APPS_PARLIB_CFLAGS    += --nodeputy --nopatch #--patch=$(PATCHFILE) 
@@ -14,7 +13,6 @@ USER_APPS_PARLIB_LDFLAGS   := $(USER_LDFLAGS) -static \
                               -T $(USER_APPS_PARLIB_DIR)/apps_$(TARGET_ARCH).ld
 
 USER_APPS_PARLIB_LDDIRS    := -L$(OBJDIR)/$(USER_PARLIB_DIR) \
-                              -L$(OBJDIR)/$(USER_PARLIB_PTHREAD_DIR) \
                               -L$(USER_PARLIB_NEWLIB_DIR)/lib/$(TARGET_ARCH)
 
 USER_APPS_PARLIB_LDLIBS    := --start-group -lc -lm -lg -lparlib -livyparlib --end-group
index 9632ece..0e1f9aa 100644 (file)
@@ -3,9 +3,9 @@ USER_APPS_PARLIB_PTHREAD_DIR := $(USER_APPS_PARLIB_DIR)/pthread
 USER_APPS_PARLIB_PTHREAD_LDLIBS := $(USER_APPS_PARLIB_LDLIBS) -lpthread
                              
 USER_APPS_PARLIB_PTHREAD_LDDEPENDS := $(OBJDIR)/$(USER_APPS_PARLIB_PTHREAD_DIR)/%.o \
-                                      $(OBJDIR)/$(USER_PARLIB_PTHREAD_DIR)/libpthread.a \
                                       $(USER_APPS_PARLIB_LDOBJS) \
                                       $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a \
+                                      $(OBJDIR)/$(USER_PARLIB_DIR)/libpthread.a \
                                       $(OBJDIR)/$(USER_PARLIB_DIR)/libivyparlib.a
 
 $(OBJDIR)/$(USER_APPS_PARLIB_PTHREAD_DIR)/%: $(USER_APPS_PARLIB_PTHREAD_LDDEPENDS)
index e58e749..7258923 100644 (file)
@@ -3,11 +3,9 @@ USER_PARLIB_INCLUDE_DIR  := $(USER_PARLIB_DIR)/inc
 \r
 # This is defined here for use by the parlib library\r
 USER_PARLIB_NEWLIB_DIR := $(USER_PARLIB_DIR)/newlib\r
-USER_PARLIB_PTHREAD_DIR := $(USER_PARLIB_DIR)/pthread\r
 \r
 include $(USER_PARLIB_DIR)/src/$(TARGET_ARCH)/Makefrag\r
 include $(USER_PARLIB_DIR)/src/Makefrag\r
 include $(USER_PARLIB_DIR)/ivy/Makefrag\r
-include $(USER_PARLIB_DIR)/pthread/Makefrag\r
 \r
 .PRECIOUS: $(OBJDIR)/$(USER_PARLIB_DIR)/%.o \r
diff --git a/user/parlib/inc/pthread.h b/user/parlib/inc/pthread.h
new file mode 100644 (file)
index 0000000..59216d8
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef _PTHREAD_H
+#define _PTHREAD_H
+
+#include <hart.h>
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+struct pthread_wqt
+{
+  void* (*start_routine)(void*);
+  void* arg;
+  int finished;
+  int detached;
+  struct pthread_wqt* next;
+};
+
+typedef struct
+{
+  int* local_sense;
+  volatile int sense;
+  int count;
+  int nprocs;
+  hart_lock_t lock;
+} pthread_barrier_t;
+
+typedef struct
+{
+  int type;
+} pthread_mutexattr_t;
+
+typedef struct
+{
+  const pthread_mutexattr_t* attr;
+  size_t lock;
+} pthread_mutex_t;
+
+typedef struct
+{
+  int pshared;
+} pthread_condattr_t;
+
+typedef struct
+{
+  const pthread_condattr_t* attr;
+  int waiters[HART_MAX_MAX_HARTS];
+} 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 size_t 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
+
+int pthread_attr_init(pthread_attr_t *);
+int pthread_attr_destroy(pthread_attr_t *);
+int pthread_create(pthread_t *, const pthread_attr_t *,
+                   void *(*)(void *), void *);
+int pthread_join(pthread_t, void **);
+
+int pthread_mutex_destroy(pthread_mutex_t *);
+int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int pthread_mutex_lock(pthread_mutex_t *);
+int pthread_mutex_trylock(pthread_mutex_t *);
+int pthread_mutex_unlock(pthread_mutex_t *);
+int pthread_mutex_destroy(pthread_mutex_t *);
+
+int pthread_mutexattr_init(pthread_mutexattr_t *);
+int pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *);
+int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+
+int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+int pthread_cond_destroy(pthread_cond_t *);
+int pthread_cond_broadcast(pthread_cond_t *);
+int pthread_cond_signal(pthread_cond_t *);
+int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+
+int pthread_condattr_init(pthread_condattr_t *);
+int pthread_condattr_destroy(pthread_condattr_t *);
+int pthread_condattr_setpshared(pthread_condattr_t *, int);
+int pthread_condattr_getpshared(pthread_condattr_t *, int *);
+
+#define pthread_rwlock_t pthread_mutex_t
+#define pthread_rwlockattr_t pthread_mutexattr_t
+#define pthread_rwlock_destroy pthread_mutex_destroy
+#define pthread_rwlock_init pthread_mutex_init
+#define pthread_rwlock_unlock pthread_mutex_unlock
+#define pthread_rwlock_rdlock pthread_mutex_lock
+#define pthread_rwlock_wrlock pthread_mutex_lock
+#define pthread_rwlock_tryrdlock pthread_mutex_trylock
+#define pthread_rwlock_trywrlock pthread_mutex_trylock
+
+pthread_t pthread_self();
+int pthread_equal(pthread_t t1, pthread_t t2);
+void pthread_exit(void* ret);
+int pthread_once(pthread_once_t* once_control, void (*init_routine)(void));
+
+int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count);
+int pthread_barrier_wait(pthread_barrier_t* b);
+int pthread_barrier_destroy(pthread_barrier_t* b);
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
index 558de88..b521785 100644 (file)
@@ -25,6 +25,15 @@ USER_PARLIB_SRC_OBJFILES := $(patsubst $(USER_PARLIB_SRC_DIR)/%.S, \
                             $(OBJDIR)/$(USER_PARLIB_SRC_DIR)/%.o, \
                             $(USER_PARLIB_SRC_OBJFILES))
 
+USER_PARLIB_PTHREAD_SRCFILES := $(USER_PARLIB_SRC_DIR)/pthread.c
+
+USER_PARLIB_PTHREAD_OBJFILES := $(patsubst $(USER_PARLIB_SRC_DIR)/%.c, \
+                                $(OBJDIR)/$(USER_PARLIB_SRC_DIR)/%.o, \
+                                $(USER_PARLIB_PTHREAD_SRCFILES))
+USER_PARLIB_PTHREAD_OBJFILES := $(patsubst $(USER_PARLIB_SRC_DIR)/%.S, \
+                                $(OBJDIR)/$(USER_PARLIB_SRC_DIR)/%.o, \
+                                $(USER_PARLIB_PTHREAD_OBJFILES))
+
 ANNOTS := $(shell dirname $(shell which ivycc))
 ANNOTS := $(ANNOTS)/../lib/ivy/include/deputy/annots.h
 
@@ -48,3 +57,8 @@ $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a: $(USER_PARLIB_SRC_OBJFILES)
        @mkdir -p $(@D)
        $(V)$(AR) r $@ $(USER_PARLIB_SRC_OBJFILES) 2>/dev/null
 
+$(OBJDIR)/$(USER_PARLIB_DIR)/libpthread.a: $(USER_PARLIB_PTHREAD_OBJFILES)
+       @echo + ar [PARLIB] $@
+       @mkdir -p $(@D)
+       $(V)$(AR) r $@ $(USER_PARLIB_PTHREAD_OBJFILES) 2>/dev/null
+
diff --git a/user/parlib/src/pthread.c b/user/parlib/src/pthread.c
new file mode 100644 (file)
index 0000000..996bd9d
--- /dev/null
@@ -0,0 +1,306 @@
+#include <pthread.h>
+#include <hart.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+int threads_active = 1;
+int current_harts = 1;
+hart_lock_t work_queue_lock = HART_LOCK_INIT;
+pthread_t work_queue_head = 0;
+pthread_t work_queue_tail = 0;
+pthread_once_t init_once = PTHREAD_ONCE_INIT;
+pthread_t active_threads[HART_MAX_MAX_HARTS] = {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;
+}
+
+pthread_t queue_remove(pthread_t* head, pthread_t* tail)
+{
+  pthread_t node = *head;
+  *head = (*head)->next;
+  if(*head == 0)
+    *tail = 0;
+  node->next = 0;
+  return node;
+}
+
+void hart_entry()
+{
+  pthread_t node = NULL;
+  while(1)
+  {
+    hart_lock_lock(&work_queue_lock);
+    if(work_queue_head)
+      node = queue_remove(&work_queue_head,&work_queue_tail);
+    hart_lock_unlock(&work_queue_lock);
+
+    if(node)
+      break;
+    hart_relax();
+  }
+
+  active_threads[hart_self()] = node;
+
+  pthread_exit(node->start_routine(node->arg));
+}
+
+void _pthread_init()
+{
+  // if we allocated active_threads dynamically, we'd do so here
+}
+
+int pthread_attr_init(pthread_attr_t *a)
+{
+  return 0;
+}
+
+int pthread_attr_destroy(pthread_attr_t *a)
+{
+  return 0;
+}
+
+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;
+
+  int request_hart = 0;
+
+  hart_lock_lock(&work_queue_lock);
+  {
+    threads_active++;
+    if(threads_active > current_harts)
+      request_hart = 1;
+
+    queue_insert(&work_queue_head,&work_queue_tail,*thread);
+  }
+  hart_lock_unlock(&work_queue_lock);
+
+  // don't return until we get a hart
+  while(request_hart && hart_request(1));
+  return 0;
+}
+
+int pthread_join(pthread_t t, void** arg)
+{
+  volatile pthread_t thread = t;
+  while(!thread->finished);
+  if(arg) *arg = thread->arg;
+  free(thread);
+  return 0;
+}
+
+int pthread_mutexattr_init(pthread_mutexattr_t* attr)
+{
+  attr->type = PTHREAD_MUTEX_DEFAULT;
+  return 0;
+}
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
+{
+  return 0;
+}
+
+int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type)
+{
+  *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
+  return 0;
+}
+
+int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
+{
+  if(type != PTHREAD_MUTEX_NORMAL)
+    return -EINVAL;
+  attr->type = type;
+  return 0;
+}
+
+int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
+{
+  m->attr = attr;
+  m->lock = 0;
+  return 0;
+}
+
+int pthread_mutex_lock(pthread_mutex_t* m)
+{
+  while(pthread_mutex_trylock(m))
+    while((volatile size_t*)m->lock);
+  return 0;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t* m)
+{
+  return hart_swap(&m->lock,1) == 0 ? 0 : -EBUSY;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t* m)
+{
+  m->lock = 0;
+  return 0;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t* m)
+{
+  return 0;
+}
+
+int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
+{
+  c->attr = a;
+  memset(c->waiters,0,sizeof(c->waiters));
+  return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *c)
+{
+  return 0;
+}
+
+int pthread_cond_broadcast(pthread_cond_t *c)
+{
+  memset(c->waiters,0,sizeof(c->waiters));
+  return 0;
+}
+
+int pthread_cond_signal(pthread_cond_t *c)
+{
+  int i;
+  for(i = 0; i < hart_max_harts(); i++)
+  {
+    if(c->waiters[i])
+    {
+      c->waiters[i] = 0;
+      break;
+    }
+  }
+  return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
+{
+  c->waiters[hart_self()] = 1;
+  pthread_mutex_unlock(m);
+
+  volatile int* poll = &c->waiters[hart_self()];
+  while(*poll);
+
+  pthread_mutex_lock(m);
+
+  return 0;
+}
+
+int pthread_condattr_init(pthread_condattr_t *a)
+{
+  a = PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t *a)
+{
+  return 0;
+}
+
+int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
+{
+  a->pshared = s;
+  return 0;
+}
+
+int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
+{
+  *s = a->pshared;
+  return 0;
+}
+
+pthread_t pthread_self()
+{
+  return active_threads[hart_self()];
+}
+
+int pthread_equal(pthread_t t1, pthread_t t2)
+{
+  return t1 == t2;
+}
+
+void pthread_exit(void* ret)
+{
+  pthread_once(&init_once,&_pthread_init);
+
+  pthread_t t = pthread_self();
+
+  hart_lock_lock(&work_queue_lock);
+  threads_active--;
+  if(threads_active == 0)
+    exit(0);
+  hart_lock_unlock(&work_queue_lock);
+
+  if(t)
+  {
+    t->arg = ret;
+    t->finished = 1;
+    if(t->detached)
+      free(t);
+  }
+
+  hart_entry();
+}
+
+int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
+{
+  if(hart_swap(once_control,1) == 0)
+    init_routine();
+  return 0;
+}
+
+int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count)
+{
+  b->local_sense = (int*)calloc(32*sizeof(int),count);
+  b->sense = 0;
+  b->nprocs = b->count = count;
+  hart_lock_init(&b->lock);
+  return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* b)
+{
+  int id = hart_self();
+  int ls = b->local_sense[32*id] = 1 - b->local_sense[32*id];
+
+  hart_lock_lock(&b->lock);
+  int count = --b->count;
+  hart_lock_unlock(&b->lock);
+
+  if(count == 0)
+  {
+    b->count = b->nprocs;
+    b->sense = ls;
+    return PTHREAD_BARRIER_SERIAL_THREAD;
+  }
+  else
+  {
+    while(b->sense != ls);
+    return 0;
+  }
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* b)
+{
+  free(b->local_sense);
+  return 0;
+}