1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 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 "SDL_thread.h"
25 #include "SDL_timer.h"
26
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/ipc.h>
32 #include <sys/sem.h>
33 #include <errno.h>
34
35 #include "SDL_error.h"
36 #include "SDL_thread.h"
37
38
39 struct SDL_semaphore {
40 int id;
41 };
42
43 /* Not defined by many operating systems, use configure to detect */
44 /*
45 #if !defined(HAVE_SEMUN)
46 union semun {
47 int val;
48 struct semid_ds *buf;
49 ushort *array;
50 };
51 #endif
52 */
53
54 static struct sembuf op_trywait[2] = {
55 { 0, -1, (IPC_NOWAIT|SEM_UNDO) } /* Decrement semaphore, no block */
56 };
57 static struct sembuf op_wait[2] = {
58 { 0, -1, SEM_UNDO } /* Decrement semaphore */
59 };
60 static struct sembuf op_post[1] = {
61 { 0, 1, (IPC_NOWAIT|SEM_UNDO) } /* Increment semaphore */
62 };
63
64 /* Create a blockable semaphore */
SDL_CreateSemaphore(Uint32 initial_value)65 SDL_sem *SDL_CreateSemaphore(Uint32 initial_value)
66 {
67 extern int _creating_thread_lock; /* SDL_threads.c */
68 SDL_sem *sem;
69 union semun init;
70
71 sem = (SDL_sem *)SDL_malloc(sizeof(*sem));
72 if ( sem == NULL ) {
73 SDL_OutOfMemory();
74 return(NULL);
75 }
76 sem->id = semget(IPC_PRIVATE, 1, (0600|IPC_CREAT));
77 if ( sem->id < 0 ) {
78 SDL_SetError("Couldn't create semaphore");
79 SDL_free(sem);
80 return(NULL);
81 }
82 init.val = initial_value; /* Initialize semaphore */
83 semctl(sem->id, 0, SETVAL, init);
84 return(sem);
85 }
86
SDL_DestroySemaphore(SDL_sem * sem)87 void SDL_DestroySemaphore(SDL_sem *sem)
88 {
89 if ( sem ) {
90 #ifdef __IRIX__
91 semctl(sem->id, 0, IPC_RMID);
92 #else
93 union semun dummy;
94 dummy.val = 0;
95 semctl(sem->id, 0, IPC_RMID, dummy);
96 #endif
97 SDL_free(sem);
98 }
99 }
100
SDL_SemTryWait(SDL_sem * sem)101 int SDL_SemTryWait(SDL_sem *sem)
102 {
103 int retval;
104
105 if ( ! sem ) {
106 SDL_SetError("Passed a NULL semaphore");
107 return -1;
108 }
109
110 retval = 0;
111 tryagain:
112 if ( semop(sem->id, op_trywait, 1) < 0 ) {
113 if ( errno == EINTR ) {
114 goto tryagain;
115 }
116 retval = SDL_MUTEX_TIMEDOUT;
117 }
118 return retval;
119 }
120
SDL_SemWait(SDL_sem * sem)121 int SDL_SemWait(SDL_sem *sem)
122 {
123 int retval;
124
125 if ( ! sem ) {
126 SDL_SetError("Passed a NULL semaphore");
127 return -1;
128 }
129
130 retval = 0;
131 tryagain:
132 if ( semop(sem->id, op_wait, 1) < 0 ) {
133 if ( errno == EINTR ) {
134 goto tryagain;
135 }
136 SDL_SetError("Semaphore operation error");
137 retval = -1;
138 }
139 return retval;
140 }
141
SDL_SemWaitTimeout(SDL_sem * sem,Uint32 timeout)142 int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
143 {
144 int retval;
145
146 if ( ! sem ) {
147 SDL_SetError("Passed a NULL semaphore");
148 return -1;
149 }
150
151 /* Try the easy cases first */
152 if ( timeout == 0 ) {
153 return SDL_SemTryWait(sem);
154 }
155 if ( timeout == SDL_MUTEX_MAXWAIT ) {
156 return SDL_SemWait(sem);
157 }
158
159 /* Ack! We have to busy wait... */
160 timeout += SDL_GetTicks();
161 do {
162 retval = SDL_SemTryWait(sem);
163 if ( retval == 0 ) {
164 break;
165 }
166 SDL_Delay(1);
167 } while ( SDL_GetTicks() < timeout );
168
169 return retval;
170 }
171
SDL_SemValue(SDL_sem * sem)172 Uint32 SDL_SemValue(SDL_sem *sem)
173 {
174 int semval;
175 Uint32 value;
176
177 value = 0;
178 if ( sem ) {
179 tryagain:
180 #ifdef __IRIX__
181 semval = semctl(sem->id, 0, GETVAL);
182 #else
183 {
184 union semun arg;
185 arg.val = 0;
186 semval = semctl(sem->id, 0, GETVAL, arg);
187 }
188 #endif
189 if ( semval < 0 ) {
190 if ( errno == EINTR ) {
191 goto tryagain;
192 }
193 } else {
194 value = (Uint32)semval;
195 }
196 }
197 return value;
198 }
199
SDL_SemPost(SDL_sem * sem)200 int SDL_SemPost(SDL_sem *sem)
201 {
202 int retval;
203
204 if ( ! sem ) {
205 SDL_SetError("Passed a NULL semaphore");
206 return -1;
207 }
208
209 retval = 0;
210 tryagain:
211 if ( semop(sem->id, op_post, 1) < 0 ) {
212 if ( errno == EINTR ) {
213 goto tryagain;
214 }
215 SDL_SetError("Semaphore operation error");
216 retval = -1;
217 }
218 return retval;
219 }
220