#ifndef WASMPOSIXTHREADS1#define WASMPOSIXTHREADS23#include <time.h>4#include <stdbool.h>56#define CLOCK_THREAD_CPUTIME_ID 378#define SCHED_OTHER 09#define PTHREAD_CANCEL_ASYNCHRONOUS 110#define PTHREAD_CANCEL_ENABLE 211#define PTHREAD_CANCEL_DEFERRED 312#define PTHREAD_CANCEL_DISABLE 413#define PTHREAD_CREATE_DETACHED 514#define PTHREAD_CREATE_JOINABLE 615#define PTHREAD_EXPLICIT_SCHED 716#define PTHREAD_INHERIT_SCHED 817#define PTHREAD_MUTEX_DEFAULT 918#define PTHREAD_MUTEX_ERRORCHECK 1019#define PTHREAD_MUTEX_NORMAL 1120#define PTHREAD_MUTEX_RECURSIVE 1221#define PTHREAD_MUTEX_ROBUST 1322#define PTHREAD_MUTEX_STALLED 1423#define PTHREAD_PRIO_INHERIT 1524#define PTHREAD_PRIO_NONE 1625#define PTHREAD_PRIO_PROTECT 1726#define PTHREAD_PROCESS_SHARED 1827#define PTHREAD_PROCESS_PRIVATE 1928#define PTHREAD_SCOPE_PROCESS 2029#define PTHREAD_SCOPE_SYSTEM 2130#define PTHREAD_BARRIER_SERIAL_THREAD 223132/* Data structure to describe a process' schedulability. */33// This struct is copied from zig's34// lib/libc/include/generic-glibc/bits/types/struct_sched_param.h which is35// copied from glibc.36// We do this because unthread had37// #include <bits/types/struct_sched_param.h>38// which is including something from glibc, which is NOT in musl.39struct sched_param {40int sched_priority;41};4243// pthread_attr_t is defined as a union somewhere in some glibc header, so we44// pretend its a union here as well.45union pthread_attr_t {46struct {47int initialized;48int detach_state;49size_t guard_size;50int inherit_sched;51int scope;52struct sched_param sched_param;53int sched_policy;54void **stack_addr;55size_t stack_size;56} data;57};5859typedef struct {60int initialized;61int pshared;62clockid_t clock_id;63} pthread_condattr_t;6465typedef struct pthread_fiber *pthread_t;6667// We would rather not expose these internals, but C does not leave us much68// choice unless we want to heap allocate each of these.697071struct pthread_fiber;72struct pthread_list {73size_t len;74size_t cap;75union {76// Store a small list inline or a large list on the heap. Possibly an77// unnecessary micro-optimization, but eh.78struct pthread_fiber *small[4];79struct pthread_fiber **big;80} threads;81};828384typedef struct {85int initialized;86struct pthread_fiber *locked_by;87struct pthread_list waiting;88int type;89unsigned int rec_count;90int prioceiling;91int robust;92} pthread_mutex_t;939495typedef struct {96int initialized;97struct pthread_list waiting;98} pthread_cond_t;99100#define PTHREAD_EMPTY_LIST_INITIALIZER \101{ \102.len = 0, \103.cap = sizeof((struct pthread_list){}.threads.small) / \104sizeof(*(struct pthread_list){}.threads.small), \105}106107static const struct pthread_list pthread_empty_list =108PTHREAD_EMPTY_LIST_INITIALIZER;109110111112enum thread_state {113RUNNING,114};115116117struct tls_entry {118size_t id;119void *value;120void (*destructor)(void *);121};122123struct tls {124struct tls_entry *entries;125size_t cap, len;126};127128typedef struct pthread_cleanup_t {129void (*routine)(void *);130void *arg;131struct pthread_cleanup_t *prev;132} pthread_cleanup_t;133134typedef struct {135int initialized;136int prioceiling;137int protocol;138int pshared;139int type;140int robust;141} pthread_mutexattr_t;142143typedef struct {144int initialized;145unsigned int id;146void (*destructor)(void *);147} pthread_key_t;148149150struct pthread_fiber {151unsigned int id;152153bool detached;154bool owns_stack;155156// The index of this thread in the lists we are currently a member of.157//158// For example, when waiting on a mutex the current thread is added to the159// list. Having the index in the thread itself means operations like160// pop_specific can be implemented in O(1) time.161//162// A thread may be a member of the threads_ready list in addition to one163// other list. This means there are two "slots" for indices, with 0 being for164// the index in the threads_ready list and 1 for the index in the other list.165// This is used when blocking on a timed lock, where a thread may both be166// ready (for the purposes of Unthread) and waiting on a lock at the same167// time.168size_t list_index[2];169170// pthread_attr_t used to create this thread.171union pthread_attr_t attr;172173enum thread_state state;174175union {176// When blocked on pthread_join, contains the thread being joined177pthread_t joining;178179// When blocked on pthread_cond_wait and pthread_cond_timedwait, this will180// be the mutex to acquire when the condition variable is signalled.181pthread_mutex_t *cond_mutex;182183// When blocked on pthread_barrier_wait, this will be true if the thread184// was chosen as the serial thread of the barrier.185bool barrier_serial;186187// When a thread is stopped, this will be the return value of the thread.188void *retval;189190// When blocked on pthread_rwlock or pthread_rwlock_timedrdlock, this is191// whether the current thread has been granted reader access.192bool rwlock_reader;193} state_data;194195// The thread that this thread is being joined by, or NULL if no thread is196// currently joining this thread.197pthread_t joined_by;198199// Thread local storage map for this thread200struct tls tls;201202int cancel_state;203int cancel_type;204205// Whether a cancellation signal has been sent. Since the signal is206// asynchronous, we may act on them much sooner than it is sent.207bool canceled;208209pthread_cleanup_t *cleanup;210211int sched_policy;212struct sched_param sched_param;213214__attribute__((aligned(16))) char stack[];215};216217218#endif219220