137597c7107062e27d7a2eccd38ecd29f41dc7f4
[xonotic/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 = 10*dispatch / workcount;
63         if (f != oldf)
64         {
65                 oldf = f;
66                 if (pacifier)
67                 {
68                         Sys_Printf ("%i...", f);
69                         fflush( stdout );       /* ydnar */
70                 }
71         }
72
73         r = dispatch;
74         dispatch++;
75         ThreadUnlock ();
76
77         return r;
78 }
79
80
81 void (*workfunction) (int);
82
83 void ThreadWorkerFunction (int threadnum)
84 {
85         int             work;
86
87         while (1)
88         {
89                 work = GetThreadWork ();
90                 if (work == -1)
91                         break;
92 //Sys_Printf ("thread %i, work %i\n", threadnum, work);
93                 workfunction(work);
94         }
95 }
96
97 void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
98 {
99         if (numthreads == -1)
100                 ThreadSetDefault ();
101         workfunction = func;
102   RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
103 }
104
105
106 /*
107 ===================================================================
108
109 WIN32
110
111 ===================================================================
112 */
113 #ifdef WIN32
114
115 #define USED
116
117 #include <windows.h>
118
119 int             numthreads = -1;
120 CRITICAL_SECTION                crit;
121 static int enter;
122
123 void ThreadSetDefault (void)
124 {
125         SYSTEM_INFO info;
126
127         if (numthreads == -1)   // not set manually
128         {
129                 GetSystemInfo (&info);
130                 numthreads = info.dwNumberOfProcessors;
131                 if (numthreads < 1 || numthreads > 32)
132                         numthreads = 1;
133         }
134
135         Sys_Printf ("%i threads\n", numthreads);
136 }
137
138
139 void ThreadLock (void)
140 {
141         if (!threaded)
142                 return;
143         EnterCriticalSection (&crit);
144         if (enter)
145                 Error ("Recursive ThreadLock\n");
146         enter = 1;
147 }
148
149 void ThreadUnlock (void)
150 {
151         if (!threaded)
152                 return;
153         if (!enter)
154                 Error ("ThreadUnlock without lock\n");
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 {
166         int             threadid[MAX_THREADS];
167         HANDLE  threadhandle[MAX_THREADS];
168         int             i;
169         int             start, end;
170
171         start = I_FloatTime ();
172         dispatch = 0;
173         workcount = workcnt;
174         oldf = -1;
175         pacifier = showpacifier;
176         threaded = qtrue;
177
178         //
179         // run threads in parallel
180         //
181         InitializeCriticalSection (&crit);
182
183         if (numthreads == 1)
184         {       // use same thread
185                 func (0);
186         }
187         else
188         {
189                 for (i=0 ; i<numthreads ; i++)
190                 {
191                         threadhandle[i] = CreateThread(
192                            NULL,        // LPSECURITY_ATTRIBUTES lpsa,
193                            //0,         // DWORD cbStack,
194
195                                 /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */
196                                 (4096 * 1024),
197
198                            (LPTHREAD_START_ROUTINE)func,        // LPTHREAD_START_ROUTINE lpStartAddr,
199                            (LPVOID)i,   // LPVOID lpvThreadParm,
200                            0,                   //   DWORD fdwCreate,
201                            &threadid[i]);
202                 }
203
204                 for (i=0 ; i<numthreads ; i++)
205                         WaitForSingleObject (threadhandle[i], INFINITE);
206         }
207         DeleteCriticalSection (&crit);
208
209         threaded = qfalse;
210         end = I_FloatTime ();
211         if (pacifier)
212                 Sys_Printf (" (%i)\n", end-start);
213 }
214
215
216 #endif
217
218 /*
219 ===================================================================
220
221 OSF1
222
223 ===================================================================
224 */
225
226 #ifdef __osf__
227 #define USED
228
229 int             numthreads = 4;
230
231 void ThreadSetDefault (void)
232 {
233         if (numthreads == -1)   // not set manually
234         {
235                 numthreads = 4;
236         }
237 }
238
239
240 #include <pthread.h>
241
242 pthread_mutex_t *my_mutex;
243
244 void ThreadLock (void)
245 {
246         if (my_mutex)
247                 pthread_mutex_lock (my_mutex);
248 }
249
250 void ThreadUnlock (void)
251 {
252         if (my_mutex)
253                 pthread_mutex_unlock (my_mutex);
254 }
255
256
257 /*
258 =============
259 RunThreadsOn
260 =============
261 */
262 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
263 {
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         if (!my_mutex)
282         {
283                 my_mutex = safe_malloc (sizeof(*my_mutex));
284                 if (pthread_mutexattr_create (&mattrib) == -1)
285                         Error ("pthread_mutex_attr_create failed");
286                 if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
287                         Error ("pthread_mutexattr_setkind_np failed");
288                 if (pthread_mutex_init (my_mutex, mattrib) == -1)
289                         Error ("pthread_mutex_init failed");
290         }
291
292         if (pthread_attr_create (&attrib) == -1)
293                 Error ("pthread_attr_create failed");
294         if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
295                 Error ("pthread_attr_setstacksize failed");
296         
297         for (i=0 ; i<numthreads ; i++)
298         {
299                 if (pthread_create(&work_threads[i], attrib
300                 , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
301                         Error ("pthread_create failed");
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         threaded = qfalse;
311
312         end = I_FloatTime ();
313         if (pacifier)
314                 Sys_Printf (" (%i)\n", end-start);
315 }
316
317
318 #endif
319
320 /*
321 ===================================================================
322
323 IRIX
324
325 ===================================================================
326 */
327
328 #ifdef _MIPS_ISA 
329 #define USED
330
331 #include <task.h>
332 #include <abi_mutex.h>
333 #include <sys/types.h>
334 #include <sys/prctl.h>
335
336
337 int             numthreads = -1;
338 abilock_t               lck;
339
340 void ThreadSetDefault (void)
341 {
342         if (numthreads == -1)
343                 numthreads = prctl(PR_MAXPPROCS);
344         Sys_Printf ("%i threads\n", numthreads);
345         usconfig (CONF_INITUSERS, numthreads);
346 }
347
348
349 void ThreadLock (void)
350 {
351         spin_lock (&lck);
352 }
353
354 void ThreadUnlock (void)
355 {
356         release_lock (&lck);
357 }
358
359
360 /*
361 =============
362 RunThreadsOn
363 =============
364 */
365 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
366 {
367         int             i;
368         int             pid[MAX_THREADS];
369         int             start, end;
370
371         start = I_FloatTime ();
372         dispatch = 0;
373         workcount = workcnt;
374         oldf = -1;
375         pacifier = showpacifier;
376         threaded = qtrue;
377
378         if (pacifier)
379                 setbuf (stdout, NULL);
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                 {
389                         perror ("sproc");
390                         Error ("sproc failed");
391                 }
392         }
393                 
394         func(i);
395                         
396         for (i=0 ; i<numthreads-1 ; i++)
397                 wait (NULL);
398
399         threaded = qfalse;
400
401         end = I_FloatTime ();
402         if (pacifier)
403                 Sys_Printf (" (%i)\n", end-start);
404 }
405
406
407 #endif
408
409
410 /*
411 =======================================================================
412
413   Linux pthreads
414
415 =======================================================================
416 */
417
418 #ifdef __linux__
419 #define USED
420
421 int numthreads = 4;
422
423 void ThreadSetDefault (void)
424 {
425         if (numthreads == -1)   // not set manually
426         {
427     /* default to one thread, only multi-thread when specifically told to */
428                 numthreads = 1;
429         }
430   if(numthreads > 1)
431     Sys_Printf("threads: %d\n", numthreads);
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 {
448   pt_mutex_t *pt_mutex = &global_lock;
449
450   if(!threaded)
451     return;
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   else
457   {
458     if((!pt_mutex->owner) && (pt_mutex->lock == 0))
459     {
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         {
470           pt_mutex->owner = (pthread_t *)pthread_self();
471           pt_mutex->lock  = 1;
472           break;
473         }
474       }
475     }
476   }
477   pthread_mutex_unlock(&pt_mutex->a_mutex);
478 }
479
480 void ThreadUnlock(void)
481 {
482   pt_mutex_t *pt_mutex = &global_lock;
483   
484   if(!threaded)
485     return;
486
487   pthread_mutex_lock(&pt_mutex->a_mutex);
488   pt_mutex->lock--;
489   
490   if(pt_mutex->lock == 0)
491   {
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 {
501   pt_mutex_t *pt_mutex = &global_lock;
502   
503   pt_mutex->owner = NULL;
504   if(pthread_mutex_init(&pt_mutex->a_mutex, &attribs) != 0)
505     Error("pthread_mutex_init failed\n");
506   if(pthread_cond_init(&pt_mutex->cond, NULL) != 0)
507     Error("pthread_cond_init failed\n");
508   
509   pt_mutex->lock = 0;
510 }
511
512 /*
513 =============
514 RunThreadsOn
515 =============
516 */
517 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
518 {
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   else
535   {    
536     threaded  = qtrue;
537       
538     if(pacifier)
539       setbuf(stdout, NULL);
540
541     if(pthread_mutexattr_init(&mattrib) != 0)
542       Error("pthread_mutexattr_init failed");
543 #if __GLIBC_MINOR__ == 1
544     if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_FAST_NP) != 0)
545 #else
546     if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)
547 #endif
548       Error ("pthread_mutexattr_settype failed");
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     for (i=0 ; i<numthreads ; i++)
558     {
559       if(pthread_join(work_threads[i], (void **)&status) != 0)
560         Error("pthread_join failed");
561     }
562     pthread_mutexattr_destroy(&mattrib);
563     threaded = qfalse;
564   }
565   
566   end = I_FloatTime ();
567   if (pacifier)
568     Sys_Printf (" (%i)\n", end-start);
569 }
570 #endif // ifdef __linux__
571
572
573 /*
574 =======================================================================
575
576   SINGLE THREAD
577
578 =======================================================================
579 */
580
581 #ifndef USED
582
583 int             numthreads = 1;
584
585 void ThreadSetDefault (void)
586 {
587         numthreads = 1;
588 }
589
590 void ThreadLock (void)
591 {
592 }
593
594 void ThreadUnlock (void)
595 {
596 }
597
598 /*
599 =============
600 RunThreadsOn
601 =============
602 */
603 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
604 {
605         int             i;
606         int             start, end;
607
608         dispatch = 0;
609         workcount = workcnt;
610         oldf = -1;
611         pacifier = showpacifier;
612         start = I_FloatTime (); 
613         func(0);
614
615         end = I_FloatTime ();
616         if (pacifier)
617                 Sys_Printf (" (%i)\n", end-start);
618 }
619
620 #endif