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