1
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <unistd.h>
9 #include <errno.h>
10 #include <pthread.h>
11
12 #include <core/mutex.h>
13
14 #include <syscall.h>
15 #include <sys/syscall.h>
16
17 struct pthread_attr {
18 uint64_t _unused;
19 };
20
21 struct pthread {
22 uint64_t tid;
23 int error; // errno
24 TAILQ_ENTRY(pthread) threadTable;
25
26 // Initialization
27 void *(*entry)(void *);
28 void *arg;
29
30 // Termination
31 void *result;
32
33 // Condition Variables
34 TAILQ_ENTRY(pthread) cvTable;
35 };
36
37 typedef TAILQ_HEAD(pthreadList, pthread) pthreadList;
38
39 #define THREAD_HASH_SLOTS 32
40
41 static CoreMutex __threadTableLock;
42 static pthreadList __threads[THREAD_HASH_SLOTS];
43
44 int *
__error(void)45 __error(void)
46 {
47 struct pthread *pth = pthread_self();
48
49 return &(pth->error);
50 }
51
52 void
__pthread_init(void)53 __pthread_init(void)
54 {
55 int i;
56 struct pthread *thr = (struct pthread *)malloc(sizeof(*thr));
57
58 for (i = 0; i < THREAD_HASH_SLOTS; i++) {
59 TAILQ_INIT(&__threads[i]);
60 }
61
62 if (thr == NULL) {
63 abort();
64 }
65
66 thr->tid = OSGetTID();
67 thr->error = 0;
68 thr->entry = NULL;
69 thr->arg = 0;
70
71 CoreMutex_Init(&__threadTableLock);
72
73 CoreMutex_Lock(&__threadTableLock);
74 TAILQ_INSERT_HEAD(&__threads[thr->tid % THREAD_HASH_SLOTS], thr, threadTable);
75 CoreMutex_Unlock(&__threadTableLock);
76 }
77
78 pthread_t
pthread_self(void)79 pthread_self(void)
80 {
81 int tid = OSGetTID();
82 struct pthread *thr;
83
84 CoreMutex_Lock(&__threadTableLock);
85 TAILQ_FOREACH(thr, &__threads[tid % THREAD_HASH_SLOTS], threadTable) {
86 if (thr->tid == tid) {
87 CoreMutex_Unlock(&__threadTableLock);
88 return thr;
89 }
90 }
91 CoreMutex_Unlock(&__threadTableLock);
92
93 printf("pthread_self failed to find current thread!\n");
94 abort();
95 }
96
97 void
pthreadCreateHelper(void * arg)98 pthreadCreateHelper(void *arg)
99 {
100 struct pthread *thr = (struct pthread *)arg;
101
102 thr->result = (thr->entry)(thr->arg);
103
104 OSThreadExit(0);
105 }
106
107 int
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)108 pthread_create(pthread_t *thread, const pthread_attr_t *attr,
109 void *(*start_routine)(void *), void *arg)
110 {
111 uint64_t status;
112 struct pthread *thr;
113
114 thr = malloc(sizeof(*thr));
115 if (!thr) {
116 return EAGAIN;
117 }
118
119 memset(thr, 0, sizeof(*thr));
120
121 thr->entry = start_routine;
122 thr->arg = arg;
123
124 status = OSThreadCreate((uintptr_t)&pthreadCreateHelper, (uint64_t)thr);
125 if (SYSCALL_ERRCODE(status) != 0) {
126 free(thr);
127 return SYSCALL_ERRCODE(status);
128 }
129
130 thr->tid = SYSCALL_VALUE(status);
131
132 CoreMutex_Lock(&__threadTableLock);
133 TAILQ_INSERT_HEAD(&__threads[thr->tid % THREAD_HASH_SLOTS], thr, threadTable);
134 CoreMutex_Unlock(&__threadTableLock);
135
136 *thread = thr;
137
138 return 0;
139 }
140
141 void
pthread_exit(void * value_ptr)142 pthread_exit(void *value_ptr)
143 {
144 struct pthread *thr = pthread_self();
145
146 thr->result = value_ptr;
147
148 OSThreadExit(0);
149 }
150
151 int
pthread_join(pthread_t thread,void ** value_ptr)152 pthread_join(pthread_t thread, void **value_ptr)
153 {
154 struct pthread *thr = thread;
155 uint64_t status = OSThreadWait(0);//thr->tid);
156 if (SYSCALL_ERRCODE(status) != 0) {
157 return status;
158 }
159
160 *value_ptr = (void *)thr->result;
161
162 CoreMutex_Lock(&__threadTableLock);
163 TAILQ_REMOVE(&__threads[thr->tid % THREAD_HASH_SLOTS], thr, threadTable);
164 CoreMutex_Unlock(&__threadTableLock);
165
166 // Cleanup
167 free(thr);
168
169 return 0;
170 }
171
172 void
pthread_yield(void)173 pthread_yield(void)
174 {
175 OSThreadSleep(0);
176 }
177
178 /*
179 * Barriers
180 */
181
182 int
pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)183 pthread_barrier_init(pthread_barrier_t *barrier,
184 const pthread_barrierattr_t *attr,
185 unsigned count)
186 {
187 return EINVAL;
188 }
189
190 int
pthread_barrier_destroy(pthread_barrier_t * barrier)191 pthread_barrier_destroy(pthread_barrier_t *barrier)
192 {
193 return EINVAL;
194 }
195
196 int
pthread_barrier_wait(pthread_barrier_t * barrier)197 pthread_barrier_wait(pthread_barrier_t *barrier)
198 {
199 return EINVAL;
200 }
201
202 /*
203 * Mutex
204 */
205
206 struct pthread_mutexattr {
207 uint64_t _unused;
208 };
209
210 struct pthread_mutex {
211 uint64_t lock;
212 };
213
214 int
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)215 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
216 {
217 struct pthread_mutex *mtx = (struct pthread_mutex *)malloc(sizeof(*mtx));
218
219 if (mtx == NULL) {
220 return ENOMEM;
221 }
222
223 mtx->lock = 0;
224 *mutex = mtx;
225
226 return 0;
227 }
228
229 int
pthread_mutex_destroy(pthread_mutex_t * mutex)230 pthread_mutex_destroy(pthread_mutex_t *mutex)
231 {
232 struct pthread_mutex *mtx = *mutex;
233
234 if (mtx == NULL) {
235 return EINVAL;
236 } else if (mtx->lock == 1) {
237 return EBUSY;
238 } else {
239 *mutex = NULL;
240 free(mtx);
241 return 0;
242 }
243 }
244
245 int
pthread_mutex_lock(pthread_mutex_t * mutex)246 pthread_mutex_lock(pthread_mutex_t *mutex)
247 {
248 struct pthread_mutex *mtx;
249
250 if (*mutex == NULL) {
251 int status = pthread_mutex_init(mutex, NULL);
252 if (status != 0)
253 return status;
254 }
255
256 mtx = *mutex;
257
258 // XXX: Should have the kernel wait kernel instead of yielding
259 while (__sync_lock_test_and_set(&mtx->lock, 1) == 1) {
260 OSThreadSleep(0);
261 }
262
263 return 0;
264 }
265
266 int
pthread_mutex_trylock(pthread_mutex_t * mutex)267 pthread_mutex_trylock(pthread_mutex_t *mutex)
268 {
269 struct pthread_mutex *mtx;
270
271 if (*mutex == NULL) {
272 int status = pthread_mutex_init(mutex, NULL);
273 if (status != 0)
274 return status;
275 }
276
277 mtx = *mutex;
278
279 if (__sync_lock_test_and_set(&mtx->lock, 1) == 1) {
280 return EBUSY;
281 } else {
282 // Lock acquired
283 return 0;
284 }
285 }
286
287 int
pthread_mutex_unlock(pthread_mutex_t * mutex)288 pthread_mutex_unlock(pthread_mutex_t *mutex)
289 {
290 struct pthread_mutex *mtx;
291
292 if (*mutex == NULL) {
293 int status = pthread_mutex_init(mutex, NULL);
294 if (status != 0)
295 return status;
296 }
297
298 mtx = *mutex;
299
300 __sync_lock_release(&mtx->lock);
301 // XXX: Wakeup a sleeping thread
302
303 return 0;
304 }
305
306
307 /*
308 * Reader/Writer Lock
309 */
310
311 /*
312 * Condition Variables
313 */
314
315 struct pthread_condattr {
316 uint64_t _unused;
317 };
318
319 struct pthread_cond {
320 CoreMutex mtx;
321 uint64_t enter;
322 uint64_t exit;
323 };
324
325 int
pthread_cond_init(pthread_cond_t * cond,const pthread_condattr_t * attr)326 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
327 {
328 struct pthread_cond *cnd = (struct pthread_cond *)malloc(sizeof(*cnd));
329
330 if (cnd == NULL) {
331 return ENOMEM;
332 }
333
334 CoreMutex_Init(&cnd->mtx);
335 cnd->enter = 0;
336 cnd->exit = 0;
337
338 *cond = cnd;
339
340 return 0;
341 }
342
343 int
pthread_cond_destroy(pthread_cond_t * cond)344 pthread_cond_destroy(pthread_cond_t *cond)
345 {
346 struct pthread_cond *cnd = *cond;
347
348 *cond = NULL;
349 free(cnd);
350
351 return 0;
352 }
353
354 int
pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex)355 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
356 {
357 int status;
358 struct pthread_cond *cnd;
359 uint64_t level;
360
361 if (*cond == NULL) {
362 status = pthread_cond_init(cond, NULL);
363 if (status != 0)
364 return status;
365 }
366 cnd = *cond;
367
368 if (mutex) {
369 status = pthread_mutex_unlock(mutex);
370 if (status != 0)
371 return status;
372 }
373
374 CoreMutex_Lock(&cnd->mtx);
375 level = cnd->enter;
376 cnd->enter++;
377 CoreMutex_Unlock(&cnd->mtx);
378
379 while (level >= cnd->exit) {
380 OSThreadSleep(0);
381 }
382
383 if (mutex) {
384 status = pthread_mutex_lock(mutex);
385 if (status != 0)
386 return status;
387 }
388
389 return 0;
390 }
391
392 int
pthread_cond_timedwait(pthread_cond_t * cond,pthread_mutex_t * mutex,const struct timespec * abstime)393 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
394 const struct timespec *abstime)
395 {
396 int status = 0;
397 int rstatus = 0;
398 struct pthread_cond *cnd;
399 uint64_t level;
400 uint64_t endtime = abstime->tv_sec * 1000000000 + abstime->tv_nsec;
401
402 if (*cond == NULL) {
403 status = pthread_cond_init(cond, NULL);
404 if (status != 0)
405 return status;
406 }
407 cnd = *cond;
408
409 if (mutex) {
410 status = pthread_mutex_unlock(mutex);
411 if (status != 0)
412 return status;
413 }
414
415 CoreMutex_Lock(&cnd->mtx);
416 level = cnd->enter;
417 cnd->enter++;
418 CoreMutex_Unlock(&cnd->mtx);
419
420 while (level >= cnd->exit) {
421 OSThreadSleep(0);
422
423 if (endtime < OSTime()) {
424 rstatus = ETIMEDOUT;
425 break;
426 }
427 }
428
429 if (mutex) {
430 status = pthread_mutex_lock(mutex);
431 if (status != 0)
432 return status;
433 }
434
435 return rstatus;
436 }
437
438
439 int
pthread_cond_signal(pthread_cond_t * cond)440 pthread_cond_signal(pthread_cond_t *cond)
441 {
442 struct pthread_cond *cnd;
443
444 if (*cond == NULL) {
445 int status = pthread_cond_init(cond, NULL);
446 if (status != 0)
447 return status;
448 }
449 cnd = *cond;
450
451 CoreMutex_Lock(&cnd->mtx);
452 cnd->exit++;
453 CoreMutex_Unlock(&cnd->mtx);
454
455 return 0;
456 }
457
458 int
pthread_cond_broadcast(pthread_cond_t * cond)459 pthread_cond_broadcast(pthread_cond_t *cond)
460 {
461 struct pthread_cond *cnd;
462
463 if (*cond == NULL) {
464 int status = pthread_cond_init(cond, NULL);
465 if (status != 0)
466 return status;
467 }
468 cnd = *cond;
469
470 CoreMutex_Lock(&cnd->mtx);
471 cnd->exit = cnd->enter;
472 CoreMutex_Unlock(&cnd->mtx);
473
474 return 0;
475 }
476
477