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