2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
28 #include <sys/types.h>
39 #include "../../idlib/precompiled.h"
40 #include "posix_public.h"
43 // #define ID_VERBOSE_PTHREADS
47 ======================================================
49 ======================================================
52 // we use an extra lock for the local stuff
53 const int MAX_LOCAL_CRITICAL_SECTIONS = MAX_CRITICAL_SECTIONS + 1;
54 static pthread_mutex_t global_lock[ MAX_LOCAL_CRITICAL_SECTIONS ];
58 Sys_EnterCriticalSection
61 void Sys_EnterCriticalSection( int index ) {
62 assert( index >= 0 && index < MAX_LOCAL_CRITICAL_SECTIONS );
63 #ifdef ID_VERBOSE_PTHREADS
64 if ( pthread_mutex_trylock( &global_lock[index] ) == EBUSY ) {
65 Sys_Printf( "busy lock %d in thread '%s'\n", index, Sys_GetThreadName() );
66 if ( pthread_mutex_lock( &global_lock[index] ) == EDEADLK ) {
67 Sys_Printf( "FATAL: DEADLOCK %d, in thread '%s'\n", index, Sys_GetThreadName() );
71 pthread_mutex_lock( &global_lock[index] );
77 Sys_LeaveCriticalSection
80 void Sys_LeaveCriticalSection( int index ) {
81 assert( index >= 0 && index < MAX_LOCAL_CRITICAL_SECTIONS );
82 #ifdef ID_VERBOSE_PTHREADS
83 if ( pthread_mutex_unlock( &global_lock[index] ) == EPERM ) {
84 Sys_Printf( "FATAL: NOT LOCKED %d, in thread '%s'\n", index, Sys_GetThreadName() );
87 pthread_mutex_unlock( &global_lock[index] );
92 ======================================================
93 wait and trigger events
94 we use a single lock to manipulate the conditions, MAX_LOCAL_CRITICAL_SECTIONS-1
96 the semantics match the win32 version. signals raised while no one is waiting stay raised until a wait happens (which then does a simple pass-through)
98 NOTE: we use the same mutex for all the events. I don't think this would become much of a problem
99 cond_wait unlocks atomically with setting the wait condition, and locks it back before exiting the function
100 the potential for time wasting lock waits is very low
101 ======================================================
104 pthread_cond_t event_cond[ MAX_TRIGGER_EVENTS ];
105 bool signaled[ MAX_TRIGGER_EVENTS ];
106 bool waiting[ MAX_TRIGGER_EVENTS ];
113 void Sys_WaitForEvent( int index ) {
114 assert( index >= 0 && index < MAX_TRIGGER_EVENTS );
115 Sys_EnterCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 );
116 assert( !waiting[ index ] ); // WaitForEvent from multiple threads? that wouldn't be good
117 if ( signaled[ index ] ) {
118 // emulate windows behaviour: signal has been raised already. clear and keep going
119 signaled[ index ] = false;
121 waiting[ index ] = true;
122 pthread_cond_wait( &event_cond[ index ], &global_lock[ MAX_LOCAL_CRITICAL_SECTIONS - 1 ] );
123 waiting[ index ] = false;
125 Sys_LeaveCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 );
133 void Sys_TriggerEvent( int index ) {
134 assert( index >= 0 && index < MAX_TRIGGER_EVENTS );
135 Sys_EnterCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 );
136 if ( waiting[ index ] ) {
137 pthread_cond_signal( &event_cond[ index ] );
139 // emulate windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going
140 signaled[ index ] = true;
142 Sys_LeaveCriticalSection( MAX_LOCAL_CRITICAL_SECTIONS - 1 );
146 ======================================================
147 thread create and destroy
148 ======================================================
151 // not a hard limit, just what we keep track of for debugging
152 #define MAX_THREADS 10
153 xthreadInfo *g_threads[MAX_THREADS];
155 int g_thread_count = 0;
157 typedef void *(*pthread_function_t) (void *);
164 void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo& info, const char *name, xthreadInfo **threads, int *thread_count ) {
165 Sys_EnterCriticalSection( );
167 pthread_attr_init( &attr );
168 if ( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) != 0 ) {
169 common->Error( "ERROR: pthread_attr_setdetachstate %s failed\n", name );
171 if ( pthread_create( ( pthread_t* )&info.threadHandle, &attr, ( pthread_function_t )function, parms ) != 0 ) {
172 common->Error( "ERROR: pthread_create %s failed\n", name );
174 pthread_attr_destroy( &attr );
176 if ( *thread_count < MAX_THREADS ) {
177 threads[ ( *thread_count )++ ] = &info;
179 common->DPrintf( "WARNING: MAX_THREADS reached\n" );
181 Sys_LeaveCriticalSection( );
189 void Sys_DestroyThread( xthreadInfo& info ) {
190 // the target thread must have a cancelation point, otherwise pthread_cancel is useless
191 assert( info.threadHandle );
192 if ( pthread_cancel( ( pthread_t )info.threadHandle ) != 0 ) {
193 common->Error( "ERROR: pthread_cancel %s failed\n", info.name );
195 if ( pthread_join( ( pthread_t )info.threadHandle, NULL ) != 0 ) {
196 common->Error( "ERROR: pthread_join %s failed\n", info.name );
198 info.threadHandle = 0;
199 Sys_EnterCriticalSection( );
200 for( int i = 0 ; i < g_thread_count ; i++ ) {
201 if ( &info == g_threads[ i ] ) {
202 g_threads[ i ] = NULL;
204 for( j = i+1 ; j < g_thread_count ; j++ ) {
205 g_threads[ j-1 ] = g_threads[ j ];
207 g_threads[ j-1 ] = NULL;
209 Sys_LeaveCriticalSection( );
213 Sys_LeaveCriticalSection( );
219 find the name of the calling thread
222 const char* Sys_GetThreadName( int *index ) {
223 Sys_EnterCriticalSection( );
224 pthread_t thread = pthread_self();
225 for( int i = 0 ; i < g_thread_count ; i++ ) {
226 if ( thread == (pthread_t)g_threads[ i ]->threadHandle ) {
230 Sys_LeaveCriticalSection( );
231 return g_threads[ i ]->name;
237 Sys_LeaveCriticalSection( );
242 =========================================================
244 =========================================================
247 xthreadInfo asyncThread;
251 Posix_StartAsyncThread
254 void Posix_StartAsyncThread() {
255 if ( asyncThread.threadHandle == 0 ) {
256 Sys_CreateThread( (xthread_t)Sys_AsyncThread, NULL, THREAD_NORMAL, asyncThread, "Async", g_threads, &g_thread_count );
258 common->Printf( "Async thread already running\n" );
260 common->Printf( "Async thread started\n" );
268 void Posix_InitPThreads( ) {
270 pthread_mutexattr_t attr;
272 // init critical sections
273 for ( i = 0; i < MAX_LOCAL_CRITICAL_SECTIONS; i++ ) {
274 pthread_mutexattr_init( &attr );
275 pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
276 pthread_mutex_init( &global_lock[i], &attr );
277 pthread_mutexattr_destroy( &attr );
280 // init event sleep/triggers
281 for ( i = 0; i < MAX_TRIGGER_EVENTS; i++ ) {
282 pthread_cond_init( &event_cond[ i ], NULL );
287 // init threads table
288 for ( i = 0; i < MAX_THREADS; i++ ) {
289 g_threads[ i ] = NULL;