Implemented an API for thread-local storage: SDL_TLSCreate(), SDL_TLSSet(), SDL_TLSGet()
--- a/VisualC/SDL/SDL_VS2008.vcproj Tue Jul 09 12:58:54 2013 -0700
+++ b/VisualC/SDL/SDL_VS2008.vcproj Wed Jul 10 02:32:04 2013 -0700
@@ -1133,6 +1133,10 @@
>
</File>
<File
+ RelativePath="..\..\src\thread\windows\SDL_systls.c"
+ >
+ </File>
+ <File
RelativePath="..\..\src\thread\SDL_systhread.h"
>
</File>
--- a/VisualC/SDL/SDL_VS2010.vcxproj Tue Jul 09 12:58:54 2013 -0700
+++ b/VisualC/SDL/SDL_VS2010.vcxproj Wed Jul 10 02:32:04 2013 -0700
@@ -438,6 +438,7 @@
<ClCompile Include="..\..\src\power\windows\SDL_syspower.c" />
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c" />
<ClCompile Include="..\..\src\thread\windows\SDL_systhread.c" />
+ <ClCompile Include="..\..\src\thread\windows\SDL_systls.c" />
<ClCompile Include="..\..\src\timer\windows\SDL_systimer.c" />
<ClCompile Include="..\..\src\thread\SDL_thread.c" />
<ClCompile Include="..\..\src\timer\SDL_timer.c" />
@@ -462,4 +463,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
--- a/VisualC/SDL/SDL_VS2012.vcxproj Tue Jul 09 12:58:54 2013 -0700
+++ b/VisualC/SDL/SDL_VS2012.vcxproj Wed Jul 10 02:32:04 2013 -0700
@@ -441,6 +441,7 @@
<ClCompile Include="..\..\src\power\windows\SDL_syspower.c" />
<ClCompile Include="..\..\src\thread\windows\SDL_syssem.c" />
<ClCompile Include="..\..\src\thread\windows\SDL_systhread.c" />
+ <ClCompile Include="..\..\src\thread\windows\SDL_systls.c" />
<ClCompile Include="..\..\src\timer\windows\SDL_systimer.c" />
<ClCompile Include="..\..\src\thread\SDL_thread.c" />
<ClCompile Include="..\..\src\timer\SDL_timer.c" />
@@ -466,4 +467,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
--- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj Tue Jul 09 12:58:54 2013 -0700
+++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj Wed Jul 10 02:32:04 2013 -0700
@@ -76,6 +76,7 @@
93CB792613FC5F5300BD3E05 /* SDL_uikitviewcontroller.m in Sources */ = {isa = PBXBuildFile; fileRef = 93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */; };
AA0AD06216647BBB00CE5896 /* SDL_gamecontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */; };
AA0AD06516647BD400CE5896 /* SDL_gamecontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0AD06416647BD400CE5896 /* SDL_gamecontroller.h */; };
+ AA0F8495178D5F1A00823F9D /* SDL_systls.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0F8494178D5F1A00823F9D /* SDL_systls.c */; };
AA126AD41617C5E7005ABC8F /* SDL_uikitmodes.h in Headers */ = {isa = PBXBuildFile; fileRef = AA126AD21617C5E6005ABC8F /* SDL_uikitmodes.h */; };
AA126AD51617C5E7005ABC8F /* SDL_uikitmodes.m in Sources */ = {isa = PBXBuildFile; fileRef = AA126AD31617C5E6005ABC8F /* SDL_uikitmodes.m */; };
AA628ADB159369E3005138DD /* SDL_rotate.c in Sources */ = {isa = PBXBuildFile; fileRef = AA628AD9159369E3005138DD /* SDL_rotate.c */; };
@@ -268,6 +269,7 @@
93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitviewcontroller.m; sourceTree = "<group>"; };
AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gamecontroller.c; sourceTree = "<group>"; };
AA0AD06416647BD400CE5896 /* SDL_gamecontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamecontroller.h; sourceTree = "<group>"; };
+ AA0F8494178D5F1A00823F9D /* SDL_systls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_systls.c; sourceTree = "<group>"; };
AA126AD21617C5E6005ABC8F /* SDL_uikitmodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitmodes.h; sourceTree = "<group>"; };
AA126AD31617C5E6005ABC8F /* SDL_uikitmodes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitmodes.m; sourceTree = "<group>"; };
AA628AD9159369E3005138DD /* SDL_rotate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_rotate.c; sourceTree = "<group>"; };
@@ -851,6 +853,7 @@
FD99BA0A0DD52EDC00FB1D6B /* SDL_syssem.c */,
FD99BA0B0DD52EDC00FB1D6B /* SDL_systhread.c */,
FD99BA0C0DD52EDC00FB1D6B /* SDL_systhread_c.h */,
+ AA0F8494178D5F1A00823F9D /* SDL_systls.c */,
);
path = pthread;
sourceTree = "<group>";
@@ -1189,6 +1192,7 @@
AA704DD7162AA90A0076D1C1 /* SDL_dropevents.c in Sources */,
AABCC3951640643D00AB8930 /* SDL_uikitmessagebox.m in Sources */,
AA0AD06216647BBB00CE5896 /* SDL_gamecontroller.c in Sources */,
+ AA0F8495178D5F1A00823F9D /* SDL_systls.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
--- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj Tue Jul 09 12:58:54 2013 -0700
+++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj Wed Jul 10 02:32:04 2013 -0700
@@ -398,6 +398,9 @@
A77E6EB4167AB0A90010E40B /* SDL_gamecontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A77E6EB3167AB0A90010E40B /* SDL_gamecontroller.h */; settings = {ATTRIBUTES = (Public, ); }; };
A77E6EB5167AB0A90010E40B /* SDL_gamecontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A77E6EB3167AB0A90010E40B /* SDL_gamecontroller.h */; };
AA0AD09D16648D1700CE5896 /* SDL_gamecontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = BBFC088A164C6514003E6A99 /* SDL_gamecontroller.c */; };
+ AA0F8491178D5ECC00823F9D /* SDL_systls.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0F8490178D5ECC00823F9D /* SDL_systls.c */; };
+ AA0F8492178D5ECC00823F9D /* SDL_systls.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0F8490178D5ECC00823F9D /* SDL_systls.c */; };
+ AA0F8493178D5ECC00823F9D /* SDL_systls.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0F8490178D5ECC00823F9D /* SDL_systls.c */; };
AA41F88014B8F1F500993C4F /* SDL_dropevents.c in Sources */ = {isa = PBXBuildFile; fileRef = 566CDE8E148F0AC200C5A9BB /* SDL_dropevents.c */; };
AA628ACA159367B7005138DD /* SDL_rotate.c in Sources */ = {isa = PBXBuildFile; fileRef = AA628AC8159367B7005138DD /* SDL_rotate.c */; };
AA628ACB159367B7005138DD /* SDL_rotate.c in Sources */ = {isa = PBXBuildFile; fileRef = AA628AC8159367B7005138DD /* SDL_rotate.c */; };
@@ -984,6 +987,7 @@
566CDE8D148F0AC200C5A9BB /* SDL_dropevents_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_dropevents_c.h; sourceTree = "<group>"; };
566CDE8E148F0AC200C5A9BB /* SDL_dropevents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_dropevents.c; sourceTree = "<group>"; };
A77E6EB3167AB0A90010E40B /* SDL_gamecontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamecontroller.h; sourceTree = "<group>"; };
+ AA0F8490178D5ECC00823F9D /* SDL_systls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_systls.c; sourceTree = "<group>"; };
AA628AC8159367B7005138DD /* SDL_rotate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_rotate.c; sourceTree = "<group>"; };
AA628AC9159367B7005138DD /* SDL_rotate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_rotate.h; sourceTree = "<group>"; };
AA628ACF159367F2005138DD /* SDL_x11xinput2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_x11xinput2.c; sourceTree = "<group>"; };
@@ -1462,6 +1466,7 @@
04BDFE8112E6671800899322 /* SDL_syssem.c */,
04BDFE8212E6671800899322 /* SDL_systhread.c */,
04BDFE8312E6671800899322 /* SDL_systhread_c.h */,
+ AA0F8490178D5ECC00823F9D /* SDL_systls.c */,
);
path = pthread;
sourceTree = "<group>";
@@ -2403,6 +2408,7 @@
AA9E4093163BE51E007A2AD0 /* SDL_x11messagebox.c in Sources */,
AABCC38F164063D200AB8930 /* SDL_cocoamessagebox.m in Sources */,
AA0AD09D16648D1700CE5896 /* SDL_gamecontroller.c in Sources */,
+ AA0F8491178D5ECC00823F9D /* SDL_systls.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2519,6 +2525,7 @@
AA628AD2159367F2005138DD /* SDL_x11xinput2.c in Sources */,
AA9E4094163BE51E007A2AD0 /* SDL_x11messagebox.c in Sources */,
AABCC390164063D200AB8930 /* SDL_cocoamessagebox.m in Sources */,
+ AA0F8492178D5ECC00823F9D /* SDL_systls.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2635,6 +2642,7 @@
DB31406817554B71006C0E22 /* SDL_x11xinput2.c in Sources */,
DB31406917554B71006C0E22 /* SDL_x11messagebox.c in Sources */,
DB31406A17554B71006C0E22 /* SDL_cocoamessagebox.m in Sources */,
+ AA0F8493178D5ECC00823F9D /* SDL_systls.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
--- a/configure Tue Jul 09 12:58:54 2013 -0700
+++ b/configure Wed Jul 10 02:32:04 2013 -0700
@@ -1511,7 +1511,7 @@
--enable-sse use SSE assembly routines [[default=yes]]
--enable-sse2 use SSE2 assembly routines [[default=no]]
--enable-altivec use Altivec assembly routines [[default=yes]]
- --enable-oss support the OSS audio API [[default=yes]]
+ --enable-oss support the OSS audio API [[default=maybe]]
--enable-alsa support the ALSA audio API [[default=yes]]
--disable-alsatest Do not try to compile and run a test Alsa program
--enable-alsa-shared dynamically load ALSA audio support [[default=yes]]
@@ -17535,8 +17535,20 @@
if test "${enable_oss+set}" = set; then :
enableval=$enable_oss;
else
- enable_oss=yes
-fi
+ enable_oss=maybe
+fi
+
+
+ # OpenBSD "has" OSS, but it's not really for app use. They want you to
+ # use sndio instead. So on there, we default to disabled. You can force
+ # it on if you really want, though.
+ if test x$enable_oss = xmaybe; then
+ enable_oss=yes
+ case "$host" in
+ *-*-openbsd*)
+ enable_oss=no;;
+ esac
+ fi
if test x$enable_audio = xyes -a x$enable_oss = xyes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OSS audio support" >&5
@@ -21423,6 +21435,9 @@
# We can fake these with semaphores and mutexes if necessary
SOURCES="$SOURCES $srcdir/src/thread/pthread/SDL_syscond.c"
+ # Thread local storage
+ SOURCES="$SOURCES $srcdir/src/thread/pthread/SDL_systls.c"
+
have_threads=yes
fi
fi
@@ -22206,7 +22221,7 @@
SOURCES="$SOURCES $srcdir/src/audio/sun/*.c"
have_audio=yes
;;
- netbsd|openbsd)
+ netbsd) # Don't use this on OpenBSD, it's busted.
$as_echo "#define SDL_AUDIO_DRIVER_BSD 1" >>confdefs.h
@@ -22367,9 +22382,7 @@
$as_echo "#define SDL_THREAD_WINDOWS 1" >>confdefs.h
- SOURCES="$SOURCES $srcdir/src/thread/windows/SDL_sysmutex.c"
- SOURCES="$SOURCES $srcdir/src/thread/windows/SDL_syssem.c"
- SOURCES="$SOURCES $srcdir/src/thread/windows/SDL_systhread.c"
+ SOURCES="$SOURCES $srcdir/src/thread/windows/*.c"
SOURCES="$SOURCES $srcdir/src/thread/generic/SDL_syscond.c"
have_threads=yes
fi
--- a/configure.in Tue Jul 09 12:58:54 2013 -0700
+++ b/configure.in Wed Jul 10 02:32:04 2013 -0700
@@ -657,6 +657,7 @@
case "$host" in
*-*-openbsd*)
enable_oss=no;;
+ esac
fi
if test x$enable_audio = xyes -a x$enable_oss = xyes; then
@@ -2019,6 +2020,9 @@
# We can fake these with semaphores and mutexes if necessary
SOURCES="$SOURCES $srcdir/src/thread/pthread/SDL_syscond.c"
+ # Thread local storage
+ SOURCES="$SOURCES $srcdir/src/thread/pthread/SDL_systls.c"
+
have_threads=yes
fi
fi
@@ -2470,9 +2474,7 @@
# Set up files for the thread library
if test x$enable_threads = xyes; then
AC_DEFINE(SDL_THREAD_WINDOWS, 1, [ ])
- SOURCES="$SOURCES $srcdir/src/thread/windows/SDL_sysmutex.c"
- SOURCES="$SOURCES $srcdir/src/thread/windows/SDL_syssem.c"
- SOURCES="$SOURCES $srcdir/src/thread/windows/SDL_systhread.c"
+ SOURCES="$SOURCES $srcdir/src/thread/windows/*.c"
SOURCES="$SOURCES $srcdir/src/thread/generic/SDL_syscond.c"
have_threads=yes
fi
--- a/include/SDL_thread.h Tue Jul 09 12:58:54 2013 -0700
+++ b/include/SDL_thread.h Wed Jul 10 02:32:04 2013 -0700
@@ -32,6 +32,7 @@
#include "SDL_error.h"
/* Thread synchronization primitives */
+#include "SDL_atomic.h"
#include "SDL_mutex.h"
#include "begin_code.h"
@@ -47,6 +48,9 @@
/* The SDL thread ID */
typedef unsigned long SDL_threadID;
+/* Thread local storage ID */
+typedef int SDL_TLSID;
+
/* The SDL thread priority
*
* Note: On many systems you require special privileges to set high priority.
@@ -166,6 +170,63 @@
*/
extern DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread * thread, int *status);
+/**
+ * \brief Create an identifier that is globally visible to all threads but refers to data that is thread-specific.
+ *
+ * \return The newly created thread local storage identifier, or 0 on error
+ *
+ * \code
+ * static SDL_SpinLock tls_lock;
+ * static SDL_TLSID thread_local_storage;
+ *
+ * void SetMyThreadData(void *value)
+ * {
+ * if (!thread_local_storage) {
+ * SDL_AtomicLock(&tls_lock);
+ * if (!thread_local_storage) {
+ * thread_local_storage = SDL_TLSCreate();
+ * }
+ * SDL_AtomicUnLock(&tls_lock);
+ * }
+ * SDL_TLSSet(thread_local_storage, value);
+ * }
+ *
+ * void *GetMyThreadData(void)
+ * {
+ * return SDL_TLSGet(thread_local_storage);
+ * }
+ * \endcode
+ *
+ * \sa SDL_TLSGet()
+ * \sa SDL_TLSSet()
+ */
+extern DECLSPEC SDL_TLSID SDLCALL SDL_TLSCreate();
+
+/**
+ * \brief Get the value associated with a thread local storage ID for the current thread.
+ *
+ * \param id The thread local storage ID
+ *
+ * \return The value associated with the ID for the current thread, or NULL if no value has been set.
+ *
+ * \sa SDL_TLSCreate()
+ * \sa SDL_TLSSet()
+ */
+extern DECLSPEC void * SDLCALL SDL_TLSGet(SDL_TLSID id);
+
+/**
+ * \brief Set the value associated with a thread local storage ID for the current thread.
+ *
+ * \param id The thread local storage ID
+ * \param value The value to associate with the ID for the current thread
+ *
+ * \return 0 on success, -1 on error
+ *
+ * \sa SDL_TLSCreate()
+ * \sa SDL_TLSGet()
+ */
+extern DECLSPEC int SDLCALL SDL_TLSSet(SDL_TLSID id, const void *value);
+
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
--- a/src/thread/SDL_thread.c Tue Jul 09 12:58:54 2013 -0700
+++ b/src/thread/SDL_thread.c Wed Jul 10 02:32:04 2013 -0700
@@ -22,158 +22,46 @@
/* System independent thread management routines for SDL */
-#include "SDL_mutex.h"
#include "SDL_thread.h"
#include "SDL_thread_c.h"
#include "SDL_systhread.h"
#include "../SDL_error_c.h"
-#define ARRAY_CHUNKSIZE 32
-/* The array of threads currently active in the application
- (except the main thread)
- The manipulation of an array here is safer than using a linked list.
-*/
-static int SDL_maxthreads = 0;
-static int SDL_numthreads = 0;
-static SDL_Thread **SDL_Threads = NULL;
-static SDL_mutex *thread_lock = NULL;
-
-static int
-SDL_ThreadsInit(void)
-{
- int retval;
-
- retval = 0;
- thread_lock = SDL_CreateMutex();
- if (thread_lock == NULL) {
- retval = -1;
- }
- return (retval);
-}
-
-/* This should never be called...
- If this is called by SDL_Quit(), we don't know whether or not we should
- clean up threads here. If any threads are still running after this call,
- they will no longer have access to any per-thread data.
- */
-#if 0
-static void
-SDL_ThreadsQuit(void)
-{
- SDL_mutex *mutex;
-
- mutex = thread_lock;
- thread_lock = NULL;
- if (mutex != NULL) {
- SDL_DestroyMutex(mutex);
- }
-}
-#endif
-
-/* Routines for manipulating the thread list */
-static void
-SDL_AddThread(SDL_Thread * thread)
-{
- /* WARNING:
- If the very first threads are created simultaneously, then
- there could be a race condition causing memory corruption.
- In practice, this isn't a problem because by definition there
- is only one thread running the first time this is called.
- */
- if (!thread_lock) {
- if (SDL_ThreadsInit() < 0) {
- return;
- }
- }
- SDL_LockMutex(thread_lock);
-
- /* Expand the list of threads, if necessary */
-#ifdef DEBUG_THREADS
- printf("Adding thread (%d already - %d max)\n",
- SDL_numthreads, SDL_maxthreads);
-#endif
- if (SDL_numthreads == SDL_maxthreads) {
- SDL_Thread **threads;
- threads = (SDL_Thread **) SDL_realloc(SDL_Threads,
- (SDL_maxthreads +
- ARRAY_CHUNKSIZE) *
- (sizeof *threads));
- if (threads == NULL) {
- SDL_OutOfMemory();
- goto done;
- }
- SDL_maxthreads += ARRAY_CHUNKSIZE;
- SDL_Threads = threads;
- }
- SDL_Threads[SDL_numthreads++] = thread;
- done:
- SDL_mutexV(thread_lock);
-}
-
-static void
-SDL_DelThread(SDL_Thread * thread)
-{
- int i;
-
- if (!thread_lock) {
- return;
- }
- SDL_LockMutex(thread_lock);
- for (i = 0; i < SDL_numthreads; ++i) {
- if (thread == SDL_Threads[i]) {
- break;
- }
- }
- if (i < SDL_numthreads) {
- if (--SDL_numthreads > 0) {
- while (i < SDL_numthreads) {
- SDL_Threads[i] = SDL_Threads[i + 1];
- ++i;
- }
- } else {
- SDL_maxthreads = 0;
- SDL_free(SDL_Threads);
- SDL_Threads = NULL;
- }
-#ifdef DEBUG_THREADS
- printf("Deleting thread (%d left - %d max)\n",
- SDL_numthreads, SDL_maxthreads);
-#endif
- }
- SDL_mutexV(thread_lock);
-
-#if 0 /* There could be memory corruption if another thread is starting */
- if (SDL_Threads == NULL) {
- SDL_ThreadsQuit();
- }
-#endif
-}
-
-/* The default (non-thread-safe) global error variable */
-static SDL_error SDL_global_error;
/* Routine to get the thread-specific error variable */
SDL_error *
SDL_GetErrBuf(void)
{
+ static SDL_SpinLock spinlock;
+ static SDL_bool tls_being_created;
+ static SDL_TLSID tls_errbuf;
+ static SDL_error SDL_global_errbuf;
SDL_error *errbuf;
- errbuf = &SDL_global_error;
- if (SDL_Threads) {
- int i;
- SDL_threadID this_thread;
+ if (!tls_errbuf && !tls_being_created) {
+ SDL_AtomicLock(&spinlock);
+ if (!tls_errbuf) {
+ /* SDL_TLSCreate() could fail and call SDL_SetError() */
+ tls_being_created = SDL_TRUE;
+ tls_errbuf = SDL_TLSCreate();
+ tls_being_created = SDL_FALSE;
+ }
+ SDL_AtomicUnlock(&spinlock);
+ }
+ if (!tls_errbuf) {
+ return &SDL_global_errbuf;
+ }
- this_thread = SDL_ThreadID();
- SDL_LockMutex(thread_lock);
- for (i = 0; i < SDL_numthreads; ++i) {
- if (this_thread == SDL_Threads[i]->threadid) {
- errbuf = &SDL_Threads[i]->errbuf;
- break;
- }
+ errbuf = SDL_TLSGet(tls_errbuf);
+ if (!errbuf) {
+ errbuf = (SDL_error *)SDL_malloc(sizeof(*errbuf));
+ if (!errbuf) {
+ return &SDL_global_errbuf;
}
- SDL_mutexV(thread_lock);
+ SDL_zerop(errbuf);
+ SDL_TLSSet(tls_errbuf, errbuf);
}
- return (errbuf);
+ return errbuf;
}
@@ -264,9 +152,6 @@
return (NULL);
}
- /* Add the thread to the list of available threads */
- SDL_AddThread(thread);
-
/* Create the thread and go! */
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
@@ -278,7 +163,6 @@
SDL_SemWait(args->wait);
} else {
/* Oops, failed. Gotta free everything */
- SDL_DelThread(thread);
SDL_free(thread->name);
SDL_free(thread);
thread = NULL;
@@ -323,7 +207,6 @@
if (status) {
*status = thread->status;
}
- SDL_DelThread(thread);
SDL_free(thread->name);
SDL_free(thread);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread/beos/SDL_systls.c Wed Jul 10 02:32:04 2013 -0700
@@ -0,0 +1,106 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+#include "SDL_thread.h"
+
+#if SDL_THREAD_BEOS
+
+#include <support/TLS.h>
+
+
+#define TLS_ALLOC_CHUNKSIZE 8
+
+typedef struct {
+ int limit;
+ void *data[1];
+} SDL_TLSData;
+
+static SDL_SpinLock tls_lock;
+static int32 thread_local_storage = B_NO_MEMORY;
+static SDL_atomic_t tls_id;
+
+
+SDL_TLSID
+SDL_TLSCreate()
+{
+ if (thread_local_storage == B_NO_MEMORY) {
+ SDL_AtomicLock(&tls_lock);
+ if (thread_local_storage == B_NO_MEMORY) {
+ thread_local_storage = tls_allocate();
+ if (thread_local_storage == B_NO_MEMORY) {
+ SDL_SetError("tls_allocate() failed");
+ SDL_AtomicUnlock(&tls_lock);
+ return 0;
+ }
+ }
+ SDL_AtomicUnlock(&tls_lock);
+ }
+ return SDL_AtomicIncRef(&tls_id)+1;
+}
+
+void *
+SDL_TLSGet(SDL_TLSID id)
+{
+ SDL_TLSData *data;
+
+ data = (SDL_TLSData *)tls_get(thread_local_storage);
+ if (!data || id <= 0 || id > data->limit) {
+ return NULL;
+ }
+ return data->data[id-1];
+}
+
+int
+SDL_TLSSet(SDL_TLSID id, const void *value)
+{
+ SDL_TLSData *data;
+
+ if (thread_local_storage == B_NO_MEMORY || id <= 0) {
+ return SDL_InvalidParamError(id);
+ }
+
+ data = (SDL_TLSData *)tls_get(thread_local_storage);
+ if (!data || id > data->limit) {
+ int i, oldlimit, newlimit;
+
+ oldlimit = data ? data->limit : 0;
+ newlimit = (id + TLS_ALLOC_CHUNKSIZE);
+ data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
+ if (!data) {
+ return SDL_OutOfMemory();
+ }
+ data->limit = newlimit;
+ for (i = oldlimit; i < newlimit; ++i) {
+ data->data[i] = NULL;
+ }
+ if (!tls_set(thread_local_storage, data)) {
+ return SDL_SetError("TlsSetValue() failed");
+ }
+ }
+
+ data->data[id-1] = SDL_const_cast(void*, value);
+ return 0;
+}
+
+#endif /* SDL_THREAD_BEOS */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread/generic/SDL_systls.c Wed Jul 10 02:32:04 2013 -0700
@@ -0,0 +1,163 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+#include "SDL_thread.h"
+
+/* This is a generic implementation of thread-local storage which doesn't
+ require additional OS support.
+
+ It is not especially efficient and doesn't clean up thread-local storage
+ as threads exit. If there is a real OS that doesn't support thread-local
+ storage this implementation should be improved to be production quality.
+*/
+
+#define TLS_ALLOC_CHUNKSIZE 8
+
+typedef struct {
+ int limit;
+ void *data[1];
+} SDL_TLSData;
+
+typedef struct SDL_TLSEntry {
+ SDL_threadID thread;
+ SDL_TLSData *data;
+ struct SDL_TLSEntry *next;
+} SDL_TLSEntry;
+
+static SDL_SpinLock tls_lock;
+static SDL_mutex *tls_mutex;
+static SDL_TLSEntry *thread_local_storage;
+static SDL_atomic_t tls_id;
+
+
+static SDL_TLSData *GetTLSData()
+{
+ SDL_threadID thread = SDL_ThreadID();
+ SDL_TLSEntry *entry;
+ SDL_TLSData *data = NULL;
+
+ if (!tls_mutex) {
+ SDL_AtomicLock(&tls_lock);
+ if (!tls_mutex) {
+ tls_mutex = SDL_CreateMutex();
+ if (!tls_mutex) {
+ SDL_AtomicUnlock(&tls_lock);
+ return NULL;
+ }
+ }
+ SDL_AtomicUnlock(&tls_lock);
+ }
+
+ SDL_LockMutex(tls_mutex);
+ for (entry = thread_local_storage; entry; entry = entry->next) {
+ if (entry->thread == thread) {
+ data = entry->data;
+ break;
+ }
+ }
+ SDL_UnlockMutex(tls_mutex);
+
+ return data;
+}
+
+static int SetTLSData(SDL_TLSData *data)
+{
+ SDL_threadID thread = SDL_ThreadID();
+ SDL_TLSEntry *entry;
+
+ /* GetTLSData() is always called first, so we can assume tls_mutex */
+ SDL_LockMutex(tls_mutex);
+ for (entry = thread_local_storage; entry; entry = entry->next) {
+ if (entry->thread == thread) {
+ entry->data = data;
+ break;
+ }
+ }
+ if (!entry) {
+ entry = (SDL_TLSEntry *)SDL_malloc(sizeof(*entry));
+ if (entry) {
+ entry->thread = thread;
+ entry->data = data;
+ entry->next = thread_local_storage;
+ thread_local_storage = entry;
+ }
+ }
+ SDL_UnlockMutex(tls_mutex);
+
+ if (!entry) {
+ return SDL_OutOfMemory();
+ }
+ return 0;
+}
+
+
+SDL_TLSID
+SDL_TLSCreate()
+{
+ return SDL_AtomicIncRef(&tls_id)+1;
+}
+
+void *
+SDL_TLSGet(SDL_TLSID id)
+{
+ SDL_TLSData *data;
+
+ data = GetTLSData();
+ if (!data || id <= 0 || id > data->limit) {
+ return NULL;
+ }
+ return data->data[id-1];
+}
+
+int
+SDL_TLSSet(SDL_TLSID id, const void *value)
+{
+ SDL_TLSData *data;
+
+ if (id <= 0) {
+ return SDL_InvalidParamError(id);
+ }
+
+ data = GetTLSData();
+ if (!data || id > data->limit) {
+ int i, oldlimit, newlimit;
+
+ oldlimit = data ? data->limit : 0;
+ newlimit = (id + TLS_ALLOC_CHUNKSIZE);
+ data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
+ if (!data) {
+ return SDL_OutOfMemory();
+ }
+ data->limit = newlimit;
+ for (i = oldlimit; i < newlimit; ++i) {
+ data->data[i] = NULL;
+ }
+ if (SetTLSData(data) != 0) {
+ return -1;
+ }
+ }
+
+ data->data[id-1] = SDL_const_cast(void*, value);
+ return 0;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread/pthread/SDL_systls.c Wed Jul 10 02:32:04 2013 -0700
@@ -0,0 +1,101 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+#include "SDL_thread.h"
+
+#include <pthread.h>
+
+
+#define TLS_ALLOC_CHUNKSIZE 8
+
+typedef struct {
+ int limit;
+ void *data[1];
+} SDL_TLSData;
+
+static SDL_SpinLock tls_lock;
+static pthread_key_t thread_local_storage;
+static SDL_atomic_t tls_id;
+
+
+SDL_TLSID
+SDL_TLSCreate()
+{
+ if (!thread_local_storage) {
+ SDL_AtomicLock(&tls_lock);
+ if (!thread_local_storage) {
+ if (pthread_key_create(&thread_local_storage, NULL) != 0) {
+ SDL_SetError("pthread_key_create() failed");
+ SDL_AtomicUnlock(&tls_lock);
+ return 0;
+ }
+ }
+ SDL_AtomicUnlock(&tls_lock);
+ }
+ return SDL_AtomicIncRef(&tls_id)+1;
+}
+
+void *
+SDL_TLSGet(SDL_TLSID id)
+{
+ SDL_TLSData *data;
+
+ data = (SDL_TLSData *)pthread_getspecific(thread_local_storage);
+ if (!data || id <= 0 || id > data->limit) {
+ return NULL;
+ }
+ return data->data[id-1];
+}
+
+int
+SDL_TLSSet(SDL_TLSID id, const void *value)
+{
+ SDL_TLSData *data;
+
+ if (!thread_local_storage || id <= 0) {
+ return SDL_InvalidParamError(id);
+ }
+
+ data = (SDL_TLSData *)pthread_getspecific(thread_local_storage);
+ if (!data || id > data->limit) {
+ int i, oldlimit, newlimit;
+
+ oldlimit = data ? data->limit : 0;
+ newlimit = (id + TLS_ALLOC_CHUNKSIZE);
+ data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
+ if (!data) {
+ return SDL_OutOfMemory();
+ }
+ data->limit = newlimit;
+ for (i = oldlimit; i < newlimit; ++i) {
+ data->data[i] = NULL;
+ }
+ if (pthread_setspecific(thread_local_storage, data) != 0) {
+ return SDL_SetError("pthread_setspecific() failed");
+ }
+ }
+
+ data->data[id-1] = SDL_const_cast(void*, value);
+ return 0;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/thread/windows/SDL_systls.c Wed Jul 10 02:32:04 2013 -0700
@@ -0,0 +1,106 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_config.h"
+#include "SDL_thread.h"
+
+#if SDL_THREAD_WINDOWS
+
+#include "../../core/windows/SDL_windows.h"
+
+
+#define TLS_ALLOC_CHUNKSIZE 8
+
+typedef struct {
+ int limit;
+ void *data[1];
+} SDL_TLSData;
+
+static SDL_SpinLock tls_lock;
+static DWORD thread_local_storage = TLS_OUT_OF_INDEXES;
+static SDL_atomic_t tls_id;
+
+
+SDL_TLSID
+SDL_TLSCreate()
+{
+ if (thread_local_storage == TLS_OUT_OF_INDEXES) {
+ SDL_AtomicLock(&tls_lock);
+ if (thread_local_storage == TLS_OUT_OF_INDEXES) {
+ thread_local_storage = TlsAlloc();
+ if (thread_local_storage == TLS_OUT_OF_INDEXES) {
+ SDL_SetError("TlsAlloc() failed");
+ SDL_AtomicUnlock(&tls_lock);
+ return 0;
+ }
+ }
+ SDL_AtomicUnlock(&tls_lock);
+ }
+ return SDL_AtomicIncRef(&tls_id)+1;
+}
+
+void *
+SDL_TLSGet(SDL_TLSID id)
+{
+ SDL_TLSData *data;
+
+ data = (SDL_TLSData *)TlsGetValue(thread_local_storage);
+ if (!data || id <= 0 || id > data->limit) {
+ return NULL;
+ }
+ return data->data[id-1];
+}
+
+int
+SDL_TLSSet(SDL_TLSID id, const void *value)
+{
+ SDL_TLSData *data;
+
+ if (thread_local_storage == TLS_OUT_OF_INDEXES || id <= 0) {
+ return SDL_InvalidParamError(id);
+ }
+
+ data = (SDL_TLSData *)TlsGetValue(thread_local_storage);
+ if (!data || id > data->limit) {
+ int i, oldlimit, newlimit;
+
+ oldlimit = data ? data->limit : 0;
+ newlimit = (id + TLS_ALLOC_CHUNKSIZE);
+ data = (SDL_TLSData *)SDL_realloc(data, sizeof(*data)+(newlimit-1)*sizeof(void*));
+ if (!data) {
+ return SDL_OutOfMemory();
+ }
+ data->limit = newlimit;
+ for (i = oldlimit; i < newlimit; ++i) {
+ data->data[i] = NULL;
+ }
+ if (!TlsSetValue(thread_local_storage, data)) {
+ return SDL_SetError("TlsSetValue() failed");
+ }
+ }
+
+ data->data[id-1] = SDL_const_cast(void*, value);
+ return 0;
+}
+
+#endif /* SDL_THREAD_WINDOWS */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/test/testthread.c Tue Jul 09 12:58:54 2013 -0700
+++ b/test/testthread.c Wed Jul 10 02:32:04 2013 -0700
@@ -19,6 +19,7 @@
#include "SDL.h"
#include "SDL_thread.h"
+static SDL_TLSID tls;
static int alive = 0;
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
@@ -32,8 +33,9 @@
int SDLCALL
ThreadFunc(void *data)
{
- printf("Started thread %s: My thread id is %lu\n",
- (char *) data, SDL_ThreadID());
+ SDL_TLSSet(tls, "baby thread");
+ printf("Started thread %s: My thread id is %lu, thread data = %s\n",
+ (char *) data, SDL_ThreadID(), (const char *)SDL_TLSGet(tls));
while (alive) {
printf("Thread '%s' is alive!\n", (char *) data);
SDL_Delay(1 * 1000);
@@ -62,6 +64,11 @@
return (1);
}
+ tls = SDL_TLSCreate();
+ SDL_assert(tls);
+ SDL_TLSSet(tls, "main thread");
+ printf("Main thread data initially: %s\n", (const char *)SDL_TLSGet(tls));
+
alive = 1;
thread = SDL_CreateThread(ThreadFunc, "One", "#1");
if (thread == NULL) {
@@ -73,6 +80,8 @@
alive = 0;
SDL_WaitThread(thread, NULL);
+ printf("Main thread data finally: %s\n", (const char *)SDL_TLSGet(tls));
+
alive = 1;
signal(SIGTERM, killed);
thread = SDL_CreateThread(ThreadFunc, "Two", "#2");