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