home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / threads / src / cond.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  390 lines

  1. /* Copyright (C) 1992, the Florida State University
  2.    Distributed by the Florida State University under the terms of the
  3.    GNU Library General Public License.
  4.  
  5. This file is part of Pthreads.
  6.  
  7. Pthreads is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public
  9. License as published by the Free Software Foundation (version 2).
  10.  
  11. Pthreads is distributed "AS IS" in the hope that it will be
  12. useful, but WITHOUT ANY WARRANTY; without even the implied
  13. warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. See the GNU Library General Public License for more details.
  15.  
  16. You should have received a copy of the GNU Library General Public
  17. License along with Pthreads; see the file COPYING.  If not, write
  18. to the Free Software Foundation, 675 Mass Ave, Cambridge,
  19. MA 02139, USA.
  20.  
  21. Report problems and direct all questions to:
  22.  
  23.   pthreads-bugs@ada.cs.fsu.edu
  24.  
  25.   @(#)cond.c    2.5 4/12/95
  26.  
  27. */
  28.  
  29. /*
  30.  * Functions supporting condition variables and their attributes. 
  31.  * Condition variables block the q that the thread is running on by waiting
  32.  * for an event.
  33.  */
  34.  
  35. #include "pthread_internals.h"
  36. #ifdef NOERR_CHECK
  37. #undef NOERR_CHECK
  38. #include "mutex.h"
  39. #define NOERR_CHECK
  40. #else
  41. #include "mutex.h"
  42. #endif
  43.  
  44. /*------------------------------------------------------------*/
  45. /*
  46.  * pthread_cond_destroy - Destroys the condition variable.
  47.  * 
  48.  */
  49. int pthread_cond_destroy(cond) 
  50. pthread_cond_t *cond;
  51. {
  52.   if (cond == NO_COND) {
  53.     set_errno(EINVAL);
  54.     return(-1);
  55.   }
  56.  
  57.   /*
  58.    *   Check to see if anyone is one the queue waiting to be signalled
  59.    *   If so we return an error.
  60.    */
  61.   
  62.   if (cond->waiters) {
  63.     set_errno(EBUSY);
  64.     return(-1);
  65.   }
  66.  
  67.   /*
  68.    * No one is waiting. Make the condition structure invalid
  69.    * so future calls with this handle fail and then unlock it.
  70.    */
  71.   cond->flags = FALSE;
  72.   cond = NO_COND;
  73.   return(0);
  74.  
  75. }
  76.  
  77. /*------------------------------------------------------------*/
  78. /*
  79.  * pthread_cond_init - Initializes the condition variable referred
  80.  * by cond with attributes specified by attr. If attr is NULL, 
  81.  * default values are used.
  82.  */
  83. int pthread_cond_init(cond, attr)
  84.      pthread_cond_t *cond;
  85.      pthread_condattr_t *attr;
  86. {
  87.   if (cond == NO_COND) {
  88.     set_errno(EINVAL);
  89.     return(-1);
  90.   }
  91.  
  92.   if (!attr) 
  93.     attr = &pthread_condattr_default;
  94.  
  95.   cond->flags = attr->flags;
  96.   cond->waiters = 0;
  97.   cond->mutex = NO_MUTEX;
  98.   pthread_queue_init(&cond->queue);
  99.   return(0);
  100. }
  101.  
  102. /*------------------------------------------------------------*/
  103. /*
  104.  * pthread_condattr_init - Initializes a condition attributes
  105.  * object with the default values.
  106.  *
  107.  */
  108. int pthread_condattr_init(attr)
  109. pthread_condattr_t *attr;
  110. {
  111.   if (!attr) {
  112.     set_errno(EINVAL);
  113.     return(-1);
  114.   }
  115.  
  116.   attr->flags = TRUE;
  117.   return(0);
  118. }
  119.  
  120. /*------------------------------------------------------------*/
  121. /*
  122.  * pthread_condattr_destroy - Destoys a condition attribute object.
  123.  */
  124. int pthread_condattr_destroy(attr)
  125. pthread_condattr_t *attr;
  126. {
  127.   if (!attr || !attr->flags) {
  128.     set_errno(EINVAL);
  129.     return(-1);
  130.   }
  131.   attr->flags = FALSE;
  132.   return(0);
  133. }
  134.  
  135. /*------------------------------------------------------------*/
  136. /*
  137.  * pthread_cond_wait - Atomically releases the mutex and causes the 
  138.  * thread to block on condition variable cond. The thread is taken 
  139.  * off the thread queues and queued onto condition variable with the 
  140.  * state changed to indicate the wait. The thread is then blocked 
  141.  * waiting for an event. This will be a signal event meaning that the 
  142.  * condition has been signalled or broadcast.  If it was signalled 
  143.  * the thread has already been reactivated and so the mutex is reaquired 
  144.  * and return.
  145.  */
  146. int pthread_cond_wait(cond, mutex)
  147. pthread_cond_t *cond;
  148. pthread_mutex_t *mutex;
  149. {
  150.   register pthread_t p = mac_pthread_self();
  151.   
  152.   if (cond == NO_COND || mutex == NO_MUTEX ||
  153.       (cond->mutex != mutex && cond->mutex != NO_MUTEX) ||
  154.       !(mutex->lock) || mutex->owner != p) {
  155.     set_errno(EINVAL);
  156.     return(-1);
  157.   }
  158.  
  159.   SET_KERNEL_FLAG;
  160.  
  161.   /*
  162.    * clear error number before suspending
  163.    */
  164.   set_errno(0);
  165.  
  166.   cond->mutex = mutex;
  167.   cond->waiters++;
  168.   p->cond = cond;
  169.  
  170.   mac_mutex_unlock(mutex, p, pthread_q_sleep(&cond->queue, PRIMARY_QUEUE));
  171.   p->state |= T_INTR_POINT;
  172.   if (sigismember(&p->pending, SIGCANCEL) &&
  173.       !sigismember(&p->mask, SIGCANCEL))
  174.     SIG_CLEAR_KERNEL_FLAG(TRUE);
  175.   else {
  176.     SIM_SYSCALL(TRUE);
  177.     CLEAR_KERNEL_FLAG;
  178.   }
  179.  
  180.   /*
  181.    * relock the mutex under contention, but only if it was not already
  182.    * locked as a side-effect of executing an signal handler and thereby
  183.    * pthread_cond_wait_terminate(). Notice that locking the mutex before
  184.    * executing the signal handler is a feature not required by the standard.
  185.    */
  186.   SET_KERNEL_FLAG;
  187.   SIM_SYSCALL(mutex->lock);
  188.   if (mutex->owner != p) {
  189.     mac_mutex_lock(mutex, p);
  190.     if (!--p->cond->waiters)
  191.       cond->mutex = NO_MUTEX;
  192.     p->cond = NO_COND;
  193.   }
  194.   CLEAR_KERNEL_FLAG;
  195.  
  196.   if (get_errno())
  197.     return(-1);
  198.  
  199.   return(0);
  200. }
  201.  
  202. /*------------------------------------------------------------*/
  203. /*
  204.  * pthread_cond_timedwait - This function works in the same way as 
  205.  * pthread_cond_wait with the exception of the added complexity of
  206.  * the timeout. The timeout is delivered as a timeout event. If the
  207.  * timeout happened then the thread is put back on the active queue.
  208.  */
  209. int pthread_cond_timedwait(cond, mutex, timeout)
  210. pthread_cond_t *cond;
  211. pthread_mutex_t *mutex;
  212. struct timespec *timeout;
  213. {
  214.   register pthread_t p = mac_pthread_self();
  215.  
  216.   if (cond == NO_COND || mutex == NO_MUTEX ||
  217.       (cond->mutex != mutex && cond->mutex != NO_MUTEX) ||
  218.       !(mutex->lock) || mutex->owner != p) {
  219.     set_errno(EINVAL);
  220.     return(-1);
  221.   }
  222.  
  223.   SET_KERNEL_FLAG;
  224.   if (pthread_timed_sigwait(p, timeout, ABS_TIME, NULL, p) == -1) {
  225.     CLEAR_KERNEL_FLAG;
  226.     return(-1);
  227.   }
  228.  
  229.   /*
  230.    * clear error number before suspending
  231.    */
  232.   set_errno(0);
  233.  
  234.   cond->mutex = mutex;
  235.   cond->waiters++;
  236.   p->cond = cond;
  237.  
  238.   mac_mutex_unlock(mutex, p, pthread_q_sleep(&cond->queue, PRIMARY_QUEUE));
  239.   p->state |= T_CONDTIMER | T_SYNCTIMER | T_INTR_POINT;
  240.   if (sigismember(&p->pending, SIGCANCEL) &&
  241.       !sigismember(&p->mask, SIGCANCEL))
  242.     SIG_CLEAR_KERNEL_FLAG(TRUE);
  243.   else {
  244.     SIM_SYSCALL(TRUE);
  245.     CLEAR_KERNEL_FLAG;
  246.   }
  247.  
  248.   /*
  249.    * relock the mutex under contention, but only if it was not already
  250.    * locked as a side-effect of executing an signal handler and thereby
  251.    * pthread_cond_wait_terminate(). Notice that locking the mutex before
  252.    * executing the signal handler is a feature not required by the standard.
  253.    */
  254.   SET_KERNEL_FLAG;
  255.   SIM_SYSCALL(mutex->lock);
  256.   if (mutex->owner != p) {
  257.     mac_mutex_lock(mutex, p);
  258.     if (!--p->cond->waiters)
  259.       cond->mutex = NO_MUTEX;
  260.     p->cond = NO_COND;
  261.   }
  262.   CLEAR_KERNEL_FLAG;
  263.  
  264.   if (get_errno())
  265.     return(-1);
  266.  
  267.   return(0);
  268. }
  269.  
  270. /*------------------------------------------------------------*/
  271. /*
  272.  * pthread_cond_wait_terminate - terminate conditional wait prematurely,
  273.  * relocks the mutex and disassociates the condition variable
  274.  * (used when signal received while in conditional wait)
  275.  * Notice: This is a feature. Pthreads does not require that the mutex be
  276.  * locked inside a user signal handler when a signal interrupts
  277.  * pthread_cond_wait().
  278.  * assumes SET_KERNEL_FLAG for C_CONTEXT_SWITCH
  279.  */
  280. void pthread_cond_wait_terminate()
  281. {
  282.   pthread_t p = mac_pthread_self();
  283.  
  284. #ifndef C_CONTEXT_SWITCH
  285.   SET_KERNEL_FLAG;
  286. #endif
  287.   /*
  288.    * done only once by innermost user handler if handlers are nested
  289.    * cond must therefore be retrieved out of TCB
  290.    */
  291.   if (p->cond != NO_COND) {
  292.     mac_mutex_lock(p->cond->mutex, p);
  293.     if (!--p->cond->waiters)
  294.       p->cond->mutex = NO_MUTEX;
  295.     p->cond = NO_COND;
  296.   }
  297. #ifndef C_CONTEXT_SWITCH
  298.   CLEAR_KERNEL_FLAG;
  299. #endif
  300. }
  301.  
  302. /*------------------------------------------------------------*/
  303. /*
  304.  * pthread_cond_signal - Unblocks (by def. at least) one thread, blocked on
  305.  * this condition. Scan through the waiter queue of threads looking 
  306.  * for one. The first one found is removed from the list, put on 
  307.  * the active thread list and sent the signal event.
  308.  * The mutex ownership is tranferred right away, unless the mutex protocol
  309.  * is the ceiling protocol.
  310.  */
  311. int pthread_cond_signal(cond)
  312. pthread_cond_t *cond;
  313. {
  314.   pthread_t p;
  315.  
  316.   if (cond == NO_COND) {
  317.     set_errno(EINVAL);
  318.     return(-1);
  319.   }
  320.  
  321.   SET_KERNEL_FLAG;
  322.   if ((p = cond->queue.head) != NO_PTHREAD) {
  323.     if (p->state & T_SYNCTIMER)
  324.       pthread_cancel_timed_sigwait(p, FALSE, SYNC_TIME, TRUE);
  325.     else {
  326.       p->state &= ~T_CONDTIMER;
  327.       pthread_q_wakeup(&cond->queue, PRIMARY_QUEUE);
  328.     }
  329.     SIM_SYSCALL(TRUE);
  330.   }
  331.   CLEAR_KERNEL_FLAG;
  332.   return(0);
  333. }
  334.  
  335. /*------------------------------------------------------------*/
  336. /*
  337.  * pthread_cond_broadcast - Step through the queue of waiting threads 
  338.  * and send a signal event to every thread.
  339.  * The mutex ownership is tranferred right away, unless the mutex protocol
  340.  * is the ceiling protocol.
  341.  */
  342. int pthread_cond_broadcast(cond)
  343. pthread_cond_t *cond;
  344. {
  345.   pthread_t p;
  346.  
  347.   if (cond == NO_COND) {
  348.     set_errno(EINVAL);
  349.     return(-1);
  350.   }
  351.   SET_KERNEL_FLAG;
  352.   SIM_SYSCALL(cond->queue.head != NO_PTHREAD);
  353.   while ((p = cond->queue.head) != NO_PTHREAD)
  354.     if (p->state & T_SYNCTIMER)
  355.       pthread_cancel_timed_sigwait(p, FALSE, SYNC_TIME, TRUE);
  356.     else {
  357.       p->state &= ~T_CONDTIMER;
  358.       pthread_q_wakeup(&cond->queue, PRIMARY_QUEUE);
  359.     }
  360.   CLEAR_KERNEL_FLAG;
  361.   return(0);
  362. }
  363.  
  364. /*------------------------------------------------------------*/
  365. /*
  366.  * pthread_condattr_getpshared - Not Implemented. Returns ENOSYS.
  367.  */
  368.  
  369. int pthread_condattr_getpshared(attr, pshared)
  370. pthread_condattr_t *attr;
  371. int *pshared;
  372. {
  373.   set_errno(ENOSYS);
  374.   return(-1);
  375. }
  376.  
  377. /*------------------------------------------------------------*/
  378. /*
  379.  * pthread_condattr_setpshared - Not Implemented. Returns ENOSYS.
  380.  */
  381.  
  382. int pthread_condattr_setpshared(attr, pshared)
  383. pthread_condattr_t *attr;
  384. int pshared;
  385. {
  386.   set_errno(ENOSYS);
  387.   return(-1);
  388. }
  389. /*------------------------------------------------------------*/
  390.