• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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