static void CALLBACK ptw32_cancel_callback (DWORD unused) { ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ }
static INLINE void ptw32_cancel_self(void) { ptw32_throw(PTW32_EPS_CANCEL); /* Never reached */ }
static void CALLBACK ptw32_cancel_callback (ULONG_PTR unused) { ptw32_throw (PTW32_EPS_CANCEL); }
static void ptw32_cancel_self (void) { ptw32_throw (PTW32_EPS_CANCEL); }
int pthread_setcanceltype (int type, int *oldtype) { ptw32_mcs_local_node_t stateLock; int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL || (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)) { return EINVAL; } ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (oldtype != NULL) { *oldtype = sp->cancelType; } sp->cancelType = type; if (sp->cancelState == PTHREAD_CANCEL_ENABLE && type == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); } ptw32_mcs_lock_release (&stateLock); return (result); }
int pthread_cancel (pthread_t thread) /* * ------------------------------------------------------ * DOCPUBLIC * This function requests cancellation of 'thread'. * * PARAMETERS * thread * reference to an instance of pthread_t * * * DESCRIPTION * This function requests cancellation of 'thread'. * NOTE: cancellation is asynchronous; use pthread_join to * wait for termination of 'thread' if necessary. * * RESULTS * 0 successfully requested cancellation, * ESRCH no thread found corresponding to 'thread', * ENOMEM implicit self thread create failed. * ------------------------------------------------------ */ { int result; int cancel_self; pthread_t self; ptw32_thread_t * tp; result = pthread_kill (thread, 0); if (0 != result) { return result; } if ((self = pthread_self ()).p == NULL) { return ENOMEM; }; /* * FIXME!! * * Can a thread cancel itself? * * The standard doesn't * specify an error to be returned if the target * thread is itself. * * If it may, then we need to ensure that a thread can't * deadlock itself trying to cancel itself asyncronously * (pthread_cancel is required to be an async-cancel * safe function). */ cancel_self = pthread_equal (thread, self); tp = (ptw32_thread_t *) thread.p; /* * Lock for async-cancel safety. */ (void) pthread_mutex_lock (&tp->cancelLock); if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && tp->cancelState == PTHREAD_CANCEL_ENABLE && tp->state < PThreadStateCanceling) { if (cancel_self) { tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&tp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } else { HANDLE threadH = tp->threadH; SuspendThread (threadH); if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) { tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; /* * If alertdrv and QueueUserAPCEx is available then the following * will result in a call to QueueUserAPCEx with the args given, otherwise * this will result in a call to ptw32_RegisterCancelation and only * the threadH arg will be used. */ ptw32_register_cancelation (ptw32_cancel_callback, threadH, 0); (void) pthread_mutex_unlock (&tp->cancelLock); //ResumeThread (threadH); } } } else { /* * Set for deferred cancellation. */ if (tp->state < PThreadStateCancelPending) { tp->state = PThreadStateCancelPending; if (!SetEvent (tp->cancelEvent)) { result = ESRCH; } } else if (tp->state >= PThreadStateCanceling) { result = ESRCH; } (void) pthread_mutex_unlock (&tp->cancelLock); } return (result); }
int pthread_cancel (pthread_t thread) /* * ------------------------------------------------------ * DOCPUBLIC * This function requests cancellation of 'thread'. * * PARAMETERS * thread * reference to an instance of pthread_t * * * DESCRIPTION * This function requests cancellation of 'thread'. * NOTE: cancellation is asynchronous; use pthread_join to * wait for termination of 'thread' if necessary. * * RESULTS * 0 successfully requested cancellation, * ESRCH no thread found corresponding to 'thread', * ENOMEM implicit self thread create failed. * ------------------------------------------------------ */ { int result; int cancel_self; pthread_t self; if (thread == NULL ) { return ESRCH; } result = 0; if ((self = pthread_self()) == NULL) { return ENOMEM; }; /* * FIXME!! * * Can a thread cancel itself? * * The standard doesn't * specify an error to be returned if the target * thread is itself. * * If it may, then we need to ensure that a thread can't * deadlock itself trying to cancel itself asyncronously * (pthread_cancel is required to be an async-cancel * safe function). */ cancel_self = pthread_equal(thread, self); /* * Lock for async-cancel safety. */ (void) pthread_mutex_lock(&thread->cancelLock); if (thread->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && thread->cancelState == PTHREAD_CANCEL_ENABLE && thread->state < PThreadStateCanceling ) { if (cancel_self) { thread->state = PThreadStateCanceling; thread->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock(&thread->cancelLock); ptw32_throw(PTW32_EPS_CANCEL); /* Never reached */ } else { HANDLE threadH = thread->threadH; SuspendThread(threadH); if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT ) { CONTEXT context; thread->state = PThreadStateCanceling; thread->cancelState = PTHREAD_CANCEL_DISABLE; context.ContextFlags = CONTEXT_CONTROL; GetThreadContext(threadH, &context); PTW32_PROGCTR(context) = (DWORD) ptw32_cancel_self; SetThreadContext(threadH, &context); (void) pthread_mutex_unlock(&thread->cancelLock); ResumeThread(threadH); } } } else { /* * Set for deferred cancellation. */ if ( thread->state >= PThreadStateCanceling || !SetEvent (thread->cancelEvent)) { result = ESRCH; } (void) pthread_mutex_unlock(&thread->cancelLock); } return (result); }
void pthread_exit (void *value_ptr) /* * ------------------------------------------------------ * DOCPUBLIC * This function terminates the calling thread, returning * the value 'value_ptr' to any joining thread. * * PARAMETERS * value_ptr * a generic data value (i.e. not the address of a value) * * * DESCRIPTION * This function terminates the calling thread, returning * the value 'value_ptr' to any joining thread. * NOTE: thread should be joinable. * * RESULTS * N/A * * ------------------------------------------------------ */ { ptw32_thread_t * sp; /* * Don't use pthread_self() to avoid creating an implicit POSIX thread handle * unnecessarily. */ sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); #ifdef _UWIN if (--pthread_count <= 0) exit ((int) value_ptr); #endif if (NULL == sp) { /* * A POSIX thread handle was never created. I.e. this is a * Win32 thread that has never called a pthreads-win32 routine that * required a POSIX handle. * * Implicit POSIX handles are cleaned up in ptw32_throw() now. */ #if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__) _endthreadex ((unsigned) value_ptr); #else _endthread (); #endif /* Never reached */ } sp->exitStatus = value_ptr; ptw32_throw (PTW32_EPS_EXIT); /* Never reached. */ }
static INLINE int ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) /* * ------------------------------------------------------------------- * This provides an extra hook into the pthread_cancel * mechanism that will allow you to wait on a Windows handle and make it a * cancellation point. This function blocks until the given WIN32 handle is * signaled or pthread_cancel has been called. It is implemented using * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32 * event used to implement pthread_cancel. * * Given this hook it would be possible to implement more of the cancellation * points. * ------------------------------------------------------------------- */ { int result; pthread_t self; ptw32_thread_t * sp; HANDLE handles[2]; DWORD nHandles = 1; DWORD status; handles[0] = waitHandle; self = pthread_self(); sp = (ptw32_thread_t *) to_internal(self).p; if (sp != NULL) { /* * Get cancelEvent handle */ if (sp->cancelState == PTHREAD_CANCEL_ENABLE) { if ((handles[1] = sp->cancelEvent) != NULL) { nHandles++; } } } else { handles[1] = NULL; } status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout); switch (status - WAIT_OBJECT_0) { case 0: /* * Got the handle. * In the event that both handles are signalled, the smallest index * value (us) is returned. As it has been arranged, this ensures that * we don't drop a signal that we should act on (i.e. semaphore, * mutex, or condition variable etc). */ result = 0; break; case 1: /* * Got cancel request. * In the event that both handles are signaled, the cancel will * be ignored (see case 0 comment). */ ResetEvent (handles[1]); if (sp != NULL) { ptw32_mcs_local_node_t stateLock; /* * Should handle POSIX and implicit POSIX threads.. * Make sure we haven't been async-canceled in the meantime. */ ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } ptw32_mcs_lock_release (&stateLock); } /* Should never get to here. */ result = EINVAL; break; default: if (status == WAIT_TIMEOUT) { result = ETIMEDOUT; } else { result = EINVAL; } break; } return (result); } /* CancelableWait */
/* * pthread_delay_np * * DESCRIPTION * * This routine causes a thread to delay execution for a specific period of time. * This period ends at the current time plus the specified interval. The routine * will not return before the end of the period is reached, but may return an * arbitrary amount of time after the period has gone by. This can be due to * system load, thread priorities, and system timer granularity. * * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is * allowed and can be used to force the thread to give up the processor or to * deliver a pending cancelation request. * * The timespec structure contains the following two fields: * * tv_sec is an integer number of seconds. * tv_nsec is an integer number of nanoseconds. * * Return Values * * If an error condition occurs, this routine returns an integer value indicating * the type of error. Possible return values are as follows: * * 0 * Successful completion. * [EINVAL] * The value specified by interval is invalid. * * Example * * The following code segment would wait for 5 and 1/2 seconds * * struct timespec tsWait; * int intRC; * * tsWait.tv_sec = 5; * tsWait.tv_nsec = 500000000L; * intRC = pthread_delay_np(&tsWait); */ int pthread_delay_np (struct timespec *interval) { DWORD wait_time; DWORD secs_in_millisecs; DWORD millisecs; DWORD status; pthread_t self; ptw32_thread_t * sp; if (interval == NULL) { return EINVAL; } if (interval->tv_sec == 0L && interval->tv_nsec == 0L) { pthread_testcancel (); Sleep (0); pthread_testcancel (); return (0); } /* convert secs to millisecs */ secs_in_millisecs = interval->tv_sec * 1000L; /* convert nanosecs to millisecs (rounding up) */ millisecs = (interval->tv_nsec + 999999L) / 1000000L; #if defined(__WATCOMC__) #pragma disable_message (124) #endif /* * Most compilers will issue a warning 'comparison always 0' * because the variable type is unsigned, but we need to keep this * for some reason I can't recall now. */ if (0 > (wait_time = secs_in_millisecs + millisecs)) { return EINVAL; } #if defined(__WATCOMC__) #pragma enable_message (124) #endif if (NULL == (self = pthread_self ()).p) { return ENOMEM; } sp = (ptw32_thread_t *) self.p; if (sp->cancelState == PTHREAD_CANCEL_ENABLE) { /* * Async cancelation won't catch us until wait_time is up. * Deferred cancelation will cancel us immediately. */ if (WAIT_OBJECT_0 == (status = WaitForSingleObject (sp->cancelEvent, wait_time))) { /* * Canceling! */ (void) pthread_mutex_lock (&sp->cancelLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); } (void) pthread_mutex_unlock (&sp->cancelLock); return ESRCH; } else if (status != WAIT_TIMEOUT) { return EINVAL; } } else { Sleep (wait_time); } return (0); }
void pthread_testcancel (void) /* * ------------------------------------------------------ * DOCPUBLIC * This function creates a deferred cancellation point * in the calling thread. The call has no effect if the * current cancelability state is * PTHREAD_CANCEL_DISABLE * * PARAMETERS * N/A * * * DESCRIPTION * This function creates a deferred cancellation point * in the calling thread. The call has no effect if the * current cancelability state is * PTHREAD_CANCEL_DISABLE * * NOTES: * 1) Cancellation is asynchronous. Use pthread_join * to wait for termination of thread if necessary * * RESULTS * N/A * * ------------------------------------------------------ */ { pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL) { return; } /* * Pthread_cancel() will have set sp->state to PThreadStateCancelPending * and set an event, so no need to enter kernel space if * sp->state != PThreadStateCancelPending - that only slows us down. */ if (sp->state != PThreadStateCancelPending) { return; } (void) pthread_mutex_lock (&sp->cancelLock); if (sp->cancelState != PTHREAD_CANCEL_DISABLE) { ResetEvent(sp->cancelEvent); sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; (void) pthread_mutex_unlock (&sp->cancelLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never returns here */ } (void) pthread_mutex_unlock (&sp->cancelLock); } /* pthread_testcancel */
int pthread_setcancelstate (int state, int *oldstate) /* * ------------------------------------------------------ * DOCPUBLIC * This function atomically sets the calling thread's * cancelability state to 'state' and returns the previous * cancelability state at the location referenced by * 'oldstate' * * PARAMETERS * state, * oldstate * PTHREAD_CANCEL_ENABLE * cancellation is enabled, * * PTHREAD_CANCEL_DISABLE * cancellation is disabled * * * DESCRIPTION * This function atomically sets the calling thread's * cancelability state to 'state' and returns the previous * cancelability state at the location referenced by * 'oldstate'. * * NOTES: * 1) Use to disable cancellation around 'atomic' code that * includes cancellation points * * COMPATIBILITY ADDITIONS * If 'oldstate' is NULL then the previous state is not returned * but the function still succeeds. (Solaris) * * RESULTS * 0 successfully set cancelability type, * EINVAL 'state' is invalid * * ------------------------------------------------------ */ { ptw32_mcs_local_node_t stateLock; int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)) { return EINVAL; } /* * Lock for async-cancel safety. */ ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (oldstate != NULL) { *oldstate = sp->cancelState; } sp->cancelState = state; /* * Check if there is a pending asynchronous cancel */ if (state == PTHREAD_CANCEL_ENABLE && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } ptw32_mcs_lock_release (&stateLock); return (result); } /* pthread_setcancelstate */
int pthread_cancel (pthread_t thread) { int result; int cancel_self; pthread_t self; ptw32_thread_t * tp; ptw32_mcs_local_node_t stateLock; result = pthread_kill (thread, 0); if (0 != result) { return result; } if ((self = pthread_self ()).p == NULL) { return ENOMEM; }; cancel_self = pthread_equal (thread, self); tp = (ptw32_thread_t *) thread.p; ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock); if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS && tp->cancelState == PTHREAD_CANCEL_ENABLE && tp->state < PThreadStateCanceling) { if (cancel_self) { tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); } else { HANDLE threadH = tp->threadH; SuspendThread (threadH); if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) { tp->state = PThreadStateCanceling; tp->cancelState = PTHREAD_CANCEL_DISABLE; ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0); ptw32_mcs_lock_release (&stateLock); ResumeThread (threadH); } } } else { if (tp->state < PThreadStateCancelPending) { tp->state = PThreadStateCancelPending; if (!SetEvent (tp->cancelEvent)) { result = ESRCH; } } else if (tp->state >= PThreadStateCanceling) { result = ESRCH; } ptw32_mcs_lock_release (&stateLock); } return (result); }
int pthread_setcanceltype (int type, int *oldtype) /* * ------------------------------------------------------ * DOCPUBLIC * This function atomically sets the calling thread's * cancelability type to 'type' and returns the previous * cancelability type at the location referenced by * 'oldtype' * * PARAMETERS * type, * oldtype * PTHREAD_CANCEL_DEFERRED * only deferred cancelation is allowed, * * PTHREAD_CANCEL_ASYNCHRONOUS * Asynchronous cancellation is allowed * * * DESCRIPTION * This function atomically sets the calling thread's * cancelability type to 'type' and returns the previous * cancelability type at the location referenced by * 'oldtype' * * NOTES: * 1) Use with caution; most code is not safe for use * with asynchronous cancelability. * * COMPATIBILITY ADDITIONS * If 'oldtype' is NULL then the previous type is not returned * but the function still succeeds. (Solaris) * * RESULTS * 0 successfully set cancelability type, * EINVAL 'type' is invalid * * ------------------------------------------------------ */ { ptw32_mcs_local_node_t stateLock; int result = 0; pthread_t self = pthread_self (); ptw32_thread_t * sp = (ptw32_thread_t *) self.p; if (sp == NULL || (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS)) { return EINVAL; } /* * Lock for async-cancel safety. */ ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (oldtype != NULL) { *oldtype = sp->cancelType; } sp->cancelType = type; /* * Check if there is a pending asynchronous cancel */ if (sp->cancelState == PTHREAD_CANCEL_ENABLE && type == PTHREAD_CANCEL_ASYNCHRONOUS && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ResetEvent (sp->cancelEvent); ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); /* Never reached */ } ptw32_mcs_lock_release (&stateLock); return (result); } /* pthread_setcanceltype */
int pthread_delay_np (struct timespec *interval) { DWORD wait_time; DWORD secs_in_millisecs; DWORD millisecs; DWORD status; pthread_t self; ptw32_thread_t * sp; if (interval == NULL) { return EINVAL; } if (interval->tv_sec == 0L && interval->tv_nsec == 0L) { pthread_testcancel (); Sleep (0); pthread_testcancel (); return (0); } secs_in_millisecs = (DWORD)interval->tv_sec * 1000L; millisecs = (interval->tv_nsec + 999999L) / 1000000L; #if defined(__WATCOMC__) #pragma disable_message (124) #endif if (0 > (wait_time = secs_in_millisecs + millisecs)) { return EINVAL; } #if defined(__WATCOMC__) #pragma enable_message (124) #endif if (NULL == (self = pthread_self ()).p) { return ENOMEM; } sp = (ptw32_thread_t *) self.p; if (sp->cancelState == PTHREAD_CANCEL_ENABLE) { if (WAIT_OBJECT_0 == (status = WaitForSingleObject (sp->cancelEvent, wait_time))) { ptw32_mcs_local_node_t stateLock; ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); if (sp->state < PThreadStateCanceling) { sp->state = PThreadStateCanceling; sp->cancelState = PTHREAD_CANCEL_DISABLE; ptw32_mcs_lock_release (&stateLock); ptw32_throw (PTW32_EPS_CANCEL); } ptw32_mcs_lock_release (&stateLock); return ESRCH; } else if (status != WAIT_TIMEOUT) { return EINVAL; } } else { Sleep (wait_time); } return (0); }