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