static INLINE int ptw32_timed_eventwait (HANDLE event, const struct timespec *abstime) /* * ------------------------------------------------------ * DESCRIPTION * This function waits on an event until signaled or until * abstime passes. * If abstime has passed when this routine is called then * it returns a result to indicate this. * * If 'abstime' is a NULL pointer then this function will * block until it can successfully decrease the value or * until interrupted by a signal. * * This routine is not a cancellation point. * * RESULTS * 0 successfully signaled, * ETIMEDOUT abstime passed * EINVAL 'event' is not a valid event, * * ------------------------------------------------------ */ { DWORD milliseconds; DWORD status; if (event == NULL) { return EINVAL; } else { if (abstime == NULL) { milliseconds = INFINITE; } else { /* * Calculate timeout as milliseconds from current system time. */ milliseconds = ptw32_relmillisecs (abstime); } status = WaitForSingleObject (event, milliseconds); if (status != WAIT_OBJECT_0) { if (status == WAIT_TIMEOUT) { return ETIMEDOUT; } else { return EINVAL; } } } return 0; } /* ptw32_timed_semwait */
int sem_timedwait (sem_t * sem, const struct timespec *abstime) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits on a semaphore possibly until * 'abstime' time. * * PARAMETERS * sem * pointer to an instance of sem_t * * abstime * pointer to an instance of struct timespec * * 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. * * If 'abstime' is a NULL pointer then this function will * block 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. * ETIMEDOUT abstime elapsed before success. * * ------------------------------------------------------ */ { int result = 0; sem_t s = *sem; if (sem == NULL) { result = EINVAL; } else { DWORD milliseconds; if (abstime == NULL) { milliseconds = INFINITE; } else { /* * Calculate timeout as milliseconds from current system time. */ milliseconds = ptw32_relmillisecs (abstime); } pthread_testcancel(); if ((result = pthread_mutex_lock (&s->lock)) == 0) { int v = --s->value; (void) pthread_mutex_unlock (&s->lock); if (v < 0) { #ifdef NEED_SEM int timedout; #endif sem_timedwait_cleanup_args_t cleanup_args; cleanup_args.sem = s; cleanup_args.resultPtr = &result; #ifdef _MSC_VER #pragma inline_depth(0) #endif /* Must wait */ pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args); #ifdef NEED_SEM timedout = #endif result = pthreadCancelableTimedWait (s->sem, milliseconds); pthread_cleanup_pop(result); #ifdef _MSC_VER #pragma inline_depth() #endif #ifdef NEED_SEM if (!timedout && pthread_mutex_lock (&s->lock) == 0) { 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_timedwait */
int pthread_timedjoin_np (pthread_t thread, void **value_ptr, const struct timespec *abstime) /* * ------------------------------------------------------ * DOCPUBLIC * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL or until 'abstime' passes and returns an * error. If 'abstime' is NULL then the function waits * forever, i.e. reverts to pthread_join behaviour. * This function detaches the thread on successful * completion. * * PARAMETERS * thread * an instance of pthread_t * * value_ptr * pointer to an instance of pointer to void * * abstime * pointer to an instance of struct timespec * representing an absolute time value * * * DESCRIPTION * This function waits for 'thread' to terminate and * returns the thread's exit value if 'value_ptr' is not * NULL or until 'abstime' passes and returns an * error. If 'abstime' is NULL then the function waits * forever, i.e. reverts to pthread_join behaviour. * This function detaches the thread on successful * completion. * NOTE: Detached threads cannot be joined or canceled. * In this implementation 'abstime' will be * resolved to the nearest millisecond. * * RESULTS * 0 'thread' has completed * ETIMEDOUT abstime passed * 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; DWORD milliseconds; ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; ptw32_mcs_local_node_t node; if (abstime == NULL) { milliseconds = INFINITE; } else { /* * Calculate timeout as milliseconds from current system time. */ milliseconds = ptw32_relmillisecs (abstime); } ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); if (NULL == tp || thread.x != tp->ptHandle.x) { result = ESRCH; } else if (PTHREAD_CREATE_DETACHED == tp->detachState) { result = EINVAL; } else { result = 0; } ptw32_mcs_lock_release(&node); 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 cancellation point. * If we are canceled then our target thread must not be * detached (destroyed). This is guaranteed because * pthreadCancelableTimedWait will not return if we * are canceled. */ result = pthreadCancelableTimedWait (tp->threadH, milliseconds); if (0 == result) { if (value_ptr != NULL) { *value_ptr = tp->exitStatus; } /* * The result of making multiple simultaneous calls to * pthread_join() or pthread_timedjoin_np() or pthread_detach() * specifying the same target is undefined. */ result = pthread_detach (thread); } else if (ETIMEDOUT != result) { result = ESRCH; } } } return (result); }