src/thread/nds/SDL_syscond.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Aug 2008 15:10:03 +0000
changeset 2735 204be4fc2726
child 2859 99210400e8b9
permissions -rw-r--r--
Final merge of Google Summer of Code 2008 work...

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