summaryrefslogtreecommitdiff
path: root/cancel.c
diff options
context:
space:
mode:
authorrpj <rpj>2000-01-04 10:19:28 +0000
committerrpj <rpj>2000-01-04 10:19:28 +0000
commita378d97dc9d9eadaef00a9f01816948db5f3a796 (patch)
tree654435cc0a85156c2a9b4793ab7d8e0da8424e32 /cancel.c
parent27d833666dfd72cc6e74c3900d3e8e66321bea3a (diff)
Main changes (see ChangeLog diff for details and attributions):-
- asynchronous cancellation added - attempt to hide internal exceptions from applications - kernel32 load/free problem fixed - new tests - changes only to comments in some tests
Diffstat (limited to 'cancel.c')
-rw-r--r--cancel.c254
1 files changed, 188 insertions, 66 deletions
diff --git a/cancel.c b/cancel.c
index a5d923d..b687c78 100644
--- a/cancel.c
+++ b/cancel.c
@@ -26,6 +26,64 @@
#include "pthread.h"
#include "implement.h"
+
+static void
+_pthread_cancel_self(void)
+{
+#ifdef _MSC_VER
+
+ DWORD exceptionInformation[3];
+
+ exceptionInformation[0] = (DWORD) (_PTHREAD_EPS_CANCEL);
+ exceptionInformation[1] = (DWORD) (0);
+ exceptionInformation[2] = (DWORD) (0);
+
+ RaiseException (
+ EXCEPTION_PTHREAD_SERVICES,
+ 0,
+ 3,
+ exceptionInformation);
+
+#else /* _MSC_VER */
+
+# ifdef __cplusplus
+
+ throw Pthread_exception_cancel();
+
+# endif /* __cplusplus */
+
+#endif /* _MSC_VER */
+
+ /* Never reached */
+}
+
+
+/*
+ * _pthread_cancel_thread implements asynchronous cancellation.
+ */
+static void
+_pthread_cancel_thread(pthread_t thread)
+{
+ HANDLE threadH = thread->threadH;
+
+ (void) pthread_mutex_lock(&thread->cancelLock);
+
+ SuspendThread(threadH);
+
+ if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT)
+ {
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_CONTROL;
+ GetThreadContext(threadH, &context);
+ context.Eip = (DWORD) _pthread_cancel_self;
+ SetThreadContext(threadH, &context);
+ ResumeThread(threadH);
+ }
+
+ (void) pthread_mutex_unlock(&thread->cancelLock);
+}
+
+
int
pthread_setcancelstate (int state, int *oldstate)
/*
@@ -37,8 +95,8 @@ pthread_setcancelstate (int state, int *oldstate)
* 'oldstate'
*
* PARAMETERS
- * type,
- * oldtype
+ * state,
+ * oldstate
* PTHREAD_CANCEL_ENABLE
* cancellation is enabled,
*
@@ -67,28 +125,44 @@ pthread_setcancelstate (int state, int *oldstate)
* ------------------------------------------------------
*/
{
- pthread_t self;
- int result;
+ int result = 0;
+ pthread_t self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey);
- if (((self = pthread_self ()) != NULL) &&
- (state == PTHREAD_CANCEL_ENABLE ||
- state == PTHREAD_CANCEL_DISABLE))
+ if (self == NULL
+ || (state != PTHREAD_CANCEL_ENABLE
+ && state != PTHREAD_CANCEL_DISABLE))
{
+ return EINVAL;
+ }
- if (oldstate != NULL)
- {
- *oldstate = self->cancelState;
- }
-
- self->cancelState = state;
- result = 0;
+ /*
+ * Lock for async-cancel safety.
+ */
+ (void) pthread_mutex_lock(&self->cancelLock);
+ if (oldstate != NULL)
+ {
+ *oldstate = self->cancelState;
}
- else
+
+ self->cancelState = state;
+
+ /*
+ * Check if there is a pending asynchronous cancel
+ */
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE
+ && self->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
+ && WaitForSingleObject(self->cancelEvent, 0) == WAIT_OBJECT_0)
{
- result = EINVAL;
+ ResetEvent(self->cancelEvent);
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ _pthread_cancel_self();
+
+ /* Never reached */
}
+ (void) pthread_mutex_unlock(&self->cancelLock);
+
return (result);
} /* pthread_setcancelstate */
@@ -135,28 +209,44 @@ pthread_setcanceltype (int type, int *oldtype)
* ------------------------------------------------------
*/
{
- pthread_t self;
- int result;
+ int result = 0;
+ pthread_t self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey);
- if (((self = pthread_self ()) != NULL) &&
- (type == PTHREAD_CANCEL_DEFERRED ||
- type == PTHREAD_CANCEL_ASYNCHRONOUS))
+ if (self == NULL
+ || (type != PTHREAD_CANCEL_DEFERRED
+ && type != PTHREAD_CANCEL_ASYNCHRONOUS))
{
+ return EINVAL;
+ }
- if (oldtype != NULL)
- {
- *oldtype = self->cancelType;
- }
-
- self->cancelType = type;
- result = 0;
+ /*
+ * Lock for async-cancel safety.
+ */
+ (void) pthread_mutex_lock(&self->cancelLock);
+ if (oldtype != NULL)
+ {
+ *oldtype = self->cancelType;
}
- else
+
+ self->cancelType = type;
+
+ /*
+ * Check if there is a pending asynchronous cancel
+ */
+ if (self->cancelState == PTHREAD_CANCEL_ENABLE
+ && self->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
+ && WaitForSingleObject(self->cancelEvent, 0) == WAIT_OBJECT_0)
{
- result = EINVAL;
+ ResetEvent(self->cancelEvent);
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ _pthread_cancel_self();
+
+ /* Never reached */
}
+ (void) pthread_mutex_unlock(&self->cancelLock);
+
return (result);
} /* pthread_setcanceltype */
@@ -191,50 +281,42 @@ pthread_testcancel (void)
* ------------------------------------------------------
*/
{
- pthread_t self;
+ pthread_t self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey);
- if ((self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey))
- != NULL)
+ if (self != NULL
+ && self->cancelState == PTHREAD_CANCEL_ENABLE
+ && WaitForSingleObject (self->cancelEvent, 0) == WAIT_OBJECT_0
+ )
{
-
- if (self->cancelState == PTHREAD_CANCEL_ENABLE)
- {
-
- if (WaitForSingleObject (self->cancelEvent, 0) ==
- WAIT_OBJECT_0)
- {
- /*
- * Canceling!
- */
+ /*
+ * Canceling!
+ */
#ifdef _MSC_VER
- DWORD exceptionInformation[3];
+ DWORD exceptionInformation[3];
- exceptionInformation[0] = (DWORD) (_PTHREAD_EPS_CANCEL);
- exceptionInformation[1] = (DWORD) (0);
- exceptionInformation[2] = (DWORD) (0);
+ exceptionInformation[0] = (DWORD) (_PTHREAD_EPS_CANCEL);
+ exceptionInformation[1] = (DWORD) (0);
+ exceptionInformation[2] = (DWORD) (0);
- RaiseException (
- EXCEPTION_PTHREAD_SERVICES,
- 0,
- 3,
- exceptionInformation);
+ RaiseException (
+ EXCEPTION_PTHREAD_SERVICES,
+ 0,
+ 3,
+ exceptionInformation);
#else /* _MSC_VER */
#ifdef __cplusplus
- throw Pthread_exception_cancel();
+ throw Pthread_exception_cancel();
#endif /* __cplusplus */
#endif /* _MSC_VER */
- }
- }
}
-
} /* pthread_testcancel */
int
@@ -262,8 +344,52 @@ pthread_cancel (pthread_t thread)
*/
{
int result;
+ int cancel_self;
+ pthread_t self;
+
+ if (thread == NULL )
+ {
+ return ESRCH;
+ }
- if (thread != NULL)
+ result = 0;
+ self = (pthread_t) pthread_getspecific (_pthread_selfThreadKey);
+
+ /*
+ * 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(&self->cancelLock);
+
+ if (thread->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS
+ && thread->cancelState == PTHREAD_CANCEL_ENABLE )
+ {
+ if (cancel_self)
+ {
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ _pthread_cancel_self();
+
+ /* Never reached */
+ }
+
+ _pthread_cancel_thread(thread);
+ }
+ else
{
/*
* Set for deferred cancellation.
@@ -272,17 +398,13 @@ pthread_cancel (pthread_t thread)
{
result = ESRCH;
}
- else
- {
- result = 0;
- }
-
- }
- else
- {
- result = ESRCH;
}
+ (void) pthread_mutex_unlock(&self->cancelLock);
+
return (result);
+
}
+
+