src/thread/pthread/SDL_syssem.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sun, 08 Jun 2014 12:51:02 +0200
changeset 8844 d35c1b1798c8
parent 8831 9326ec96c132
child 9244 9f8962b9b09e
permissions -rw-r--r--
Fixed typo in source comment.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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 #include <errno.h>
    24 #include <pthread.h>
    25 #include <semaphore.h>
    26 #include <sys/time.h>
    27 
    28 #include "SDL_thread.h"
    29 #include "SDL_timer.h"
    30 
    31 /* Wrapper around POSIX 1003.1b semaphores */
    32 
    33 #if defined(__MACOSX__) || defined(__IPHONEOS__)
    34 /* Mac OS X doesn't support sem_getvalue() as of version 10.4 */
    35 #include "../generic/SDL_syssem.c"
    36 #else
    37 
    38 struct SDL_semaphore
    39 {
    40     sem_t sem;
    41 };
    42 
    43 /* Create a semaphore, initialized with value */
    44 SDL_sem *
    45 SDL_CreateSemaphore(Uint32 initial_value)
    46 {
    47     SDL_sem *sem = (SDL_sem *) SDL_malloc(sizeof(SDL_sem));
    48     if (sem) {
    49         if (sem_init(&sem->sem, 0, initial_value) < 0) {
    50             SDL_SetError("sem_init() failed");
    51             SDL_free(sem);
    52             sem = NULL;
    53         }
    54     } else {
    55         SDL_OutOfMemory();
    56     }
    57     return sem;
    58 }
    59 
    60 void
    61 SDL_DestroySemaphore(SDL_sem * sem)
    62 {
    63     if (sem) {
    64         sem_destroy(&sem->sem);
    65         SDL_free(sem);
    66     }
    67 }
    68 
    69 int
    70 SDL_SemTryWait(SDL_sem * sem)
    71 {
    72     int retval;
    73 
    74     if (!sem) {
    75         return SDL_SetError("Passed a NULL semaphore");
    76     }
    77     retval = SDL_MUTEX_TIMEDOUT;
    78     if (sem_trywait(&sem->sem) == 0) {
    79         retval = 0;
    80     }
    81     return retval;
    82 }
    83 
    84 int
    85 SDL_SemWait(SDL_sem * sem)
    86 {
    87     int retval;
    88 
    89     if (!sem) {
    90         return SDL_SetError("Passed a NULL semaphore");
    91     }
    92 
    93     retval = sem_wait(&sem->sem);
    94     if (retval < 0) {
    95         retval = SDL_SetError("sem_wait() failed");
    96     }
    97     return retval;
    98 }
    99 
   100 int
   101 SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
   102 {
   103     int retval;
   104 #ifdef HAVE_SEM_TIMEDWAIT
   105     struct timeval now;
   106     struct timespec ts_timeout;
   107 #else
   108     Uint32 end;
   109 #endif
   110 
   111     if (!sem) {
   112         return SDL_SetError("Passed a NULL semaphore");
   113     }
   114 
   115     /* Try the easy cases first */
   116     if (timeout == 0) {
   117         return SDL_SemTryWait(sem);
   118     }
   119     if (timeout == SDL_MUTEX_MAXWAIT) {
   120         return SDL_SemWait(sem);
   121     }
   122 
   123 #ifdef HAVE_SEM_TIMEDWAIT
   124     /* Setup the timeout. sem_timedwait doesn't wait for
   125     * a lapse of time, but until we reach a certain time.
   126     * This time is now plus the timeout.
   127     */
   128     gettimeofday(&now, NULL);
   129 
   130     /* Add our timeout to current time */
   131     now.tv_usec += (timeout % 1000) * 1000;
   132     now.tv_sec += timeout / 1000;
   133 
   134     /* Wrap the second if needed */
   135     if ( now.tv_usec >= 1000000 ) {
   136         now.tv_usec -= 1000000;
   137         now.tv_sec ++;
   138     }
   139 
   140     /* Convert to timespec */
   141     ts_timeout.tv_sec = now.tv_sec;
   142     ts_timeout.tv_nsec = now.tv_usec * 1000;
   143 
   144     /* Wait. */
   145     do {
   146         retval = sem_timedwait(&sem->sem, &ts_timeout);
   147     } while (retval < 0 && errno == EINTR);
   148 
   149     if (retval < 0) {
   150         if (errno == ETIMEDOUT) {
   151             retval = SDL_MUTEX_TIMEDOUT;
   152         } else {
   153             SDL_SetError("sem_timedwait returned an error: %s", strerror(errno));
   154         }
   155     }
   156 #else
   157     end = SDL_GetTicks() + timeout;
   158     while ((retval = SDL_SemTryWait(sem)) == SDL_MUTEX_TIMEDOUT) {
   159         if (SDL_TICKS_PASSED(SDL_GetTicks(), end)) {
   160             break;
   161         }
   162         SDL_Delay(1);
   163     }
   164 #endif /* HAVE_SEM_TIMEDWAIT */
   165 
   166     return retval;
   167 }
   168 
   169 Uint32
   170 SDL_SemValue(SDL_sem * sem)
   171 {
   172     int ret = 0;
   173     if (sem) {
   174         sem_getvalue(&sem->sem, &ret);
   175         if (ret < 0) {
   176             ret = 0;
   177         }
   178     }
   179     return (Uint32) ret;
   180 }
   181 
   182 int
   183 SDL_SemPost(SDL_sem * sem)
   184 {
   185     int retval;
   186 
   187     if (!sem) {
   188         return SDL_SetError("Passed a NULL semaphore");
   189     }
   190 
   191     retval = sem_post(&sem->sem);
   192     if (retval < 0) {
   193         SDL_SetError("sem_post() failed");
   194     }
   195     return retval;
   196 }
   197 
   198 #endif /* __MACOSX__ */
   199 /* vi: set ts=4 sw=4 expandtab: */