posixcompat: properly handle PTHREAD_MUTEX_RECURSIVE and BF thread id assignment.
[barrelfish] / lib / posixcompat / pthreads.c
1 #include <pthread.h>
2 #include <assert.h>
3 #include <barrelfish/barrelfish.h>
4 #include <errno.h>
5 #include <string.h>
6
7 typedef void (*destructor_fn_t)(void *);
8 typedef void *(*start_fn_t)(void *);
9
10 struct   pthread_mutex_attr
11 {
12   int pshared;
13   int kind;
14   int robustness;
15 };
16
17
18 struct pthread_mutex {
19     struct thread_mutex mutex;
20     int locked;
21     struct pthread_mutex_attr attrs;
22 };
23
24
25
26
27 struct pthread_cond {
28     struct thread_cond cond;
29 };
30
31 #define PTHREADS_RWLOCK_MAGIC 0xdeadbeef
32
33 struct pthread_rwlock
34 {
35   pthread_mutex_t mtxExclusiveAccess;
36   pthread_mutex_t mtxSharedAccessCompleted;
37   pthread_cond_t cndSharedAccessCompleted;
38   int nSharedAccessCount;
39   int nExclusiveAccessCount;
40   int nCompletedSharedAccessCount;
41   int nMagic;
42 };
43
44
45 struct pthread {
46     struct thread *thread;
47     const void *keys[PTHREAD_KEYS_MAX];
48     start_fn_t start_fn;
49     void *arg;
50     void *retval;
51 };
52
53 static pthread_key_t key_index = 0;
54 static struct thread_mutex key_mutex = THREAD_MUTEX_INITIALIZER;
55 static destructor_fn_t destructors[PTHREAD_KEYS_MAX];
56
57 static int start_pthread(void *arg)
58 {
59     struct pthread *myself = arg;
60
61     // Initialize TLS
62     thread_set_tls_key(0, myself);
63
64     // Run the thread
65     myself->retval = myself->start_fn(myself->arg);
66
67     // Call all key destructors
68     for(pthread_key_t i = 0; i < key_index; i++) {
69         if ((destructors[i] != NULL) && (myself->keys[i] != NULL)) {
70             void *value = (void *) myself->keys[i];
71             myself->keys[i] = NULL;
72             destructors[i](value);
73         }
74     }
75
76     // 'myself' data structure is freed when joined with this thread
77     return 0;
78 }
79
80 int pthread_create(pthread_t *pthread, const pthread_attr_t *attr,
81                    void *(*start_routine) (void *), void *arg)
82 {
83     *pthread = malloc(sizeof(struct pthread));
84     assert(*pthread != NULL);
85     memset(*pthread, 0, sizeof(struct pthread));
86
87     // XXX: attributes are ignored.
88     (*pthread)->start_fn = start_routine;
89     (*pthread)->arg = arg;
90
91     // Start the thread
92     (*pthread)->thread = thread_create(start_pthread, *pthread);
93     return 0;
94 }
95
96 pthread_t pthread_self(void)
97 {
98     pthread_t self = thread_get_tls_key(0);
99
100     // If NULL, we're the first thread, not created via pthreads.
101     // Create a pthread structure.
102     if(self == NULL) {
103         struct pthread *myself = malloc(sizeof(struct pthread));
104         assert(myself != NULL);
105         memset(myself, 0, sizeof(struct pthread));
106         myself->thread = thread_self();
107         thread_set_tls_key(0, myself);
108         self = myself;
109     }
110
111     return self;
112 }
113
114 void *pthread_getspecific(pthread_key_t key)
115 {
116     if(key >= PTHREAD_KEYS_MAX) {
117         return NULL;
118     }
119
120     return (void *)pthread_self()->keys[key];
121 }
122
123 int pthread_setspecific(pthread_key_t key, const void *val)
124 {
125     if(key >= PTHREAD_KEYS_MAX) {
126         return EINVAL;
127     }
128
129     pthread_self()->keys[key] = val;
130     return 0;
131 }
132
133 int pthread_attr_init(pthread_attr_t *attr)
134 {
135     // No attributes
136     return 0;
137 }
138
139 static struct thread_mutex mutex_mutex = THREAD_MUTEX_INITIALIZER;
140
141 int pthread_mutex_init(pthread_mutex_t *mutex,
142                        const pthread_mutexattr_t *attr)
143 {
144     // XXX: Attributes ignored.
145     *mutex = malloc(sizeof(struct pthread_mutex));
146     if(*mutex == NULL) {
147         return -1;
148     }
149
150     thread_mutex_init(&(*mutex)->mutex);
151     (*mutex)->locked = 0;
152     if (attr && *attr) {
153         debug_printf("kind = %u\n", (*attr)->kind);
154         memcpy(&(*mutex)->attrs, *attr, sizeof(struct pthread_mutex_attr));
155     } else {
156         (*mutex)->attrs.kind = PTHREAD_MUTEX_NORMAL;
157         (*mutex)->attrs.robustness = 0;
158         (*mutex)->attrs.pshared = PTHREAD_PROCESS_PRIVATE;
159     }
160     return  0;
161 }
162
163 int pthread_mutex_destroy(pthread_mutex_t *mutex)
164 {
165     if(*mutex != PTHREAD_MUTEX_INITIALIZER) {
166         free(*mutex);
167     }
168
169     return 0;
170 }
171
172 int pthread_mutex_lock(pthread_mutex_t *mutex)
173 {
174     thread_mutex_lock(&mutex_mutex);
175
176     if(*mutex == PTHREAD_MUTEX_INITIALIZER) {
177         pthread_mutex_init(mutex, NULL);
178     }
179
180     (*mutex)->locked++;
181     thread_mutex_unlock(&mutex_mutex);
182     if ((*mutex)->attrs.kind == PTHREAD_MUTEX_RECURSIVE) {
183         thread_mutex_lock_nested(&(*mutex)->mutex);
184     } else {
185         thread_mutex_lock(&(*mutex)->mutex);
186     }
187     return 0;
188 }
189
190 int pthread_mutex_unlock(pthread_mutex_t *mutex)
191 {
192     thread_mutex_lock(&mutex_mutex);
193
194     if(*mutex == PTHREAD_MUTEX_INITIALIZER) {
195         pthread_mutex_init(mutex, NULL);
196     }
197
198     if((*mutex)->locked == 0) {
199         thread_mutex_unlock(&mutex_mutex);
200         return 0;
201     }
202
203     (*mutex)->locked--;
204     thread_mutex_unlock(&mutex_mutex);
205     thread_mutex_unlock(&(*mutex)->mutex);
206     return 0;
207 }
208
209 int pthread_mutex_trylock(pthread_mutex_t *mutex)
210 {
211     thread_mutex_lock(&mutex_mutex);
212
213     if(*mutex == PTHREAD_MUTEX_INITIALIZER) {
214         pthread_mutex_init(mutex, NULL);
215     }
216
217     thread_mutex_unlock(&mutex_mutex);
218
219     int retval = (thread_mutex_trylock(&(*mutex)->mutex) ? 0 : EBUSY);
220
221     if(retval != EBUSY) {
222         thread_mutex_lock(&mutex_mutex);
223         (*mutex)->locked++;
224         thread_mutex_unlock(&mutex_mutex);
225     }
226
227     return retval;
228 }
229
230 int pthread_cond_init(pthread_cond_t *cond,
231                         const pthread_condattr_t *attr)
232 {
233     *cond = malloc(sizeof(struct pthread_cond));
234     if(*cond == NULL) {
235         return -1;
236     }
237
238     thread_cond_init(&(*cond)->cond);
239     return 0;
240 }
241
242 int pthread_cond_signal(pthread_cond_t *cond)
243 {
244     thread_mutex_lock(&mutex_mutex);
245     if(*cond == PTHREAD_COND_INITIALIZER) {
246         pthread_cond_init(cond, NULL);
247     }
248     thread_mutex_unlock(&mutex_mutex);
249
250     thread_cond_signal(&(*cond)->cond);
251     return 0;
252 }
253
254 int pthread_cond_timedwait(pthread_cond_t *cond,
255                            pthread_mutex_t *mutex,
256                            const struct timespec *timeout)
257 {
258     thread_mutex_lock(&mutex_mutex);
259     if(*cond == PTHREAD_COND_INITIALIZER) {
260         pthread_cond_init(cond, NULL);
261     }
262     if(*mutex == PTHREAD_MUTEX_INITIALIZER) {
263         pthread_mutex_init(mutex, NULL);
264     }
265     thread_mutex_unlock(&mutex_mutex);
266
267     assert(!"NYI");
268     return -1;
269 }
270
271 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
272 {
273     thread_mutex_lock(&mutex_mutex);
274     if(*cond == PTHREAD_COND_INITIALIZER) {
275         pthread_cond_init(cond, NULL);
276     }
277     if(*mutex == PTHREAD_MUTEX_INITIALIZER) {
278         pthread_mutex_init(mutex, NULL);
279     }
280     thread_mutex_unlock(&mutex_mutex);
281
282     thread_cond_wait(&(*cond)->cond, &(*mutex)->mutex);
283     return 0;
284 }
285
286 int pthread_cond_broadcast(pthread_cond_t *cond)
287 {
288     thread_mutex_lock(&mutex_mutex);
289
290     if(*cond == PTHREAD_COND_INITIALIZER) {
291          pthread_cond_init(cond, NULL);
292     }
293     thread_mutex_unlock(&mutex_mutex);
294
295     thread_cond_broadcast(&(*cond)->cond);
296
297     return 0;
298 }
299
300 int pthread_cond_destroy(pthread_cond_t *cond)
301 {
302     free(cond);
303     return 0;
304 }
305
306 int pthread_join(pthread_t thread, void **retval)
307 {
308     errval_t err = thread_join(thread->thread, NULL);
309     assert(err_is_ok(err));
310
311     if (retval != NULL) {
312         *retval = thread->retval;
313     }
314     free(thread);
315     return 0;
316 }
317
318 int pthread_key_create(pthread_key_t *key,
319                        void (*callback) (void *))
320 {
321     int retval = 0;
322
323     thread_mutex_lock(&key_mutex);
324
325     if(key_index == PTHREAD_KEYS_MAX) {
326         retval = EAGAIN;
327         goto out;
328     }
329
330     *key = key_index;
331     destructors[key_index] = callback;
332     key_index++;
333
334  out:
335     thread_mutex_unlock(&key_mutex);
336     return retval;
337 }
338
339 int pthread_key_delete(pthread_key_t key)
340 {
341     thread_mutex_lock(&key_mutex);
342
343     int result = EINVAL;
344     if ((key < PTHREAD_KEYS_MAX) && (destructors[key] != NULL)) {
345         destructors[key] = NULL;
346         result = 0;
347     }
348
349     thread_mutex_unlock(&key_mutex);
350     return result;
351 }
352
353 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
354 {
355     int result = 0;
356     pthread_mutexattr_t ma;
357
358     ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma));
359
360     if (ma == NULL) {
361         result = ENOMEM;
362     }
363     else {
364         ma->pshared = PTHREAD_PROCESS_PRIVATE;
365         ma->kind = PTHREAD_MUTEX_DEFAULT;
366     }
367
368     *attr = ma;
369
370     return result;
371 }
372
373 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
374 {
375     int result = 0;
376
377     if (attr == NULL || *attr == NULL) {
378         result = EINVAL;
379     } else {
380         pthread_mutexattr_t ma = *attr;
381
382         *attr = NULL;
383         free (ma);
384     }
385
386     return result;
387 }
388
389 int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr,
390                                  int *pshared)
391 {
392     int result;
393
394     if ((attr != NULL && *attr != NULL) && (pshared != NULL)) {
395         *pshared = (*attr)->pshared;
396         result = 0;
397     } else {
398         result = EINVAL;
399     }
400
401     return result;
402 }
403
404 int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type)
405 {
406     int result = 0;
407
408     if (attr != NULL && *attr != NULL && type != NULL) {
409         *type = (*attr)->kind;
410     } else {
411         result = EINVAL;
412     }
413
414     return result;
415 }
416
417 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
418 {
419     int result = 0;
420
421     if ((attr != NULL && *attr != NULL)) {
422         switch (type) {
423             case PTHREAD_MUTEX_NORMAL:
424             case PTHREAD_MUTEX_RECURSIVE:
425             case PTHREAD_MUTEX_ERRORCHECK:
426                 (*attr)->kind = type;
427                 break;
428             default:
429                 result = EINVAL;
430                 break;
431         }
432     } else {
433         result = EINVAL;
434     }
435
436     return result;
437 }
438
439 int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
440 {
441     int result;
442
443     if ((attr != NULL && *attr != NULL)
444          && ((pshared == PTHREAD_PROCESS_SHARED)
445                   || (pshared == PTHREAD_PROCESS_PRIVATE))) {
446
447         if (pshared == PTHREAD_PROCESS_SHARED) {
448 #if !defined( _POSIX_THREAD_PROCESS_SHARED )
449             result = ENOSYS;
450             pshared = PTHREAD_PROCESS_PRIVATE;
451 #else
452             result = 0;
453 #endif /* _POSIX_THREAD_PROCESS_SHARED */
454         } else {
455             result = 0;
456         }
457
458         (*attr)->pshared = pshared;
459     } else {
460         result = EINVAL;
461     }
462
463     return (result);
464 }
465
466
467
468 int pthread_equal(pthread_t pt1, pthread_t pt2)
469 {
470     if (pt1 == NULL && pt2 == NULL) {
471         return 1;
472     }
473     return pt1->thread == pt2->thread;
474 }
475
476 int pthread_rwlock_init(pthread_rwlock_t *rwlock,
477             const pthread_rwlockattr_t *attr)
478 {
479     pthread_rwlock_t rwl;
480
481     rwl = calloc(1, sizeof(struct pthread_rwlock));
482     if (rwl == NULL) {
483         return ENOMEM;
484     }
485
486     rwl->nMagic = PTHREADS_RWLOCK_MAGIC;
487     rwl->mtxExclusiveAccess = PTHREAD_MUTEX_INITIALIZER;
488     rwl->mtxSharedAccessCompleted = PTHREAD_MUTEX_INITIALIZER;
489
490     pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL);
491     *rwlock = rwl;
492
493     return 0;
494 }
495
496 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
497 {
498     int result, result1;
499     pthread_rwlock_t rwl;
500
501     if (rwlock == NULL || *rwlock == NULL) {
502         return (EINVAL);
503     }
504
505     if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) {
506         result = pthread_rwlock_init(rwlock, NULL);
507         if (result) {
508             return result;
509         }
510     }
511
512     rwl = *rwlock;
513
514     if (rwl->nMagic != PTHREADS_RWLOCK_MAGIC) {
515         return EINVAL;
516     }
517
518     if (rwl->nExclusiveAccessCount == 0) {
519         if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) {
520             return result;
521         }
522
523         if (++rwl->nCompletedSharedAccessCount == 0) {
524             result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted));
525         }
526
527         result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
528     } else {
529         rwl->nExclusiveAccessCount--;
530         result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted));
531         result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
532     }
533
534     return ((result != 0) ? result : result1);
535 }
536
537 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
538 {
539     int result;
540     pthread_rwlock_t rwl;
541
542     if (rwlock == NULL || *rwlock == NULL) {
543         return (EINVAL);
544     }
545
546     if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) {
547         result = pthread_rwlock_init(rwlock, NULL);
548         if (result) {
549             return result;
550         }
551     }
552
553     rwl = *rwlock;
554
555     if (rwl->nMagic != PTHREADS_RWLOCK_MAGIC) {
556         return EINVAL;
557     }
558
559     if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) {
560         return result;
561     }
562
563     if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) {
564         (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
565         return result;
566     }
567
568     if (rwl->nExclusiveAccessCount == 0) {
569         if (rwl->nCompletedSharedAccessCount > 0) {
570             rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
571             rwl->nCompletedSharedAccessCount = 0;
572         }
573
574         if (rwl->nSharedAccessCount > 0) {
575             rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount;
576
577             /*
578              * This routine may be a cancelation point
579              * according to POSIX 1003.1j section 18.1.2.
580              */
581            // pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl);
582
583             do {
584                 result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted),
585                                             &(rwl->mtxSharedAccessCompleted));
586             } while (result == 0 && rwl->nCompletedSharedAccessCount < 0);
587
588             //pthread_cleanup_pop ((result != 0) ? 1 : 0);
589
590             if (result == 0) {
591                 rwl->nSharedAccessCount = 0;
592             }
593         }
594     }
595
596     if (result == 0) {
597         rwl->nExclusiveAccessCount++;
598     }
599
600     return result;
601 }
602
603 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
604 {
605   int result;
606   pthread_rwlock_t rwl;
607
608   if (rwlock == NULL || *rwlock == NULL) {
609       return EINVAL;
610   }
611
612   /*
613    * We do a quick check to see if we need to do more work
614    * to initialise a static rwlock. We check
615    * again inside the guarded section of ptw32_rwlock_check_need_init()
616    * to avoid race conditions.
617    */
618    if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) {
619         result = pthread_rwlock_init(rwlock, NULL);
620         if (result) {
621             return result;
622         }
623     }
624
625   rwl = *rwlock;
626
627   if (rwl->nMagic != PTHREADS_RWLOCK_MAGIC) {
628       return EINVAL;
629   }
630
631   if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) {
632       return result;
633   }
634
635   if (++rwl->nSharedAccessCount == 0xFFFFFFFF) {
636       if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) {
637           (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
638           return result;
639       }
640
641       rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount;
642       rwl->nCompletedSharedAccessCount = 0;
643
644       if ((result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) {
645           (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess));
646           return result;
647       }
648   }
649
650   return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)));
651 }
652
653
654 int _pthread_once(pthread_once_t *ctrl, void (*init) (void))
655 {
656     if (ctrl == NULL || init == NULL) {
657         return EINVAL;
658     }
659
660
661     pthread_mutex_lock(&ctrl->mutex);
662
663
664     if (!ctrl->state)
665     {
666         //pthread_cleanup_push(ptw32_mcs_lock_release, &node);
667         (*init)();
668         //pthread_cleanup_pop(0);
669         ctrl->state = 1;
670     }
671
672     pthread_mutex_unlock(&ctrl->mutex);
673
674     return 0;
675 }