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