pthread_cancel.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* ==== pthread_cancel.c ====================================================
  2.  * Copyright (c) 1996 by Larry V. Streepy, Jr.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *  This product includes software developed by Larry V. Streepy, Jr.
  16.  * 4. The name of Larry V. Streepy, Jr. may not be used to endorse or promote 
  17.  *   products derived from this software without specific prior written
  18.  *   permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY Larry V. Streepy, Jr. ``AS IS'' AND
  21.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED.  IN NO EVENT SHALL Larry V. Streepy, Jr. BE LIABLE FOR ANY 
  24.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  26.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  28.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  30.  * SUCH DAMAGE.
  31.  *
  32.  * Description : pthread_cancel operations
  33.  *
  34.  * 27 Sep 1996 - Larry V. Streepy, Jr.
  35.  *      - Initial coding
  36.  */
  37. #ifndef lint  
  38. static const char rcsid[] = "$Id:";
  39. #endif
  40. #include <pthread.h>
  41. #include <errno.h>
  42. static void possiblyMakeRunnable( pthread_t pthread );
  43. /*----------------------------------------------------------------------
  44.  * Function: pthread_cancel
  45.  * Purpose: Allows a thread to request that it or another thread
  46.  * terminate execution
  47.  * Args:
  48.  * thread = thread to mark as cancelled
  49.  * Returns:
  50.  * int 0 = ok, -1 = some error (see errno)
  51.  * Notes:
  52.  * The thread is simply marked as CANCELLED, it is up to the cancelled
  53.  * thread to decide how to handle it.
  54.  *----------------------------------------------------------------------*/  int  
  55. pthread_cancel( pthread_t pthread )
  56. {
  57.   int rtn = 0; /* Assume all ok */
  58.   pthread_sched_prevent();
  59.   /* Ensure they gave us a legal pthread pointer */
  60.   if( ! __pthread_is_valid( pthread ) ) {
  61.     rtn = ESRCH; /* No such thread */
  62.   } else if( pthread->state == PS_UNALLOCED || pthread->state == PS_DEAD ) {
  63.     /* The standard doesn't call these out as errors, so return 0 */
  64.     rtn = 0;
  65.   } else {
  66.     SET_PF_CANCELLED(pthread); /* Set the flag */
  67.     /* If the thread is in the right state, then stick it on the
  68.      * run queue so it will get a chance to process the cancel.
  69.      */
  70.     if( pthread != pthread_run ) {
  71.       possiblyMakeRunnable( pthread );
  72.     }
  73.   }
  74.   pthread_sched_resume();
  75.   if( rtn == 0 )
  76.     pthread_testcancel(); /* See if we cancelled ourself */
  77.   return rtn;
  78. }
  79. /*----------------------------------------------------------------------
  80.  * Function: pthread_setcancelstate
  81.  * Purpose: Set the current thread's cancellability state
  82.  * Args:
  83.  * state = PTHREAD_CANCEL_DISABLE or PTHREAD_CANCEL_ENABLE
  84.  * oldstate= pointer to holder for old state or NULL (*MODIFIED*)
  85.  * Returns:
  86.  * int 0        = ok
  87.  * EINVAL   = state is neither of the legal states
  88.  * Notes:
  89.  * This has to be async-cancel safe, so we prevent scheduling in
  90.  * here
  91.  *----------------------------------------------------------------------*/
  92. int  
  93. pthread_setcancelstate( int newstate, int *oldstate )
  94. {
  95.   int ostate = TEST_PF_CANCEL_STATE(pthread_run);
  96.   int rtn = 0;
  97.   pthread_sched_prevent();
  98.   if( newstate == PTHREAD_CANCEL_ENABLE ||
  99.       newstate == PTHREAD_CANCEL_DISABLE ) {
  100.     SET_PF_CANCEL_STATE(pthread_run, newstate);
  101.     if( oldstate != NULL )
  102.       *oldstate = ostate;
  103.   } else { /* Invalid new state */
  104.     rtn = EINVAL;
  105.   }
  106.   pthread_sched_resume();
  107.   if( rtn == 0 ) {
  108.     /* Test to see if we have a pending cancel to handle */
  109.     pthread_testcancel();
  110.   }
  111.   return rtn;
  112. }
  113. /*----------------------------------------------------------------------
  114.  * Function: pthread_setcanceltype
  115.  * Purpose: Set the current thread's cancellability type
  116.  * Args:
  117.  * type = PTHREAD_CANCEL_DEFERRED or PTHREAD_CANCEL_ASYNCHRONOUS
  118.  * oldtype = pointer to holder for old type or NULL (*MODIFIED*)
  119.  * Returns:
  120.  * int 0        = ok
  121.  * EINVAL   = type is neither of the legal states
  122.  * Notes:
  123.  * This has to be async-cancel safe, so we prevent scheduling in
  124.  *  here
  125.  *----------------------------------------------------------------------*/
  126. int  
  127. pthread_setcanceltype( int newtype, int *oldtype )
  128. {
  129.   int otype = TEST_PF_CANCEL_TYPE(pthread_run);
  130.   int rtn = 0;
  131.   pthread_sched_prevent();
  132.   if( newtype == PTHREAD_CANCEL_DEFERRED ||
  133.       newtype == PTHREAD_CANCEL_ASYNCHRONOUS) {
  134.     SET_PF_CANCEL_TYPE(pthread_run, newtype);
  135.     if( oldtype != NULL )
  136.       *oldtype = otype;
  137.   } else { /* Invalid new type */
  138.     rtn = EINVAL;
  139.   }
  140.   pthread_sched_resume();
  141.   if( rtn == 0 ) {
  142.     /* Test to see if we have a pending cancel to handle */
  143.     pthread_testcancel();
  144.   }
  145.   return rtn;
  146. }
  147. /*----------------------------------------------------------------------
  148.  * Function: pthread_testcancel
  149.  * Purpose: Requests delivery of a pending cancel to the current thread
  150.  * Args: void
  151.  * Returns: void
  152.  * Notes:
  153.  * If the current thread has been cancelled, this function will not
  154.  * return and the threads exit processing will be initiated.
  155.  *----------------------------------------------------------------------*/
  156. void
  157. pthread_testcancel( void )
  158. {
  159.   if(  TEST_PF_CANCEL_STATE(pthread_run) == PTHREAD_CANCEL_DISABLE ) {
  160.     return; /* Can't be cancelled */
  161.   }
  162.   /* Ensure that we aren't in the process of exiting already */
  163.   if( TEST_PF_RUNNING_TO_CANCEL(pthread_run) )
  164.     return;
  165.   /* See if we have been cancelled */
  166.   if( TEST_PF_CANCELLED(pthread_run) ) {
  167.     /* Set this flag to avoid recursively calling pthread_exit */
  168.     SET_PF_RUNNING_TO_CANCEL(pthread_run);
  169.     pthread_exit( PTHREAD_CANCELLED ); /* Easy - just call pthread_exit */
  170.   }
  171.   return; /* Not cancelled */
  172. }
  173. /*----------------------------------------------------------------------
  174.  * Function: pthread_cancel_internal
  175.  * Purpose: An internal routine to begin the cancel processing
  176.  * Args: freelocks = do we need to free locks before exiting
  177.  * Returns: void
  178.  * Notes:
  179.  * This routine is called from pthread_resched_resume
  180.  * prior to a context switch, and after a thread has resumed.
  181.  *
  182.  * The kernel must *NOT* be locked on entry here
  183.  *----------------------------------------------------------------------*/
  184. void  
  185. pthread_cancel_internal( int freelocks )
  186. {
  187.   pthread_sched_prevent(); /* gotta stay focused */
  188.   /* Since we can be called from pthread_resched_resume(), our
  189.    * state is currently not PS_RUNNING.  Since we side stepped
  190.    * the actually blocking, we need to be removed from the queue
  191.    * and marked as running.
  192.    */
  193.   if( pthread_run->state != PS_RUNNING ) {
  194.     if( pthread_run->queue == NULL ) {
  195.       PANIC(); /* Must be on a queue */
  196.     }
  197.     /* We MUST NOT put the thread on the prio_queue here.  It
  198.      * is already running (although it's state has changed) and if we
  199.      * put it on the run queue, it will get resumed after it is dead
  200.      * and we end up with a nice panic.
  201.      */
  202.     pthread_queue_remove(pthread_run->queue, pthread_run);
  203.     pthread_run->state = PS_RUNNING; /* we are running */
  204.   }
  205.   /* Set this flag to avoid recursively calling pthread_exit */
  206.   SET_PF_RUNNING_TO_CANCEL(pthread_run);
  207.   /* Free up any locks we hold if told to. */
  208.   if( freelocks ) {
  209.     fd_unlock_for_cancel();
  210.   }
  211.   pthread_sched_resume();
  212.   pthread_exit( PTHREAD_CANCELLED ); /* Easy - just call pthread_exit */
  213. }
  214. /*----------------------------------------------------------------------
  215.  * Function: possiblyMakeRunnable
  216.  * Purpose: Make a thread runnable so it can be cancelled if state allows
  217.  * Args:
  218.  * pthread = thread to process
  219.  * Returns:
  220.  * Notes:
  221.  *----------------------------------------------------------------------*/
  222. static void  
  223. possiblyMakeRunnable( pthread_t pthread )
  224. {
  225.   if( ! TEST_PTHREAD_IS_CANCELLABLE(pthread) )
  226.     return; /* Not currently cancellable */
  227.   /* If the thread is currently runnable, then we just let things
  228.    * take their course when it is next resumed.
  229.    */
  230.   if( pthread->state == PS_RUNNING )
  231.     return; /* will happen at context switch */
  232.   /* If the thread is sleeping, the it isn't on a queue. */
  233.   if( pthread->state == PS_SLEEP_WAIT ) {
  234.     sleep_cancel( pthread );                /* Remove from sleep list */
  235.   } else {
  236.     /* Otherwise, we need to take it off the queue and make it runnable */
  237.     if( pthread->queue == NULL ) {
  238.       PANIC(); /* Must be on a queue */
  239.     }
  240.     pthread_queue_remove(pthread->queue, pthread);
  241.   }
  242.   /* And make it runnable */
  243.   pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
  244.   pthread->old_state = pthread->state;
  245.   pthread->state = PS_RUNNING;
  246. }