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