src/thread/nds/SDL_syscond.c
author Darren Alton <dalton@stevens.edu>
Tue, 10 Jun 2008 06:57:57 +0000
branchgsoc2008_nds
changeset 2670 6e4669f4db49
child 2671 c3e7c0698cbb
permissions -rw-r--r--
Fix for the previous commit: actually 'svn add'ed some files.
     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.2 2001/04/26 16:50:18 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)
    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)
    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)
    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)
   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)
   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)
   221 {
   222 	return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
   223 }