5fe2894098480d6320f54b6b35c6ce91c0e7c62b
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / common / threads.c
1 /*
2    Copyright (C) 1999-2007 id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "globaldefs.h"
23
24 #if !GDEF_OS_WINDOWS
25 // The below define is necessary to use
26 // pthreads extensions like pthread_mutexattr_settype
27 #define _GNU_SOURCE
28 #endif // !GDEF_OS_WINDOWS
29
30 #include "cmdlib.h"
31 #include "mathlib.h"
32 #include "inout.h"
33 #include "her2_threads.h"
34
35 #define MAX_THREADS 64
36
37 int dispatch;
38 int workcount;
39 int oldf;
40 qboolean pacifier;
41
42 qboolean threaded;
43
44 /*
45    =============
46    GetThreadWork
47
48    =============
49  */
50 int GetThreadWork( void ){
51         int r;
52         int f;
53
54         ThreadLock();
55
56         if ( dispatch == workcount ) {
57                 ThreadUnlock();
58                 return -1;
59         }
60
61         f = 10 * dispatch / workcount;
62         if ( f != oldf ) {
63                 oldf = f;
64                 if ( pacifier ) {
65                         Sys_Printf( "%i...", f );
66                         fflush( stdout );   /* ydnar */
67                 }
68         }
69
70         r = dispatch;
71         dispatch++;
72         ThreadUnlock();
73
74         return r;
75 }
76
77
78 void ( *workfunction )( int );
79
80 void ThreadWorkerFunction( int threadnum ){
81         int work;
82
83         while ( 1 )
84         {
85                 work = GetThreadWork();
86                 if ( work == -1 ) {
87                         break;
88                 }
89 //Sys_Printf ("thread %i, work %i\n", threadnum, work);
90                 workfunction( work );
91         }
92 }
93
94 void RunThreadsOnIndividual( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
95         if ( numthreads == -1 ) {
96                 ThreadSetDefault();
97         }
98         workfunction = func;
99         RunThreadsOn( workcnt, showpacifier, ThreadWorkerFunction );
100 }
101
102
103 #if GDEF_OS_WINDOWS
104
105 /*
106    ===================================================================
107
108    WIN32
109
110    ===================================================================
111  */
112
113 #include <windows.h>
114
115 int numthreads = -1;
116 CRITICAL_SECTION crit;
117 static int enter;
118
119 void ThreadSetDefault( void ){
120         SYSTEM_INFO info;
121
122         if ( numthreads == -1 ) { // not set manually
123                 GetSystemInfo( &info );
124                 numthreads = info.dwNumberOfProcessors;
125                 if ( numthreads < 1 || numthreads > 32 ) {
126                         numthreads = 1;
127                 }
128         }
129
130         Sys_Printf( "%i threads\n", numthreads );
131 }
132
133
134 void ThreadLock( void ){
135         if ( !threaded ) {
136                 return;
137         }
138         EnterCriticalSection( &crit );
139         if ( enter ) {
140                 Error( "Recursive ThreadLock\n" );
141         }
142         enter = 1;
143 }
144
145 void ThreadUnlock( void ){
146         if ( !threaded ) {
147                 return;
148         }
149         if ( !enter ) {
150                 Error( "ThreadUnlock without lock\n" );
151         }
152         enter = 0;
153         LeaveCriticalSection( &crit );
154 }
155
156 /*
157    =============
158    RunThreadsOn
159    =============
160  */
161 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
162         int threadid[MAX_THREADS];
163         HANDLE threadhandle[MAX_THREADS];
164         int i;
165         int start, end;
166
167         start = I_FloatTime();
168         dispatch = 0;
169         workcount = workcnt;
170         oldf = -1;
171         pacifier = showpacifier;
172         threaded = true;
173
174         //
175         // run threads in parallel
176         //
177         InitializeCriticalSection( &crit );
178
179         if ( numthreads == 1 ) { // use same thread
180                 func( 0 );
181         }
182         else
183         {
184                 for ( i = 0 ; i < numthreads ; i++ )
185                 {
186                         threadhandle[i] = CreateThread(
187                                 NULL,   // LPSECURITY_ATTRIBUTES lpsa,
188                             //0,                // DWORD cbStack,
189
190                             /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */
191                                 ( 4096 * 1024 ),
192
193                                 (LPTHREAD_START_ROUTINE)func,   // LPTHREAD_START_ROUTINE lpStartAddr,
194                                 (LPVOID)i,  // LPVOID lpvThreadParm,
195                                 0,          //   DWORD fdwCreate,
196                                 &threadid[i] );
197                 }
198
199                 for ( i = 0 ; i < numthreads ; i++ )
200                         WaitForSingleObject( threadhandle[i], INFINITE );
201         }
202         DeleteCriticalSection( &crit );
203
204         threaded = false;
205         end = I_FloatTime();
206         if ( pacifier ) {
207                 Sys_Printf( " (%i)\n", end - start );
208         }
209 }
210
211
212 #elif GDEF_OS_OSF1
213
214 /*
215    ===================================================================
216
217    OSF1
218
219    ===================================================================
220  */
221
222 int numthreads = 4;
223
224 void ThreadSetDefault( void ){
225         if ( numthreads == -1 ) { // not set manually
226                 numthreads = 4;
227         }
228 }
229
230 #include <pthread.h>
231
232 pthread_mutex_t *my_mutex;
233
234 void ThreadLock( void ){
235         if ( my_mutex ) {
236                 pthread_mutex_lock( my_mutex );
237         }
238 }
239
240 void ThreadUnlock( void ){
241         if ( my_mutex ) {
242                 pthread_mutex_unlock( my_mutex );
243         }
244 }
245
246
247 /*
248    =============
249    RunThreadsOn
250    =============
251  */
252 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
253         int i;
254         pthread_t work_threads[MAX_THREADS];
255         pthread_addr_t status;
256         pthread_attr_t attrib;
257         pthread_mutexattr_t mattrib;
258         int start, end;
259
260         start = I_FloatTime();
261         dispatch = 0;
262         workcount = workcnt;
263         oldf = -1;
264         pacifier = showpacifier;
265         threaded = true;
266
267         if ( pacifier ) {
268                 setbuf( stdout, NULL );
269         }
270
271         if ( !my_mutex ) {
272                 my_mutex = safe_malloc( sizeof( *my_mutex ) );
273                 if ( pthread_mutexattr_create( &mattrib ) == -1 ) {
274                         Error( "pthread_mutex_attr_create failed" );
275                 }
276                 if ( pthread_mutexattr_setkind_np( &mattrib, MUTEX_FAST_NP ) == -1 ) {
277                         Error( "pthread_mutexattr_setkind_np failed" );
278                 }
279                 if ( pthread_mutex_init( my_mutex, mattrib ) == -1 ) {
280                         Error( "pthread_mutex_init failed" );
281                 }
282         }
283
284         if ( pthread_attr_create( &attrib ) == -1 ) {
285                 Error( "pthread_attr_create failed" );
286         }
287         if ( pthread_attr_setstacksize( &attrib, 0x100000 ) == -1 ) {
288                 Error( "pthread_attr_setstacksize failed" );
289         }
290
291         for ( i = 0 ; i < numthreads ; i++ )
292         {
293                 if ( pthread_create( &work_threads[i], attrib
294                                                          , (pthread_startroutine_t)func, (pthread_addr_t)i ) == -1 ) {
295                         Error( "pthread_create failed" );
296                 }
297         }
298
299         for ( i = 0 ; i < numthreads ; i++ )
300         {
301                 if ( pthread_join( work_threads[i], &status ) == -1 ) {
302                         Error( "pthread_join failed" );
303                 }
304         }
305
306         threaded = false;
307
308         end = I_FloatTime();
309         if ( pacifier ) {
310                 Sys_Printf( " (%i)\n", end - start );
311         }
312 }
313
314
315 #elif GDEF_OS_IRIX
316
317 /*
318    ===================================================================
319
320    IRIX
321
322    ===================================================================
323  */
324
325 #include <task.h>
326 #include <abi_mutex.h>
327 #include <sys/types.h>
328 #include <sys/prctl.h>
329
330 int numthreads = -1;
331 abilock_t lck;
332
333 void ThreadSetDefault( void ){
334         if ( numthreads == -1 ) {
335                 numthreads = prctl( PR_MAXPPROCS );
336         }
337         Sys_Printf( "%i threads\n", numthreads );
338         usconfig( CONF_INITUSERS, numthreads );
339 }
340
341
342 void ThreadLock( void ){
343         spin_lock( &lck );
344 }
345
346 void ThreadUnlock( void ){
347         release_lock( &lck );
348 }
349
350
351 /*
352    =============
353    RunThreadsOn
354    =============
355  */
356 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
357         int i;
358         int pid[MAX_THREADS];
359         int start, end;
360
361         start = I_FloatTime();
362         dispatch = 0;
363         workcount = workcnt;
364         oldf = -1;
365         pacifier = showpacifier;
366         threaded = true;
367
368         if ( pacifier ) {
369                 setbuf( stdout, NULL );
370         }
371
372         init_lock( &lck );
373
374         for ( i = 0 ; i < numthreads - 1 ; i++ )
375         {
376                 pid[i] = sprocsp( ( void ( * )( void *, size_t ) )func, PR_SALL, (void *)i
377                                                   , NULL, 0x200000 ); // 2 meg stacks
378                 if ( pid[i] == -1 ) {
379                         perror( "sproc" );
380                         Error( "sproc failed" );
381                 }
382         }
383
384         func( i );
385
386         for ( i = 0 ; i < numthreads - 1 ; i++ )
387                 wait( NULL );
388
389         threaded = false;
390
391         end = I_FloatTime();
392         if ( pacifier ) {
393                 Sys_Printf( " (%i)\n", end - start );
394         }
395 }
396
397
398 #elif GDEF_OS_LINUX || GDEF_OS_BSD || GDEF_OS_MACOS
399
400 /*
401    =======================================================================
402
403    Linux pthreads
404
405    =======================================================================
406  */
407
408 int numthreads = 4;
409
410 void ThreadSetDefault( void ){
411         if ( numthreads == -1 ) { // not set manually
412                 /* default to one thread, only multi-thread when specifically told to */
413                 numthreads = 1;
414         }
415         if ( numthreads > 1 ) {
416                 Sys_Printf( "threads: %d\n", numthreads );
417         }
418 }
419
420 #include <pthread.h>
421
422 typedef struct pt_mutex_s
423 {
424         pthread_t       *owner;
425         pthread_mutex_t a_mutex;
426         pthread_cond_t cond;
427         unsigned int lock;
428 } pt_mutex_t;
429
430 pt_mutex_t global_lock;
431
432 void ThreadLock( void ){
433         pt_mutex_t *pt_mutex = &global_lock;
434
435         if ( !threaded ) {
436                 return;
437         }
438
439         pthread_mutex_lock( &pt_mutex->a_mutex );
440         if ( pthread_equal( pthread_self(), (pthread_t)&pt_mutex->owner ) ) {
441                 pt_mutex->lock++;
442         }
443         else
444         {
445                 if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) {
446                         pt_mutex->owner = (pthread_t *)pthread_self();
447                         pt_mutex->lock  = 1;
448                 }
449                 else
450                 {
451                         while ( 1 )
452                         {
453                                 pthread_cond_wait( &pt_mutex->cond, &pt_mutex->a_mutex );
454                                 if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) {
455                                         pt_mutex->owner = (pthread_t *)pthread_self();
456                                         pt_mutex->lock  = 1;
457                                         break;
458                                 }
459                         }
460                 }
461         }
462         pthread_mutex_unlock( &pt_mutex->a_mutex );
463 }
464
465 void ThreadUnlock( void ){
466         pt_mutex_t *pt_mutex = &global_lock;
467
468         if ( !threaded ) {
469                 return;
470         }
471
472         pthread_mutex_lock( &pt_mutex->a_mutex );
473         pt_mutex->lock--;
474
475         if ( pt_mutex->lock == 0 ) {
476                 pt_mutex->owner = NULL;
477                 pthread_cond_signal( &pt_mutex->cond );
478         }
479
480         pthread_mutex_unlock( &pt_mutex->a_mutex );
481 }
482
483 void recursive_mutex_init( pthread_mutexattr_t attribs ){
484         pt_mutex_t *pt_mutex = &global_lock;
485
486         pt_mutex->owner = NULL;
487         if ( pthread_mutex_init( &pt_mutex->a_mutex, &attribs ) != 0 ) {
488                 Error( "pthread_mutex_init failed\n" );
489         }
490         if ( pthread_cond_init( &pt_mutex->cond, NULL ) != 0 ) {
491                 Error( "pthread_cond_init failed\n" );
492         }
493
494         pt_mutex->lock = 0;
495 }
496
497 /*
498    =============
499    RunThreadsOn
500    =============
501  */
502 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
503         pthread_mutexattr_t mattrib;
504         pthread_t work_threads[MAX_THREADS];
505
506         int start, end;
507         int i = 0, status = 0;
508
509         start     = I_FloatTime();
510         pacifier  = showpacifier;
511
512         dispatch  = 0;
513         oldf      = -1;
514         workcount = workcnt;
515
516         if ( numthreads == 1 ) {
517                 func( 0 );
518         }
519         else
520         {
521                 threaded  = true;
522
523                 if ( pacifier ) {
524                         setbuf( stdout, NULL );
525                 }
526
527                 if ( pthread_mutexattr_init( &mattrib ) != 0 ) {
528                         Error( "pthread_mutexattr_init failed" );
529                 }
530 #if __GLIBC_MINOR__ == 1
531                 if ( pthread_mutexattr_settype( &mattrib, PTHREAD_MUTEX_FAST_NP ) != 0 )
532 #else
533                 if ( pthread_mutexattr_settype( &mattrib, PTHREAD_MUTEX_ADAPTIVE_NP ) != 0 )
534 #endif
535                 { Error( "pthread_mutexattr_settype failed" ); }
536                 recursive_mutex_init( mattrib );
537
538                 for ( i = 0 ; i < numthreads ; i++ )
539                 {
540                         /* Default pthread attributes: joinable & non-realtime scheduling */
541                         if ( pthread_create( &work_threads[i], NULL, (void*)func, (void*)i ) != 0 ) {
542                                 Error( "pthread_create failed" );
543                         }
544                 }
545                 for ( i = 0 ; i < numthreads ; i++ )
546                 {
547                         if ( pthread_join( work_threads[i], (void **)&status ) != 0 ) {
548                                 Error( "pthread_join failed" );
549                         }
550                 }
551                 pthread_mutexattr_destroy( &mattrib );
552                 threaded = false;
553         }
554
555         end = I_FloatTime();
556         if ( pacifier ) {
557                 Sys_Printf( " (%i)\n", end - start );
558         }
559 }
560
561
562 #else // UNKNOWN OS
563
564 /*
565    =======================================================================
566
567    SINGLE THREAD
568
569    =======================================================================
570  */
571
572 int numthreads = 1;
573
574 void ThreadSetDefault( void ){
575         numthreads = 1;
576 }
577
578 void ThreadLock( void ){
579 }
580
581 void ThreadUnlock( void ){
582 }
583
584 /*
585    =============
586    RunThreadsOn
587    =============
588  */
589 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
590         int i;
591         int start, end;
592
593         dispatch = 0;
594         workcount = workcnt;
595         oldf = -1;
596         pacifier = showpacifier;
597         start = I_FloatTime();
598         func( 0 );
599
600         end = I_FloatTime();
601         if ( pacifier ) {
602                 Sys_Printf( " (%i)\n", end - start );
603         }
604 }
605
606 #endif // UNKNOWN OS