doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
posix_threads.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
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.
13 
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.
18 
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/>.
21 
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.
23 
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.
25 
26 ===========================================================================
27 */
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <dirent.h>
33 #include <unistd.h>
34 #include <sys/mman.h>
35 #include <sys/time.h>
36 #include <pwd.h>
37 #include <pthread.h>
38 
39 #include "../../idlib/precompiled.h"
40 #include "posix_public.h"
41 
42 #if defined(_DEBUG)
43 // #define ID_VERBOSE_PTHREADS
44 #endif
45 
46 /*
47 ======================================================
48 locks
49 ======================================================
50 */
51 
52 // we use an extra lock for the local stuff
54 static pthread_mutex_t global_lock[ MAX_LOCAL_CRITICAL_SECTIONS ];
55 
56 /*
57 ==================
58 Sys_EnterCriticalSection
59 ==================
60 */
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() );
68  }
69  }
70 #else
71  pthread_mutex_lock( &global_lock[index] );
72 #endif
73 }
74 
75 /*
76 ==================
77 Sys_LeaveCriticalSection
78 ==================
79 */
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() );
85  }
86 #else
87  pthread_mutex_unlock( &global_lock[index] );
88 #endif
89 }
90 
91 /*
92 ======================================================
93 wait and trigger events
94 we use a single lock to manipulate the conditions, MAX_LOCAL_CRITICAL_SECTIONS-1
95 
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)
97 
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 ======================================================
102 */
103 
104 pthread_cond_t event_cond[ MAX_TRIGGER_EVENTS ];
107 
108 /*
109 ==================
110 Sys_WaitForEvent
111 ==================
112 */
113 void Sys_WaitForEvent( int index ) {
114  assert( index >= 0 && index < MAX_TRIGGER_EVENTS );
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;
120  } else {
121  waiting[ index ] = true;
122  pthread_cond_wait( &event_cond[ index ], &global_lock[ MAX_LOCAL_CRITICAL_SECTIONS - 1 ] );
123  waiting[ index ] = false;
124  }
126 }
127 
128 /*
129 ==================
130 Sys_TriggerEvent
131 ==================
132 */
133 void Sys_TriggerEvent( int index ) {
134  assert( index >= 0 && index < MAX_TRIGGER_EVENTS );
136  if ( waiting[ index ] ) {
137  pthread_cond_signal( &event_cond[ index ] );
138  } else {
139  // emulate windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going
140  signaled[ index ] = true;
141  }
143 }
144 
145 /*
146 ======================================================
147 thread create and destroy
148 ======================================================
149 */
150 
151 // not a hard limit, just what we keep track of for debugging
152 #define MAX_THREADS 10
154 
156 
157 typedef void *(*pthread_function_t) (void *);
158 
159 /*
160 ==================
161 Sys_CreateThread
162 ==================
163 */
164 void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo& info, const char *name, xthreadInfo **threads, int *thread_count ) {
166  pthread_attr_t attr;
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 );
170  }
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 );
173  }
174  pthread_attr_destroy( &attr );
175  info.name = name;
176  if ( *thread_count < MAX_THREADS ) {
177  threads[ ( *thread_count )++ ] = &info;
178  } else {
179  common->DPrintf( "WARNING: MAX_THREADS reached\n" );
180  }
182 }
183 
184 /*
185 ==================
186 Sys_DestroyThread
187 ==================
188 */
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 );
194  }
195  if ( pthread_join( ( pthread_t )info.threadHandle, NULL ) != 0 ) {
196  common->Error( "ERROR: pthread_join %s failed\n", info.name );
197  }
198  info.threadHandle = 0;
200  for( int i = 0 ; i < g_thread_count ; i++ ) {
201  if ( &info == g_threads[ i ] ) {
202  g_threads[ i ] = NULL;
203  int j;
204  for( j = i+1 ; j < g_thread_count ; j++ ) {
205  g_threads[ j-1 ] = g_threads[ j ];
206  }
207  g_threads[ j-1 ] = NULL;
208  g_thread_count--;
210  return;
211  }
212  }
214 }
215 
216 /*
217 ==================
218 Sys_GetThreadName
219 find the name of the calling thread
220 ==================
221 */
222 const char* Sys_GetThreadName( int *index ) {
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 ) {
227  if ( index ) {
228  *index = i;
229  }
231  return g_threads[ i ]->name;
232  }
233  }
234  if ( index ) {
235  *index = -1;
236  }
238  return "main";
239 }
240 
241 /*
242 =========================================================
243 Async Thread
244 =========================================================
245 */
246 
248 
249 /*
250 =================
251 Posix_StartAsyncThread
252 =================
253 */
255  if ( asyncThread.threadHandle == 0 ) {
256  Sys_CreateThread( (xthread_t)Sys_AsyncThread, NULL, THREAD_NORMAL, asyncThread, "Async", g_threads, &g_thread_count );
257  } else {
258  common->Printf( "Async thread already running\n" );
259  }
260  common->Printf( "Async thread started\n" );
261 }
262 
263 /*
264 ==================
265 Posix_InitPThreads
266 ==================
267 */
269  int i;
270  pthread_mutexattr_t attr;
271 
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 );
278  }
279 
280  // init event sleep/triggers
281  for ( i = 0; i < MAX_TRIGGER_EVENTS; i++ ) {
282  pthread_cond_init( &event_cond[ i ], NULL );
283  signaled[i] = false;
284  waiting[i] = false;
285  }
286 
287  // init threads table
288  for ( i = 0; i < MAX_THREADS; i++ ) {
289  g_threads[ i ] = NULL;
290  }
291 }
292 
void Sys_AsyncThread(void)
Definition: main.cpp:61
pthread_cond_t event_cond[MAX_TRIGGER_EVENTS]
assert(prefInfo.fullscreenBtn)
void Posix_InitPThreads()
xthreadPriority
Definition: sys_public.h:482
bool signaled[MAX_TRIGGER_EVENTS]
const char * name
Definition: sys_public.h:489
void Sys_Printf(const char *msg,...)
const int MAX_LOCAL_CRITICAL_SECTIONS
const int MAX_CRITICAL_SECTIONS
Definition: sys_public.h:505
int i
Definition: process.py:33
GLuint index
Definition: glext.h:3476
idCommon * common
Definition: Common.cpp:206
#define NULL
Definition: Lib.h:88
int g_thread_count
const int MAX_TRIGGER_EVENTS
Definition: sys_public.h:517
void Sys_DestroyThread(xthreadInfo &info)
xthreadInfo * g_threads[MAX_THREADS]
unsigned int(* xthread_t)(void *)
Definition: sys_public.h:480
const char * Sys_GetThreadName(int *index)
virtual void Printf(const char *fmt,...) id_attribute((format(printf
bool waiting[MAX_TRIGGER_EVENTS]
void Sys_TriggerEvent(int index)
xthreadInfo asyncThread
const GLcharARB * name
Definition: glext.h:3629
void Posix_StartAsyncThread()
int threadHandle
Definition: sys_public.h:490
#define MAX_THREADS
void *(* pthread_function_t)(void *)
GLint j
Definition: qgl.h:264
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
virtual void Error(const char *fmt,...) id_attribute((format(printf
void Sys_LeaveCriticalSection(int index)
void Sys_EnterCriticalSection(int index)
void Sys_WaitForEvent(int index)
void Sys_CreateThread(xthread_t function, void *parms, xthreadPriority priority, xthreadInfo &info, const char *name, xthreadInfo **threads, int *thread_count)