diff options
Diffstat (limited to 'winsup/cygwin/thread.cc')
-rw-r--r-- | winsup/cygwin/thread.cc | 1543 |
1 files changed, 961 insertions, 582 deletions
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 8b6f1b6d6..84add47c5 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -1,9 +1,9 @@ -/*thread.cc: Locking and threading module functions +/* thread.cc: Locking and threading module functions - Copyright 1998, 1999, 2000, 2001 Red Hat, Inc. + Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. Originally written by Marco Fuykschot <marco@ddi.nl> - Substantialy enhanced by Robert Collins <<rbtcollins@hotmail.com> + Substantialy enhanced by Robert Collins <rbtcollins@hotmail.com> This file is part of Cygwin. @@ -37,8 +37,6 @@ details. */ #include <assert.h> #include <stdlib.h> #include <syslog.h> -#include "sync.h" -#include "sigproc.h" #include "pinfo.h" #include "perprocess.h" #include "security.h" @@ -48,92 +46,6 @@ details. */ extern int threadsafe; -/*pthread_key_destructor_list class: to-be threadsafe single linked list - *FIXME: Put me in a dedicated file, or a least a tools area ! - */ - -pthread_key_destructor * -pthread_key_destructor::InsertAfter (pthread_key_destructor *node) -{ - pthread_key_destructor *temp = next; - next = node; - return temp; -} - -pthread_key_destructor * -pthread_key_destructor::UnlinkNext () -{ - pthread_key_destructor *temp = next; - if (next) - next = next->Next (); - return temp; -} - -pthread_key_destructor * -pthread_key_destructor::Next () -{ - return next; -} - -void -pthread_key_destructor_list::Insert (pthread_key_destructor *node) -{ - if (!node) - return; - head = node->InsertAfter (head); - if (!head) - head = node; /*first node special case */ -} - - /*remove a given dataitem, wherever in the list it is */ -pthread_key_destructor * -pthread_key_destructor_list::Remove (pthread_key *key) -{ - if (!key) - return NULL; - if (!head) - return NULL; - if (key == head->key) - return Pop (); - pthread_key_destructor *temp = head; - while (temp && temp->Next () && !(key == temp->Next ()->key)) - { - temp = temp->Next (); - } - if (temp) - return temp->UnlinkNext (); - return NULL; -} - - /*get the first item and remove at the same time */ -pthread_key_destructor * -pthread_key_destructor_list::Pop () -{ - pthread_key_destructor *temp = head; - head = head->Next (); - return temp; -} - -pthread_key_destructor:: -pthread_key_destructor (void (*thedestructor) (void *), pthread_key *key) -{ - destructor = thedestructor; - next = NULL; - this->key = key; -} - -void -pthread_key_destructor_list::IterateNull () -{ - pthread_key_destructor *temp = head; - while (temp) - { - temp->destructor ((temp->key)->get ()); - temp = temp->Next (); - } -} - - #define MT_INTERFACE user_data->threadinterface struct _reent * @@ -254,51 +166,30 @@ ResourceLocks::Delete () void MTinterface::Init (int forked) { -#if 0 - for (int i = 0; i < MT_MAX_ITEMS; i++) - { - threadlist.items[i] = NULL; - mutexlist.items[i] = NULL; - semalist.items[i] = NULL; - } - - threadlist.index = 0; - mutexlist.index = 0; - semalist.index = 0; -#endif reent_index = TlsAlloc (); reents._clib = _impure_ptr; reents._winsup = &winsup_reent; winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG); -#if 0 - winsup_reent._grp_pos = 0; - winsup_reent._process_ident = 0; - winsup_reent._process_logopt = 0; - winsup_reent._process_facility = 0; -#endif TlsSetValue (reent_index, &reents); // the static reent_data will be used in the main thread - if (!indexallocated) { - indexallocated = (-1); thread_self_dwTlsIndex = TlsAlloc (); if (thread_self_dwTlsIndex == TLS_OUT_OF_INDEXES) system_printf - ("local storage for thread couldn't be set\nThis means that we are not thread safe!\n"); + ("local storage for thread couldn't be set\nThis means that we are not thread safe!"); + else + indexallocated = (-1); } concurrency = 0; threadcount = 1; /*1 current thread when Init occurs.*/ - mainthread.win32_obj_id = myself->hProcess; - mainthread.setThreadIdtoCurrent (); - /*store the main thread's self pointer */ - TlsSetValue (thread_self_dwTlsIndex, &mainthread); + pthread::initMainThread (&mainthread, myself->hProcess); if (forked) return; @@ -307,37 +198,35 @@ MTinterface::Init (int forked) conds = NULL; semaphores = NULL; - /*possible the atfork lists should be inited here as well */ - -#if 0 - item->function = NULL; +} - item->sigs = NULL; - item->sigmask = NULL; - item->sigtodo = NULL; -#endif +void +MTinterface::fixup_before_fork (void) +{ + pthread_key::fixup_before_fork (); } /* This function is called from a single threaded process */ void MTinterface::fixup_after_fork (void) { + pthread_key::fixup_after_fork (); pthread_mutex *mutex = mutexs; - debug_printf("mutexs is %x\n",mutexs); + debug_printf ("mutexs is %x",mutexs); while (mutex) { mutex->fixup_after_fork (); mutex = mutex->next; } pthread_cond *cond = conds; - debug_printf("conds is %x\n",conds); + debug_printf ("conds is %x",conds); while (cond) { cond->fixup_after_fork (); cond = cond->next; } semaphore *sem = semaphores; - debug_printf("semaphores is %x\n",semaphores); + debug_printf ("semaphores is %x",semaphores); while (sem) { sem->fixup_after_fork (); @@ -345,8 +234,46 @@ MTinterface::fixup_after_fork (void) } } +/* pthread calls */ + +/* static methods */ +void +pthread::initMainThread (pthread *mainThread, HANDLE win32_obj_id) +{ + mainThread->win32_obj_id = win32_obj_id; + mainThread->setThreadIdtoCurrent (); + setTlsSelfPointer (mainThread); +} + +pthread * +pthread::self () +{ + pthread *temp = (pthread *) TlsGetValue (MT_INTERFACE->thread_self_dwTlsIndex); + if (temp) + return temp; + temp = new pthread (); + temp->precreate (NULL); + if (!temp->magic) { + delete temp; + return pthreadNull::getNullpthread (); + } + temp->postcreate (); + return temp; +} + +void +pthread::setTlsSelfPointer (pthread *thisThread) +{ + /*the OS doesn't check this for <= 64 Tls entries (pre win2k) */ + TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thisThread); +} + + + +/* member methods */ pthread::pthread ():verifyable_object (PTHREAD_MAGIC), win32_obj_id (0), -cancelstate (0), canceltype (0) + cancelstate (0), canceltype (0), cancel_event (0), + joiner (NULL), cleanup_stack (NULL) { } @@ -354,13 +281,21 @@ pthread::~pthread () { if (win32_obj_id) CloseHandle (win32_obj_id); + if (cancel_event) + CloseHandle (cancel_event); } +void +pthread::setThreadIdtoCurrent () +{ + thread_id = GetCurrentThreadId (); +} void -pthread::create (void *(*func) (void *), pthread_attr *newattr, - void *threadarg) +pthread::precreate (pthread_attr *newattr) { + pthread_mutex *verifyable_mutex_obj = &mutex; + /*already running ? */ if (win32_obj_id) return; @@ -372,27 +307,424 @@ pthread::create (void *(*func) (void *), pthread_attr *newattr, attr.inheritsched = newattr->inheritsched; attr.stacksize = newattr->stacksize; } - function = func; - arg = threadarg; - win32_obj_id =::CreateThread (&sec_none_nih, attr.stacksize, + if (!pthread_mutex::isGoodObject (&verifyable_mutex_obj)) + { + thread_printf ("New thread object access mutex is not valid. this %p", + this); + magic = 0; + return; + } + + cancel_event = ::CreateEvent (NULL,TRUE,FALSE,NULL); + if (!cancel_event) + { + system_printf ("couldn't create cancel event, this %p LastError %d", this, GetLastError () ); + /*we need the event for correct behaviour */ + magic = 0; + return; + } +} + +void +pthread::create (void *(*func) (void *), pthread_attr *newattr, + void *threadarg) +{ + precreate (newattr); + if (!magic) + return; + function = func; + arg = threadarg; + + win32_obj_id = ::CreateThread (&sec_none_nih, attr.stacksize, (LPTHREAD_START_ROUTINE) thread_init_wrapper, this, CREATE_SUSPENDED, &thread_id); if (!win32_obj_id) - magic = 0; - else { - /*FIXME: set the priority appropriately for system contention scope */ - if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) - { - /*FIXME: set the scheduling settings for the new thread */ - /*sched_thread_setparam (win32_obj_id, attr.schedparam); */ - } + thread_printf ("CreateThread failed: this %p LastError %E", this); + magic = 0; + } + else { + postcreate (); ResumeThread (win32_obj_id); + } +} + +void +pthread::postcreate () +{ + InterlockedIncrement (&MT_INTERFACE->threadcount); + /*FIXME: set the priority appropriately for system contention scope */ + if (attr.inheritsched == PTHREAD_EXPLICIT_SCHED) + { + /*FIXME: set the scheduling settings for the new thread */ + /*sched_thread_setparam (win32_obj_id, attr.schedparam); */ + } +} + +void +pthread::exit (void *value_ptr) +{ + class pthread *thread = this; + + // run cleanup handlers + pop_all_cleanup_handlers (); + + pthread_key::runAllDestructors (); + + mutex.Lock (); + // cleanup if thread is in detached state and not joined + if (__pthread_equal (&joiner, &thread ) ) + delete this; + else + { + return_ptr = value_ptr; + mutex.UnLock (); + } + + /* Prevent DLL_THREAD_DETACH Attempting to clean us up */ + setTlsSelfPointer (0); + + if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0) + ::exit (0); + else + ExitThread (0); +} + +int +pthread::cancel (void) +{ + class pthread *thread = this; + class pthread *self = pthread::self (); + + mutex.Lock (); + + if (canceltype == PTHREAD_CANCEL_DEFERRED || + cancelstate == PTHREAD_CANCEL_DISABLE) + { + // cancel deferred + mutex.UnLock (); + SetEvent (cancel_event); + return 0; + } + + else if (__pthread_equal (&thread, &self)) + { + mutex.UnLock (); + cancel_self (); + return 0; // Never reached + } + + // cancel asynchronous + SuspendThread (win32_obj_id); + if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT) + { + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL; + GetThreadContext (win32_obj_id, &context); + context.Eip = (DWORD) pthread::static_cancel_self; + SetThreadContext (win32_obj_id, &context); + } + mutex.UnLock (); + ResumeThread (win32_obj_id); + + return 0; +/* + TODO: insert pthread_testcancel into the required functions + the required function list is: *indicates done, X indicates not present in cygwin. +aio_suspend () +*close () +*creat () +fcntl () +fsync () +getmsg () +getpmsg () +lockf () +mq_receive () +mq_send () +msgrcv () +msgsnd () +msync () +nanosleep () +open () +pause () +poll () +pread () +pthread_cond_timedwait () +pthread_cond_wait () +*pthread_join () +pthread_testcancel () +putmsg () +putpmsg () +pwrite () +read () +readv () +select () +sem_wait () +sigpause () +sigsuspend () +sigtimedwait () +sigwait () +sigwaitinfo () +*sleep () +system () +tcdrain () +*usleep () +wait () +wait3() +waitid () +waitpid () +write () +writev () + +the optional list is: +catclose () +catgets () +catopen () +closedir () +closelog () +ctermid () +dbm_close () +dbm_delete () +dbm_fetch () +dbm_nextkey () +dbm_open () +dbm_store () +dlclose () +dlopen () +endgrent () +endpwent () +endutxent () +fclose () +fcntl () +fflush () +fgetc () +fgetpos () +fgets () +fgetwc () +fgetws () +fopen () +fprintf () +fputc () +fputs () +fputwc () +fputws () +fread () +freopen () +fscanf () +fseek () +fseeko () +fsetpos () +ftell () +ftello () +ftw () +fwprintf () +fwrite () +fwscanf () +getc () +getc_unlocked () +getchar () +getchar_unlocked () +getcwd () +getdate () +getgrent () +getgrgid () +getgrgid_r () +getgrnam () +getgrnam_r () +getlogin () +getlogin_r () +getpwent () +*getpwnam () +*getpwnam_r () +*getpwuid () +*getpwuid_r () +gets () +getutxent () +getutxid () +getutxline () +getw () +getwc () +getwchar () +getwd () +glob () +iconv_close () +iconv_open () +ioctl () +lseek () +mkstemp () +nftw () +opendir () +openlog () +pclose () +perror () +popen () +printf () +putc () +putc_unlocked () +putchar () +putchar_unlocked () +puts () +pututxline () +putw () +putwc () +putwchar () +readdir () +readdir_r () +remove () +rename () +rewind () +rewinddir () +scanf () +seekdir () +semop () +setgrent () +setpwent () +setutxent () +strerror () +syslog () +tmpfile () +tmpnam () +ttyname () +ttyname_r () +ungetc () +ungetwc () +unlink () +vfprintf () +vfwprintf () +vprintf () +vwprintf () +wprintf () +wscanf () + +Note, that for fcntl (), for any value of the cmd argument. + +And we must not introduce cancellation points anywhere else that's part of the posix or +opengroup specs. + */ +} + +void +pthread::testcancel (void) +{ + if (cancelstate == PTHREAD_CANCEL_DISABLE) + return; + + if (WAIT_OBJECT_0 == WaitForSingleObject (cancel_event, 0 ) ) + cancel_self (); +} + +void +pthread::static_cancel_self (void) +{ + pthread::self ()->cancel_self (); +} + + +int +pthread::setcancelstate (int state, int *oldstate) +{ + int result = 0; + + mutex.Lock (); + + if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) + result = EINVAL; + else + { + if (oldstate) + *oldstate = cancelstate; + cancelstate = state; + } + + mutex.UnLock (); + + return result; +} + +int +pthread::setcanceltype (int type, int *oldtype) +{ + int result = 0; + + mutex.Lock (); + + if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) + result = EINVAL; + else + { + if (oldtype) + *oldtype = canceltype; + canceltype = type; + } + + mutex.UnLock (); + + return result; +} + +void +pthread::push_cleanup_handler (__pthread_cleanup_handler *handler) +{ + if (this != self ()) + // TODO: do it? + api_fatal ("Attempt to push a cleanup handler across threads"); + handler->next = cleanup_stack; + InterlockedExchangePointer (&cleanup_stack, handler ); +} + +void +pthread::pop_cleanup_handler (int const execute) +{ + if (this != self ()) + // TODO: send a signal or something to the thread ? + api_fatal ("Attempt to execute a cleanup handler across threads"); + + mutex.Lock (); + + if (cleanup_stack != NULL) + { + __pthread_cleanup_handler *handler = cleanup_stack; + + if (execute) + (*handler->function) (handler->arg); + cleanup_stack = handler->next; } + + mutex.UnLock (); } +void +pthread::pop_all_cleanup_handlers () +{ + while (cleanup_stack != NULL) + pop_cleanup_handler (1); +} + +void +pthread::cancel_self () +{ + exit (PTHREAD_CANCELED); +} + +DWORD +pthread::getThreadId () +{ + return thread_id; +} + +/* static members */ +bool +pthread_attr::isGoodObject (pthread_attr_t const *attr) +{ + if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +/* instance members */ + pthread_attr::pthread_attr ():verifyable_object (PTHREAD_ATTR_MAGIC), joinable (PTHREAD_CREATE_JOINABLE), contentionscope (PTHREAD_SCOPE_PROCESS), inheritsched (PTHREAD_INHERIT_SCHED), stacksize (0) @@ -404,6 +736,14 @@ pthread_attr::~pthread_attr () { } +bool +pthread_condattr::isGoodObject (pthread_condattr_t const *attr) +{ + if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + return false; + return true; +} + pthread_condattr::pthread_condattr ():verifyable_object (PTHREAD_CONDATTR_MAGIC), shared (PTHREAD_PROCESS_PRIVATE) { @@ -420,14 +760,14 @@ pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_C this->mutex = NULL; this->waiting = 0; - this->win32_obj_id =::CreateEvent (&sec_none_nih, false, /*auto signal reset - which I think is pthreads like ? */ + this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, /*auto signal reset - which I think is pthreads like ? */ false, /*start non signaled */ NULL /*no name */); /*TODO: make a shared mem mutex if out attributes request shared mem cond */ - cond_access=NULL; + cond_access = NULL; if ((temperr = pthread_mutex_init (&this->cond_access, NULL))) { - system_printf ("couldn't init mutex, this %0p errno=%d\n", this, temperr); + system_printf ("couldn't init mutex, this %p errno %d", this, temperr); /*we need the mutex for correct behaviour */ magic = 0; } @@ -435,7 +775,7 @@ pthread_cond::pthread_cond (pthread_condattr *attr):verifyable_object (PTHREAD_C if (!this->win32_obj_id) magic = 0; /* threadsafe addition is easy */ - next = (pthread_cond *)InterlockedExchangePointer (&MT_INTERFACE->conds, this); + next = (pthread_cond *) InterlockedExchangePointer (&MT_INTERFACE->conds, this); } pthread_cond::~pthread_cond () @@ -461,33 +801,33 @@ pthread_cond::BroadCast () { /* TODO: implement the same race fix as Signal has */ if (pthread_mutex_lock (&cond_access)) - system_printf ("Failed to lock condition variable access mutex, this %0p\n", this); + system_printf ("Failed to lock condition variable access mutex, this %p", this); int count = waiting; - if (verifyable_object_isvalid (&mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (&mutex)) { if (pthread_mutex_unlock (&cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); + system_printf ("Failed to unlock condition variable access mutex, this %p", this); /*This isn't and API error - users are allowed to call this when no threads are waiting - system_printf ("Broadcast called with invalid mutex\n"); + system_printf ("Broadcast called with invalid mutex"); */ return; } while (count--) PulseEvent (win32_obj_id); if (pthread_mutex_unlock (&cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); + system_printf ("Failed to unlock condition variable access mutex, this %p", this); } void pthread_cond::Signal () { if (pthread_mutex_lock (&cond_access)) - system_printf ("Failed to lock condition variable access mutex, this %0p\n", this); - if (verifyable_object_isvalid (&mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + system_printf ("Failed to lock condition variable access mutex, this %p", this); + if (!pthread_mutex::isGoodObject (&mutex)) { if (pthread_mutex_unlock (&cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", + system_printf ("Failed to unlock condition variable access mutex, this %p", this); return; } @@ -496,29 +836,42 @@ pthread_cond::Signal () /* nothing to signal */ { if (pthread_mutex_unlock (&cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); + system_printf ("Failed to unlock condition variable access mutex, this %p", this); return; } + /* Prime the detection flag */ + ExitingWait = 1; + /* Signal any waiting thread */ PulseEvent (win32_obj_id); /* No one can start waiting until we release the condition access mutex */ /* The released thread will decrement waiting when it gets a time slice... without waiting for the access mutex + * InterLockedIncrement on 98 +, NT4 + returns the incremented value. + * On 95, nt 3.51 < it returns a sign correct number - 0=0, + for greater than 0, - + * for less than 0. + * Because of this we cannot spin on the waiting count, but rather we need a + * dedicated flag for a thread exiting the Wait function. + * Also not that Interlocked* sync CPU caches with memory. */ int spins = 10; - while (InterlockedIncrement (&waiting) != (temp - 1) && spins) + /* When ExitingWait is nonzero after a decrement, the leaving thread has + * done it's thing + */ + while (InterlockedDecrement (&ExitingWait) == 0 && spins) { - InterlockedDecrement (&waiting); + InterlockedIncrement (&ExitingWait); /* give up the cpu to force a context switch. */ Sleep (0); if (spins == 5) - /* we've had 5 timeslices, and the woekn thread still hasn't done it's + /* we've had 5 timeslices, and the woken thread still hasn't done it's * thing - maybe we raced it with the event? */ PulseEvent (win32_obj_id); spins--; } - InterlockedDecrement (&waiting); + if (waiting + 1 != temp) + system_printf ("Released too many threads - %d now %d originally", waiting, temp); if (pthread_mutex_unlock (&cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", this); + system_printf ("Failed to unlock condition variable access mutex, this %p", this); } int @@ -563,40 +916,90 @@ pthread_cond::TimedWait (DWORD dwMilliseconds) void pthread_cond::fixup_after_fork () { - debug_printf("cond %x in fixup_after_fork\n", this); + debug_printf ("cond %x in fixup_after_fork", this); if (shared != PTHREAD_PROCESS_PRIVATE) - api_fatal("doesn't understand PROCESS_SHARED condition variables\n"); + api_fatal ("doesn't understand PROCESS_SHARED condition variables"); /* FIXME: duplicate code here and in the constructor. */ - this->win32_obj_id =::CreateEvent (&sec_none_nih, false, false, NULL); + this->win32_obj_id = ::CreateEvent (&sec_none_nih, false, false, NULL); if (!win32_obj_id) - api_fatal("failed to create new win32 mutex\n"); + api_fatal ("failed to create new win32 mutex"); #if DETECT_BAD_APPS if (waiting) - api_fatal("Forked() while a condition variable has waiting threads.\nReport to cygwin@cygwin.com\n"); + api_fatal ("Forked () while a condition variable has waiting threads.\nReport to cygwin@cygwin.com"); #else waiting = 0; mutex = NULL; #endif } +/* pthread_key */ +/* static members */ +List<pthread_key> pthread_key::keys; + +void +pthread_key::saveAKey (pthread_key *key) +{ + key->saveKeyToBuffer (); +} -pthread_key::pthread_key (void (*destructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC) +void +pthread_key::fixup_before_fork () +{ + keys.forEach (saveAKey); +} + +void +pthread_key::restoreAKey (pthread_key *key) +{ + key->recreateKeyFromBuffer (); +} + +void +pthread_key::fixup_after_fork () +{ + keys.forEach (restoreAKey); +} + +void +pthread_key::destroyAKey (pthread_key *key) +{ + key->run_destructor (); +} + +void +pthread_key::runAllDestructors () +{ + keys.forEach (destroyAKey); +} + +bool +pthread_key::isGoodObject (pthread_key_t const *key) +{ + if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +/* non-static members */ + +pthread_key::pthread_key (void (*aDestructor) (void *)):verifyable_object (PTHREAD_KEY_MAGIC), destructor (aDestructor) { dwTlsIndex = TlsAlloc (); if (dwTlsIndex == TLS_OUT_OF_INDEXES) magic = 0; - else if (destructor) - { - MT_INTERFACE->destructors. - Insert (new pthread_key_destructor (destructor, this)); - } + else + keys.Insert (this); } pthread_key::~pthread_key () { - if (pthread_key_destructor *dest = MT_INTERFACE->destructors.Remove (this)) - delete dest; - TlsFree (dwTlsIndex); + /* We may need to make the list code lock the list during operations + */ + if (magic != 0) + { + keys.Remove (this); + TlsFree (dwTlsIndex); + } } int @@ -608,10 +1011,34 @@ pthread_key::set (const void *value) } void * -pthread_key::get () +pthread_key::get () const +{ + int savedError = ::GetLastError (); + void *result = TlsGetValue (dwTlsIndex); + ::SetLastError (savedError); + return result; +} + +void +pthread_key::saveKeyToBuffer () +{ + fork_buf = get (); +} + +void +pthread_key::recreateKeyFromBuffer () { - set_errno (0); - return TlsGetValue (dwTlsIndex); + dwTlsIndex = TlsAlloc (); + if (dwTlsIndex == TLS_OUT_OF_INDEXES) + api_fatal ("pthread_key::recreateKeyFromBuffer () failed to reallocate Tls storage"); + set (fork_buf); +} + +void +pthread_key::run_destructor () const +{ + if (destructor) + destructor (get ()); } /*pshared mutexs: @@ -638,10 +1065,35 @@ pthread_key::get () *Isn't duplicated, it's reopened. */ +/* static members */ +bool +pthread_mutex::isGoodObject (pthread_mutex_t const *mutex) +{ + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +bool +pthread_mutex::isGoodInitializer (pthread_mutex_t const *mutex) +{ + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != VALID_STATIC_OBJECT) + return false; + return true; +} + +bool +pthread_mutex::isGoodInitializerOrObject (pthread_mutex_t const *mutex) +{ + if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) == INVALID_OBJECT) + return false; + return true; +} + pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREAD_MUTEX_MAGIC) { /*attr checked in the C call */ - if (attr && attr->pshared==PTHREAD_PROCESS_SHARED) + if (attr && attr->pshared == PTHREAD_PROCESS_SHARED) { // fail magic = 0; @@ -651,14 +1103,14 @@ pthread_mutex::pthread_mutex (pthread_mutexattr *attr):verifyable_object (PTHREA InitializeCriticalSection (&criticalsection); else { - this->win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL); + this->win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL); if (!win32_obj_id) magic = 0; } condwaits = 0; pshared = PTHREAD_PROCESS_PRIVATE; /* threadsafe addition is easy */ - next = (pthread_mutex *)InterlockedExchangePointer (&MT_INTERFACE->mutexs, this); + next = (pthread_mutex *) InterlockedExchangePointer (&MT_INTERFACE->mutexs, this); } pthread_mutex::~pthread_mutex () @@ -721,26 +1173,34 @@ pthread_mutex::UnLock () void pthread_mutex::fixup_after_fork () { - debug_printf("mutex %x in fixup_after_fork\n", this); + debug_printf ("mutex %x in fixup_after_fork", this); if (pshared != PTHREAD_PROCESS_PRIVATE) - api_fatal("pthread_mutex::fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's\n"); + api_fatal ("pthread_mutex::fixup_after_fork () doesn'tunderstand PROCESS_SHARED mutex's"); /* FIXME: duplicate code here and in the constructor. */ if (wincap.has_try_enter_critical_section ()) - InitializeCriticalSection(&criticalsection); + InitializeCriticalSection (&criticalsection); else { - win32_obj_id =::CreateMutex (&sec_none_nih, false, NULL); + win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL); if (!win32_obj_id) - api_fatal("pthread_mutex::fixup_after_fork() failed to create new win32 mutex\n"); + api_fatal ("pthread_mutex::fixup_after_fork () failed to create new win32 mutex"); } #if DETECT_BAD_APPS if (condwaits) - api_fatal("Forked() while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com\n"); + api_fatal ("Forked () while a mutex has condition variables waiting on it.\nReport to cygwin@cygwin.com"); #else condwaits = 0; #endif } +bool +pthread_mutexattr::isGoodObject (pthread_mutexattr_t const * attr) +{ + if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + return false; + return true; +} + pthread_mutexattr::pthread_mutexattr ():verifyable_object (PTHREAD_MUTEXATTR_MAGIC), pshared (PTHREAD_PROCESS_PRIVATE), mutextype (PTHREAD_MUTEX_DEFAULT) { @@ -752,14 +1212,14 @@ pthread_mutexattr::~pthread_mutexattr () semaphore::semaphore (int pshared, unsigned int value):verifyable_object (SEM_MAGIC) { - this->win32_obj_id =::CreateSemaphore (&sec_none_nih, value, LONG_MAX, + this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, value, LONG_MAX, NULL); if (!this->win32_obj_id) magic = 0; this->shared = pshared; currentvalue = value; /* threadsafe addition is easy */ - next = (semaphore *)InterlockedExchangePointer (&MT_INTERFACE->semaphores, this); + next = (semaphore *) InterlockedExchangePointer (&MT_INTERFACE->semaphores, this); } semaphore::~semaphore () @@ -794,7 +1254,10 @@ semaphore::TryWait () *We probably need WaitForMultipleObjects here. */ if (WaitForSingleObject (win32_obj_id, 0) == WAIT_TIMEOUT) - return EAGAIN; + { + set_errno (EAGAIN); + return -1; + } currentvalue--; return 0; } @@ -809,13 +1272,13 @@ semaphore::Wait () void semaphore::fixup_after_fork () { - debug_printf("sem %x in fixup_after_fork\n", this); + debug_printf ("sem %x in fixup_after_fork", this); if (shared != PTHREAD_PROCESS_PRIVATE) - api_fatal("doesn't understand PROCESS_SHARED semaphores variables\n"); + api_fatal ("doesn't understand PROCESS_SHARED semaphores variables"); /* FIXME: duplicate code here and in the constructor. */ - this->win32_obj_id =::CreateSemaphore (&sec_none_nih, currentvalue, LONG_MAX, NULL); + this->win32_obj_id = ::CreateSemaphore (&sec_none_nih, currentvalue, LONG_MAX, NULL); if (!win32_obj_id) - api_fatal("failed to create new win32 semaphore\n"); + api_fatal ("failed to create new win32 semaphore"); } verifyable_object::verifyable_object (long verifyer): @@ -862,14 +1325,14 @@ verifyable_object_isvalid (void const * objectptr, long magic) /* Pthreads */ void * -thread_init_wrapper (void *_arg) +pthread::thread_init_wrapper (void *_arg) { // Setup the local/global storage of this thread pthread *thread = (pthread *) _arg; struct __reent_t local_reent; struct _winsup_t local_winsup; - struct _reent local_clib = _REENT_INIT(local_clib); + struct _reent local_clib = _REENT_INIT (local_clib); struct sigaction _sigs[NSIG]; sigset_t _sig_mask; /*one set for everything to ignore. */ @@ -891,8 +1354,13 @@ thread_init_wrapper (void *_arg) if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent)) system_printf ("local storage for thread couldn't be set"); - /*the OS doesn't check this for <=64 Tls entries (pre win2k) */ - TlsSetValue (MT_INTERFACE->thread_self_dwTlsIndex, thread); + setTlsSelfPointer (thread); + + thread->mutex.Lock (); + // if thread is detached force cleanup on exit + if (thread->attr.joinable == PTHREAD_CREATE_DETACHED && thread->joiner == NULL) + thread->joiner = pthread::self (); + thread->mutex.UnLock (); #ifdef _CYG_THREAD_FAILSAFE if (_REENT == _impure_ptr) @@ -905,7 +1373,7 @@ thread_init_wrapper (void *_arg) // call the user's thread void *ret = thread->function (thread->arg); - __pthread_exit (ret); + thread->exit (ret); #if 0 // ??? This code only runs if the thread exits by returning. @@ -915,29 +1383,47 @@ thread_init_wrapper (void *_arg) return 0; } +bool +pthread::isGoodObject (pthread_t const *thread) +{ + if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +unsigned long +pthread::getsequence_np () +{ + return getThreadId (); +} + int -__pthread_create (pthread_t *thread, const pthread_attr_t *attr, +pthread::create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { - if (attr && verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + DECLARE_TLS_STORAGE; + if (attr && !pthread_attr::isGoodObject (attr)) return EINVAL; *thread = new pthread (); (*thread)->create (start_routine, attr ? *attr : NULL, arg); - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!isGoodObject (thread)) { delete (*thread); *thread = NULL; return EAGAIN; } - InterlockedIncrement (&MT_INTERFACE->threadcount); return 0; } int -__pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) +pthread::once (pthread_once_t *once_control, void (*init_routine) (void)) { + // already done ? + if (once_control->state) + return 0; + pthread_mutex_lock (&once_control->mutex); /*Here we must set a cancellation handler to unlock the mutex if needed */ /*but a cancellation handler is not the right thing. We need this in the thread @@ -945,7 +1431,7 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) *at a time. Stote a mutex_t *in the pthread_structure. if that's non null unlock *on pthread_exit (); */ - if (once_control->state == 0) + if (!once_control->state) { init_routine (); once_control->state = 1; @@ -955,251 +1441,13 @@ __pthread_once (pthread_once_t *once_control, void (*init_routine) (void)) return 0; } -/*Cancelability states */ - - -/*Perform the actual cancel */ -void -__pthread_cleanup (pthread_t thread) -{ -} - - int -__pthread_cancel (pthread_t thread) +pthread::cancel (pthread_t thread) { - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!isGoodObject (&thread)) return ESRCH; - if (thread->cancelstate == PTHREAD_CANCEL_ENABLE) - { -#if 0 - /*once all the functions call testcancel (), we will do this */ - if (thread->canceltype == PTHREAD_CANCEL_DEFERRED) - { - } - else - { - /*possible FIXME: this function is meant to return asynchronously - *from the cancellation routine actually firing. So we may need some sort - *of signal to be sent that is immediately recieved and acted on. - */ - __pthread_cleanup (thread); - } -#endif - } -/* return 0; -*/ - - return ESRCH; -/* - we return ESRCH until all the required functions call testcancel (); - this will give applications predictable behaviour. - - the required function list is: *indicates done, X indicates not present in cygwin. -aio_suspend () -*close () -*creat () -fcntl () -fsync () -getmsg () -getpmsg () -lockf () -mq_receive () -mq_send () -msgrcv () -msgsnd () -msync () -nanosleep () -open () -pause () -poll () -pread () -pthread_cond_timedwait () -pthread_cond_wait () -*pthread_join () -pthread_testcancel () -putmsg () -putpmsg () -pwrite () -read () -readv () -select () -sem_wait () -sigpause () -sigsuspend () -sigtimedwait () -sigwait () -sigwaitinfo () -*sleep () -system () -tcdrain () -*usleep () -wait () -wait3() -waitid () -waitpid () -write () -writev () -the optional list is: -catclose () -catgets () -catopen () -closedir () -closelog () -ctermid () -dbm_close () -dbm_delete () -dbm_fetch () -dbm_nextkey () -dbm_open () -dbm_store () -dlclose () -dlopen () -endgrent () -endpwent () -endutxent () -fclose () -fcntl () -fflush () -fgetc () -fgetpos () -fgets () -fgetwc () -fgetws () -fopen () -fprintf () -fputc () -fputs () -fputwc () -fputws () -fread () -freopen () -fscanf () -fseek () -fseeko () -fsetpos () -ftell () -ftello () -ftw () -fwprintf () -fwrite () -fwscanf () -getc () -getc_unlocked () -getchar () -getchar_unlocked () -getcwd () -getdate () -getgrent () -getgrgid () -getgrgid_r () -getgrnam () -getgrnam_r () -getlogin () -getlogin_r () -getpwent () -*getpwnam () -*getpwnam_r () -*getpwuid () -*getpwuid_r () -gets () -getutxent () -getutxid () -getutxline () -getw () -getwc () -getwchar () -getwd () -glob () -iconv_close () -iconv_open () -ioctl () -lseek () -mkstemp () -nftw () -opendir () -openlog () -pclose () -perror () -popen () -printf () -putc () -putc_unlocked () -putchar () -putchar_unlocked () -puts () -pututxline () -putw () -putwc () -putwchar () -readdir () -readdir_r () -remove () -rename () -rewind () -rewinddir () -scanf () -seekdir () -semop () -setgrent () -setpwent () -setutxent () -strerror () -syslog () -tmpfile () -tmpnam () -ttyname () -ttyname_r () -ungetc () -ungetwc () -unlink () -vfprintf () -vfwprintf () -vprintf () -vwprintf () -wprintf () -wscanf () - -Note, that for fcntl (), for any value of the cmd argument. - -And we must not introduce cancellation points anywhere else that's part of the posix or -opengroup specs. - */ -} - -/*no races in these three functions: they are all current-thread-only */ -int -__pthread_setcancelstate (int state, int *oldstate) -{ - class pthread *thread = __pthread_self (); - if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) - return EINVAL; - *oldstate = thread->cancelstate; - thread->cancelstate = state; - return 0; -} - -int -__pthread_setcanceltype (int type, int *oldtype) -{ - class pthread *thread = __pthread_self (); - if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) - return EINVAL; - *oldtype = thread->canceltype; - thread->canceltype = type; - return 0; -} - -/*deferred cancellation request handler */ -void -__pthread_testcancel (void) -{ - class pthread *thread = __pthread_self (); - if (thread->cancelstate == PTHREAD_CANCEL_DISABLE) - return; - /*check the cancellation event object here - not neededuntil pthread_cancel actually - *does something*/ + return thread->cancel (); } /* @@ -1221,8 +1469,10 @@ __pthread_testcancel (void) *If yes, we're safe, if no, we're not. */ void -__pthread_atforkprepare (void) +pthread::atforkprepare (void) { + MT_INTERFACE->fixup_before_fork (); + callback *cb = MT_INTERFACE->pthread_prepare; while (cb) { @@ -1232,7 +1482,7 @@ __pthread_atforkprepare (void) } void -__pthread_atforkparent (void) +pthread::atforkparent (void) { callback *cb = MT_INTERFACE->pthread_parent; while (cb) @@ -1243,8 +1493,10 @@ __pthread_atforkparent (void) } void -__pthread_atforkchild (void) +pthread::atforkchild (void) { + MT_INTERFACE->fixup_after_fork (); + callback *cb = MT_INTERFACE->pthread_child; while (cb) { @@ -1258,7 +1510,7 @@ __pthread_atforkchild (void) *parent and child calls are called in FI-FC order. */ int -__pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void)) +pthread::atfork (void (*prepare)(void), void (*parent)(void), void (*child)(void)) { callback *prepcb = NULL, *parentcb = NULL, *childcb = NULL; if (prepare) @@ -1293,7 +1545,7 @@ __pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(voi if (prepcb) { prepcb->cb = prepare; - prepcb->next=(callback *)InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb); + prepcb->next = (callback *) InterlockedExchangePointer ((LONG *) &MT_INTERFACE->pthread_prepare, (long int) prepcb); } if (parentcb) { @@ -1302,7 +1554,7 @@ __pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(voi while (*t) t = &(*t)->next; /*t = pointer to last next in the list */ - parentcb->next=(callback *)InterlockedExchangePointer ((LONG *) t, (long int) parentcb); + parentcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) parentcb); } if (childcb) { @@ -1311,7 +1563,7 @@ __pthread_atfork (void (*prepare)(void), void (*parent)(void), void (*child)(voi while (*t) t = &(*t)->next; /*t = pointer to last next in the list */ - childcb->next=(callback *)InterlockedExchangePointer ((LONG *) t, (long int) childcb); + childcb->next = (callback *) InterlockedExchangePointer ((LONG *) t, (long int) childcb); } return 0; } @@ -1322,7 +1574,7 @@ __pthread_attr_init (pthread_attr_t *attr) if (check_valid_pointer (attr)) return EINVAL; *attr = new pthread_attr; - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) { delete (*attr); *attr = NULL; @@ -1335,7 +1587,7 @@ int __pthread_attr_getinheritsched (const pthread_attr_t *attr, int *inheritsched) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; *inheritsched = (*attr)->inheritsched; return 0; @@ -1345,7 +1597,7 @@ int __pthread_attr_getschedparam (const pthread_attr_t *attr, struct sched_param *param) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; *param = (*attr)->schedparam; return 0; @@ -1358,7 +1610,7 @@ __pthread_attr_getschedparam (const pthread_attr_t *attr, int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; *policy = SCHED_FIFO; return 0; @@ -1368,7 +1620,7 @@ __pthread_attr_getschedpolicy (const pthread_attr_t *attr, int *policy) int __pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; *contentionscope = (*attr)->contentionscope; return 0; @@ -1377,7 +1629,7 @@ __pthread_attr_getscope (const pthread_attr_t *attr, int *contentionscope) int __pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; if (detachstate < 0 || detachstate > 1) return EINVAL; @@ -1388,7 +1640,7 @@ __pthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) int __pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; *detachstate = (*attr)->joinable; return 0; @@ -1397,7 +1649,7 @@ __pthread_attr_getdetachstate (const pthread_attr_t *attr, int *detachstate) int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inheritsched) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; if (inheritsched != PTHREAD_INHERIT_SCHED && inheritsched != PTHREAD_EXPLICIT_SCHED) @@ -1410,7 +1662,7 @@ int __pthread_attr_setschedparam (pthread_attr_t *attr, const struct sched_param *param) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; if (!valid_sched_parameters (param)) return ENOTSUP; @@ -1422,7 +1674,7 @@ __pthread_attr_setschedparam (pthread_attr_t *attr, int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; if (policy != SCHED_FIFO) return ENOTSUP; @@ -1432,7 +1684,7 @@ __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy) int __pthread_attr_setscope (pthread_attr_t *attr, int contentionscope) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; if (contentionscope != PTHREAD_SCOPE_SYSTEM && contentionscope != PTHREAD_SCOPE_PROCESS) @@ -1448,7 +1700,7 @@ __pthread_attr_setscope (pthread_attr_t *attr, int contentionscope) int __pthread_attr_setstacksize (pthread_attr_t *attr, size_t size) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; (*attr)->stacksize = size; return 0; @@ -1457,7 +1709,7 @@ __pthread_attr_setstacksize (pthread_attr_t *attr, size_t size) int __pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; *size = (*attr)->stacksize; return 0; @@ -1466,46 +1718,46 @@ __pthread_attr_getstacksize (const pthread_attr_t *attr, size_t *size) int __pthread_attr_destroy (pthread_attr_t *attr) { - if (verifyable_object_isvalid (attr, PTHREAD_ATTR_MAGIC) != VALID_OBJECT) + if (!pthread_attr::isGoodObject (attr)) return EINVAL; delete (*attr); *attr = NULL; return 0; } -void -__pthread_exit (void *value_ptr) +int +pthread::join (pthread_t *thread, void **return_val) { - class pthread *thread = __pthread_self (); + pthread_t joiner = self (); - MT_INTERFACE->destructors.IterateNull (); + // Initialize return val with NULL + if (return_val) + *return_val = NULL; - thread->return_ptr = value_ptr; - if (InterlockedDecrement (&MT_INTERFACE->threadcount) == 0) - exit (0); - else - ExitThread (0); -} - -int -__pthread_join (pthread_t *thread, void **return_val) -{ /*FIXME: wait on the thread cancellation event as well - we are a cancellation point*/ - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!isGoodObject (thread)) return ESRCH; + if (__pthread_equal (thread,&joiner)) + return EDEADLK; + + (*thread)->mutex.Lock (); + if ((*thread)->attr.joinable == PTHREAD_CREATE_DETACHED) { - if (return_val) - *return_val = NULL; + (*thread)->mutex.UnLock (); return EINVAL; } else { + (*thread)->joiner = joiner; (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED; + (*thread)->mutex.UnLock (); WaitForSingleObject ((*thread)->win32_obj_id, INFINITE); if (return_val) - *return_val = (*thread)->return_ptr; + *return_val = (*thread)->return_ptr; + // cleanup + delete (*thread); } /*End if */ pthread_testcancel (); @@ -1514,25 +1766,40 @@ __pthread_join (pthread_t *thread, void **return_val) } int -__pthread_detach (pthread_t *thread) +pthread::detach (pthread_t *thread) { - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!isGoodObject (thread)) return ESRCH; + (*thread)->mutex.Lock (); if ((*thread)->attr.joinable == PTHREAD_CREATE_DETACHED) { - (*thread)->return_ptr = NULL; + (*thread)->mutex.UnLock (); return EINVAL; } - (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED; + // check if thread is still alive + if (WAIT_TIMEOUT == WaitForSingleObject ((*thread)->win32_obj_id, 0) ) + { + // force cleanup on exit + (*thread)->joiner = *thread; + (*thread)->attr.joinable = PTHREAD_CREATE_DETACHED; + (*thread)->mutex.UnLock (); + } + else + { + // thread has already terminated. + (*thread)->mutex.UnLock (); + delete (*thread); + } + return 0; } int -__pthread_suspend (pthread_t *thread) +pthread::suspend (pthread_t *thread) { - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!isGoodObject (thread)) return ESRCH; if ((*thread)->suspended == false) @@ -1546,9 +1813,9 @@ __pthread_suspend (pthread_t *thread) int -__pthread_continue (pthread_t *thread) +pthread::resume (pthread_t *thread) { - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!isGoodObject (thread)) return ESRCH; if ((*thread)->suspended == true) @@ -1572,7 +1839,7 @@ int __pthread_getschedparam (pthread_t thread, int *policy, struct sched_param *param) { - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return ESRCH; *policy = SCHED_FIFO; /*we don't return the current effective priority, we return the current requested @@ -1581,15 +1848,6 @@ __pthread_getschedparam (pthread_t thread, int *policy, return 0; } - -unsigned long -__pthread_getsequence_np (pthread_t *thread) -{ - if (verifyable_object_isvalid (thread, PTHREAD_MAGIC) != VALID_OBJECT) - return EINVAL; - return (*thread)->GetThreadId (); -} - /*Thread SpecificData */ int __pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) @@ -1597,12 +1855,12 @@ __pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) /*The opengroup docs don't define if we should check this or not, *but creation is relatively rare.. */ - if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) == VALID_OBJECT) + if (pthread_key::isGoodObject (key)) return EBUSY; *key = new pthread_key (destructor); - if (verifyable_object_isvalid (key, PTHREAD_KEY_MAGIC) != VALID_OBJECT) + if (!pthread_key::isGoodObject (key)) { delete (*key); *key = NULL; @@ -1614,7 +1872,7 @@ __pthread_key_create (pthread_key_t *key, void (*destructor) (void *)) int __pthread_key_delete (pthread_key_t key) { - if (verifyable_object_isvalid (&key, PTHREAD_KEY_MAGIC) != VALID_OBJECT) + if (!pthread_key::isGoodObject (&key)) return EINVAL; delete (key); @@ -1638,7 +1896,7 @@ int __pthread_setschedparam (pthread_t thread, int policy, const struct sched_param *param) { - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return ESRCH; if (policy != SCHED_FIFO) return ENOTSUP; @@ -1655,7 +1913,7 @@ __pthread_setschedparam (pthread_t thread, int policy, int __pthread_setspecific (pthread_key_t key, const void *value) { - if (verifyable_object_isvalid (&key, PTHREAD_KEY_MAGIC) != VALID_OBJECT) + if (!pthread_key::isGoodObject (&key)) return EINVAL; (key)->set (value); return 0; @@ -1664,7 +1922,7 @@ __pthread_setspecific (pthread_key_t key, const void *value) void * __pthread_getspecific (pthread_key_t key) { - if (verifyable_object_isvalid (&key, PTHREAD_KEY_MAGIC) != VALID_OBJECT) + if (!pthread_key::isGoodObject (&key)) return NULL; return (key)->get (); @@ -1672,11 +1930,36 @@ __pthread_getspecific (pthread_key_t key) } /*Thread synchronisation */ +bool +pthread_cond::isGoodObject (pthread_cond_t const *cond) +{ + if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + return false; + return true; +} + +bool +pthread_cond::isGoodInitializer (pthread_cond_t const *cond) +{ + if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) != VALID_STATIC_OBJECT) + return false; + return true; +} + +bool +pthread_cond::isGoodInitializerOrObject (pthread_cond_t const *cond) +{ + if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC, PTHREAD_COND_INITIALIZER) == INVALID_OBJECT) + return false; + return true; +} int __pthread_cond_destroy (pthread_cond_t *cond) { - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (pthread_cond::isGoodInitializer (cond)) + return 0; + if (!pthread_cond::isGoodObject (cond)) return EINVAL; /*reads are atomic */ @@ -1692,15 +1975,15 @@ __pthread_cond_destroy (pthread_cond_t *cond) int __pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr) { - if (attr && verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (attr && !pthread_condattr::isGoodObject (attr)) return EINVAL; - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != INVALID_OBJECT) + if (pthread_cond::isGoodObject (cond)) return EBUSY; *cond = new pthread_cond (attr ? (*attr) : NULL); - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) { delete (*cond); *cond = NULL; @@ -1713,7 +1996,9 @@ __pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr) int __pthread_cond_broadcast (pthread_cond_t *cond) { - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (pthread_cond::isGoodInitializer (cond)) + __pthread_cond_init (cond, NULL); + if (!pthread_cond::isGoodObject (cond)) return EINVAL; (*cond)->BroadCast (); @@ -1724,7 +2009,9 @@ __pthread_cond_broadcast (pthread_cond_t *cond) int __pthread_cond_signal (pthread_cond_t *cond) { - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (pthread_cond::isGoodInitializer (cond)) + __pthread_cond_init (cond, NULL); + if (!pthread_cond::isGoodObject (cond)) return EINVAL; (*cond)->Signal (); @@ -1743,21 +2030,23 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex, if (*mutex == PTHREAD_MUTEX_INITIALIZER) __pthread_mutex_init (mutex, NULL); themutex = mutex; + if (pthread_cond::isGoodInitializer (cond)) + __pthread_cond_init (cond, NULL); - if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; - if (verifyable_object_isvalid (cond, PTHREAD_COND_MAGIC) != VALID_OBJECT) + if (!pthread_cond::isGoodObject (cond)) return EINVAL; /*if the cond variable is blocked, then the above timer test maybe wrong. *shrug**/ if (pthread_mutex_lock (&(*cond)->cond_access)) - system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond); + system_printf ("Failed to lock condition variable access mutex, this %p", *cond); if ((*cond)->waiting) if ((*cond)->mutex && ((*cond)->mutex != (*themutex))) { if (pthread_mutex_unlock (&(*cond)->cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); + system_printf ("Failed to unlock condition variable access mutex, this %p", *cond); return EINVAL; } InterlockedIncrement (&((*cond)->waiting)); @@ -1765,22 +2054,26 @@ __pthread_cond_dowait (pthread_cond_t *cond, pthread_mutex_t *mutex, (*cond)->mutex = (*themutex); InterlockedIncrement (&((*themutex)->condwaits)); if (pthread_mutex_unlock (&(*cond)->cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); + system_printf ("Failed to unlock condition variable access mutex, this %p", *cond); + /* At this point calls to Signal will progress evebn if we aren' yet waiting + * However, the loop there should allow us to get scheduled and call wait, + * and have them call PulseEvent again if we dont' respond. + */ rv = (*cond)->TimedWait (waitlength); - /* this may allow a race on the mutex acquisition and waits.. + /* this may allow a race on the mutex acquisition and waits.. * But doing this within the cond access mutex creates a different race */ - bool last = false; - if (InterlockedDecrement (&((*cond)->waiting)) == 0) - last = true; + InterlockedDecrement (&((*cond)->waiting)); + /* Tell Signal that we have been released */ + InterlockedDecrement (&((*cond)->ExitingWait)); (*themutex)->Lock (); - if (last == true) - (*cond)->mutex = NULL; if (pthread_mutex_lock (&(*cond)->cond_access)) - system_printf ("Failed to lock condition variable access mutex, this %0p\n", *cond); + system_printf ("Failed to lock condition variable access mutex, this %p", *cond); + if ((*cond)->waiting == 0) + (*cond)->mutex = NULL; InterlockedDecrement (&((*themutex)->condwaits)); if (pthread_mutex_unlock (&(*cond)->cond_access)) - system_printf ("Failed to unlock condition variable access mutex, this %0p\n", *cond); + system_printf ("Failed to unlock condition variable access mutex, this %p", *cond); return rv; } @@ -1789,11 +2082,11 @@ extern "C" int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime) { - if (check_valid_pointer(abstime)) + if (check_valid_pointer (abstime)) return EINVAL; struct timeb currSysTime; long waitlength; - ftime(&currSysTime); + ftime (&currSysTime); waitlength = (abstime->tv_sec - currSysTime.time) *1000; if (waitlength < 0) return ETIMEDOUT; @@ -1809,8 +2102,9 @@ pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) int __pthread_condattr_init (pthread_condattr_t *condattr) { + /* FIXME: we dereference blindly! */ *condattr = new pthread_condattr; - if (verifyable_object_isvalid (condattr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (condattr)) { delete (*condattr); *condattr = NULL; @@ -1822,7 +2116,7 @@ __pthread_condattr_init (pthread_condattr_t *condattr) int __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (attr)) return EINVAL; *pshared = (*attr)->shared; return 0; @@ -1831,7 +2125,7 @@ __pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) int __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (attr)) return EINVAL; if ((pshared < 0) || (pshared > 1)) return EINVAL; @@ -1845,7 +2139,7 @@ __pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) int __pthread_condattr_destroy (pthread_condattr_t *condattr) { - if (verifyable_object_isvalid (condattr, PTHREAD_CONDATTR_MAGIC) != VALID_OBJECT) + if (!pthread_condattr::isGoodObject (condattr)) return EINVAL; delete (*condattr); *condattr = NULL; @@ -1859,7 +2153,7 @@ __pthread_kill (pthread_t thread, int sig) // lock myself, for the use of thread2signal // two different kills might clash: FIXME - if (verifyable_object_isvalid (&thread, PTHREAD_MAGIC) != VALID_OBJECT) + if (!pthread::isGoodObject (&thread)) return EINVAL; if (thread->sigs) @@ -1874,7 +2168,7 @@ __pthread_kill (pthread_t thread, int sig) int __pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) { - pthread *thread = __pthread_self (); + pthread *thread = pthread::self (); // lock this myself, for the use of thread2signal // two differt kills might clash: FIXME @@ -1890,11 +2184,6 @@ __pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) } /* ID */ -pthread_t -__pthread_self () -{ - return (pthread *) TlsGetValue (MT_INTERFACE->thread_self_dwTlsIndex); -} int __pthread_equal (pthread_t *t1, pthread_t *t2) @@ -1917,14 +2206,15 @@ int __pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { - if (attr && verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT || check_valid_pointer (mutex)) + if (attr && !pthread_mutexattr::isGoodObject (attr) || check_valid_pointer (mutex)) return EINVAL; - if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER) != INVALID_OBJECT) + /* FIXME: bugfix: we should check *mutex being a valid address */ + if (pthread_mutex::isGoodObject (mutex)) return EBUSY; *mutex = new pthread_mutex (attr ? (*attr) : NULL); - if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (mutex)) { delete (*mutex); *mutex = NULL; @@ -1937,10 +2227,10 @@ int __pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling) { - pthread_mutex_t *themutex=(pthread_mutex_t *) mutex; - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + pthread_mutex_t *themutex = (pthread_mutex_t *) mutex; + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init ((pthread_mutex_t *) mutex, NULL); - if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; /*We don't define _POSIX_THREAD_PRIO_PROTECT because we do't currently support *mutex priorities. @@ -1957,18 +2247,22 @@ int __pthread_mutex_lock (pthread_mutex_t *mutex) { pthread_mutex_t *themutex = mutex; + /* This could be simplified via isGoodInitializerOrObject + and isGoodInitializer, but in a performance critical call like this.... + no. + */ switch (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC, PTHREAD_MUTEX_INITIALIZER)) { case INVALID_OBJECT: return EINVAL; break; case VALID_STATIC_OBJECT: - if (*mutex == PTHREAD_MUTEX_INITIALIZER) - { - int rv = __pthread_mutex_init (mutex, NULL); - if (rv) + if (pthread_mutex::isGoodInitializer (mutex)) + { + int rv = __pthread_mutex_init (mutex, NULL); + if (rv) return rv; - } + } break; case VALID_OBJECT: break; @@ -1981,9 +2275,9 @@ int __pthread_mutex_trylock (pthread_mutex_t *mutex) { pthread_mutex_t *themutex = mutex; - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init (mutex, NULL); - if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; if ((*themutex)->TryLock ()) return EBUSY; @@ -1993,9 +2287,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) int __pthread_mutex_unlock (pthread_mutex_t *mutex) { - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init (mutex, NULL); - if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (mutex)) return EINVAL; (*mutex)->UnLock (); return 0; @@ -2004,9 +2298,9 @@ __pthread_mutex_unlock (pthread_mutex_t *mutex) int __pthread_mutex_destroy (pthread_mutex_t *mutex) { - if (check_valid_pointer (mutex) && (*mutex == PTHREAD_MUTEX_INITIALIZER)) + if (pthread_mutex::isGoodInitializer (mutex)) return 0; - if (verifyable_object_isvalid (mutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (mutex)) return EINVAL; /*reading a word is atomic */ @@ -2023,9 +2317,9 @@ __pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, int *old_ceiling) { pthread_mutex_t *themutex = mutex; - if (*mutex == PTHREAD_MUTEX_INITIALIZER) + if (pthread_mutex::isGoodInitializer (mutex)) __pthread_mutex_init (mutex, NULL); - if (verifyable_object_isvalid (themutex, PTHREAD_MUTEX_MAGIC) != VALID_OBJECT) + if (!pthread_mutex::isGoodObject (themutex)) return EINVAL; return ENOSYS; } @@ -2036,7 +2330,7 @@ int __pthread_mutexattr_getprotocol (const pthread_mutexattr_t *attr, int *protocol) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2045,7 +2339,7 @@ int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int *pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; *pshared = (*attr)->pshared; return 0; @@ -2058,7 +2352,7 @@ __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, int __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; *type = (*attr)->mutextype; return 0; @@ -2072,11 +2366,11 @@ __pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *type) int __pthread_mutexattr_init (pthread_mutexattr_t *attr) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != INVALID_OBJECT) + if (pthread_mutexattr::isGoodObject (attr)) return EBUSY; *attr = new pthread_mutexattr (); - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) { delete (*attr); *attr = NULL; @@ -2088,7 +2382,7 @@ __pthread_mutexattr_init (pthread_mutexattr_t *attr) int __pthread_mutexattr_destroy (pthread_mutexattr_t *attr) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; delete (*attr); *attr = NULL; @@ -2100,7 +2394,7 @@ __pthread_mutexattr_destroy (pthread_mutexattr_t *attr) int __pthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int protocol) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2110,7 +2404,7 @@ int __pthread_mutexattr_setprioceiling (pthread_mutexattr_t *attr, int prioceiling) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2119,7 +2413,7 @@ int __pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr, int *prioceiling) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; return ENOSYS; } @@ -2127,7 +2421,7 @@ __pthread_mutexattr_getprioceiling (const pthread_mutexattr_t *attr, int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; /*we don't use pshared for anything as yet. We need to test PROCESS_SHARED *functionality @@ -2142,7 +2436,7 @@ __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) int __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) { - if (verifyable_object_isvalid (attr, PTHREAD_MUTEXATTR_MAGIC) != VALID_OBJECT) + if (!pthread_mutexattr::isGoodObject (attr)) return EINVAL; if (type != PTHREAD_MUTEX_RECURSIVE) return EINVAL; @@ -2151,11 +2445,21 @@ __pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type) } /*Semaphores */ + +/* static members */ +bool +semaphore::isGoodObject (sem_t const * sem) +{ + if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + return false; + return true; +} + int -__sem_init (sem_t *sem, int pshared, unsigned int value) +semaphore::init (sem_t *sem, int pshared, unsigned int value) { /*opengroup calls this undefined */ - if (verifyable_object_isvalid (sem, SEM_MAGIC) != INVALID_OBJECT) + if (isGoodObject (sem)) return EBUSY; if (value > SEM_VALUE_MAX) @@ -2163,7 +2467,7 @@ __sem_init (sem_t *sem, int pshared, unsigned int value) *sem = new semaphore (pshared, value); - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) { delete (*sem); *sem = NULL; @@ -2173,9 +2477,9 @@ __sem_init (sem_t *sem, int pshared, unsigned int value) } int -__sem_destroy (sem_t *sem) +semaphore::destroy (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) return EINVAL; /*FIXME - new feature - test for busy against threads... */ @@ -2186,32 +2490,107 @@ __sem_destroy (sem_t *sem) } int -__sem_wait (sem_t *sem) +semaphore::wait (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) - return EINVAL; + if (!isGoodObject (sem)) + { + set_errno (EINVAL); + return -1; + } (*sem)->Wait (); return 0; } int -__sem_trywait (sem_t *sem) +semaphore::trywait (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) - return EINVAL; + if (!isGoodObject (sem)) + { + set_errno (EINVAL); + return -1; + } return (*sem)->TryWait (); } int -__sem_post (sem_t *sem) +semaphore::post (sem_t *sem) { - if (verifyable_object_isvalid (sem, SEM_MAGIC) != VALID_OBJECT) + if (!isGoodObject (sem)) return EINVAL; (*sem)->Post (); return 0; } +/* pthreadNull */ +pthread * +pthreadNull::getNullpthread () +{ + /* because of weird entry points */ + _instance.magic = 0; + return &_instance; +} + +pthreadNull::pthreadNull () +{ + /* Mark ourselves as invalid */ + magic = 0; +} + +pthreadNull::~pthreadNull () +{ +} + +void +pthreadNull::create (void *(*)(void *), pthread_attr *, void *) +{ +} + +void +pthreadNull::exit (void *value_ptr) +{ +} + +int +pthreadNull::cancel () +{ + return 0; +} + +void +pthreadNull::testcancel () +{ +} + +int +pthreadNull::setcancelstate (int state, int *oldstate) +{ + return EINVAL; +} + +int +pthreadNull::setcanceltype (int type, int *oldtype) +{ + return EINVAL; +} + +void +pthreadNull::push_cleanup_handler (__pthread_cleanup_handler *handler) +{ +} + +void +pthreadNull::pop_cleanup_handler (int const execute) +{ +} +unsigned long +pthreadNull::getsequence_np () +{ + return 0; +} + +pthreadNull pthreadNull::_instance = pthreadNull (); + #endif // MT_SAFE |