src/thread/pthread/SDL_syssem.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Feb 2011 22:37:15 -0800
changeset 5262 b530ef003506
parent 5106 d547877e355e
child 5535 96594ac5fd1a
permissions -rw-r--r--
Happy 2011! :)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include <errno.h>
    25 #include <pthread.h>
    26 #include <semaphore.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         SDL_SetError("Passed a NULL semaphore");
    76         return -1;
    77     }
    78     retval = SDL_MUTEX_TIMEDOUT;
    79     if (sem_trywait(&sem->sem) == 0) {
    80         retval = 0;
    81     }
    82     return retval;
    83 }
    84 
    85 int
    86 SDL_SemWait(SDL_sem * sem)
    87 {
    88     int retval;
    89 
    90     if (!sem) {
    91         SDL_SetError("Passed a NULL semaphore");
    92         return -1;
    93     }
    94 
    95     retval = sem_wait(&sem->sem);
    96     if (retval < 0) {
    97         SDL_SetError("sem_wait() failed");
    98     }
    99     return retval;
   100 }
   101 
   102 int
   103 SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
   104 {
   105     int retval;
   106     struct timeval now;
   107     struct timespec ts_timeout;
   108 
   109     if (!sem) {
   110         SDL_SetError("Passed a NULL semaphore");
   111         return -1;
   112     }
   113 
   114     /* Try the easy cases first */
   115     if (timeout == 0) {
   116         return SDL_SemTryWait(sem);
   117     }
   118     if (timeout == SDL_MUTEX_MAXWAIT) {
   119         return SDL_SemWait(sem);
   120     }
   121 
   122     /* Setup the timeout. sem_timedwait doesn't wait for
   123     * a lapse of time, but until we reach a certain time.
   124     * This time is now plus the timeout.
   125     */
   126     gettimeofday(&now, NULL);
   127 
   128     /* Add our timeout to current time */
   129     now.tv_usec += (timeout % 1000) * 1000;
   130     now.tv_sec += timeout / 1000;
   131 
   132     /* Wrap the second if needed */
   133     if ( now.tv_usec >= 1000000 ) {
   134         now.tv_usec -= 1000000;
   135         now.tv_sec ++;
   136     }
   137 
   138     /* Convert to timespec */
   139     ts_timeout.tv_sec = now.tv_sec;
   140     ts_timeout.tv_nsec = now.tv_usec * 1000;
   141 
   142     /* Wait. */
   143     do {
   144         retval = sem_timedwait(&sem->sem, &ts_timeout);
   145     } while (retval < 0 && errno == EINTR);
   146 
   147     if (retval < 0) {
   148         SDL_SetError("sem_timedwait() failed");
   149     }
   150 
   151     return retval;
   152 }
   153 
   154 Uint32
   155 SDL_SemValue(SDL_sem * sem)
   156 {
   157     int ret = 0;
   158     if (sem) {
   159         sem_getvalue(&sem->sem, &ret);
   160         if (ret < 0) {
   161             ret = 0;
   162         }
   163     }
   164     return (Uint32) ret;
   165 }
   166 
   167 int
   168 SDL_SemPost(SDL_sem * sem)
   169 {
   170     int retval;
   171 
   172     if (!sem) {
   173         SDL_SetError("Passed a NULL semaphore");
   174         return -1;
   175     }
   176 
   177     retval = sem_post(&sem->sem);
   178     if (retval < 0) {
   179         SDL_SetError("sem_post() failed");
   180     }
   181     return retval;
   182 }
   183 
   184 #endif /* __MACOSX__ */
   185 /* vi: set ts=4 sw=4 expandtab: */