int sem_wait (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function waits on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value or until interrupted by * a signal. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; pthread_testcancel(); if (s == NULL) { result = EINVAL; } else { if ((result = pthread_mutex_lock (&s->lock)) == 0) { int v; /* See sem_destroy.c */ if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } v = --s->value; (void) pthread_mutex_unlock (&s->lock); if (v < 0) { #if defined(_MSC_VER) && _MSC_VER < 1400 #pragma inline_depth(0) #endif /* Must wait */ pthread_cleanup_push(ptw32_sem_wait_cleanup, (void *) s); result = pthreadCancelableWait (s->sem); /* Cleanup if we're canceled or on any other error */ pthread_cleanup_pop(result); #if defined(_MSC_VER) && _MSC_VER < 1400 #pragma inline_depth() #endif } #if defined(NEED_SEM) if (!result && pthread_mutex_lock (&s->lock) == 0) { if (*sem == NULL) { (void) pthread_mutex_unlock (&s->lock); errno = EINVAL; return -1; } if (s->leftToUnblock > 0) { --s->leftToUnblock; SetEvent(s->sem); } (void) pthread_mutex_unlock (&s->lock); } #endif /* NEED_SEM */ } } if (result != 0) { errno = result; return -1; } return 0; } /* sem_wait */
int pthread_join (pthread_t thread, void **value_ptr) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL. This also detaches the thread on successful * completion. * * PARAMETERS * thread * an instance of pthread_t * * value_ptr * pointer to an instance of pointer to void * * * DESCRIPTION * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL. This also detaches the thread on successful * completion. * NOTE: detached threads cannot be joined or canceled * * RESULTS * 0 'thread' has completed * EINVAL thread is not a joinable thread, * ESRCH no thread could be found with ID 'thread', * ENOENT thread couldn't find it's own valid handle, * EDEADLK attempt to join thread with self * * ------------------------------------------------------ */ { int result; pthread_t self; ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; EnterCriticalSection (&ptw32_thread_reuse_lock); if (NULL == tp || thread.x != tp->ptHandle.x) { result = ESRCH; } else if (PTHREAD_CREATE_DETACHED == tp->detachState) { result = EINVAL; } else { result = 0; } LeaveCriticalSection (&ptw32_thread_reuse_lock); if (result == 0) { /* * The target thread is joinable and can't be reused before we join it. */ self = pthread_self(); if (NULL == self.p) { result = ENOENT; } else if (pthread_equal (self, thread)) { result = EDEADLK; } else { /* * Pthread_join is a cancelation point. * If we are canceled then our target thread must not be * detached (destroyed). This is guarranteed because * pthreadCancelableWait will not return if we * are canceled. */ result = pthreadCancelableWait (tp->threadH); if (0 == result) { if (value_ptr != NULL) { *value_ptr = tp->exitStatus; } /* * The result of making multiple simultaneous calls to * pthread_join() or pthread_detach() specifying the same * target is undefined. */ result = pthread_detach (thread); } else { result = ESRCH; } } } return (result); } /* pthread_join */
int sem_wait (sem_t * sem) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a semaphore. * * PARAMETERS * sem * pointer to an instance of sem_t * * DESCRIPTION * This function waits on a semaphore. If the * semaphore value is greater than zero, it decreases * its value by one. If the semaphore value is zero, then * the calling thread (or process) is blocked until it can * successfully decrease the value or until interrupted by * a signal. * * RESULTS * 0 successfully decreased semaphore, * -1 failed, error in errno * ERRNO * EINVAL 'sem' is not a valid semaphore, * ENOSYS semaphores are not supported, * EINTR the function was interrupted by a signal, * EDEADLK a deadlock condition was detected. * * ------------------------------------------------------ */ { int result = 0; if (sem == NULL || *sem == NULL) { result = EINVAL; } else { #ifdef NEED_SEM result = pthreadCancelableWait ((*sem)->event); #else /* NEED_SEM */ result = pthreadCancelableWait ((*sem)->sem); #endif /* NEED_SEM */ } if (result != 0) { errno = result; return -1; } #ifdef NEED_SEM ptw32_decrease_semaphore (sem); #endif /* NEED_SEM */ return 0; } /* sem_wait */
int pthread_join (pthread_t thread, void **value_ptr) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL. This also detaches the thread on successful * completion. * * PARAMETERS * thread * an instance of pthread_t * * value_ptr * pointer to an instance of pointer to void * * * DESCRIPTION * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL. This also detaches the thread on successful * completion. * NOTE: detached threads cannot be joined or canceled * * RESULTS * 0 'thread' has completed * EINVAL thread is not a joinable thread, * ESRCH no thread could be found with ID 'thread', * ENOENT thread couldn't find it's own valid handle, * EDEADLK attempt to join thread with self * * ------------------------------------------------------ */ { int result; pthread_t self; /* This is the proper way to test for a valid thread ID */ result = pthread_kill (thread, 0); if (0 != result) { return result; } self = pthread_self (); if (NULL == self) { return ENOENT; } if (0 != pthread_equal (self, thread)) { result = EDEADLK; } else if (PTHREAD_CREATE_DETACHED == thread->detachState) { result = EINVAL; } else { /* * Pthread_join is a cancelation point. * If we are canceled then our target thread must not be * detached (destroyed). This is guarranteed because * pthreadCancelableWait will not return if we * are canceled. */ result = pthreadCancelableWait (thread->threadH); if (result == 0) { #if ! defined (__MINGW32__) || defined (__MSVCRT__) if (value_ptr != NULL && !GetExitCodeThread (thread->threadH, (LPDWORD) value_ptr)) { result = ESRCH; } else { /* * The result of making multiple simultaneous calls to * pthread_join() specifying the same target is undefined. */ ptw32_threadDestroy (thread); } #else /* __MINGW32__ && ! __MSVCRT__ */ /* * If using CRTDLL, the thread may have exited, and endthread * will have closed the handle. */ if (value_ptr != NULL) { *value_ptr = thread->exitStatus; } /* * The result of making multiple simultaneous calls to * pthread_join() specifying the same target is undefined. */ ptw32_threadDestroy (thread); #endif /* __MINGW32__ && ! __MSVCRT__ */ } else { result = ESRCH; } } return (result); } /* pthread_join */