| #ifndef _PTHREAD_H |
| #define _PTHREAD_H |
| |
| #include <sys/queue.h> |
| #include <signal.h> |
| #include <vcore.h> |
| #include <uthread.h> |
| #include <mcs.h> |
| #include <dtls.h> |
| #include <spinlock.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* Pthread states. These are mostly examples for other 2LSs */ |
| #define PTH_CREATED 1 |
| #define PTH_RUNNABLE 2 |
| #define PTH_RUNNING 3 |
| #define PTH_EXITING 4 |
| #define PTH_BLK_YIELDING 5 /* brief state btw pth_yield and pth_runnable */ |
| #define PTH_BLK_JOINING 6 /* joining on a child */ |
| #define PTH_BLK_SYSC 7 /* blocked on a syscall */ |
| #define PTH_BLK_MUTEX 8 /* blocked externally, possibly on a mutex */ |
| #define PTH_BLK_PAUSED 9 /* handed back to us from uthread code */ |
| |
| /* Pthread struct. First has to be the uthread struct, which the vcore code |
| * will access directly (as if pthread_tcb is a struct uthread). */ |
| struct pthread_tcb; |
| struct pthread_tcb { |
| struct uthread uthread; |
| TAILQ_ENTRY(pthread_tcb) next; |
| int state; |
| bool detached; |
| struct pthread_tcb *joiner; /* raced on by exit and join */ |
| uint32_t id; |
| uint32_t stacksize; |
| void *stacktop; |
| void *(*start_routine)(void*); |
| void *arg; |
| void *retval; |
| uint64_t sigmask; |
| }; |
| typedef struct pthread_tcb* pthread_t; |
| TAILQ_HEAD(pthread_queue, pthread_tcb); |
| |
| /* Per-vcore data structures to manage syscalls. The ev_q is where we tell the |
| * kernel to signal us. We don't need a lock since this is per-vcore and |
| * accessed in vcore context. */ |
| struct sysc_mgmt { |
| struct event_queue *ev_q; |
| }; |
| |
| #define PTHREAD_ONCE_INIT 0 |
| #define PTHREAD_BARRIER_SERIAL_THREAD 12345 |
| #define PTHREAD_MUTEX_INITIALIZER {0,0} |
| #define PTHREAD_MUTEX_NORMAL 0 |
| #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL |
| #define PTHREAD_MUTEX_SPINS 100 // totally arbitrary |
| #define PTHREAD_BARRIER_SPINS 100 // totally arbitrary |
| #define PTHREAD_COND_INITIALIZER {0,{0},{0},0} |
| #define PTHREAD_PROCESS_PRIVATE 0 |
| #define PTHREAD_PROCESS_SHARED 1 |
| |
| typedef struct |
| { |
| int type; |
| } pthread_mutexattr_t; |
| |
| typedef struct |
| { |
| const pthread_mutexattr_t* attr; |
| atomic_t lock; |
| } pthread_mutex_t; |
| |
| typedef struct |
| { |
| int total_threads; |
| volatile int sense; /* state of barrier, flips btw runs */ |
| atomic_t count; |
| struct spin_pdr_lock lock; |
| struct pthread_queue waiters; |
| int nr_waiters; |
| } pthread_barrier_t; |
| |
| #define WAITER_CLEARED 0 |
| #define WAITER_WAITING 1 |
| #define SLOT_FREE 0 |
| #define SLOT_IN_USE 1 |
| |
| /* Detach state. */ |
| enum |
| { |
| PTHREAD_CREATE_JOINABLE, |
| #define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE |
| PTHREAD_CREATE_DETACHED |
| #define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED |
| }; |
| |
| // TODO: how big do we want these? ideally, we want to be able to guard and map |
| // more space if we go too far. |
| #define PTHREAD_STACK_PAGES 4 |
| #define PTHREAD_STACK_SIZE (PTHREAD_STACK_PAGES*PGSIZE) |
| |
| typedef int clockid_t; |
| typedef struct |
| { |
| int pshared; |
| clockid_t clock; |
| } pthread_condattr_t; |
| |
| /* Regarding the spinlock vs MCS, I don't expect this lock to be heavily |
| * contended. Most of the time, the caller already holds the mutex associated |
| * with the cond var. */ |
| typedef struct |
| { |
| struct pthread_queue waiters; |
| struct spin_pdr_lock spdr_lock; |
| int attr_pshared; |
| int attr_clock; |
| } pthread_cond_t; |
| |
| typedef struct |
| { |
| size_t stacksize; |
| int detachstate; |
| } pthread_attr_t; |
| typedef int pthread_barrierattr_t; |
| typedef int pthread_once_t; |
| typedef dtls_key_t pthread_key_t; |
| |
| /* Akaros pthread extensions / hacks */ |
| void pthread_can_vcore_request(bool can); /* default is TRUE */ |
| void pthread_need_tls(bool need); /* default is TRUE */ |
| void pthread_lib_init(void); |
| void __pthread_generic_yield(struct pthread_tcb *pthread); |
| |
| /* 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 *, |
| void *(*)(void *), void *); |
| int pthread_detach(pthread_t __th); |
| int pthread_join(pthread_t, void **); |
| int pthread_yield(void); |
| |
| int pthread_attr_setdetachstate(pthread_attr_t *__attr,int __detachstate); |
| int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); |
| int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize); |
| |
| 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_getpshared(pthread_condattr_t *, int *); |
| int pthread_condattr_setpshared(pthread_condattr_t *, int); |
| int pthread_condattr_getclock(const pthread_condattr_t *attr, |
| clockid_t *clock_id); |
| int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id); |
| |
| #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); |
| |
| // POSIX signal compliance |
| int pthread_kill (pthread_t __threadid, int __signo); |
| int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset); |
| int pthread_sigqueue(pthread_t *thread, int sig, const union sigval value); |
| |
| // Dynamic TLS stuff |
| int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)); |
| int pthread_key_delete(pthread_key_t key); |
| void *pthread_getspecific(pthread_key_t key); |
| int pthread_setspecific(pthread_key_t key, const void *value); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif |