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