src/thread/stdcpp/SDL_syscond.cpp
author David Ludwig
Thu, 22 Nov 2012 23:12:06 -0500
changeset 8357 8d788bb003f2
parent 8356 src/thread/stdcpp/SDL_syscond.c@4d85eba58f0a
child 8360 7f1bc00e59fc
permissions -rw-r--r--
WinRT: made the skeleton C++11 thread implementation use .cpp files, not .c
dludwig@8356
     1
/*
dludwig@8356
     2
  Simple DirectMedia Layer
dludwig@8356
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
dludwig@8356
     4
dludwig@8356
     5
  This software is provided 'as-is', without any express or implied
dludwig@8356
     6
  warranty.  In no event will the authors be held liable for any damages
dludwig@8356
     7
  arising from the use of this software.
dludwig@8356
     8
dludwig@8356
     9
  Permission is granted to anyone to use this software for any purpose,
dludwig@8356
    10
  including commercial applications, and to alter it and redistribute it
dludwig@8356
    11
  freely, subject to the following restrictions:
dludwig@8356
    12
dludwig@8356
    13
  1. The origin of this software must not be misrepresented; you must not
dludwig@8356
    14
     claim that you wrote the original software. If you use this software
dludwig@8356
    15
     in a product, an acknowledgment in the product documentation would be
dludwig@8356
    16
     appreciated but is not required.
dludwig@8356
    17
  2. Altered source versions must be plainly marked as such, and must not be
dludwig@8356
    18
     misrepresented as being the original software.
dludwig@8356
    19
  3. This notice may not be removed or altered from any source distribution.
dludwig@8356
    20
*/
dludwig@8356
    21
#include "SDL_config.h"
dludwig@8356
    22
dludwig@8356
    23
/* An implementation of condition variables using semaphores and mutexes */
dludwig@8356
    24
/*
dludwig@8356
    25
   This implementation borrows heavily from the BeOS condition variable
dludwig@8356
    26
   implementation, written by Christopher Tate and Owen Smith.  Thanks!
dludwig@8356
    27
 */
dludwig@8356
    28
dludwig@8356
    29
#include "SDL_thread.h"
dludwig@8356
    30
dludwig@8356
    31
struct SDL_cond
dludwig@8356
    32
{
dludwig@8356
    33
    SDL_mutex *lock;
dludwig@8356
    34
    int waiting;
dludwig@8356
    35
    int signals;
dludwig@8356
    36
    SDL_sem *wait_sem;
dludwig@8356
    37
    SDL_sem *wait_done;
dludwig@8356
    38
};
dludwig@8356
    39
dludwig@8356
    40
/* Create a condition variable */
dludwig@8357
    41
extern "C"
dludwig@8356
    42
SDL_cond *
dludwig@8356
    43
SDL_CreateCond(void)
dludwig@8356
    44
{
dludwig@8356
    45
    SDL_cond *cond;
dludwig@8356
    46
dludwig@8356
    47
    cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond));
dludwig@8356
    48
    if (cond) {
dludwig@8356
    49
        cond->lock = SDL_CreateMutex();
dludwig@8356
    50
        cond->wait_sem = SDL_CreateSemaphore(0);
dludwig@8356
    51
        cond->wait_done = SDL_CreateSemaphore(0);
dludwig@8356
    52
        cond->waiting = cond->signals = 0;
dludwig@8356
    53
        if (!cond->lock || !cond->wait_sem || !cond->wait_done) {
dludwig@8356
    54
            SDL_DestroyCond(cond);
dludwig@8356
    55
            cond = NULL;
dludwig@8356
    56
        }
dludwig@8356
    57
    } else {
dludwig@8356
    58
        SDL_OutOfMemory();
dludwig@8356
    59
    }
dludwig@8356
    60
    return (cond);
dludwig@8356
    61
}
dludwig@8356
    62
dludwig@8356
    63
/* Destroy a condition variable */
dludwig@8357
    64
extern "C"
dludwig@8356
    65
void
dludwig@8356
    66
SDL_DestroyCond(SDL_cond * cond)
dludwig@8356
    67
{
dludwig@8356
    68
    if (cond) {
dludwig@8356
    69
        if (cond->wait_sem) {
dludwig@8356
    70
            SDL_DestroySemaphore(cond->wait_sem);
dludwig@8356
    71
        }
dludwig@8356
    72
        if (cond->wait_done) {
dludwig@8356
    73
            SDL_DestroySemaphore(cond->wait_done);
dludwig@8356
    74
        }
dludwig@8356
    75
        if (cond->lock) {
dludwig@8356
    76
            SDL_DestroyMutex(cond->lock);
dludwig@8356
    77
        }
dludwig@8356
    78
        SDL_free(cond);
dludwig@8356
    79
    }
dludwig@8356
    80
}
dludwig@8356
    81
dludwig@8356
    82
/* Restart one of the threads that are waiting on the condition variable */
dludwig@8357
    83
extern "C"
dludwig@8356
    84
int
dludwig@8356
    85
SDL_CondSignal(SDL_cond * cond)
dludwig@8356
    86
{
dludwig@8356
    87
    if (!cond) {
dludwig@8356
    88
        SDL_SetError("Passed a NULL condition variable");
dludwig@8356
    89
        return -1;
dludwig@8356
    90
    }
dludwig@8356
    91
dludwig@8356
    92
    /* If there are waiting threads not already signalled, then
dludwig@8356
    93
       signal the condition and wait for the thread to respond.
dludwig@8356
    94
     */
dludwig@8356
    95
    SDL_LockMutex(cond->lock);
dludwig@8356
    96
    if (cond->waiting > cond->signals) {
dludwig@8356
    97
        ++cond->signals;
dludwig@8356
    98
        SDL_SemPost(cond->wait_sem);
dludwig@8356
    99
        SDL_UnlockMutex(cond->lock);
dludwig@8356
   100
        SDL_SemWait(cond->wait_done);
dludwig@8356
   101
    } else {
dludwig@8356
   102
        SDL_UnlockMutex(cond->lock);
dludwig@8356
   103
    }
dludwig@8356
   104
dludwig@8356
   105
    return 0;
dludwig@8356
   106
}
dludwig@8356
   107
dludwig@8356
   108
/* Restart all threads that are waiting on the condition variable */
dludwig@8357
   109
extern "C"
dludwig@8356
   110
int
dludwig@8356
   111
SDL_CondBroadcast(SDL_cond * cond)
dludwig@8356
   112
{
dludwig@8356
   113
    if (!cond) {
dludwig@8356
   114
        SDL_SetError("Passed a NULL condition variable");
dludwig@8356
   115
        return -1;
dludwig@8356
   116
    }
dludwig@8356
   117
dludwig@8356
   118
    /* If there are waiting threads not already signalled, then
dludwig@8356
   119
       signal the condition and wait for the thread to respond.
dludwig@8356
   120
     */
dludwig@8356
   121
    SDL_LockMutex(cond->lock);
dludwig@8356
   122
    if (cond->waiting > cond->signals) {
dludwig@8356
   123
        int i, num_waiting;
dludwig@8356
   124
dludwig@8356
   125
        num_waiting = (cond->waiting - cond->signals);
dludwig@8356
   126
        cond->signals = cond->waiting;
dludwig@8356
   127
        for (i = 0; i < num_waiting; ++i) {
dludwig@8356
   128
            SDL_SemPost(cond->wait_sem);
dludwig@8356
   129
        }
dludwig@8356
   130
        /* Now all released threads are blocked here, waiting for us.
dludwig@8356
   131
           Collect them all (and win fabulous prizes!) :-)
dludwig@8356
   132
         */
dludwig@8356
   133
        SDL_UnlockMutex(cond->lock);
dludwig@8356
   134
        for (i = 0; i < num_waiting; ++i) {
dludwig@8356
   135
            SDL_SemWait(cond->wait_done);
dludwig@8356
   136
        }
dludwig@8356
   137
    } else {
dludwig@8356
   138
        SDL_UnlockMutex(cond->lock);
dludwig@8356
   139
    }
dludwig@8356
   140
dludwig@8356
   141
    return 0;
dludwig@8356
   142
}
dludwig@8356
   143
dludwig@8356
   144
/* Wait on the condition variable for at most 'ms' milliseconds.
dludwig@8356
   145
   The mutex must be locked before entering this function!
dludwig@8356
   146
   The mutex is unlocked during the wait, and locked again after the wait.
dludwig@8356
   147
dludwig@8356
   148
Typical use:
dludwig@8356
   149
dludwig@8356
   150
Thread A:
dludwig@8356
   151
    SDL_LockMutex(lock);
dludwig@8356
   152
    while ( ! condition ) {
dludwig@8356
   153
        SDL_CondWait(cond, lock);
dludwig@8356
   154
    }
dludwig@8356
   155
    SDL_UnlockMutex(lock);
dludwig@8356
   156
dludwig@8356
   157
Thread B:
dludwig@8356
   158
    SDL_LockMutex(lock);
dludwig@8356
   159
    ...
dludwig@8356
   160
    condition = true;
dludwig@8356
   161
    ...
dludwig@8356
   162
    SDL_CondSignal(cond);
dludwig@8356
   163
    SDL_UnlockMutex(lock);
dludwig@8356
   164
 */
dludwig@8357
   165
extern "C"
dludwig@8356
   166
int
dludwig@8356
   167
SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
dludwig@8356
   168
{
dludwig@8356
   169
    int retval;
dludwig@8356
   170
dludwig@8356
   171
    if (!cond) {
dludwig@8356
   172
        SDL_SetError("Passed a NULL condition variable");
dludwig@8356
   173
        return -1;
dludwig@8356
   174
    }
dludwig@8356
   175
dludwig@8356
   176
    /* Obtain the protection mutex, and increment the number of waiters.
dludwig@8356
   177
       This allows the signal mechanism to only perform a signal if there
dludwig@8356
   178
       are waiting threads.
dludwig@8356
   179
     */
dludwig@8356
   180
    SDL_LockMutex(cond->lock);
dludwig@8356
   181
    ++cond->waiting;
dludwig@8356
   182
    SDL_UnlockMutex(cond->lock);
dludwig@8356
   183
dludwig@8356
   184
    /* Unlock the mutex, as is required by condition variable semantics */
dludwig@8356
   185
    SDL_UnlockMutex(mutex);
dludwig@8356
   186
dludwig@8356
   187
    /* Wait for a signal */
dludwig@8356
   188
    if (ms == SDL_MUTEX_MAXWAIT) {
dludwig@8356
   189
        retval = SDL_SemWait(cond->wait_sem);
dludwig@8356
   190
    } else {
dludwig@8356
   191
        retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
dludwig@8356
   192
    }
dludwig@8356
   193
dludwig@8356
   194
    /* Let the signaler know we have completed the wait, otherwise
dludwig@8356
   195
       the signaler can race ahead and get the condition semaphore
dludwig@8356
   196
       if we are stopped between the mutex unlock and semaphore wait,
dludwig@8356
   197
       giving a deadlock.  See the following URL for details:
dludwig@8356
   198
       http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
dludwig@8356
   199
     */
dludwig@8356
   200
    SDL_LockMutex(cond->lock);
dludwig@8356
   201
    if (cond->signals > 0) {
dludwig@8356
   202
        /* If we timed out, we need to eat a condition signal */
dludwig@8356
   203
        if (retval > 0) {
dludwig@8356
   204
            SDL_SemWait(cond->wait_sem);
dludwig@8356
   205
        }
dludwig@8356
   206
        /* We always notify the signal thread that we are done */
dludwig@8356
   207
        SDL_SemPost(cond->wait_done);
dludwig@8356
   208
dludwig@8356
   209
        /* Signal handshake complete */
dludwig@8356
   210
        --cond->signals;
dludwig@8356
   211
    }
dludwig@8356
   212
    --cond->waiting;
dludwig@8356
   213
    SDL_UnlockMutex(cond->lock);
dludwig@8356
   214
dludwig@8356
   215
    /* Lock the mutex, as is required by condition variable semantics */
dludwig@8356
   216
    SDL_LockMutex(mutex);
dludwig@8356
   217
dludwig@8356
   218
    return retval;
dludwig@8356
   219
}
dludwig@8356
   220
dludwig@8356
   221
/* Wait on the condition variable forever */
dludwig@8357
   222
extern "C"
dludwig@8356
   223
int
dludwig@8356
   224
SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
dludwig@8356
   225
{
dludwig@8356
   226
    return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
dludwig@8356
   227
}
dludwig@8356
   228
dludwig@8356
   229
/* vi: set ts=4 sw=4 expandtab: */