summaryrefslogtreecommitdiff
path: root/mit-pthreads/pthreads/pthread_cancel.c
diff options
context:
space:
mode:
Diffstat (limited to 'mit-pthreads/pthreads/pthread_cancel.c')
-rw-r--r--mit-pthreads/pthreads/pthread_cancel.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/mit-pthreads/pthreads/pthread_cancel.c b/mit-pthreads/pthreads/pthread_cancel.c
new file mode 100644
index 00000000000..4191a269027
--- /dev/null
+++ b/mit-pthreads/pthreads/pthread_cancel.c
@@ -0,0 +1,258 @@
+/* ==== pthread_cancel.c ====================================================
+ * Copyright (c) 1996 by Larry V. Streepy, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Larry V. Streepy, Jr.
+ * 4. The name of Larry V. Streepy, Jr. may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Larry V. Streepy, Jr. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Larry V. Streepy, Jr. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Description : pthread_cancel operations
+ *
+ * 27 Sep 1996 - Larry V. Streepy, Jr.
+ * - Initial coding
+ */
+#ifndef lint
+static const char rcsid[] = "$Id:";
+#endif
+#include <pthread.h>
+#include <errno.h>
+static void possiblyMakeRunnable( pthread_t pthread );
+
+/*----------------------------------------------------------------------
+ * Function: pthread_cancel
+ * Purpose: Allows a thread to request that it or another thread
+ * terminate execution
+ * Args:
+ * thread = thread to mark as cancelled
+ * Returns:
+ * int 0 = ok, -1 = some error (see errno)
+ * Notes:
+ * The thread is simply marked as CANCELLED, it is up to the cancelled
+ * thread to decide how to handle it.
+ *----------------------------------------------------------------------*/ int
+pthread_cancel( pthread_t pthread )
+{
+ int rtn = 0; /* Assume all ok */
+ pthread_sched_prevent();
+ /* Ensure they gave us a legal pthread pointer */
+ if( ! __pthread_is_valid( pthread ) ) {
+ rtn = ESRCH; /* No such thread */
+ } else if( pthread->state == PS_UNALLOCED || pthread->state == PS_DEAD ) {
+ /* The standard doesn't call these out as errors, so return 0 */
+ rtn = 0;
+ } else {
+ SET_PF_CANCELLED(pthread); /* Set the flag */
+ /* If the thread is in the right state, then stick it on the
+ * run queue so it will get a chance to process the cancel.
+ */
+ if( pthread != pthread_run ) {
+ possiblyMakeRunnable( pthread );
+ }
+ }
+ pthread_sched_resume();
+ if( rtn == 0 )
+ pthread_testcancel(); /* See if we cancelled ourself */
+ return rtn;
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_setcancelstate
+ * Purpose: Set the current thread's cancellability state
+ * Args:
+ * state = PTHREAD_CANCEL_DISABLE or PTHREAD_CANCEL_ENABLE
+ * oldstate= pointer to holder for old state or NULL (*MODIFIED*)
+ * Returns:
+ * int 0 = ok
+ * EINVAL = state is neither of the legal states
+ * Notes:
+ * This has to be async-cancel safe, so we prevent scheduling in
+ * here
+ *----------------------------------------------------------------------*/
+
+int
+pthread_setcancelstate( int newstate, int *oldstate )
+{
+ int ostate = TEST_PF_CANCEL_STATE(pthread_run);
+ int rtn = 0;
+ pthread_sched_prevent();
+ if( newstate == PTHREAD_CANCEL_ENABLE ||
+ newstate == PTHREAD_CANCEL_DISABLE ) {
+ SET_PF_CANCEL_STATE(pthread_run, newstate);
+ if( oldstate != NULL )
+ *oldstate = ostate;
+ } else { /* Invalid new state */
+ rtn = EINVAL;
+ }
+ pthread_sched_resume();
+ if( rtn == 0 ) {
+ /* Test to see if we have a pending cancel to handle */
+ pthread_testcancel();
+ }
+ return rtn;
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_setcanceltype
+ * Purpose: Set the current thread's cancellability type
+ * Args:
+ * type = PTHREAD_CANCEL_DEFERRED or PTHREAD_CANCEL_ASYNCHRONOUS
+ * oldtype = pointer to holder for old type or NULL (*MODIFIED*)
+ * Returns:
+ * int 0 = ok
+ * EINVAL = type is neither of the legal states
+ * Notes:
+ * This has to be async-cancel safe, so we prevent scheduling in
+ * here
+ *----------------------------------------------------------------------*/
+
+int
+pthread_setcanceltype( int newtype, int *oldtype )
+{
+ int otype = TEST_PF_CANCEL_TYPE(pthread_run);
+ int rtn = 0;
+ pthread_sched_prevent();
+ if( newtype == PTHREAD_CANCEL_DEFERRED ||
+ newtype == PTHREAD_CANCEL_ASYNCHRONOUS) {
+ SET_PF_CANCEL_TYPE(pthread_run, newtype);
+ if( oldtype != NULL )
+ *oldtype = otype;
+ } else { /* Invalid new type */
+ rtn = EINVAL;
+ }
+ pthread_sched_resume();
+ if( rtn == 0 ) {
+ /* Test to see if we have a pending cancel to handle */
+ pthread_testcancel();
+ }
+ return rtn;
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_testcancel
+ * Purpose: Requests delivery of a pending cancel to the current thread
+ * Args: void
+ * Returns: void
+ * Notes:
+ * If the current thread has been cancelled, this function will not
+ * return and the threads exit processing will be initiated.
+ *----------------------------------------------------------------------*/
+
+void
+pthread_testcancel( void )
+{
+ if( TEST_PF_CANCEL_STATE(pthread_run) == PTHREAD_CANCEL_DISABLE ) {
+ return; /* Can't be cancelled */
+ }
+ /* Ensure that we aren't in the process of exiting already */
+ if( TEST_PF_RUNNING_TO_CANCEL(pthread_run) )
+ return;
+
+ /* See if we have been cancelled */
+ if( TEST_PF_CANCELLED(pthread_run) ) {
+ /* Set this flag to avoid recursively calling pthread_exit */
+ SET_PF_RUNNING_TO_CANCEL(pthread_run);
+ pthread_exit( PTHREAD_CANCELLED ); /* Easy - just call pthread_exit */
+ }
+ return; /* Not cancelled */
+}
+
+/*----------------------------------------------------------------------
+ * Function: pthread_cancel_internal
+ * Purpose: An internal routine to begin the cancel processing
+ * Args: freelocks = do we need to free locks before exiting
+ * Returns: void
+ * Notes:
+ * This routine is called from pthread_resched_resume
+ * prior to a context switch, and after a thread has resumed.
+ *
+ * The kernel must *NOT* be locked on entry here
+ *----------------------------------------------------------------------*/
+
+void
+pthread_cancel_internal( int freelocks )
+{
+ pthread_sched_prevent(); /* gotta stay focused */
+ /* Since we can be called from pthread_resched_resume(), our
+ * state is currently not PS_RUNNING. Since we side stepped
+ * the actually blocking, we need to be removed from the queue
+ * and marked as running.
+ */
+ if( pthread_run->state != PS_RUNNING ) {
+ if( pthread_run->queue == NULL ) {
+ PANIC(); /* Must be on a queue */
+ }
+ /* We MUST NOT put the thread on the prio_queue here. It
+ * is already running (although it's state has changed) and if we
+ * put it on the run queue, it will get resumed after it is dead
+ * and we end up with a nice panic.
+ */
+ pthread_queue_remove(pthread_run->queue, pthread_run);
+ pthread_run->state = PS_RUNNING; /* we are running */
+ }
+ /* Set this flag to avoid recursively calling pthread_exit */
+ SET_PF_RUNNING_TO_CANCEL(pthread_run);
+ /* Free up any locks we hold if told to. */
+ if( freelocks ) {
+ fd_unlock_for_cancel();
+ }
+ pthread_sched_resume();
+ pthread_exit( PTHREAD_CANCELLED ); /* Easy - just call pthread_exit */
+}
+
+/*----------------------------------------------------------------------
+ * Function: possiblyMakeRunnable
+ * Purpose: Make a thread runnable so it can be cancelled if state allows
+ * Args:
+ * pthread = thread to process
+ * Returns:
+ * Notes:
+ *----------------------------------------------------------------------*/
+
+static void
+possiblyMakeRunnable( pthread_t pthread )
+{
+ if( ! TEST_PTHREAD_IS_CANCELLABLE(pthread) )
+ return; /* Not currently cancellable */
+ /* If the thread is currently runnable, then we just let things
+ * take their course when it is next resumed.
+ */
+ if( pthread->state == PS_RUNNING )
+ return; /* will happen at context switch */
+ /* If the thread is sleeping, the it isn't on a queue. */
+ if( pthread->state == PS_SLEEP_WAIT ) {
+ sleep_cancel( pthread ); /* Remove from sleep list */
+ } else {
+ /* Otherwise, we need to take it off the queue and make it runnable */
+ if( pthread->queue == NULL ) {
+ PANIC(); /* Must be on a queue */
+ }
+ pthread_queue_remove(pthread->queue, pthread);
+ }
+ /* And make it runnable */
+ pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
+ pthread->old_state = pthread->state;
+ pthread->state = PS_RUNNING;
+}