Here is a patch for POSIX-like counting semaphores in SDL. There are two
implementations : a generic one that works on top of SDL mutexes and should be
portable across all platforms, and another one that relies on the POSIX
1003.1b sem_* functions. You can chose to use either one with the
–enable-native-sem configure flag. Of course it would be nice to have other
native implementations (Win32, MacOS, Be…).
The API is pretty much the same as the POSIX one :
/* Create a semaphore, initialized with value */
extern DECLSPEC SDL_sem * SDL_CreateSemaphore(Uint32 value);
/* Destroy a semaphore */
extern DECLSPEC void SDL_DestroySemaphore(SDL_sem *sem);
/* Suspend the calling thread until the semaphore count is non-zero,
then decreases the counter
*/
extern DECLSPEC SDL_bool SDL_SemWait(SDL_sem *sem);
/* Non-blocking variant of SDL_SemWait(), returns SDL_FALSE if counter is zero
*/
extern DECLSPEC SDL_bool SDL_SemTryWait(SDL_sem *sem);
/* Returns the current count of the semaphore */
extern DECLSPEC Uint32 SDL_SemGetValue(SDL_sem *sem);
/* Atomically increases the semaphore’s count (not blocking) */
extern DECLSPEC SDL_bool SDL_SemPost(SDL_sem *sem);
If that patch looks good, let me know so that I commit it. The next logical
step would be to add that kind of functionality for condition variables (that
would actually have made the generic semaphore implementation cleaner). Maybe
another day
Sim City 3000 is going to use SDL semaphores right now to avoid problems with
glibc breaking compatibility of POSIX semaphores between minor releases… :-/–
Stephane Peter
Programmer
Loki Entertainment Software
“Microsoft has done to computers what McDonald’s has done to gastronomy”
-------------- next part --------------
Index: configure.in
RCS file: /cvs/SDL/configure.in,v
retrieving revision 1.25.2.48
diff -u -r1.25.2.48 configure.in
— configure.in 2000/04/15 01:40:49 1.25.2.48
+++ configure.in 2000/04/19 00:47:39
@@ -545,6 +545,15 @@
AM_CONDITIONAL(USE_CLONE, test x$use_clone = xyes)
}
+dnl Check if we want to include native semaphore code
+CheckSEM()
+{
- AC_ARG_ENABLE(native-sem,
+[ --enable-native-sem Use native semaphores [default=yes]], -
, enable_native_sem=yes)
- AM_CONDITIONAL(USE_NATIVE_SEM, test x$enable_native_sem = xyes)
+}
dnl Determine whether the compiler can produce Win32 executables
CheckWIN32()
{
@@ -635,6 +644,7 @@
CheckAAlib
CheckOpenGL
CheckPTHREAD
-
CheckSEM # Set up files for the main() stub COPY_ARCH_SRC(src/main, linux, SDL_main.c) # Set up files for the audio library
@@ -655,6 +665,7 @@
fi
COPY_ARCH_SRC(src/thread, linux, SDL_mutex.c)
COPY_ARCH_SRC(src/thread, linux, SDL_systhread.c)
-
COPY_ARCH_SRC(src/thread, linux, SDL_syssemaphore.c) COPY_ARCH_SRC(src/thread, linux, SDL_systhread_c.h) fi # Set up files for the timer library
@@ -670,6 +681,7 @@
CheckOpenGL
CheckPTHREAD
CheckKSTAT
-
CheckSEM # Set up files for the main() stub COPY_ARCH_SRC(src/main, linux, SDL_main.c) # Set up files for the audio library
@@ -688,6 +700,7 @@
if test x$enable_threads = xyes; then
COPY_ARCH_SRC(src/thread, linux, SDL_mutex.c)
COPY_ARCH_SRC(src/thread, linux, SDL_systhread.c)
-
COPY_ARCH_SRC(src/thread, linux, SDL_syssemaphore.c) COPY_ARCH_SRC(src/thread, linux, SDL_systhread_c.h) fi # Set up files for the timer library
@@ -732,6 +745,7 @@
CheckAAlib
CheckOpenGL
CheckPTHREAD
-
CheckSEM # Set up files for the main() stub COPY_ARCH_SRC(src/main, linux, SDL_main.c) # Set up files for the audio library
@@ -750,6 +764,7 @@
if test x$enable_threads = xyes; then
COPY_ARCH_SRC(src/thread, linux, SDL_mutex.c)
COPY_ARCH_SRC(src/thread, linux, SDL_systhread.c)
-
COPY_ARCH_SRC(src/thread, linux, SDL_syssemaphore.c) COPY_ARCH_SRC(src/thread, linux, SDL_systhread_c.h) fi # Set up files for the timer library
@@ -764,6 +779,7 @@
CheckAAlib
CheckOpenGL
CheckPTHREAD
-
CheckSEM # Set up files for the main() stub COPY_ARCH_SRC(src/main, linux, SDL_main.c) # Set up files for the audio library
@@ -785,6 +801,7 @@
if test x$enable_threads = xyes; then
COPY_ARCH_SRC(src/thread, linux, SDL_mutex.c)
COPY_ARCH_SRC(src/thread, linux, SDL_systhread.c)
-
COPY_ARCH_SRC(src/thread, linux, SDL_syssemaphore.c) COPY_ARCH_SRC(src/thread, linux, SDL_systhread_c.h) fi # Set up files for the timer library
@@ -802,6 +819,7 @@
CheckAAlib
CheckOpenGL
CheckPTHREAD
-
CheckSEM # Set up files for the main() stub COPY_ARCH_SRC(src/main, linux, SDL_main.c) # Set up files for the audio library
@@ -820,6 +838,7 @@
if test x$enable_threads = xyes; then
COPY_ARCH_SRC(src/thread, linux, SDL_mutex.c)
COPY_ARCH_SRC(src/thread, linux, SDL_systhread.c)
-
COPY_ARCH_SRC(src/thread, linux, SDL_syssemaphore.c) COPY_ARCH_SRC(src/thread, linux, SDL_systhread_c.h) fi # Set up files for the timer library
Index: include/Makefile.am
RCS file: /cvs/SDL/include/Makefile.am,v
retrieving revision 1.3.2.1
diff -u -r1.3.2.1 Makefile.am
— include/Makefile.am 2000/01/05 19:30:59 1.3.2.1
+++ include/Makefile.am 2000/04/19 00:47:39
@@ -20,6 +20,7 @@
SDL_main.h
SDL_mouse.h
SDL_mutex.h \
- SDL_semaphore.h
SDL_quit.h
SDL_rwops.h
SDL_syswm.h
Index: include/SDL_semaphore.h
===================================================================
RCS file: SDL_semaphore.h
diff -N SDL_semaphore.h
— /dev/null Tue May 5 13:32:27 1998
+++ SDL_semaphore.h Tue Apr 18 17:47:39 2000
@@ -0,0 +1,71 @@
+/* - SDL - Simple DirectMedia Layer
- Copyright © 1997, 1998, 1999, 2000 Sam Lantinga
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Sam Lantinga
- slouken at devolution.com
+*/
+#ifdef SAVE_RCSID
+static char rcsid =
- “@(#) $Id: SDL_mutex.h,v 1.5.2.1 2000/03/16 15:20:37 hercules Exp $”;
+#endif
+#ifndef _SDL_semaphore_h
+#define _SDL_semaphore_h
+
+#include “SDL_types.h”
+
+/* Counting semaphores /
+
+#include “begin_code.h”
+/ Set up for C function definitions, even when using C++ /
+#ifdef __cplusplus
+extern “C” {
+#endif
+
+/ The SDL semaphore structure, defined in SDL_semaphore.c /
+struct SDL_semaphore;
+typedef struct SDL_semaphore SDL_sem;
+
+/ Create a semaphore, initialized with value /
+extern DECLSPEC SDL_sem * SDL_CreateSemaphore(Uint32 value);
+
+/ Destroy a semaphore */
+extern DECLSPEC void SDL_DestroySemaphore(SDL_sem sem);
+
+/ Suspend the calling thread until the semaphore count is non-zero,
- then decreases the counter
- */
+extern DECLSPEC SDL_bool SDL_SemWait(SDL_sem *sem);
+/* Non-blocking variant of SDL_SemWait(), returns SDL_FALSE if counter is zero
*/
+extern DECLSPEC SDL_bool SDL_SemTryWait(SDL_sem sem);
+
+/ Returns the current count of the semaphore */
+extern DECLSPEC Uint32 SDL_SemGetValue(SDL_sem sem);
+
+/ Atomically increases the semaphore’s count (not blocking) */
+extern DECLSPEC SDL_bool SDL_SemPost(SDL_sem sem);
+
+/ Ends C function definitions when using C++ /
+#ifdef __cplusplus
+};
+#endif
+#include “close_code.h”
+
+#endif / _SDL_semaphore_h */
Index: src/thread/Makefile.am
RCS file: /cvs/SDL/src/thread/Makefile.am,v
retrieving revision 1.1.1.1.2.1
diff -u -r1.1.1.1.2.1 Makefile.am
— src/thread/Makefile.am 2000/01/24 03:32:46 1.1.1.1.2.1
+++ src/thread/Makefile.am 2000/04/19 00:47:39
@@ -13,17 +13,34 @@
endif
Include the architecture-independent sources
+if USE_NATIVE_SEM
COMMON_SRCS =
SDL_systhread.h
SDL_thread.c
SDL_thread_c.h
+else
+COMMON_SRCS = \
- SDL_systhread.h \
- SDL_thread.c \
- SDL_thread_c.h \
- SDL_semaphore.c
+endif
Include the architecture-specific sources
+if USE_NATIVE_SEM
+ARCH_SRCS = \
- SDL_mutex.c \
- SDL_systhread.c \
- SDL_systhread_c.h \
- SDL_syssemaphore.c \
- $(THREAD_ASM_SRC)
+else
ARCH_SRCS = \
- SDL_mutex.c \
- SDL_mutex.c
SDL_systhread.c
SDL_systhread_c.h
$(THREAD_ASM_SRC)
+endif
libthread_la_SOURCES = $(COMMON_SRCS) $(ARCH_SRCS)
Index: src/thread/SDL_semaphore.c
RCS file: SDL_semaphore.c
diff -N SDL_semaphore.c
— /dev/null Tue May 5 13:32:27 1998
+++ SDL_semaphore.c Tue Apr 18 17:47:39 2000
@@ -0,0 +1,151 @@
+/*
- SDL - Simple DirectMedia Layer
- Copyright © 1997, 1998, 1999, 2000 Sam Lantinga
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Sam Lantinga
- slouken at devolution.com
+*/
+#ifdef SAVE_RCSID
+static char rcsid =
- “@(#) $Id: SDL_thread.c,v 1.2.2.3 2000/03/30 06:30:31 hercules Exp $”;
+#endif
+#include “SDL_error.h”
+#include “SDL_mutex.h”
+#include “SDL_semaphore.h”
+
+/* Generic implementation of semaphores on top of SDL mutexes */
+
+struct SDL_semaphore {
- SDL_mutex *mutex;
- Uint32 count;
- Uint32 refcount; /* Number of threads waiting on the semaphore */
+};
+/* Create a semaphore, initialized with value */
+SDL_sem * SDL_CreateSemaphore(Uint32 value)
+{
- SDL_sem *sem = (SDL_sem *) malloc(sizeof(SDL_sem));
- if ( sem ) {
-
sem->mutex = SDL_CreateMutex();
-
sem->count = value;
-
sem->refcount = 0;
- }
- return sem;
+}
+/* Destroy a semaphore */
+void SDL_DestroySemaphore(SDL_sem *sem)
+{
- if ( sem ) {
-
SDL_mutexP(sem->mutex);
-
if ( sem->refcount ) { /* Still threads waiting on the semaphore */
-
SDL_bool waiting = SDL_TRUE;
-
sem->count = sem->refcount; /* Should make them all stop waiting */
-
SDL_mutexV(sem->mutex);
-
/* Wait until they are not waiting anymore */
-
while ( waiting ) {
-
SDL_Delay(1);
-
SDL_mutexP(sem->mutex);
-
if ( sem->refcount == 0 ) {
-
waiting = SDL_FALSE;
-
}
-
SDL_mutexV(sem->mutex);
-
}
-
} else {
-
SDL_mutexV(sem->mutex);
-
}
-
SDL_DestroyMutex(sem->mutex);
-
free(sem);
- }
+}
+/* Suspend the calling thread until the semaphore count is non-zero,
- then decreases the counter
- */
+SDL_bool SDL_SemWait(SDL_sem *sem)
+{ - SDL_bool ret = SDL_FALSE;
- if ( sem ) {
-
SDL_mutexP(sem->mutex);
-
if( sem->count > 0 ) {
-
-- sem->count;
-
ret = SDL_TRUE;
-
SDL_mutexV(sem->mutex);
-
} else {
-
SDL_bool waiting = SDL_TRUE;
-
/* Suspend the thread */
-
++ sem->refcount;
-
SDL_mutexV(sem->mutex);
-
/* We go into a loop... Would be much better with a real condition variable
*/
-
while ( waiting ) {
-
SDL_Delay(1);
-
SDL_mutexP(sem->mutex);
-
if ( sem->count > 0 ) {
-
-- sem->count;
-
-- sem->refcount;
-
waiting = SDL_FALSE;
-
ret = SDL_TRUE;
-
}
-
SDL_mutexV(sem->mutex);
-
}
-
}
- }
- return ret;
+}
+/* Non-blocking variant of SDL_SemWait(), returns SDL_FALSE if counter is zero
*/
+SDL_bool SDL_SemTryWait(SDL_sem *sem)
+{
- SDL_bool ret = SDL_FALSE;
- if ( sem ) {
-
SDL_mutexP(sem->mutex);
-
if( sem->count > 0 ) {
-
-- sem->count;
-
ret = SDL_TRUE;
-
}
-
SDL_mutexV(sem->mutex);
- }
- return ret;
+}
+/* Returns the current count of the semaphore */
+Uint32 SDL_SemGetValue(SDL_sem *sem)
+{
- Uint32 ret = 0;
- if ( sem ) {
-
SDL_mutexP(sem->mutex);
-
ret = sem->count;
-
SDL_mutexV(sem->mutex);
- }
- return ret;
+}
+/* Atomically increases the semaphore’s count (not blocking) */
+SDL_bool SDL_SemPost(SDL_sem *sem)
+{
- SDL_bool ret = SDL_FALSE;
- if ( sem ) {
-
SDL_mutexP(sem->mutex);
-
++ sem->count;
-
SDL_mutexV(sem->mutex);
-
ret = SDL_TRUE;
- }
- return ret;
+}
Index: src/thread/linux/SDL_syssemaphore.c
===================================================================
RCS file: SDL_syssemaphore.c
diff -N SDL_syssemaphore.c
— /dev/null Tue May 5 13:32:27 1998
+++ SDL_syssemaphore.c Tue Apr 18 17:47:39 2000
@@ -0,0 +1,97 @@
+/* - SDL - Simple DirectMedia Layer
- Copyright © 1997, 1998, 1999, 2000 Sam Lantinga
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Sam Lantinga
- slouken at devolution.com
+*/
+#ifdef SAVE_RCSID
+static char rcsid =
- “@(#) $Id: SDL_thread.c,v 1.2.2.3 2000/03/30 06:30:31 hercules Exp $”;
+#endif
+#include “SDL_error.h”
+#include “SDL_semaphore.h”
+#include <semaphore.h>
+
+/* Wrapper around POSIX 1003.1b semaphores */
+
+struct SDL_semaphore {
- sem_t sem;
+};
+/* Create a semaphore, initialized with value */
+SDL_sem * SDL_CreateSemaphore(Uint32 value)
+{
- SDL_sem *sem = (SDL_sem *) malloc(sizeof(SDL_sem));
- if ( sem ) {
-
sem_init(&sem->sem, 0, value);
- }
- return sem;
+}
+/* Destroy a semaphore */
+void SDL_DestroySemaphore(SDL_sem *sem)
+{
- if ( sem ) {
-
sem_destroy(&sem->sem);
-
free(sem);
- }
+}
+/* Suspend the calling thread until the semaphore count is non-zero,
- then decreases the counter
- */
+SDL_bool SDL_SemWait(SDL_sem *sem)
+{ - SDL_bool ret = SDL_FALSE;
- if ( sem ) {
-
ret = (sem_wait(&sem->sem) == 0);
- }
- return ret;
+}
+/* Non-blocking variant of SDL_SemWait(), returns SDL_FALSE if counter is zero
*/
+SDL_bool SDL_SemTryWait(SDL_sem *sem)
+{
- SDL_bool ret = SDL_FALSE;
- if ( sem ) {
-
ret = (sem_trywait(&sem->sem) == 0);
- }
- return ret;
+}
+/* Returns the current count of the semaphore */
+Uint32 SDL_SemGetValue(SDL_sem *sem)
+{
- Uint32 ret = 0;
- if ( sem ) {
-
sem_getvalue(&sem->sem, &ret);
- }
- return ret;
+}
+/* Atomically increases the semaphore’s count (not blocking) */
+SDL_bool SDL_SemPost(SDL_sem *sem)
+{
- SDL_bool ret = SDL_FALSE;
- if ( sem ) {
-
ret = (sem_post(&sem->sem) == 0);
- }
- return ret;
+}
Index: test/Makefile.am
===================================================================
RCS file: /cvs/SDL/test/Makefile.am,v
retrieving revision 1.2.2.4
diff -u -r1.2.2.4 Makefile.am
— test/Makefile.am 2000/03/14 20:29:16 1.2.2.4
+++ test/Makefile.am 2000/04/19 00:47:39
@@ -4,7 +4,7 @@
checkkeys graywin loopwave testalpha testbitmap testcdrom
testerror testhread testkeys testlock testsprite testtimer
testtypes testver testvidinfo testwin testwm threadwin testgl \
- testjoystick
- testjoystick testsem
checkkeys_SOURCES = checkkeys.c
graywin_SOURCES = graywin.c
@@ -28,3 +28,4 @@
testgl_SOURCES = testgl.c
testgl_LDADD = @GL_LIBS@
testjoystick_SOURCES = testjoystick.c
+testsem_SOURCES = testsem.c
Index: test/testsem.c
RCS file: testsem.c
diff -N testsem.c
— /dev/null Tue May 5 13:32:27 1998
+++ testsem.c Tue Apr 18 17:47:39 2000
@@ -0,0 +1,75 @@
+/* Simple test of the SDL semaphore code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include “SDL.h”
+#include “SDL_thread.h”
+#include “SDL_semaphore.h”
+
+#define NUM_THREADS 10
+
+static SDL_sem *sem;
+int alive = 1;
+
+int ThreadFunc(void *data)
+{
- while ( alive ) {
-
SDL_SemWait(sem);
-
printf("Thread number %d has got the semaphore (value = %d)!\n", (int)data, S
DL_SemGetValue(sem));
-
fflush(stdin);
-
SDL_Delay(200);
-
SDL_SemPost(sem);
-
printf("Thread number %d has released the semaphore (value = %d)!\n", (int)da
ta, SDL_SemGetValue(sem));
-
fflush(stdin);
-
SDL_Delay(1); /* For the scheduler */
- }
- printf(“Threads number %d exiting.\n”, (int)data);
- return 0;
+}
+static void killed(int sig)
+{
- alive = 0;
+}
+int main(int argc, char **argv)
+{
- SDL_Thread *threads[NUM_THREADS];
- int i, init_sem;
- if(argc < 2) {
-
fprintf(stderr,"Usage: %s init_value\n", argv[0]);
-
exit(1);
- }
- /* Load the SDL library */
- if ( SDL_Init(0) < 0 ) {
-
fprintf(stderr, "Couldn't initialize SDL: %s\n",SDL_GetError());
-
exit(1);
- }
- atexit(SDL_Quit);
- signal(SIGTERM, killed);
- signal(SIGINT, killed);
- init_sem = atoi(argv[1]);
- sem = SDL_CreateSemaphore(init_sem);
- printf(“Running %d threads, semaphore value = %d\n”, NUM_THREADS, init_sem);
- /* Create all the threads */
- for( i = 0; i < NUM_THREADS; ++i ) {
-
threads[i] = SDL_CreateThread(ThreadFunc, (void*)i);
- }
- /* Wait 10 seconds */
- SDL_Delay(10 * 1000);
- alive = 0;
- /* Wait for all threads to finish */
- for( i = 0; i < NUM_THREADS; ++i ) {
-
SDL_WaitThread(threads[i], NULL);
- }
- SDL_DestroySemaphore(sem);
- return(0);
+}