source: libcfa/src/concurrency/pthread.cfa @ b1eefe50

Last change on this file since b1eefe50 was 9d47c1f, checked in by caparsons <caparson@…>, 10 months ago

changes over all usages of uC++ collections to use dlist instead

  • Property mode set to 100644
File size: 30.7 KB
RevLine 
[20be782]1//
2// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// pthread.cfa --
8//
9// Author           : Zhenyan Zhu
10// Created On       : Sat Aug 6 16:29:18 2022
[555af62]11// Last Modified By : Peter A. Buhr
12// Last Modified On : Mon Sep  4 15:37:51 2023
13// Update Count     : 1
[20be782]14//
[a7d696f]15
16#define __cforall_thread__
17
[9cd5bd2]18#include <signal.h>
[a7d696f]19#include <pthread.h>
[20be782]20#include <errno.h>
21#include "locks.hfa"
[a7d696f]22
[9cd5bd2]23#define check_nonnull(x) asm("": "+rm"(x)); if( x == 0p ) return EINVAL;
[a7d696f]24
[20be782]25/* pthread key, pthread once inner routine mutual exclusion */
[a7d696f]26static simple_owner_lock once_lock,key_lock,magic_mutex_check, concurrency_lock;
[20be782]27
[a7d696f]28//######################### Local Storage Helpers #########################
29
[9cd5bd2]30enum { PTHREAD_KEYS_MAX = 1024 };
31
[8bd886e]32struct pthread_values{
[9d47c1f]33        inline dlink(pthread_values);
[f5f2768]34        void * value;
[9cd5bd2]35        bool in_use;
[a7d696f]36};
[9d47c1f]37P9_EMBEDDED( pthread_values, dlink(pthread_values) )
[a7d696f]38
[8bd886e]39struct pthread_keys {
[9cd5bd2]40        bool in_use;
[3494ca9]41        void (* destructor)( void * );
[9d47c1f]42    dlist( pthread_values ) threads;
[8bd886e]43};
[a7d696f]44
[f5f2768]45static void ?{}(pthread_keys& k) {
[9cd5bd2]46        k.threads{};
[a7d696f]47}
48
49// Create storage separately to ensure no constructors are called.
[8bd886e]50static pthread_keys cfa_pthread_keys_storage[PTHREAD_KEYS_MAX] __attribute__((aligned (16)));
[a7d696f]51
[f5f2768]52static void init_pthread_storage() {
[3494ca9]53        for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
[9cd5bd2]54                cfa_pthread_keys_storage[i]{};
55        }
[a7d696f]56}
57
[8bd886e]58#define cfa_pthread_keys ((pthread_keys *)cfa_pthread_keys_storage)
[a7d696f]59
60/* Controlling the iterations of destructors for thread-specific data.  */
61#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS     4
62/* Number of iterations this implementation does.  */
63#define PTHREAD_DESTRUCTOR_ITERATIONS   _POSIX_THREAD_DESTRUCTOR_ITERATIONS
64
65//######################### Parallelism Helpers #########################
66
67struct Pthread_kernel_threads{
[9d47c1f]68        inline dlink(Pthread_kernel_threads);
[9cd5bd2]69        processor p;
[a7d696f]70};
[9d47c1f]71P9_EMBEDDED( Pthread_kernel_threads, dlink(Pthread_kernel_threads) )
[a7d696f]72
[9d47c1f]73static dlist(Pthread_kernel_threads) cfa_pthreads_kernel_threads;
[a7d696f]74static bool cfa_pthreads_kernel_threads_zero = false;   // set to zero ?
75static int cfa_pthreads_no_kernel_threads = 1;  // number of kernel threads
76
77
78//######################### Cond Helpers #########################
79
80typedef pthread_cond_var(simple_owner_lock) cfa2pthr_cond_var_t;
81
82/* condvar helper routines */
[f5f2768]83static void init(pthread_cond_t * pcond) {
[9cd5bd2]84        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
[3494ca9]85        cfa2pthr_cond_var_t * _cond = (cfa2pthr_cond_var_t *)pcond;
[9cd5bd2]86        ?{}(*_cond);
[a7d696f]87}
88
[f5f2768]89static cfa2pthr_cond_var_t * get(pthread_cond_t * pcond) {
[9cd5bd2]90        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
[3494ca9]91        return (cfa2pthr_cond_var_t *)pcond;
[a7d696f]92}
93
[3494ca9]94static void destroy(pthread_cond_t * cond) {
[9cd5bd2]95        static_assert(sizeof(pthread_cond_t) >= sizeof(cfa2pthr_cond_var_t),"sizeof(pthread_t) < sizeof(cfa2pthr_cond_var_t)");
96        ^?{}(*get(cond));
[a7d696f]97}
98
99
100//######################### Mutex Helper #########################
101
102/* mutex helper routines */
[3494ca9]103static void mutex_check(pthread_mutex_t * t) {
[8bd886e]104        // Use double check to improve performance.
105        // Check is safe on x86; volatile prevents compiler reordering
[3494ca9]106        volatile pthread_mutex_t * const mutex_ = t;
[8bd886e]107
[a7d696f]108        // SKULLDUGGERY: not a portable way to access the kind field, /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h
109        int _lock_val = ((pthread_mutex_t *)mutex_)->__data.__lock;
[8bd886e]110
[20be782]111        // if pthread_mutex_t is initialized by PTHREAD_MUTEX_INITIALIZER, _lock_val should be 0
[8bd886e]112        if ( _lock_val == 0 ) {
113                lock(magic_mutex_check);
[9cd5bd2]114                _lock_val = ((pthread_mutex_t *)mutex_)->__data.__lock;
[8bd886e]115                if ( _lock_val == 0 ) {
116                        pthread_mutex_init( t, NULL );
117                }
118                unlock(magic_mutex_check);
119        }
[a7d696f]120} // mutex_check
121
122
[3494ca9]123static void init(pthread_mutex_t * plock) {
[9cd5bd2]124        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
[3494ca9]125        simple_owner_lock * _lock = (simple_owner_lock *)plock;
[9cd5bd2]126        ?{}(*_lock);
[a7d696f]127}
128
[3494ca9]129static simple_owner_lock * get(pthread_mutex_t * plock) {
[9cd5bd2]130        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
[3494ca9]131        return (simple_owner_lock *)plock;
[a7d696f]132}
133
[3494ca9]134static void destroy(pthread_mutex_t * plock) {
[9cd5bd2]135        static_assert(sizeof(pthread_mutex_t) >= sizeof(simple_owner_lock),"sizeof(pthread_mutex_t) < sizeof(simple_owner_lock)");
136        ^?{}(*get(plock));
[a7d696f]137}
138
139//######################### Attr helpers #########################
[ff443e5]140typedef struct cfaPthread_attr_t {                                              // thread attributes
[a7d696f]141                int contentionscope;
142                int detachstate;
143                size_t stacksize;
[3494ca9]144                void * stackaddr;
[a7d696f]145                int policy;
146                int inheritsched;
147                struct sched_param param;
[ff443e5]148} cfaPthread_attr_t;
[a7d696f]149
[3494ca9]150static const cfaPthread_attr_t default_attrs {
[9cd5bd2]151        0,
152        0,
[3494ca9]153        65_000,
154        NULL,
[9cd5bd2]155        0,
156        0,
157        {0}
[a7d696f]158};
159
[3494ca9]160static cfaPthread_attr_t * get(const pthread_attr_t * attr) {
161        static_assert(sizeof(pthread_attr_t) >= sizeof(cfaPthread_attr_t), "sizeof(pthread_attr_t) < sizeof(cfaPthread_attr_t)");
162        return (cfaPthread_attr_t *)attr;
[a7d696f]163}
164
165
166//######################### Threads Helper #########################
167
[20be782]168// exception for cancel_stack in pthread_exit
[a7d696f]169exception pthread_exit_exp {};
[9cd5bd2]170static vtable(pthread_exit_exp) exp_vt;
[a7d696f]171
172thread cfaPthread{
[9cd5bd2]173        cfaPthread_attr_t attr;
174        pthread_t pthreadId;
[8bd886e]175
176        // pthreads return value
[3494ca9]177        void * joinval;
[8bd886e]178
179        // pthread attributes
180        pthread_attr_t pthread_attr;
181
[3494ca9]182        void *(* start_routine)(void *);
183        void * start_arg;
[8bd886e]184
185        // thread local data
[3494ca9]186        pthread_values * pthreadData;
[8bd886e]187
188        // flag used for tryjoin
189        bool isTerminated;
[a7d696f]190};
191
192/* thread part routines */
193//  cfaPthread entry point
[3494ca9]194void main(cfaPthread & _thread) with(_thread) {
195        joinval = start_routine(start_arg);
[9cd5bd2]196        isTerminated = true;
[a7d696f]197}
198
[f5f2768]199static cfaPthread * lookup( pthread_t p ) {
[3494ca9]200        static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *),"sizeof(pthread_t) < sizeof(cfaPthread *)");
201        return (cfaPthread *)p;
[a7d696f]202}
203
[3494ca9]204static void pthread_deletespecific_( pthread_values * values )  { // see uMachContext::invokeTask
205        pthread_values * value;
206        pthread_keys * key;
[9cd5bd2]207        bool destcalled = true;
[f5f2768]208        if (values != NULL) {
[9cd5bd2]209                for ( int attempts = 0; attempts < PTHREAD_DESTRUCTOR_ITERATIONS && destcalled ; attempts += 1 ) {
210                        destcalled = false;
211                        lock(key_lock);
[3494ca9]212                        for ( int i = 0; i < PTHREAD_KEYS_MAX; i++ ) {
[9cd5bd2]213                                // for each valid key
[f5f2768]214                                if ( values[i].in_use) {
[9cd5bd2]215                                        value = &values[i];
216                                        key = &cfa_pthread_keys[i];
217                                        value->in_use = false;
[9d47c1f]218                                        remove(*value);
219
[9cd5bd2]220                                        // if  a  key  value  has  a  non-NULL  destructor pointer,  and  the  thread  has  a  non-NULL  value associated with that key,
221                                        // the value of the key is set to NULL, and then the function pointed to is called with the previously associated value as its sole argument.
[f5f2768]222                                        if (value->value != NULL && key->destructor != NULL) {
[9cd5bd2]223                                                unlock(key_lock);
224                                                key->destructor(value->value); // run destructor
225                                                lock(key_lock);
226                                                destcalled = true;
227                                        }   // if
228                                        value->value = NULL;
229                                }   // if
230                        }   // for
231                        unlock(key_lock);
232                }   // for
233                free(values);
234        }   // if
[a7d696f]235}
236
[f5f2768]237static void ^?{}(cfaPthread & mutex t) {
[9cd5bd2]238        // delete pthread local storage
[8bd886e]239        pthread_values * values = t.pthreadData;
[9cd5bd2]240        pthread_deletespecific_(values);
[a7d696f]241}
242
[3494ca9]243static void ?{}(cfaPthread & t, pthread_t * _thread, const pthread_attr_t * _attr,void *(* start_routine)(void *), void * arg) {
244        static_assert(sizeof(pthread_t) >= sizeof(cfaPthread *), "pthread_t too small to hold a pointer: sizeof(pthread_t) < sizeof(cfaPthread *)");
[9cd5bd2]245
246        // set up user thread stackSize
247        cfaPthread_attr_t * attr = get(_attr);
[3494ca9]248        ((thread&)t){ attr ? attr->stacksize: DEFAULT_STACK_SIZE };
[9cd5bd2]249
250        // initialize _thread & cfaPthread id
[8bd886e]251        *_thread = t.pthreadId = (pthread_t)(&t);
[9cd5bd2]252
253        // if attr null, self attr will be set as default_attrs; else set to attr
254        t.attr = (attr != NULL ? *attr : default_attrs);
255
256        // init start routine and arguments
257        t.start_routine = start_routine;
[8bd886e]258        t.start_arg = arg;
[9cd5bd2]259        t.pthreadData = NULL;
[8bd886e]260}
[a7d696f]261
262
263extern "C"{
[9cd5bd2]264        //######################### Pthread Attrs #########################
265
[3494ca9]266        int pthread_attr_init(pthread_attr_t * attr) libcfa_public __THROW {
267                cfaPthread_attr_t * _attr = get(attr);
[8bd886e]268                ?{}(*_attr, default_attrs);
[9cd5bd2]269                return 0;
270        }
[3494ca9]271        int pthread_attr_destroy(pthread_attr_t * attr) libcfa_public __THROW {
[9cd5bd2]272                ^?{}(*get(attr));
273                return 0;
274        }
275
[3494ca9]276        int pthread_attr_setscope( pthread_attr_t * attr, int contentionscope ) libcfa_public __THROW {
[9cd5bd2]277                get( attr )->contentionscope = contentionscope;
278                return 0;
279        } // pthread_attr_setscope
280
[3494ca9]281        int pthread_attr_getscope( const pthread_attr_t * attr, int * contentionscope ) libcfa_public __THROW {
[9cd5bd2]282                *contentionscope = get( attr )->contentionscope;
283                return 0;
284        } // pthread_attr_getscope
285
[3494ca9]286        int pthread_attr_setdetachstate( pthread_attr_t * attr, int detachstate ) libcfa_public __THROW {
[9cd5bd2]287                get( attr )->detachstate = detachstate;
288                return 0;
289        } // pthread_attr_setdetachstate
290
[3494ca9]291        int pthread_attr_getdetachstate( const pthread_attr_t * attr, int * detachstate ) libcfa_public __THROW {
[9cd5bd2]292                *detachstate = get( attr )->detachstate;
293                return 0;
294        } // pthread_attr_getdetachstate
295
[3494ca9]296        int pthread_attr_setstacksize( pthread_attr_t * attr, size_t stacksize ) libcfa_public __THROW {
[9cd5bd2]297                get( attr )->stacksize = stacksize;
298                return 0;
299        } // pthread_attr_setstacksize
300
[3494ca9]301        int pthread_attr_getstacksize( const pthread_attr_t * attr, size_t * stacksize ) libcfa_public __THROW {
[9cd5bd2]302                *stacksize = get( attr )->stacksize;
303                return 0;
304        } // pthread_attr_getstacksize
305
306        int pthread_attr_getguardsize( const pthread_attr_t * /* attr */, size_t * /* guardsize */ ) libcfa_public __THROW {
307                return 0;
308        } // pthread_attr_getguardsize
309
310        int pthread_attr_setguardsize( pthread_attr_t * /* attr */, size_t /* guardsize */ ) libcfa_public __THROW {
311                return 0;
312        } // pthread_attr_setguardsize
313
[3494ca9]314        int pthread_attr_setstackaddr( pthread_attr_t * attr, void * stackaddr ) libcfa_public __THROW {
[9cd5bd2]315                get( attr )->stackaddr = stackaddr;
316                return 0;
317        } // pthread_attr_setstackaddr
318
[3494ca9]319        int pthread_attr_getstackaddr( const pthread_attr_t * attr, void ** stackaddr ) libcfa_public __THROW {
[9cd5bd2]320                *stackaddr = get( attr )->stackaddr;
321                return 0;
322        } // pthread_attr_getstackaddr
323
[3494ca9]324        int pthread_attr_setstack( pthread_attr_t * attr, void * stackaddr, size_t stacksize ) libcfa_public __THROW {
[9cd5bd2]325                get( attr )->stackaddr = stackaddr;
326                get( attr )->stacksize = stacksize;
327                return 0;
328        } // pthread_attr_setstack
329
[3494ca9]330        int pthread_attr_getstack( const pthread_attr_t * attr, void ** stackaddr, size_t * stacksize ) libcfa_public __THROW {
[9cd5bd2]331                *stackaddr = get( attr )->stackaddr;
332                *stacksize = get( attr )->stacksize;
333                return 0;
334        } // pthread_attr_getstack
335
336        // Initialize thread attribute *attr with attributes corresponding to the
337        // already running thread threadID. It shall be called on unitialized attr
338        // and destroyed with pthread_attr_destroy when no longer needed.
[3494ca9]339        int pthread_getattr_np( pthread_t threadID, pthread_attr_t * attr ) libcfa_public __THROW { // GNU extension
[8bd886e]340                check_nonnull(attr);
341
342                // copy all fields
343                *get(attr) = lookup( threadID )->attr;
344
[9cd5bd2]345                return 0;
346        } // pthread_getattr_np
347
348
349        //######################### Threads #########################
350
[3494ca9]351        int pthread_create(pthread_t * _thread, const pthread_attr_t * attr, void *(* start_routine)(void *), void * arg) libcfa_public __THROW {
352                cfaPthread * t = alloc();
353                (*t){_thread, attr, start_routine, arg};
[9cd5bd2]354                return 0;
[8bd886e]355        }
[9cd5bd2]356
[3494ca9]357        int pthread_join(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {
[8bd886e]358                // if thread is invalid
359                if (_thread == NULL) return EINVAL;
[9cd5bd2]360                if (_thread == pthread_self()) return EDEADLK;
[8bd886e]361
362                // get user thr pointer
[3494ca9]363                cfaPthread * p = lookup(_thread);
[9cd5bd2]364                try {
365                        join(*p);
[8bd886e]366                }
367                // if thread called pthread_exit
368                catchResume (ThreadCancelled(cfaPthread) * cancel) {}
369
370                // fetch result
371                if (value_ptr != NULL ) *value_ptr = p->joinval;
[9cd5bd2]372                delete(p);
373                return 0;
[8bd886e]374        }
[9cd5bd2]375
[3494ca9]376        int pthread_tryjoin_np(pthread_t _thread, void ** value_ptr) libcfa_public __THROW {
[8bd886e]377                // if thread is invalid
378                if (_thread == NULL) return EINVAL;
[9cd5bd2]379                if (_thread == pthread_self()) return EDEADLK;
[8bd886e]380
[3494ca9]381                cfaPthread * p = lookup(_thread);
[8bd886e]382
383                // thread not finished ?
384                if (!p->isTerminated) return EBUSY;
385
[9cd5bd2]386                join( *p );
[8bd886e]387
[9cd5bd2]388                if (value_ptr != NULL ) *value_ptr = p->joinval;
389                delete(p);
390                return 0;
[8bd886e]391        }
[9cd5bd2]392
393        pthread_t pthread_self(void) libcfa_public __THROW {
[8bd886e]394                return (pthread_t)((uintptr_t)active_thread() - (sizeof(cfaPthread) - sizeof(thread$)));
395        }
[9cd5bd2]396
397        void pthread_exit(void * status) libcfa_public __THROW {
398                pthread_t pid = pthread_self();
[3494ca9]399                cfaPthread * _thread = (cfaPthread *)pid;
[9cd5bd2]400                _thread->joinval = status;  // set return value
401                _thread->isTerminated = 1;  // set terminated flag
[3494ca9]402                cancel_stack((pthread_exit_exp){&exp_vt});
[9cd5bd2]403        }   //pthread_exit_
404
405        int pthread_yield( void ) __THROW {                     // GNU extension
406                yield();
407                return 0;
408        }
409
410
411        //######################### Mutex #########################
412
[3494ca9]413        int pthread_mutex_init(pthread_mutex_t *_mutex, const pthread_mutexattr_t * attr) libcfa_public __THROW {
[9cd5bd2]414                check_nonnull(_mutex);
415                init(_mutex);
416                return 0;
417        }   //pthread_mutex_init_
418
419
420        int pthread_mutex_destroy(pthread_mutex_t *_mutex) libcfa_public __THROW {
421                check_nonnull(_mutex);
[3494ca9]422                simple_owner_lock * _lock = get(_mutex);
[f5f2768]423                if (_lock->owner != NULL) {
[9cd5bd2]424                        return EBUSY;
425                }
426                destroy(_mutex);
427                return 0;
428        }   //pthread_mutex_destroy_
429
430        int pthread_mutex_lock(pthread_mutex_t *_mutex) libcfa_public __THROW {
431                check_nonnull(_mutex);
432                mutex_check(_mutex);
[3494ca9]433                simple_owner_lock * _lock = get(_mutex);
[9cd5bd2]434                lock(*_lock);
435                return 0;
436        }   //pthread_mutex_lock_
437
438        int pthread_mutex_unlock(pthread_mutex_t *_mutex) libcfa_public __THROW {
439                check_nonnull(_mutex);
[3494ca9]440                simple_owner_lock * _lock = get(_mutex);
[f5f2768]441                if (_lock->owner != active_thread()) {
[9cd5bd2]442                        return EPERM;
443                } // current thread does not hold the mutex
444                unlock(*_lock);
445                return 0;
446        }   //pthread_mutex_unlock_
447
448        int pthread_mutex_trylock(pthread_mutex_t *_mutex) libcfa_public __THROW {
449                check_nonnull(_mutex);
[3494ca9]450                simple_owner_lock * _lock = get(_mutex);
[f5f2768]451                if (_lock->owner != active_thread() && _lock->owner != NULL) {
[9cd5bd2]452                        return EBUSY;
453                }   // if mutex is owned
454                lock(*_lock);
455                return 0;
456        }   //pthread_mutex_trylock_
457
458        //######################### Conditional Variable #########################
459
460        /* conditional variable routines */
[3494ca9]461        int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr) libcfa_public __THROW {
[9cd5bd2]462                check_nonnull(cond);
463                init(cond);
464                return 0;
465        }  //pthread_cond_init
466
[3494ca9]467        int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t *_mutex) libcfa_public __THROW {
[9cd5bd2]468                check_nonnull(_mutex);
469                check_nonnull(cond);
470                wait(*get(cond), *get(_mutex));
471                return 0;
472        } // pthread_cond_wait
473
474        int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * _mutex, const struct timespec * abstime) libcfa_public __THROW {
475                check_nonnull(_mutex);
476                check_nonnull(cond);
477                wait(*get(cond), *get(_mutex), *abstime);
478                return 0;
479        } // pthread_cond_timedwait
480
[3494ca9]481        int pthread_cond_signal(pthread_cond_t * cond) libcfa_public __THROW {
[9cd5bd2]482                check_nonnull(cond);
483                return notify_one(*get(cond));
484        } // pthread_cond_signal
485
[3494ca9]486        int pthread_cond_broadcast(pthread_cond_t * cond) libcfa_public __THROW {
[9cd5bd2]487                check_nonnull(cond);
488                return notify_all(*get(cond));
489        } // pthread_cond_broadcast
490
[3494ca9]491        int pthread_cond_destroy(pthread_cond_t * cond) libcfa_public __THROW {
[9cd5bd2]492                check_nonnull(cond);
493                destroy(cond);
494                return 0;
495        } // pthread_cond_destroy
496
497
498
499        //######################### Local storage #########################
500
[3494ca9]501        int pthread_once(pthread_once_t * once_control, void (* init_routine)(void)) libcfa_public __THROW {
[9cd5bd2]502                static_assert(sizeof(pthread_once_t) >= sizeof(int),"sizeof(pthread_once_t) < sizeof(int)");
503                check_nonnull(once_control);
504                check_nonnull(init_routine);
505                lock(once_lock);
506                if ( *((int *)once_control) == 0 ) {
507                        init_routine();
508                        *((int *)once_control) = 1;
509                } // if
510                unlock(once_lock);
511                return 0;
512        } // pthread_once
513
[3494ca9]514        int pthread_key_create( pthread_key_t * key, void (* destructor)( void * ) ) libcfa_public __THROW {
[9cd5bd2]515                lock(key_lock);
516                for ( int i = 0; i < PTHREAD_KEYS_MAX; i += 1 ) {
517                        if ( ! cfa_pthread_keys[i].in_use ) {
518                                cfa_pthread_keys[i].in_use = true;
519                                cfa_pthread_keys[i].destructor = destructor;
520                                unlock( key_lock );
521                                *key = i;
522                                return 0;
523                        } // if
524                } // for
525                unlock(key_lock);
526                return EAGAIN;
527        }   // pthread_key_create
528
529        int pthread_key_delete( pthread_key_t key ) libcfa_public __THROW {
530                lock(key_lock);
531                if ( key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use ) {
532                        unlock( key_lock );
533                        return EINVAL;
534                } // if
535                cfa_pthread_keys[key].in_use = false;
536                cfa_pthread_keys[key].destructor = NULL;
537
538                // Remove key from all threads with a value.
[9d47c1f]539               
540                // Sequence(pthread_values)& head = cfa_pthread_keys[key].threads;
541                // for ( SeqIter(pthread_values) iter = { head }; iter | p; ) {
542                //      remove(head, p);
543                //      p.in_use = false;
544                // }
545        pthread_values * p = &try_pop_front( cfa_pthread_keys[key].threads );
546        for ( ; p; ) {           
547            p->in_use = false;
548            p = &try_pop_front( cfa_pthread_keys[key].threads );
549        }
[9cd5bd2]550                unlock(key_lock);
551                return 0;
552        }   // pthread_key_delete
553
[3494ca9]554        int pthread_setspecific( pthread_key_t key, const void * value ) libcfa_public __THROW {
[9cd5bd2]555                // get current thread
[3494ca9]556                cfaPthread * t = lookup(pthread_self());
[9cd5bd2]557                // if current thread's pthreadData is NULL; initialize it
[3494ca9]558                pthread_values * values;
[f5f2768]559                if (t->pthreadData == NULL) {
[9cd5bd2]560                        values = anew( PTHREAD_KEYS_MAX);
561                        t->pthreadData = values;
[3494ca9]562                        for ( int i = 0;i < PTHREAD_KEYS_MAX; i++ ) {
[9cd5bd2]563                                t->pthreadData[i].in_use = false;
564                        }   // for
565                }   else {
566                        values = t->pthreadData;
567                }   // if
568                // find corresponding key and set value
569                lock(key_lock);
570                // if invalid key
571                if ( key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use ) {
572                        unlock( key_lock );
573                        return EINVAL;
574                } // if
[8bd886e]575                pthread_values &entry = values[key];
[9cd5bd2]576                if ( ! entry.in_use ) {
577                        entry.in_use = true;
[9d47c1f]578                        insert_last(cfa_pthread_keys[key].threads, entry);
[9cd5bd2]579                } // if
580                entry.value = (void *)value;
581                unlock(key_lock);
582                return 0;
583        } //pthread_setspecific
584
[3494ca9]585        void * pthread_getspecific(pthread_key_t key) libcfa_public __THROW {
[9cd5bd2]586                if (key >= PTHREAD_KEYS_MAX || ! cfa_pthread_keys[key].in_use) return NULL;
587
588                // get current thread
[3494ca9]589                cfaPthread * t = lookup(pthread_self());
[9cd5bd2]590                if (t->pthreadData == NULL) return NULL;
591                lock(key_lock);
[a0a949c]592                pthread_values & entry = ((pthread_values *)t->pthreadData)[key];
[9cd5bd2]593                if ( ! entry.in_use ) {
594                        unlock( key_lock );
595                        return NULL;
596                } // if
[3494ca9]597                void * value = entry.value;
[9cd5bd2]598                unlock(key_lock);
599
600                return value;
601        }   //pthread_get_specific
602
603        //######################### Parallelism #########################
[8bd886e]604        void pthread_delete_kernel_threads_() __THROW { // see uMain::~uMain
[9d47c1f]605                Pthread_kernel_threads * p = &try_pop_front(cfa_pthreads_kernel_threads);
606                for ( ; p; ) {
607            delete(p);
608                        p = &try_pop_front(cfa_pthreads_kernel_threads);
[9cd5bd2]609                } // for
610        } // pthread_delete_kernel_threads_
611
[8bd886e]612        int pthread_getconcurrency( void ) __THROW {    // XOPEN extension
[9cd5bd2]613                return cfa_pthreads_kernel_threads_zero ? 0 : cfa_pthreads_no_kernel_threads;
614        } // pthread_getconcurrency
615
616        int pthread_setconcurrency( int new_level ) libcfa_public __THROW { // XOPEN extension
[8bd886e]617                if ( new_level < 0 ) return EINVAL;
618                if ( new_level == 0 ) {
619                        cfa_pthreads_kernel_threads_zero = true;        // remember set to zero, but ignore
620                        return 0;                                       // do not do kernel thread management
621                } // exit
622                cfa_pthreads_kernel_threads_zero = false;
623                lock( concurrency_lock );
624                for ( ; new_level > cfa_pthreads_no_kernel_threads; cfa_pthreads_no_kernel_threads += 1 ) { // add processors ?
[9d47c1f]625                        insert_last(cfa_pthreads_kernel_threads, *new() );
[8bd886e]626                } // for
627                for ( ; new_level < cfa_pthreads_no_kernel_threads; cfa_pthreads_no_kernel_threads -= 1 ) { // remove processors ?
[9d47c1f]628                        delete(&try_pop_front(cfa_pthreads_kernel_threads));
[8bd886e]629                } // for
630                unlock( concurrency_lock );
631                return 0;
[9cd5bd2]632        } // pthread_setconcurrency
633
634        //######################### Signal #########################
635
636
637         int pthread_sigmask( int /* how */, const sigset_t * /* set */, sigset_t * /* oset */ ) libcfa_public __THROW {
[8bd886e]638                abort( "pthread_sigmask : not implemented" );
639                return 0;
[9cd5bd2]640         } // pthread_sigmask
641
642        int pthread_kill( pthread_t _thread __attribute__(( unused )), int sig ) libcfa_public __THROW {
643                if ( sig == 0 ) {
644                        return 0;
645                } else {
646                        abort( "pthread_kill : not implemented" );
647                } // if
648                return 0;
649        } // pthread_kill
650
651        int pthread_sigqueue(pthread_t , int sig, const union sigval) libcfa_public __THROW {
[8bd886e]652                abort( "pthread_sigqueue : not implemented" );
[9cd5bd2]653                return 0;
654        } // pthread_sigqueue
655
656        //######################### Scheduling #########################
657        int pthread_detach( pthread_t threadID ) __THROW {
[8bd886e]658                abort( "pthread_detach : not implemented" );
[9cd5bd2]659                return 0;
660        } // pthread_detach
661
662        int pthread_setschedparam( pthread_t /* thread */, int /* policy */, const struct sched_param * /* param */ ) libcfa_public __THROW {
663                abort( "pthread_setschedparam : not implemented" );
664                return 0;
665        } // pthread_setschedparam
666
667        int pthread_getschedparam( pthread_t /* thread */, int */* policy */, struct sched_param * /* param */ ) libcfa_public __THROW {
668                abort( "pthread_getschedparam : not implemented" );
669                return 0;
670        } // pthread_getschedparam
671
672         //######################### Mutex Attr #########################
673
674        int pthread_mutexattr_init( pthread_mutexattr_t * /* attr */ ) libcfa_public __THROW {
675                return 0;
676        } // pthread_mutexattr_init
677
678        int pthread_mutexattr_destroy( pthread_mutexattr_t * /* attr */ ) libcfa_public __THROW {
[8bd886e]679                return 0;
[9cd5bd2]680        } // pthread_mutexattr_destroy
[a7d696f]681
[9cd5bd2]682        int pthread_mutexattr_setpshared( pthread_mutexattr_t * /* attr */, int /* pshared */ ) libcfa_public __THROW {
[8bd886e]683                return 0;
[9cd5bd2]684        } // pthread_mutexattr_setpshared
[a7d696f]685
[9cd5bd2]686        int pthread_mutexattr_getpshared( const pthread_mutexattr_t * /* attr */, int * /* pshared */ ) libcfa_public __THROW {
[8bd886e]687                return 0;
[9cd5bd2]688        } // pthread_mutexattr_getpshared
[a7d696f]689
[9cd5bd2]690        int pthread_mutexattr_setprotocol( pthread_mutexattr_t * /* attr */, int /* protocol */ ) libcfa_public __THROW {
[8bd886e]691                return 0;
[9cd5bd2]692        } // pthread_mutexattr_setprotocol
[a7d696f]693
[9cd5bd2]694        int pthread_mutexattr_getprotocol( const pthread_mutexattr_t * /* attr */, int * /* protocol */ ) libcfa_public __THROW {
[8bd886e]695                return 0;
[9cd5bd2]696        } // pthread_mutexattr_getprotocol
[a7d696f]697
[9cd5bd2]698        int pthread_mutexattr_setprioceiling( pthread_mutexattr_t * /* attr */, int /* prioceiling */ ) libcfa_public __THROW {
[8bd886e]699                return 0;
[9cd5bd2]700        } // pthread_mutexattr_setprioceiling
[a7d696f]701
[9cd5bd2]702        int pthread_mutexattr_getprioceiling( const pthread_mutexattr_t * /* attr */, int * /* ceiling */ ) libcfa_public __THROW {
[8bd886e]703                return 0;
[9cd5bd2]704        } // pthread_mutexattr_getprioceiling
[a7d696f]705
[9cd5bd2]706        int pthread_mutex_setprioceiling( pthread_mutex_t * /* mutex */, int /* prioceiling */, int * /* old_ceiling */ ) libcfa_public __THROW {
[8bd886e]707                return 0;
[9cd5bd2]708        } // pthread_mutex_setprioceiling
[a7d696f]709
[9cd5bd2]710        int pthread_mutex_getprioceiling( const pthread_mutex_t * /* mutex */, int * /* ceiling */ ) libcfa_public __THROW {
[8bd886e]711                return 0;
[9cd5bd2]712        } // pthread_mutex_getprioceiling
[a7d696f]713
[9cd5bd2]714        int pthread_mutexattr_gettype( __const pthread_mutexattr_t * __restrict /* __attr */, int * __restrict /* __kind */ ) libcfa_public __THROW {
[8bd886e]715                return 0;
[9cd5bd2]716        } // pthread_mutexattr_gettype
[a7d696f]717
[9cd5bd2]718        int pthread_mutexattr_settype( pthread_mutexattr_t * /* __attr */, int /* __kind */ ) libcfa_public __THROW {
[8bd886e]719                return 0;
[9cd5bd2]720        } // pthread_mutexattr_settype
[a7d696f]721
[9cd5bd2]722        //######################### Mutex #########################
[a7d696f]723
[9cd5bd2]724        int pthread_mutex_timedlock( pthread_mutex_t *__restrict /* __mutex */, __const struct timespec *__restrict /* __abstime */ ) libcfa_public __THROW {
725                abort( "pthread_mutex_timedlock" );
726        } // pthread_mutex_timedlock
[a7d696f]727
[9cd5bd2]728        //######################### Condition #########################
[a7d696f]729
[9cd5bd2]730        int pthread_condattr_getclock( __const pthread_condattr_t * __restrict /* __attr */, __clockid_t *__restrict /* __clock_id */ ) libcfa_public __THROW {
731                abort( "pthread_condattr_getclock" );
732        } // pthread_condattr_getclock
[a7d696f]733
[9cd5bd2]734        int pthread_condattr_setclock( pthread_condattr_t * /* __attr */, __clockid_t /* __clock_id */ ) libcfa_public __THROW {
735                abort( "pthread_condattr_setclock" );
736        } // pthread_condattr_setclock
[a7d696f]737
[9cd5bd2]738        //######################### Spinlock #########################
[a7d696f]739
[9cd5bd2]740        int pthread_spin_init( pthread_spinlock_t * /* __lock */, int /*__pshared */ ) libcfa_public __THROW {
741                abort( "pthread_spin_init" );
742        } // pthread_spin_init
[a7d696f]743
[9cd5bd2]744        int pthread_spin_destroy( pthread_spinlock_t * /* __lock */ ) libcfa_public __THROW {
745                abort( "pthread_spin_destroy" );
746        } // pthread_spin_destroy
[a7d696f]747
[9cd5bd2]748        int pthread_spin_lock( pthread_spinlock_t * /* __lock */ ) libcfa_public __THROW {
749                abort( "pthread_spin_lock" );
750        } // pthread_spin_lock
[a7d696f]751
[9cd5bd2]752        int pthread_spin_trylock( pthread_spinlock_t * /* __lock */ ) libcfa_public __THROW {
753                abort( "pthread_spin_trylock" );
754        } // pthread_spin_trylock
[a7d696f]755
[9cd5bd2]756        int pthread_spin_unlock( pthread_spinlock_t * /* __lock */ ) libcfa_public __THROW {
757                abort( "pthread_spin_unlock" );
758        } // pthread_spin_unlock
[a7d696f]759
[9cd5bd2]760        //######################### Barrier #########################
[a7d696f]761
[9cd5bd2]762        int pthread_barrier_init( pthread_barrier_t *__restrict /* __barrier */, __const pthread_barrierattr_t *__restrict /* __attr */, unsigned int /* __count */ ) libcfa_public __THROW {
763                abort( "pthread_barrier_init" );
764        } // pthread_barrier_init
[a7d696f]765
[9cd5bd2]766        int pthread_barrier_destroy( pthread_barrier_t * /* __barrier */ ) libcfa_public  __THROW {
767                abort( "pthread_barrier_destroy" );
768        } // pthread_barrier_destroy
[a7d696f]769
[9cd5bd2]770        int pthread_barrier_wait( pthread_barrier_t * /* __barrier */ ) libcfa_public __THROW {
771                abort( "pthread_barrier_wait" );
772        } // pthread_barrier_wait
[a7d696f]773
[9cd5bd2]774        int pthread_barrierattr_init( pthread_barrierattr_t * /* __attr */ ) libcfa_public __THROW {
775                abort( "pthread_barrierattr_init" );
776        } // pthread_barrierattr_init
[a7d696f]777
[9cd5bd2]778        int pthread_barrierattr_destroy( pthread_barrierattr_t * /* __attr */ ) libcfa_public __THROW {
779                abort( "pthread_barrierattr_destroy" );
780        } // pthread_barrierattr_destroy
[a7d696f]781
[9cd5bd2]782        int pthread_barrierattr_getpshared( __const pthread_barrierattr_t * __restrict /* __attr */, int *__restrict /* __pshared */ ) libcfa_public __THROW {
783                abort( "pthread_barrierattr_getpshared" );
784        } // pthread_barrierattr_getpshared
[a7d696f]785
[9cd5bd2]786        int pthread_barrierattr_setpshared( pthread_barrierattr_t * /* __attr */, int /* __pshared */ ) libcfa_public __THROW {
787                abort( "pthread_barrierattr_setpshared" );
788        } // pthread_barrierattr_setpshared
[a7d696f]789
[9cd5bd2]790        //######################### Clock #########################
[a7d696f]791
[9cd5bd2]792        int pthread_getcpuclockid( pthread_t /* __thread_id */, __clockid_t * /* __clock_id */ ) libcfa_public __THROW {
793                abort( "pthread_getcpuclockid" );
794        } // pthread_getcpuclockid
[a7d696f]795
[9cd5bd2]796        // pthread_atfork()
[a7d696f]797
798// UNIX98
799
[9cd5bd2]800        //######################### Read/Write #########################
[a7d696f]801
[9cd5bd2]802        int pthread_rwlock_init( pthread_rwlock_t *__restrict /* __rwlock */, __const pthread_rwlockattr_t *__restrict /* __attr */ ) libcfa_public __THROW {
803                abort( "pthread_rwlock_init" );
804        } // pthread_rwlock_init
[a7d696f]805
[9cd5bd2]806        int pthread_rwlock_destroy( pthread_rwlock_t * /* __rwlock */ ) libcfa_public __THROW {
807                abort( "pthread_rwlock_destroy" );
808        } // pthread_rwlock_destroy
[a7d696f]809
[9cd5bd2]810        int pthread_rwlock_rdlock( pthread_rwlock_t * /* __rwlock */ ) libcfa_public __THROW {
811                abort( "pthread_rwlock_rdlock" );
812        } // pthread_rwlock_rdlock
[a7d696f]813
[9cd5bd2]814        int pthread_rwlock_tryrdlock( pthread_rwlock_t * /* __rwlock */ ) libcfa_public __THROW {
815                abort( "pthread_rwlock_tryrdlock" );
816        } // pthread_rwlock_tryrdlock
[a7d696f]817
[9cd5bd2]818        int pthread_rwlock_wrlock( pthread_rwlock_t * /* __rwlock */ ) libcfa_public __THROW {
819                abort( "pthread_rwlock_wrlock" );
820        } // pthread_rwlock_wrlock
[a7d696f]821
[9cd5bd2]822        int pthread_rwlock_trywrlock( pthread_rwlock_t * /* __rwlock */ ) libcfa_public __THROW {
823                abort( "pthread_rwlock_trywrlock" );
824        } // pthread_rwlock_trywrlock
[a7d696f]825
[9cd5bd2]826        int pthread_rwlock_unlock( pthread_rwlock_t * /* __rwlock */ ) libcfa_public __THROW {
827                abort( "pthread_rwlock_unlock" );
828        } // pthread_rwlock_unlock
[a7d696f]829
[9cd5bd2]830        int pthread_rwlockattr_init( pthread_rwlockattr_t * /* __attr */ ) libcfa_public __THROW {
831                abort( "pthread_rwlockattr_init" );
832        } // pthread_rwlockattr_init
[a7d696f]833
[9cd5bd2]834        int pthread_rwlockattr_destroy( pthread_rwlockattr_t * /*__attr */ ) libcfa_public __THROW {
835                abort( "pthread_rwlockattr_destroy" );
836        } // pthread_rwlockattr_destroy
[a7d696f]837
[9cd5bd2]838        int pthread_rwlockattr_getpshared( __const pthread_rwlockattr_t * __restrict /* __attr */, int *__restrict /* __pshared */ ) libcfa_public __THROW {
839                abort( "pthread_rwlockattr_getpshared" );
840        } // pthread_rwlockattr_getpshared
[a7d696f]841
[9cd5bd2]842        int pthread_rwlockattr_setpshared( pthread_rwlockattr_t * /* __attr */, int /* __pshared */ ) libcfa_public __THROW {
843                abort( "pthread_rwlockattr_setpshared" );
844        } // pthread_rwlockattr_setpshared
[a7d696f]845
[9cd5bd2]846        int pthread_rwlockattr_getkind_np( __const pthread_rwlockattr_t * /* __attr */, int * /* __pref */ ) libcfa_public __THROW {
847                abort( "pthread_rwlockattr_getkind_np" );
848        } // pthread_rwlockattr_getkind_np
[a7d696f]849
[9cd5bd2]850        int pthread_rwlockattr_setkind_np( pthread_rwlockattr_t * /* __attr */, int /* __pref */ ) libcfa_public __THROW {
851                abort( "pthread_rwlockattr_setkind_np" );
852        } // pthread_rwlockattr_setkind_np
[a7d696f]853
854// UNIX98 + XOPEN
855
[9cd5bd2]856        int pthread_rwlock_timedrdlock( pthread_rwlock_t *__restrict  /* __rwlock */, __const struct timespec *__restrict /* __abstime */ ) libcfa_public __THROW {
857                abort( "pthread_rwlock_timedrdlock" );
858        } // pthread_rwlock_timedrdlock
[a7d696f]859
[9cd5bd2]860        int pthread_rwlock_timedwrlock( pthread_rwlock_t *__restrict  /* __rwlock */, __const struct timespec *__restrict /* __abstime */ ) libcfa_public __THROW {
861                abort( "pthread_rwlock_timedwrlock" );
862        } // pthread_rwlock_timedwrlock
[a7d696f]863
864// GNU
865
[9cd5bd2]866        //######################### Parallelism #########################
[a7d696f]867
[f5f2768]868        // int pthread_setaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
869        //      abort( "pthread_setaffinity_np" );
870        // } // pthread_setaffinity_np
[a7d696f]871
[f5f2768]872        // int pthread_getaffinity_np( pthread_t /* __th */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
873        //      abort( "pthread_getaffinity_np" );
874        // } // pthread_getaffinity_np
[a7d696f]875
[f5f2768]876        // int pthread_attr_setaffinity_np( pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, __const cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
877        //      abort( "pthread_attr_setaffinity_np" );
878        // } // pthread_attr_setaffinity_np
[a7d696f]879
[f5f2768]880        // int pthread_attr_getaffinity_np( __const pthread_attr_t * /* __attr */, size_t /* __cpusetsize */, cpu_set_t * /* __cpuset */ ) libcfa_public __THROW {
881        //      abort( "pthread_attr_getaffinity_np" );
882        // } // pthread_attr_getaffinity_np
[a7d696f]883
[9cd5bd2]884        //######################### Cancellation #########################
[a7d696f]885
[9cd5bd2]886        void _pthread_cleanup_push_defer( struct _pthread_cleanup_buffer * /* __buffer */, void( * /* __routine */ )( void * ), void * /* __arg */ ) libcfa_public __THROW {
887                abort( "_pthread_cleanup_push_defer" );
888        } // _pthread_cleanup_push_defer
[a7d696f]889
[9cd5bd2]890        void _pthread_cleanup_pop_restore( struct _pthread_cleanup_buffer * /* __buffer */, int /* __execute */ ) libcfa_public __THROW {
891                abort( "_pthread_cleanup_pop_restore" );
892        } // _pthread_cleanup_pop_res
[a7d696f]893
[9cd5bd2]894        int pthread_cancel( pthread_t threadID ) libcfa_public __THROW {
895                abort("pthread cancel not implemented");
896                return 0;
897        } // pthread_cancel
[a7d696f]898
[3494ca9]899        int pthread_setcancelstate( int state, int * oldstate ) libcfa_public __THROW {
[9cd5bd2]900                abort("pthread_setcancelstate not implemented");
901                return 0;
902        } // pthread_setcancelstate
[a7d696f]903
[3494ca9]904        int pthread_setcanceltype( int type, int * oldtype ) libcfa_public __THROW {
[9cd5bd2]905                abort("pthread_setcanceltype not implemented");
906                return 0;
907        } // pthread_setcanceltype
[20be782]908} // extern "C"
909
[a7d696f]910#pragma GCC diagnostic pop
Note: See TracBrowser for help on using the repository browser.