h2data: fix build on macos
[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 // Setting default Threads to 1
116 int numthreads = 1;
117 CRITICAL_SECTION crit;
118 static int enter;
119
120 void ThreadSetDefault( void ){
121         SYSTEM_INFO info;
122
123         if ( numthreads == -1 ) { // not set manually
124                 GetSystemInfo( &info );
125                 numthreads = info.dwNumberOfProcessors;
126                 if ( numthreads < 1 || numthreads > 32 ) {
127                         numthreads = 1;
128                 }
129         }
130
131         Sys_Printf( "%i threads\n", numthreads );
132 }
133
134
135 void ThreadLock( void ){
136         if ( !threaded ) {
137                 return;
138         }
139         EnterCriticalSection( &crit );
140         if ( enter ) {
141                 Error( "Recursive ThreadLock\n" );
142         }
143         enter = 1;
144 }
145
146 void ThreadUnlock( void ){
147         if ( !threaded ) {
148                 return;
149         }
150         if ( !enter ) {
151                 Error( "ThreadUnlock without lock\n" );
152         }
153         enter = 0;
154         LeaveCriticalSection( &crit );
155 }
156
157 /*
158    =============
159    RunThreadsOn
160    =============
161  */
162 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
163         int threadid[MAX_THREADS];
164         HANDLE threadhandle[MAX_THREADS];
165         int i;
166         int start, end;
167
168         start = I_FloatTime();
169         dispatch = 0;
170         workcount = workcnt;
171         oldf = -1;
172         pacifier = showpacifier;
173         threaded = true;
174
175         //
176         // run threads in parallel
177         //
178         InitializeCriticalSection( &crit );
179
180         if ( numthreads == 1 ) { // use same thread
181                 func( 0 );
182         }
183         else
184         {
185                 for ( i = 0 ; i < numthreads ; i++ )
186                 {
187                         threadhandle[i] = CreateThread(
188                                 NULL,   // LPSECURITY_ATTRIBUTES lpsa,
189                             //0,                // DWORD cbStack,
190
191                             /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */
192                                 ( 4096 * 1024 ),
193
194                                 (LPTHREAD_START_ROUTINE)func,   // LPTHREAD_START_ROUTINE lpStartAddr,
195                                 (LPVOID)i,  // LPVOID lpvThreadParm,
196                                 0,          //   DWORD fdwCreate,
197                                 &threadid[i] );
198                 }
199
200                 for ( i = 0 ; i < numthreads ; i++ )
201                         WaitForSingleObject( threadhandle[i], INFINITE );
202         }
203         DeleteCriticalSection( &crit );
204
205         threaded = false;
206         end = I_FloatTime();
207         if ( pacifier ) {
208                 Sys_Printf( " (%i)\n", end - start );
209         }
210 }
211
212
213 #elif GDEF_OS_OSF1
214
215 /*
216    ===================================================================
217
218    OSF1
219
220    ===================================================================
221  */
222
223 int numthreads = 4;
224
225 void ThreadSetDefault( void ){
226         if ( numthreads == -1 ) { // not set manually
227                 numthreads = 4;
228         }
229 }
230
231
232 #include <pthread.h>
233
234 pthread_mutex_t *my_mutex;
235
236 void ThreadLock( void ){
237         if ( my_mutex ) {
238                 pthread_mutex_lock( my_mutex );
239         }
240 }
241
242 void ThreadUnlock( void ){
243         if ( my_mutex ) {
244                 pthread_mutex_unlock( my_mutex );
245         }
246 }
247
248
249 /*
250    =============
251    RunThreadsOn
252    =============
253  */
254 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
255         int i;
256         pthread_t work_threads[MAX_THREADS];
257         pthread_addr_t status;
258         pthread_attr_t attrib;
259         pthread_mutexattr_t mattrib;
260         int start, end;
261
262         start = I_FloatTime();
263         dispatch = 0;
264         workcount = workcnt;
265         oldf = -1;
266         pacifier = showpacifier;
267         threaded = true;
268
269         if ( pacifier ) {
270                 setbuf( stdout, NULL );
271         }
272
273         if ( !my_mutex ) {
274                 my_mutex = safe_malloc( sizeof( *my_mutex ) );
275                 if ( pthread_mutexattr_create( &mattrib ) == -1 ) {
276                         Error( "pthread_mutex_attr_create failed" );
277                 }
278                 if ( pthread_mutexattr_setkind_np( &mattrib, MUTEX_FAST_NP ) == -1 ) {
279                         Error( "pthread_mutexattr_setkind_np failed" );
280                 }
281                 if ( pthread_mutex_init( my_mutex, mattrib ) == -1 ) {
282                         Error( "pthread_mutex_init failed" );
283                 }
284         }
285
286         if ( pthread_attr_create( &attrib ) == -1 ) {
287                 Error( "pthread_attr_create failed" );
288         }
289         if ( pthread_attr_setstacksize( &attrib, 0x100000 ) == -1 ) {
290                 Error( "pthread_attr_setstacksize failed" );
291         }
292
293         for ( i = 0 ; i < numthreads ; i++ )
294         {
295                 if ( pthread_create( &work_threads[i], attrib
296                                                          , (pthread_startroutine_t)func, (pthread_addr_t)i ) == -1 ) {
297                         Error( "pthread_create failed" );
298                 }
299         }
300
301         for ( i = 0 ; i < numthreads ; i++ )
302         {
303                 if ( pthread_join( work_threads[i], &status ) == -1 ) {
304                         Error( "pthread_join failed" );
305                 }
306         }
307
308         threaded = false;
309
310         end = I_FloatTime();
311         if ( pacifier ) {
312                 Sys_Printf( " (%i)\n", end - start );
313         }
314 }
315
316
317 #elif GDEF_OS_IRIX
318
319 /*
320    ===================================================================
321
322    IRIX
323
324    ===================================================================
325  */
326
327 #include <task.h>
328 #include <abi_mutex.h>
329 #include <sys/types.h>
330 #include <sys/prctl.h>
331
332 int numthreads = -1;
333 abilock_t lck;
334
335 void ThreadSetDefault( void ){
336         if ( numthreads == -1 ) {
337                 numthreads = prctl( PR_MAXPPROCS );
338         }
339         Sys_Printf( "%i threads\n", numthreads );
340         usconfig( CONF_INITUSERS, numthreads );
341 }
342
343
344 void ThreadLock( void ){
345         spin_lock( &lck );
346 }
347
348 void ThreadUnlock( void ){
349         release_lock( &lck );
350 }
351
352
353 /*
354    =============
355    RunThreadsOn
356    =============
357  */
358 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
359         int i;
360         int pid[MAX_THREADS];
361         int start, end;
362
363         start = I_FloatTime();
364         dispatch = 0;
365         workcount = workcnt;
366         oldf = -1;
367         pacifier = showpacifier;
368         threaded = true;
369
370         if ( pacifier ) {
371                 setbuf( stdout, NULL );
372         }
373
374         init_lock( &lck );
375
376         for ( i = 0 ; i < numthreads - 1 ; i++ )
377         {
378                 pid[i] = sprocsp( ( void ( * )( void *, size_t ) )func, PR_SALL, (void *)i
379                                                   , NULL, 0x200000 ); // 2 meg stacks
380                 if ( pid[i] == -1 ) {
381                         perror( "sproc" );
382                         Error( "sproc failed" );
383                 }
384         }
385
386         func( i );
387
388         for ( i = 0 ; i < numthreads - 1 ; i++ )
389                 wait( NULL );
390
391         threaded = false;
392
393         end = I_FloatTime();
394         if ( pacifier ) {
395                 Sys_Printf( " (%i)\n", end - start );
396         }
397 }
398
399
400 #elif GDEF_OS_LINUX || GDEF_OS_BSD || GDEF_OS_MACOS
401
402 /*
403    =======================================================================
404
405    Linux pthreads
406
407    =======================================================================
408  */
409
410 // Setting default Threads to 1
411 int numthreads = 1;
412
413 void ThreadSetDefault( void ){
414         if ( numthreads == -1 ) { // not set manually
415                 /* default to one thread, only multi-thread when specifically told to */
416                 numthreads = 1;
417         }
418         if ( numthreads > 1 ) {
419                 Sys_Printf( "threads: %d\n", numthreads );
420         }
421 }
422
423 #include <pthread.h>
424
425 typedef struct pt_mutex_s
426 {
427         pthread_t       *owner;
428         pthread_mutex_t a_mutex;
429         pthread_cond_t cond;
430         unsigned int lock;
431 } pt_mutex_t;
432
433 pt_mutex_t global_lock;
434
435 void ThreadLock( void ){
436         pt_mutex_t *pt_mutex = &global_lock;
437
438         if ( !threaded ) {
439                 return;
440         }
441
442         pthread_mutex_lock( &pt_mutex->a_mutex );
443         if ( pthread_equal( pthread_self(), (pthread_t)&pt_mutex->owner ) ) {
444                 pt_mutex->lock++;
445         }
446         else
447         {
448                 if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) {
449                         pt_mutex->owner = (pthread_t *)pthread_self();
450                         pt_mutex->lock  = 1;
451                 }
452                 else
453                 {
454                         while ( 1 )
455                         {
456                                 pthread_cond_wait( &pt_mutex->cond, &pt_mutex->a_mutex );
457                                 if ( ( !pt_mutex->owner ) && ( pt_mutex->lock == 0 ) ) {
458                                         pt_mutex->owner = (pthread_t *)pthread_self();
459                                         pt_mutex->lock  = 1;
460                                         break;
461                                 }
462                         }
463                 }
464         }
465         pthread_mutex_unlock( &pt_mutex->a_mutex );
466 }
467
468 void ThreadUnlock( void ){
469         pt_mutex_t *pt_mutex = &global_lock;
470
471         if ( !threaded ) {
472                 return;
473         }
474
475         pthread_mutex_lock( &pt_mutex->a_mutex );
476         pt_mutex->lock--;
477
478         if ( pt_mutex->lock == 0 ) {
479                 pt_mutex->owner = NULL;
480                 pthread_cond_signal( &pt_mutex->cond );
481         }
482
483         pthread_mutex_unlock( &pt_mutex->a_mutex );
484 }
485
486 void recursive_mutex_init( pthread_mutexattr_t attribs ){
487         pt_mutex_t *pt_mutex = &global_lock;
488
489         pt_mutex->owner = NULL;
490         if ( pthread_mutex_init( &pt_mutex->a_mutex, &attribs ) != 0 ) {
491                 Error( "pthread_mutex_init failed\n" );
492         }
493         if ( pthread_cond_init( &pt_mutex->cond, NULL ) != 0 ) {
494                 Error( "pthread_cond_init failed\n" );
495         }
496
497         pt_mutex->lock = 0;
498 }
499
500 /*
501    =============
502    RunThreadsOn
503    =============
504  */
505 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
506         pthread_mutexattr_t mattrib;
507         pthread_t work_threads[MAX_THREADS];
508
509         int start, end;
510         int i = 0, status = 0;
511
512         start     = I_FloatTime();
513         pacifier  = showpacifier;
514
515         dispatch  = 0;
516         oldf      = -1;
517         workcount = workcnt;
518
519         if ( numthreads == 1 ) {
520                 func( 0 );
521         }
522         else
523         {
524                 threaded  = true;
525
526                 if ( pacifier ) {
527                         setbuf( stdout, NULL );
528                 }
529
530                 if ( pthread_mutexattr_init( &mattrib ) != 0 ) {
531                         Error( "pthread_mutexattr_init failed" );
532                 }
533                 if ( pthread_mutexattr_settype( &mattrib, PTHREAD_MUTEX_ERRORCHECK ) != 0 ) {
534                         Error( "pthread_mutexattr_settype failed" );
535                 }
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