• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 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 <pthread.h>
25 #include <semaphore.h>
26 #include <errno.h>
27 #include <sys/time.h>
28 
29 #include "SDL_thread.h"
30 #include "SDL_timer.h"
31 
32 /* Wrapper around POSIX 1003.1b semaphores */
33 
34 #ifdef __MACOSX__
35 /* Mac OS X doesn't support sem_getvalue() as of version 10.4 */
36 #include "../generic/SDL_syssem.c"
37 #else
38 
39 struct SDL_semaphore {
40 	sem_t sem;
41 };
42 
43 /* Create a semaphore, initialized with value */
SDL_CreateSemaphore(Uint32 initial_value)44 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
45 {
46 	SDL_sem *sem = (SDL_sem *) SDL_malloc(sizeof(SDL_sem));
47 	if ( sem ) {
48 		if ( sem_init(&sem->sem, 0, initial_value) < 0 ) {
49 			SDL_SetError("sem_init() failed");
50 			SDL_free(sem);
51 			sem = NULL;
52 		}
53 	} else {
54 		SDL_OutOfMemory();
55 	}
56 	return sem;
57 }
58 
SDL_DestroySemaphore(SDL_sem * sem)59 void SDL_DestroySemaphore(SDL_sem *sem)
60 {
61 	if ( sem ) {
62 		sem_destroy(&sem->sem);
63 		SDL_free(sem);
64 	}
65 }
66 
SDL_SemTryWait(SDL_sem * sem)67 int SDL_SemTryWait(SDL_sem *sem)
68 {
69 	int retval;
70 
71 	if ( ! sem ) {
72 		SDL_SetError("Passed a NULL semaphore");
73 		return -1;
74 	}
75 	retval = SDL_MUTEX_TIMEDOUT;
76 	if ( sem_trywait(&sem->sem) == 0 ) {
77 		retval = 0;
78 	}
79 	return retval;
80 }
81 
SDL_SemWait(SDL_sem * sem)82 int SDL_SemWait(SDL_sem *sem)
83 {
84 	int retval;
85 
86 	if ( ! sem ) {
87 		SDL_SetError("Passed a NULL semaphore");
88 		return -1;
89 	}
90 
91 	while ( ((retval = sem_wait(&sem->sem)) == -1) && (errno == EINTR) ) {}
92 	if ( retval < 0 ) {
93 		SDL_SetError("sem_wait() failed");
94 	}
95 	return retval;
96 }
97 
SDL_SemWaitTimeout(SDL_sem * sem,Uint32 timeout)98 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
99 {
100 	int retval;
101 #ifdef HAVE_SEM_TIMEDWAIT
102 	struct timeval now;
103 	struct timespec ts_timeout;
104 #else
105 	Uint32 end;
106 #endif
107 
108 	if ( ! sem ) {
109 		SDL_SetError("Passed a NULL semaphore");
110 		return -1;
111 	}
112 
113 	/* Try the easy cases first */
114 	if ( timeout == 0 ) {
115 		return SDL_SemTryWait(sem);
116 	}
117 	if ( timeout == SDL_MUTEX_MAXWAIT ) {
118 		return SDL_SemWait(sem);
119 	}
120 
121 #ifdef HAVE_SEM_TIMEDWAIT
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 == -1 && errno == EINTR);
146 
147 	if (retval == -1)
148 		SDL_SetError(strerror(errno));
149 #else
150 	end = SDL_GetTicks() + timeout;
151 	while ((retval = SDL_SemTryWait(sem)) == SDL_MUTEX_TIMEDOUT) {
152 		if ((SDL_GetTicks() - end) >= 0) {
153 			break;
154 		}
155 		SDL_Delay(0);
156 	}
157 #endif /* HAVE_SEM_TIMEDWAIT */
158 
159 	return retval;
160 }
161 
SDL_SemValue(SDL_sem * sem)162 Uint32 SDL_SemValue(SDL_sem *sem)
163 {
164 	int ret = 0;
165 	if ( sem ) {
166 		sem_getvalue(&sem->sem, &ret);
167 		if ( ret < 0 ) {
168 			ret = 0;
169 		}
170 	}
171 	return (Uint32)ret;
172 }
173 
SDL_SemPost(SDL_sem * sem)174 int SDL_SemPost(SDL_sem *sem)
175 {
176 	int retval;
177 
178 	if ( ! sem ) {
179 		SDL_SetError("Passed a NULL semaphore");
180 		return -1;
181 	}
182 
183 	retval = sem_post(&sem->sem);
184 	if ( retval < 0 ) {
185 		SDL_SetError("sem_post() failed");
186 	}
187 	return retval;
188 }
189 
190 #endif /* __MACOSX__ */
191