Complete rewrite of c3po for multicore
[akaros.git] / user / c3po / threads / threadlib.h
1
2 #ifndef THREADLIB_H
3 #define THREADLIB_H
4
5 #include "pthread.h"
6 #include "resource_stats.h"
7 #include <stdbool.h>
8 #include <time.h>
9 #include <signal.h>
10
11 #define likely(x)   __builtin_expect(!!(x),1)
12 #define unlikely(x) __builtin_expect(!!(x),0)
13
14 struct thread_st;
15 typedef struct thread_st thread_t;
16
17 typedef enum {
18   UNLOCKED = 0,
19   LOCKED   = 1,
20 } lock_state_t;
21
22 typedef struct latch_st {
23   thread_t *state;
24 } latch_t;
25
26 // Queue used for mutex implementation
27 typedef struct queue_st {
28   void **data;   /* allocated data */
29   int size;  /* allocated size */
30   int head, tail;   /* valid data in [head, tail) */
31 } queue_t;
32
33 typedef struct {
34   latch_t latch;
35   lock_state_t state;
36   int count;   // for recursive locking
37   char *name;
38   queue_t wait_queue;
39   thread_t *owner;   // for sanity checking in thread_mutex_unlock()
40 } mutex_t;
41
42 // the read-write lock structure
43 typedef struct rwlock_st { /* not hidden to avoid destructor */
44   int            rw_state;
45   unsigned int   rw_mode;
46   unsigned long  rw_readers;
47   mutex_t    rw_mutex_rd;
48   mutex_t    rw_mutex_rw;
49 } rwlock_t;
50
51 // the condition variable structure
52 typedef struct cond_st { /* not hidden to avoid destructor */
53   unsigned long cn_state;
54   unsigned int  cn_waiters;
55   queue_t wait_queue;
56 } cond_t;
57
58
59 // All thread attributes
60 enum {
61   THREAD_ATTR_JOINABLE = 1,
62   THREAD_ATTR_NAME,  // Not implemented
63   THREAD_ATTR_PRIO   // Not implemented
64 };
65
66 // Thread joinable attribute
67 enum {
68   THREAD_CREATE_DETACHED = 0,
69   THREAD_CREATE_JOINABLE = 1
70 };
71
72 enum {
73         OK = 0,
74         TIMEDOUT = 1,
75         INTERRUPTED = 2,
76 };
77
78 typedef struct _thread_attr *thread_attr_t;
79
80 extern void switch_to_vcore();
81 extern void run_next_thread();
82 void thread_exit(void *ret);
83 void thread_exit_program(int exitcode);
84 void thread_yield();
85 thread_t *thread_spawn(char *name, void* (*func)(void *), void *arg);
86 thread_t *thread_spawn_with_attr(char *name, void* (*func)(void *), 
87                             void *arg, thread_attr_t attr);  // added for pthread layer
88 // suspend the thread, optionally for a limited period of time (timeout)
89 // timeout == 0 -> suspend infinitely unless resumed by another thread
90 // return value: OK if resumed by someone else, TIMEDOUT is timedout
91 //               INTERRUPTED is interrupted by a signal
92 int thread_suspend_self(unsigned long long timeout);
93
94 // resume is made idempotent - resuming an already runnable thread does nothing
95 void thread_resume(thread_t* t);
96 char* thread_name(thread_t *t);
97 int thread_join(thread_t *t, void **val);
98 void thread_set_daemon(thread_t *t);
99
100 extern __thread thread_t *current_thread;
101 static inline thread_t* thread_self() { return current_thread; }
102
103 // Key-based thread specific storage
104 typedef int thread_key_t;
105 #define THREAD_DESTRUCTOR_ITERATIONS 4
106 #define THREAD_KEY_MAX 256  // NOTE: change the size of thread_t.data_count if you change this!
107 int thread_key_create(thread_key_t *key, void (*destructor)(void *));
108 int thread_key_delete(thread_key_t key);
109 int thread_key_setdata(thread_key_t key, const void *value);
110 void *thread_key_getdata(thread_key_t key);
111
112 void thread_usleep(unsigned long long timeout);
113
114 // Mutex - return TRUE on success
115 int thread_mutex_init(mutex_t *m, char *name);
116 int thread_mutex_lock(mutex_t *m);
117 int thread_mutex_trylock(mutex_t *m);    // do not block, return FALSE when mutex held but others
118 int thread_mutex_unlock(mutex_t *m);
119
120 // Rwlocks
121 enum rwlock_op {
122   RWLOCK_RD = 1,
123   RWLOCK_RW
124 };
125
126 int thread_rwlock_init(rwlock_t *l);
127 int thread_rwlock_lock(rwlock_t *l, int op);
128 int thread_rwlock_trylock(rwlock_t *l, int op);
129 int thread_rwlock_unlock(rwlock_t *l);
130
131 // Condition variables
132 int thread_cond_init(cond_t *c);
133 int thread_cond_wait(cond_t *c, mutex_t *m);
134 int thread_cond_timedwait(cond_t *c, mutex_t *m, const struct timespec *timeout);
135 int thread_cond_signal(cond_t *c);
136 int thread_cond_broadcast(cond_t *c);
137
138 // attribute
139 thread_attr_t thread_attr_of(thread_t *t);
140 thread_attr_t thread_attr_new();
141 int thread_attr_init(thread_attr_t attr);
142 int thread_attr_set(thread_attr_t attr, int field, ...);
143 int thread_attr_get(thread_attr_t attr, int field, ...);
144 int thread_attr_destroy(thread_attr_t attr);
145
146 unsigned thread_tid(thread_t *t);
147
148 int thread_kill(thread_t* t, int sig);
149 int thread_kill_all(int sig);
150 int thread_sigwait(const sigset_t *set, int *sig);
151
152 extern void thread_stats_add_heap(long size);
153 extern void thread_stats_add_fds(int num);
154
155
156 typedef struct {
157   long active;
158   long long requests;
159   long long completions;
160   long long bytes_read;
161   long long bytes_written;
162   long long errors;
163 } iostats_t;
164
165 extern iostats_t sockio_stats;
166 extern iostats_t diskio_stats;
167
168 #define IOSTAT_START(type) {\
169   type##_stats.active++; \
170   type##_stats.requests++; \
171 }
172 #define IOSTAT_DONE(type, success) {\
173   type##_stats.active--; \
174   if( (success) ) type##_stats.completions++; \
175   else            type##_stats.errors++; \
176 }
177
178 extern const char *cap_current_syscall;  // used to inform the BG routines how they got there...
179 #define CAP_SET_SYSCALL()   if(!cap_current_syscall) cap_current_syscall = __FUNCTION__
180 #define CAP_CLEAR_SYSCALL() (cap_current_syscall = NULL)
181
182 extern void set_io_polling_func( void (*func)(long long) );
183
184 // latches
185
186 // FIXME: if there is a single kernel thread, it is an error if the latch is already locked 
187 // FIXME: need a spinlock, test&set, futex, etc. for multiple kernel threads 
188 #define LATCH_UNLOCKED NULL
189 #define LATCH_UNKNOWN ((thread_t*)-1)
190 #if OPTIMIZE < 2
191 #define thread_latch(latch) \
192 do {\
193   assert(latch.state == LATCH_UNLOCKED); \
194   latch.state = thread_self() ? thread_self() : LATCH_UNKNOWN; \
195 } while(0)
196 #else
197 #define thread_latch(latch) do { } while(0)
198 #endif
199  
200 #if OPTIMIZE < 2
201 #define thread_unlatch(latch) \
202 do { \
203   assert(latch.state != LATCH_UNLOCKED); \
204   latch.state = UNLOCKED; \
205 } while(0)
206 #else
207 #define thread_unlatch(latch) do { (void)(latch);} while(0)
208 #endif
209
210 #if OPTIMIZE < 2
211 #define thread_latch_init(latch) \
212 do { \
213   latch.state = LATCH_UNLOCKED; \
214 } while(0)
215 #else
216 #define thread_latch_init(latch) do {(void)(latch);} while(0)
217 #endif
218
219 #define LATCH_INITIALIZER_UNLOCKED { LATCH_UNLOCKED }
220 #define LATCH_INITIALIZER_LOCKED   { LATCH_UNKNOWN }
221
222 #endif /* THREADLIB_H */
223
224
225