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