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