src/thread/generic/SDL_syscond.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. SDL_CreateCond
  2. SDL_DestroyCond
  3. SDL_CondSignal
  4. SDL_CondBroadcast
  5. SDL_CondWaitTimeout
  6. SDL_CondWait

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_syscond.c,v 1.1.2.5 2001/02/10 07:20:04 hercules Exp $";
  26 #endif
  27 
  28 /* An implementation of condition variables using semaphores and mutexes */
  29 /*
  30    This implementation borrows heavily from the BeOS condition variable
  31    implementation, written by Christopher Tate and Owen Smith.  Thanks!
  32  */
  33 
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 
  37 #include "SDL_error.h"
  38 #include "SDL_thread.h"
  39 
  40 struct SDL_cond
  41 {
  42         SDL_mutex *lock;
  43         int waiting;
  44         int signals;
  45         SDL_sem *wait_sem;
  46         SDL_sem *wait_done;
  47 };
  48 
  49 /* Create a condition variable */
  50 SDL_cond * SDL_CreateCond(void)
     /* [<][>][^][v][top][bottom][index][help] */
  51 {
  52         SDL_cond *cond;
  53 
  54         cond = (SDL_cond *) malloc(sizeof(SDL_cond));
  55         if ( cond ) {
  56                 cond->lock = SDL_CreateMutex();
  57                 cond->wait_sem = SDL_CreateSemaphore(0);
  58                 cond->wait_done = SDL_CreateSemaphore(0);
  59                 cond->waiting = cond->signals = 0;
  60                 if ( ! cond->lock || ! cond->wait_sem || ! cond->wait_done ) {
  61                         SDL_DestroyCond(cond);
  62                         cond = NULL;
  63                 }
  64         } else {
  65                 SDL_OutOfMemory();
  66         }
  67         return(cond);
  68 }
  69 
  70 /* Destroy a condition variable */
  71 void SDL_DestroyCond(SDL_cond *cond)
     /* [<][>][^][v][top][bottom][index][help] */
  72 {
  73         if ( cond ) {
  74                 if ( cond->wait_sem ) {
  75                         SDL_DestroySemaphore(cond->wait_sem);
  76                 }
  77                 if ( cond->wait_done ) {
  78                         SDL_DestroySemaphore(cond->wait_done);
  79                 }
  80                 if ( cond->lock ) {
  81                         SDL_DestroyMutex(cond->lock);
  82                 }
  83                 free(cond);
  84         }
  85 }
  86 
  87 /* Restart one of the threads that are waiting on the condition variable */
  88 int SDL_CondSignal(SDL_cond *cond)
     /* [<][>][^][v][top][bottom][index][help] */
  89 {
  90         if ( ! cond ) {
  91                 SDL_SetError("Passed a NULL condition variable");
  92                 return -1;
  93         }
  94 
  95         /* If there are waiting threads not already signalled, then
  96            signal the condition and wait for the thread to respond.
  97         */
  98         SDL_LockMutex(cond->lock);
  99         if ( cond->waiting > cond->signals ) {
 100                 ++cond->signals;
 101                 SDL_SemPost(cond->wait_sem);
 102                 SDL_UnlockMutex(cond->lock);
 103                 SDL_SemWait(cond->wait_done);
 104         } else {
 105                 SDL_UnlockMutex(cond->lock);
 106         }
 107 
 108         return 0;
 109 }
 110 
 111 /* Restart all threads that are waiting on the condition variable */
 112 int SDL_CondBroadcast(SDL_cond *cond)
     /* [<][>][^][v][top][bottom][index][help] */
 113 {
 114         if ( ! cond ) {
 115                 SDL_SetError("Passed a NULL condition variable");
 116                 return -1;
 117         }
 118 
 119         /* If there are waiting threads not already signalled, then
 120            signal the condition and wait for the thread to respond.
 121         */
 122         SDL_LockMutex(cond->lock);
 123         if ( cond->waiting > cond->signals ) {
 124                 int i, num_waiting;
 125 
 126                 num_waiting = (cond->waiting - cond->signals);
 127                 cond->signals = cond->waiting;
 128                 for ( i=0; i<num_waiting; ++i ) {
 129                         SDL_SemPost(cond->wait_sem);
 130                 }
 131                 /* Now all released threads are blocked here, waiting for us.
 132                    Collect them all (and win fabulous prizes!) :-)
 133                  */
 134                 SDL_UnlockMutex(cond->lock);
 135                 for ( i=0; i<num_waiting; ++i ) {
 136                         SDL_SemWait(cond->wait_done);
 137                 }
 138         } else {
 139                 SDL_UnlockMutex(cond->lock);
 140         }
 141 
 142         return 0;
 143 }
 144 
 145 /* Wait on the condition variable for at most 'ms' milliseconds.
 146    The mutex must be locked before entering this function!
 147    The mutex is unlocked during the wait, and locked again after the wait.
 148 
 149 Typical use:
 150 
 151 Thread A:
 152         SDL_LockMutex(lock);
 153         while ( ! condition ) {
 154                 SDL_CondWait(cond);
 155         }
 156         SDL_UnlockMutex(lock);
 157 
 158 Thread B:
 159         SDL_LockMutex(lock);
 160         ...
 161         condition = true;
 162         ...
 163         SDL_UnlockMutex(lock);
 164  */
 165 int SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
     /* [<][>][^][v][top][bottom][index][help] */
 166 {
 167         int retval;
 168 
 169         if ( ! cond ) {
 170                 SDL_SetError("Passed a NULL condition variable");
 171                 return -1;
 172         }
 173 
 174         /* Obtain the protection mutex, and increment the number of waiters.
 175            This allows the signal mechanism to only perform a signal if there
 176            are waiting threads.
 177          */
 178         SDL_LockMutex(cond->lock);
 179         ++cond->waiting;
 180         SDL_UnlockMutex(cond->lock);
 181 
 182         /* Unlock the mutex, as is required by condition variable semantics */
 183         SDL_UnlockMutex(mutex);
 184 
 185         /* Wait for a signal */
 186         if ( ms == SDL_MUTEX_MAXWAIT ) {
 187                 retval = SDL_SemWait(cond->wait_sem);
 188         } else {
 189                 retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
 190         }
 191 
 192         /* Let the signaler know we have completed the wait, otherwise
 193            the signaler can race ahead and get the condition semaphore
 194            if we are stopped between the mutex unlock and semaphore wait,
 195            giving a deadlock.  See the following URL for details:
 196         http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
 197         */
 198         SDL_LockMutex(cond->lock);
 199         if ( cond->signals > 0 ) {
 200                 /* If we timed out, we need to eat a condition signal */
 201                 if ( retval > 0 ) {
 202                         SDL_SemWait(cond->wait_sem);
 203                 }
 204                 /* We always notify the signal thread that we are done */
 205                 SDL_SemPost(cond->wait_done);
 206 
 207                 /* Signal handshake complete */
 208                 --cond->signals;
 209         }
 210         --cond->waiting;
 211         SDL_UnlockMutex(cond->lock);
 212 
 213         /* Lock the mutex, as is required by condition variable semantics */
 214         SDL_LockMutex(mutex);
 215 
 216         return retval;
 217 }
 218 
 219 /* Wait on the condition variable forever */
 220 int SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
     /* [<][>][^][v][top][bottom][index][help] */
 221 {
 222         return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
 223 }

/* [<][>][^][v][top][bottom][index][help] */