src/thread/generic/SDL_syssem.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Jan 2016 10:10:34 -0800
changeset 9998 f67cf37e9cd4
parent 9619 b94b6d0bff0f
child 10737 3406a0f8b041
permissions -rw-r--r--
Updated copyright to 2016
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 /* An implementation of semaphores using mutexes and condition variables */
    24 
    25 #include "SDL_timer.h"
    26 #include "SDL_thread.h"
    27 #include "SDL_systhread_c.h"
    28 
    29 
    30 #if SDL_THREADS_DISABLED
    31 
    32 SDL_sem *
    33 SDL_CreateSemaphore(Uint32 initial_value)
    34 {
    35     SDL_SetError("SDL not built with thread support");
    36     return (SDL_sem *) 0;
    37 }
    38 
    39 void
    40 SDL_DestroySemaphore(SDL_sem * sem)
    41 {
    42 }
    43 
    44 int
    45 SDL_SemTryWait(SDL_sem * sem)
    46 {
    47     return SDL_SetError("SDL not built with thread support");
    48 }
    49 
    50 int
    51 SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
    52 {
    53     return SDL_SetError("SDL not built with thread support");
    54 }
    55 
    56 int
    57 SDL_SemWait(SDL_sem * sem)
    58 {
    59     return SDL_SetError("SDL not built with thread support");
    60 }
    61 
    62 Uint32
    63 SDL_SemValue(SDL_sem * sem)
    64 {
    65     return 0;
    66 }
    67 
    68 int
    69 SDL_SemPost(SDL_sem * sem)
    70 {
    71     return SDL_SetError("SDL not built with thread support");
    72 }
    73 
    74 #else
    75 
    76 struct SDL_semaphore
    77 {
    78     Uint32 count;
    79     Uint32 waiters_count;
    80     SDL_mutex *count_lock;
    81     SDL_cond *count_nonzero;
    82 };
    83 
    84 SDL_sem *
    85 SDL_CreateSemaphore(Uint32 initial_value)
    86 {
    87     SDL_sem *sem;
    88 
    89     sem = (SDL_sem *) SDL_malloc(sizeof(*sem));
    90     if (!sem) {
    91         SDL_OutOfMemory();
    92         return NULL;
    93     }
    94     sem->count = initial_value;
    95     sem->waiters_count = 0;
    96 
    97     sem->count_lock = SDL_CreateMutex();
    98     sem->count_nonzero = SDL_CreateCond();
    99     if (!sem->count_lock || !sem->count_nonzero) {
   100         SDL_DestroySemaphore(sem);
   101         return NULL;
   102     }
   103 
   104     return sem;
   105 }
   106 
   107 /* WARNING:
   108    You cannot call this function when another thread is using the semaphore.
   109 */
   110 void
   111 SDL_DestroySemaphore(SDL_sem * sem)
   112 {
   113     if (sem) {
   114         sem->count = 0xFFFFFFFF;
   115         while (sem->waiters_count > 0) {
   116             SDL_CondSignal(sem->count_nonzero);
   117             SDL_Delay(10);
   118         }
   119         SDL_DestroyCond(sem->count_nonzero);
   120         if (sem->count_lock) {
   121             SDL_LockMutex(sem->count_lock);
   122             SDL_UnlockMutex(sem->count_lock);
   123             SDL_DestroyMutex(sem->count_lock);
   124         }
   125         SDL_free(sem);
   126     }
   127 }
   128 
   129 int
   130 SDL_SemTryWait(SDL_sem * sem)
   131 {
   132     int retval;
   133 
   134     if (!sem) {
   135         return SDL_SetError("Passed a NULL semaphore");
   136     }
   137 
   138     retval = SDL_MUTEX_TIMEDOUT;
   139     SDL_LockMutex(sem->count_lock);
   140     if (sem->count > 0) {
   141         --sem->count;
   142         retval = 0;
   143     }
   144     SDL_UnlockMutex(sem->count_lock);
   145 
   146     return retval;
   147 }
   148 
   149 int
   150 SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
   151 {
   152     int retval;
   153 
   154     if (!sem) {
   155         return SDL_SetError("Passed a NULL semaphore");
   156     }
   157 
   158     /* A timeout of 0 is an easy case */
   159     if (timeout == 0) {
   160         return SDL_SemTryWait(sem);
   161     }
   162 
   163     SDL_LockMutex(sem->count_lock);
   164     ++sem->waiters_count;
   165     retval = 0;
   166     while ((sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT)) {
   167         retval = SDL_CondWaitTimeout(sem->count_nonzero,
   168                                      sem->count_lock, timeout);
   169     }
   170     --sem->waiters_count;
   171     if (retval == 0) {
   172         --sem->count;
   173     }
   174     SDL_UnlockMutex(sem->count_lock);
   175 
   176     return retval;
   177 }
   178 
   179 int
   180 SDL_SemWait(SDL_sem * sem)
   181 {
   182     return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
   183 }
   184 
   185 Uint32
   186 SDL_SemValue(SDL_sem * sem)
   187 {
   188     Uint32 value;
   189 
   190     value = 0;
   191     if (sem) {
   192         SDL_LockMutex(sem->count_lock);
   193         value = sem->count;
   194         SDL_UnlockMutex(sem->count_lock);
   195     }
   196     return value;
   197 }
   198 
   199 int
   200 SDL_SemPost(SDL_sem * sem)
   201 {
   202     if (!sem) {
   203         return SDL_SetError("Passed a NULL semaphore");
   204     }
   205 
   206     SDL_LockMutex(sem->count_lock);
   207     if (sem->waiters_count > 0) {
   208         SDL_CondSignal(sem->count_nonzero);
   209     }
   210     ++sem->count;
   211     SDL_UnlockMutex(sem->count_lock);
   212 
   213     return 0;
   214 }
   215 
   216 #endif /* SDL_THREADS_DISABLED */
   217 /* vi: set ts=4 sw=4 expandtab: */