]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/common/threads.c
Merge branch 'master' into divVerent/farplanedist-sky-fix
[xonotic/netradiant.git] / tools / quake2 / 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 #ifndef WIN32
23 // The below define is necessary to use
24 // pthreads extensions like pthread_mutexattr_settype
25 #define _GNU_SOURCE
26 #include <pthread.h>
27 #endif
28
29 #include "cmdlib.h"
30 #include "mathlib.h"
31 #include "inout.h"
32 #include "q2_threads.h"
33
34 #define MAX_THREADS 64
35
36 int dispatch;
37 int workcount;
38 int oldf;
39 qboolean pacifier;
40
41 qboolean threaded;
42
43 /*
44    =============
45    GetThreadWork
46
47    =============
48  */
49 int GetThreadWork( void ){
50         int r;
51         int f;
52
53         ThreadLock();
54
55         if ( dispatch == workcount ) {
56                 ThreadUnlock();
57                 return -1;
58         }
59
60         f = 10 * dispatch / workcount;
61         if ( f != oldf ) {
62                 oldf = f;
63                 if ( pacifier ) {
64                         Sys_Printf( "%i...", f );
65                         fflush( stdout );   /* ydnar */
66                 }
67         }
68
69         r = dispatch;
70         dispatch++;
71         ThreadUnlock();
72
73         return r;
74 }
75
76
77 void ( *workfunction )( int );
78
79 void ThreadWorkerFunction( int threadnum ){
80         int work;
81
82         while ( 1 )
83         {
84                 work = GetThreadWork();
85                 if ( work == -1 ) {
86                         break;
87                 }
88                 //Sys_FPrintf( SYS_VRB,"thread %i, work %i\n", threadnum, work);
89                 workfunction( work );
90         }
91 }
92
93 void RunThreadsOnIndividual( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
94         if ( numthreads == -1 ) {
95                 ThreadSetDefault();
96         }
97         workfunction = func;
98         RunThreadsOn( workcnt, showpacifier, ThreadWorkerFunction );
99 }
100
101
102 /*
103    ===================================================================
104
105    WIN32
106
107    ===================================================================
108  */
109 #ifdef WIN32
110
111 #define USED
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 #endif
214
215 /*
216    ===================================================================
217
218    OSF1
219
220    ===================================================================
221  */
222
223 #ifdef __osf__
224 #define USED
225
226 int numthreads = 4;
227
228 void ThreadSetDefault( void ){
229         if ( numthreads == -1 ) { // not set manually
230                 numthreads = 4;
231         }
232 }
233
234
235 #include <pthread.h>
236
237 pthread_mutex_t *my_mutex;
238
239 void ThreadLock( void ){
240         if ( my_mutex ) {
241                 pthread_mutex_lock( my_mutex );
242         }
243 }
244
245 void ThreadUnlock( void ){
246         if ( my_mutex ) {
247                 pthread_mutex_unlock( my_mutex );
248         }
249 }
250
251
252 /*
253    =============
254    RunThreadsOn
255    =============
256  */
257 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
258         int i;
259         pthread_t work_threads[MAX_THREADS];
260         pthread_addr_t status;
261         pthread_attr_t attrib;
262         pthread_mutexattr_t mattrib;
263         int start, end;
264
265         start = I_FloatTime();
266         dispatch = 0;
267         workcount = workcnt;
268         oldf = -1;
269         pacifier = showpacifier;
270         threaded = true;
271
272         if ( pacifier ) {
273                 setbuf( stdout, NULL );
274         }
275
276         if ( !my_mutex ) {
277                 my_mutex = safe_malloc( sizeof( *my_mutex ) );
278                 if ( pthread_mutexattr_create( &mattrib ) == -1 ) {
279                         Error( "pthread_mutex_attr_create failed" );
280                 }
281                 if ( pthread_mutexattr_setkind_np( &mattrib, MUTEX_FAST_NP ) == -1 ) {
282                         Error( "pthread_mutexattr_setkind_np failed" );
283                 }
284                 if ( pthread_mutex_init( my_mutex, mattrib ) == -1 ) {
285                         Error( "pthread_mutex_init failed" );
286                 }
287         }
288
289         if ( pthread_attr_create( &attrib ) == -1 ) {
290                 Error( "pthread_attr_create failed" );
291         }
292         if ( pthread_attr_setstacksize( &attrib, 0x100000 ) == -1 ) {
293                 Error( "pthread_attr_setstacksize failed" );
294         }
295
296         for ( i = 0 ; i < numthreads ; i++ )
297         {
298                 if ( pthread_create( &work_threads[i], attrib
299                                                          , (pthread_startroutine_t)func, (pthread_addr_t)i ) == -1 ) {
300                         Error( "pthread_create failed" );
301                 }
302         }
303
304         for ( i = 0 ; i < numthreads ; i++ )
305         {
306                 if ( pthread_join( work_threads[i], &status ) == -1 ) {
307                         Error( "pthread_join failed" );
308                 }
309         }
310
311         threaded = false;
312
313         end = I_FloatTime();
314         if ( pacifier ) {
315                 Sys_Printf( " (%i)\n", end - start );
316         }
317 }
318
319
320 #endif
321
322 /*
323    ===================================================================
324
325    IRIX
326
327    ===================================================================
328  */
329
330 #ifdef _MIPS_ISA
331 #define USED
332
333 #include <task.h>
334 #include <abi_mutex.h>
335 #include <sys/types.h>
336 #include <sys/prctl.h>
337
338
339 int numthreads = -1;
340 abilock_t lck;
341
342 void ThreadSetDefault( void ){
343         if ( numthreads == -1 ) {
344                 numthreads = prctl( PR_MAXPPROCS );
345         }
346         Sys_Printf( "%i threads\n", numthreads );
347         usconfig( CONF_INITUSERS, numthreads );
348 }
349
350
351 void ThreadLock( void ){
352         spin_lock( &lck );
353 }
354
355 void ThreadUnlock( void ){
356         release_lock( &lck );
357 }
358
359
360 /*
361    =============
362    RunThreadsOn
363    =============
364  */
365 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
366         int i;
367         int pid[MAX_THREADS];
368         int start, end;
369
370         start = I_FloatTime();
371         dispatch = 0;
372         workcount = workcnt;
373         oldf = -1;
374         pacifier = showpacifier;
375         threaded = true;
376
377         if ( pacifier ) {
378                 setbuf( stdout, NULL );
379         }
380
381         init_lock( &lck );
382
383         for ( i = 0 ; i < numthreads - 1 ; i++ )
384         {
385                 pid[i] = sprocsp( ( void ( * )( void *, size_t ) )func, PR_SALL, (void *)i
386                                                   , NULL, 0x200000 ); // 2 meg stacks
387                 if ( pid[i] == -1 ) {
388                         perror( "sproc" );
389                         Error( "sproc failed" );
390                 }
391         }
392
393         func( i );
394
395         for ( i = 0 ; i < numthreads - 1 ; i++ )
396                 wait( NULL );
397
398         threaded = false;
399
400         end = I_FloatTime();
401         if ( pacifier ) {
402                 Sys_Printf( " (%i)\n", end - start );
403         }
404 }
405
406
407 #endif
408
409
410 /*
411    =======================================================================
412
413    Linux pthreads
414
415    =======================================================================
416  */
417
418 #if defined( __linux__ ) || defined( __APPLE__ )
419 #define USED
420
421 // Setting default Threads to 1
422 int numthreads = 1;
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 ( pthread_mutexattr_settype( &mattrib, PTHREAD_MUTEX_ERRORCHECK ) != 0 ) {
545                         Error( "pthread_mutexattr_settype failed" );
546                 }
547                 recursive_mutex_init( mattrib );
548
549                 for ( i = 0 ; i < numthreads ; i++ )
550                 {
551                         /* Default pthread attributes: joinable & non-realtime scheduling */
552                         if ( pthread_create( &work_threads[i], NULL, (void*)func, (void*)i ) != 0 ) {
553                                 Error( "pthread_create failed" );
554                         }
555                 }
556                 for ( i = 0 ; i < numthreads ; i++ )
557                 {
558                         if ( pthread_join( work_threads[i], (void **)&status ) != 0 ) {
559                                 Error( "pthread_join failed" );
560                         }
561                 }
562                 pthread_mutexattr_destroy( &mattrib );
563                 threaded = false;
564         }
565
566         end = I_FloatTime();
567         if ( pacifier ) {
568                 Sys_Printf( " (%i)\n", end - start );
569         }
570 }
571 #endif // ifdef __linux__
572
573
574 /*
575    =======================================================================
576
577    SINGLE THREAD
578
579    =======================================================================
580  */
581
582 #ifndef USED
583
584 int numthreads = 1;
585
586 void ThreadSetDefault( void ){
587         numthreads = 1;
588 }
589
590 void ThreadLock( void ){
591 }
592
593 void ThreadUnlock( void ){
594 }
595
596 /*
597    =============
598    RunThreadsOn
599    =============
600  */
601 void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) ){
602         int i;
603         int start, end;
604
605         dispatch = 0;
606         workcount = workcnt;
607         oldf = -1;
608         pacifier = showpacifier;
609         start = I_FloatTime();
610         func( 0 );
611
612         end = I_FloatTime();
613         if ( pacifier ) {
614                 Sys_Printf( " (%i)\n", end - start );
615         }
616 }
617
618 #endif