]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/common/threads.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / common / threads.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 #ifndef WIN32\r
23 // The below define is necessary to use\r
24 // pthreads extensions like pthread_mutexattr_settype\r
25 #define _GNU_SOURCE\r
26 #include <pthread.h>\r
27 #endif\r
28 \r
29 #include "cmdlib.h"\r
30 #include "mathlib.h"\r
31 #include "inout.h"\r
32 #include "her2_threads.h"\r
33 \r
34 #define MAX_THREADS     64\r
35 \r
36 int             dispatch;\r
37 int             workcount;\r
38 int             oldf;\r
39 qboolean                pacifier;\r
40 \r
41 qboolean        threaded;\r
42 \r
43 /*\r
44 =============\r
45 GetThreadWork\r
46 \r
47 =============\r
48 */\r
49 int     GetThreadWork (void)\r
50 {\r
51         int     r;\r
52         int     f;\r
53 \r
54         ThreadLock ();\r
55 \r
56         if (dispatch == workcount)\r
57         {\r
58                 ThreadUnlock ();\r
59                 return -1;\r
60         }\r
61 \r
62         f = 10*dispatch / workcount;\r
63         if (f != oldf)\r
64         {\r
65                 oldf = f;\r
66                 if (pacifier)\r
67                 {\r
68                         Sys_Printf ("%i...", f);\r
69                         fflush( stdout );       /* ydnar */\r
70                 }\r
71         }\r
72 \r
73         r = dispatch;\r
74         dispatch++;\r
75         ThreadUnlock ();\r
76 \r
77         return r;\r
78 }\r
79 \r
80 \r
81 void (*workfunction) (int);\r
82 \r
83 void ThreadWorkerFunction (int threadnum)\r
84 {\r
85         int             work;\r
86 \r
87         while (1)\r
88         {\r
89                 work = GetThreadWork ();\r
90                 if (work == -1)\r
91                         break;\r
92 //Sys_Printf ("thread %i, work %i\n", threadnum, work);\r
93                 workfunction(work);\r
94         }\r
95 }\r
96 \r
97 void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))\r
98 {\r
99         if (numthreads == -1)\r
100                 ThreadSetDefault ();\r
101         workfunction = func;\r
102   RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);\r
103 }\r
104 \r
105 \r
106 /*\r
107 ===================================================================\r
108 \r
109 WIN32\r
110 \r
111 ===================================================================\r
112 */\r
113 #ifdef _WIN32\r
114 \r
115 #define USED\r
116 \r
117 #include <windows.h>\r
118 \r
119 int             numthreads = -1;\r
120 CRITICAL_SECTION                crit;\r
121 static int enter;\r
122 \r
123 void ThreadSetDefault (void)\r
124 {\r
125         SYSTEM_INFO info;\r
126 \r
127         if (numthreads == -1)   // not set manually\r
128         {\r
129                 GetSystemInfo (&info);\r
130                 numthreads = info.dwNumberOfProcessors;\r
131                 if (numthreads < 1 || numthreads > 32)\r
132                         numthreads = 1;\r
133         }\r
134 \r
135         Sys_Printf ("%i threads\n", numthreads);\r
136 }\r
137 \r
138 \r
139 void ThreadLock (void)\r
140 {\r
141         if (!threaded)\r
142                 return;\r
143         EnterCriticalSection (&crit);\r
144         if (enter)\r
145                 Error ("Recursive ThreadLock\n");\r
146         enter = 1;\r
147 }\r
148 \r
149 void ThreadUnlock (void)\r
150 {\r
151         if (!threaded)\r
152                 return;\r
153         if (!enter)\r
154                 Error ("ThreadUnlock without lock\n");\r
155         enter = 0;\r
156         LeaveCriticalSection (&crit);\r
157 }\r
158 \r
159 /*\r
160 =============\r
161 RunThreadsOn\r
162 =============\r
163 */\r
164 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))\r
165 {\r
166         int             threadid[MAX_THREADS];\r
167         HANDLE  threadhandle[MAX_THREADS];\r
168         int             i;\r
169         int             start, end;\r
170 \r
171         start = I_FloatTime ();\r
172         dispatch = 0;\r
173         workcount = workcnt;\r
174         oldf = -1;\r
175         pacifier = showpacifier;\r
176         threaded = true;\r
177 \r
178         //\r
179         // run threads in parallel\r
180         //\r
181         InitializeCriticalSection (&crit);\r
182 \r
183         if (numthreads == 1)\r
184         {       // use same thread\r
185                 func (0);\r
186         }\r
187         else\r
188         {\r
189                 for (i=0 ; i<numthreads ; i++)\r
190                 {\r
191                         threadhandle[i] = CreateThread(\r
192                            NULL,        // LPSECURITY_ATTRIBUTES lpsa,\r
193                            //0,         // DWORD cbStack,\r
194 \r
195                                 /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */\r
196                                 (4096 * 1024),\r
197 \r
198                            (LPTHREAD_START_ROUTINE)func,        // LPTHREAD_START_ROUTINE lpStartAddr,\r
199                            (LPVOID)i,   // LPVOID lpvThreadParm,\r
200                            0,                   //   DWORD fdwCreate,\r
201                            &threadid[i]);\r
202                 }\r
203 \r
204                 for (i=0 ; i<numthreads ; i++)\r
205                         WaitForSingleObject (threadhandle[i], INFINITE);\r
206         }\r
207         DeleteCriticalSection (&crit);\r
208 \r
209         threaded = false;\r
210         end = I_FloatTime ();\r
211         if (pacifier)\r
212                 Sys_Printf (" (%i)\n", end-start);\r
213 }\r
214 \r
215 \r
216 #endif\r
217 \r
218 /*\r
219 ===================================================================\r
220 \r
221 OSF1\r
222 \r
223 ===================================================================\r
224 */\r
225 \r
226 #ifdef __osf__\r
227 #define USED\r
228 \r
229 int             numthreads = 4;\r
230 \r
231 void ThreadSetDefault (void)\r
232 {\r
233         if (numthreads == -1)   // not set manually\r
234         {\r
235                 numthreads = 4;\r
236         }\r
237 }\r
238 \r
239 \r
240 #include <pthread.h>\r
241 \r
242 pthread_mutex_t *my_mutex;\r
243 \r
244 void ThreadLock (void)\r
245 {\r
246         if (my_mutex)\r
247                 pthread_mutex_lock (my_mutex);\r
248 }\r
249 \r
250 void ThreadUnlock (void)\r
251 {\r
252         if (my_mutex)\r
253                 pthread_mutex_unlock (my_mutex);\r
254 }\r
255 \r
256 \r
257 /*\r
258 =============\r
259 RunThreadsOn\r
260 =============\r
261 */\r
262 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))\r
263 {\r
264         int             i;\r
265         pthread_t       work_threads[MAX_THREADS];\r
266         pthread_addr_t  status;\r
267         pthread_attr_t  attrib;\r
268         pthread_mutexattr_t     mattrib;\r
269         int             start, end;\r
270 \r
271         start = I_FloatTime ();\r
272         dispatch = 0;\r
273         workcount = workcnt;\r
274         oldf = -1;\r
275         pacifier = showpacifier;\r
276         threaded = true;\r
277 \r
278         if (pacifier)\r
279                 setbuf (stdout, NULL);\r
280 \r
281         if (!my_mutex)\r
282         {\r
283                 my_mutex = safe_malloc (sizeof(*my_mutex));\r
284                 if (pthread_mutexattr_create (&mattrib) == -1)\r
285                         Error ("pthread_mutex_attr_create failed");\r
286                 if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)\r
287                         Error ("pthread_mutexattr_setkind_np failed");\r
288                 if (pthread_mutex_init (my_mutex, mattrib) == -1)\r
289                         Error ("pthread_mutex_init failed");\r
290         }\r
291 \r
292         if (pthread_attr_create (&attrib) == -1)\r
293                 Error ("pthread_attr_create failed");\r
294         if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)\r
295                 Error ("pthread_attr_setstacksize failed");\r
296         \r
297         for (i=0 ; i<numthreads ; i++)\r
298         {\r
299                 if (pthread_create(&work_threads[i], attrib\r
300                 , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)\r
301                         Error ("pthread_create failed");\r
302         }\r
303                 \r
304         for (i=0 ; i<numthreads ; i++)\r
305         {\r
306                 if (pthread_join (work_threads[i], &status) == -1)\r
307                         Error ("pthread_join failed");\r
308         }\r
309 \r
310         threaded = false;\r
311 \r
312         end = I_FloatTime ();\r
313         if (pacifier)\r
314                 Sys_Printf (" (%i)\n", end-start);\r
315 }\r
316 \r
317 \r
318 #endif\r
319 \r
320 /*\r
321 ===================================================================\r
322 \r
323 IRIX\r
324 \r
325 ===================================================================\r
326 */\r
327 \r
328 #ifdef _MIPS_ISA \r
329 #define USED\r
330 \r
331 #include <task.h>\r
332 #include <abi_mutex.h>\r
333 #include <sys/types.h>\r
334 #include <sys/prctl.h>\r
335 \r
336 \r
337 int             numthreads = -1;\r
338 abilock_t               lck;\r
339 \r
340 void ThreadSetDefault (void)\r
341 {\r
342         if (numthreads == -1)\r
343                 numthreads = prctl(PR_MAXPPROCS);\r
344         Sys_Printf ("%i threads\n", numthreads);\r
345         usconfig (CONF_INITUSERS, numthreads);\r
346 }\r
347 \r
348 \r
349 void ThreadLock (void)\r
350 {\r
351         spin_lock (&lck);\r
352 }\r
353 \r
354 void ThreadUnlock (void)\r
355 {\r
356         release_lock (&lck);\r
357 }\r
358 \r
359 \r
360 /*\r
361 =============\r
362 RunThreadsOn\r
363 =============\r
364 */\r
365 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))\r
366 {\r
367         int             i;\r
368         int             pid[MAX_THREADS];\r
369         int             start, end;\r
370 \r
371         start = I_FloatTime ();\r
372         dispatch = 0;\r
373         workcount = workcnt;\r
374         oldf = -1;\r
375         pacifier = showpacifier;\r
376         threaded = true;\r
377 \r
378         if (pacifier)\r
379                 setbuf (stdout, NULL);\r
380 \r
381         init_lock (&lck);\r
382 \r
383         for (i=0 ; i<numthreads-1 ; i++)\r
384         {\r
385                 pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i\r
386                         , NULL, 0x200000);              // 2 meg stacks\r
387                 if (pid[i] == -1)\r
388                 {\r
389                         perror ("sproc");\r
390                         Error ("sproc failed");\r
391                 }\r
392         }\r
393                 \r
394         func(i);\r
395                         \r
396         for (i=0 ; i<numthreads-1 ; i++)\r
397                 wait (NULL);\r
398 \r
399         threaded = false;\r
400 \r
401         end = I_FloatTime ();\r
402         if (pacifier)\r
403                 Sys_Printf (" (%i)\n", end-start);\r
404 }\r
405 \r
406 \r
407 #endif\r
408 \r
409 \r
410 /*\r
411 =======================================================================\r
412 \r
413   Linux pthreads\r
414 \r
415 =======================================================================\r
416 */\r
417 \r
418 #ifdef __linux__\r
419 #define USED\r
420 \r
421 int numthreads = 4;\r
422 \r
423 void ThreadSetDefault (void)\r
424 {\r
425         if (numthreads == -1)   // not set manually\r
426         {\r
427     /* default to one thread, only multi-thread when specifically told to */\r
428                 numthreads = 1;\r
429         }\r
430   if(numthreads > 1)\r
431     Sys_Printf("threads: %d\n", numthreads);\r
432 }\r
433 \r
434 #include <pthread.h>\r
435 \r
436 typedef struct pt_mutex_s\r
437 {\r
438   pthread_t       *owner;\r
439   pthread_mutex_t a_mutex;\r
440   pthread_cond_t  cond;\r
441   unsigned int    lock;\r
442 } pt_mutex_t;\r
443 \r
444 pt_mutex_t global_lock;\r
445 \r
446 void ThreadLock(void)\r
447 {\r
448   pt_mutex_t *pt_mutex = &global_lock;\r
449 \r
450   if(!threaded)\r
451     return;\r
452 \r
453   pthread_mutex_lock(&pt_mutex->a_mutex);\r
454   if(pthread_equal(pthread_self(), (pthread_t)&pt_mutex->owner)) \r
455     pt_mutex->lock++;\r
456   else\r
457   {\r
458     if((!pt_mutex->owner) && (pt_mutex->lock == 0))\r
459     {\r
460       pt_mutex->owner = (pthread_t *)pthread_self();\r
461       pt_mutex->lock  = 1;\r
462     }\r
463     else\r
464     {\r
465       while(1)\r
466       {\r
467         pthread_cond_wait(&pt_mutex->cond, &pt_mutex->a_mutex);\r
468         if((!pt_mutex->owner) && (pt_mutex->lock == 0))\r
469         {\r
470           pt_mutex->owner = (pthread_t *)pthread_self();\r
471           pt_mutex->lock  = 1;\r
472           break;\r
473         }\r
474       }\r
475     }\r
476   }\r
477   pthread_mutex_unlock(&pt_mutex->a_mutex);\r
478 }\r
479 \r
480 void ThreadUnlock(void)\r
481 {\r
482   pt_mutex_t *pt_mutex = &global_lock;\r
483   \r
484   if(!threaded)\r
485     return;\r
486 \r
487   pthread_mutex_lock(&pt_mutex->a_mutex);\r
488   pt_mutex->lock--;\r
489   \r
490   if(pt_mutex->lock == 0)\r
491   {\r
492     pt_mutex->owner = NULL;\r
493     pthread_cond_signal(&pt_mutex->cond);\r
494   }\r
495   \r
496   pthread_mutex_unlock(&pt_mutex->a_mutex);\r
497 }\r
498 \r
499 void recursive_mutex_init(pthread_mutexattr_t attribs)\r
500 {\r
501   pt_mutex_t *pt_mutex = &global_lock;\r
502   \r
503   pt_mutex->owner = NULL;\r
504   if(pthread_mutex_init(&pt_mutex->a_mutex, &attribs) != 0)\r
505     Error("pthread_mutex_init failed\n");\r
506   if(pthread_cond_init(&pt_mutex->cond, NULL) != 0)\r
507     Error("pthread_cond_init failed\n");\r
508   \r
509   pt_mutex->lock = 0;\r
510 }\r
511 \r
512 /*\r
513 =============\r
514 RunThreadsOn\r
515 =============\r
516 */\r
517 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))\r
518 {\r
519   pthread_mutexattr_t         mattrib;\r
520   pthread_t work_threads[MAX_THREADS];\r
521   \r
522   int     start, end;\r
523   int   i=0, status=0;\r
524   \r
525   start     = I_FloatTime ();\r
526   pacifier  = showpacifier;\r
527   \r
528   dispatch  = 0;\r
529   oldf      = -1;\r
530   workcount = workcnt;\r
531   \r
532   if(numthreads == 1)\r
533     func(0);\r
534   else\r
535   {    \r
536     threaded  = true;\r
537       \r
538     if(pacifier)\r
539       setbuf(stdout, NULL);\r
540 \r
541     if(pthread_mutexattr_init(&mattrib) != 0)\r
542       Error("pthread_mutexattr_init failed");\r
543 #if __GLIBC_MINOR__ == 1\r
544     if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_FAST_NP) != 0)\r
545 #else\r
546     if (pthread_mutexattr_settype(&mattrib, PTHREAD_MUTEX_ADAPTIVE_NP) != 0)\r
547 #endif\r
548       Error ("pthread_mutexattr_settype failed");\r
549     recursive_mutex_init(mattrib);\r
550 \r
551     for (i=0 ; i<numthreads ; i++)\r
552     {\r
553       /* Default pthread attributes: joinable & non-realtime scheduling */\r
554       if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0)\r
555         Error("pthread_create failed");\r
556     }\r
557     for (i=0 ; i<numthreads ; i++)\r
558     {\r
559       if(pthread_join(work_threads[i], (void **)&status) != 0)\r
560         Error("pthread_join failed");\r
561     }\r
562     pthread_mutexattr_destroy(&mattrib);\r
563     threaded = false;\r
564   }\r
565   \r
566   end = I_FloatTime ();\r
567   if (pacifier)\r
568     Sys_Printf (" (%i)\n", end-start);\r
569 }\r
570 #endif // ifdef __linux__\r
571 \r
572 \r
573 /*\r
574 =======================================================================\r
575 \r
576   SINGLE THREAD\r
577 \r
578 =======================================================================\r
579 */\r
580 \r
581 #ifndef USED\r
582 \r
583 int             numthreads = 1;\r
584 \r
585 void ThreadSetDefault (void)\r
586 {\r
587         numthreads = 1;\r
588 }\r
589 \r
590 void ThreadLock (void)\r
591 {\r
592 }\r
593 \r
594 void ThreadUnlock (void)\r
595 {\r
596 }\r
597 \r
598 /*\r
599 =============\r
600 RunThreadsOn\r
601 =============\r
602 */\r
603 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))\r
604 {\r
605         int             i;\r
606         int             start, end;\r
607 \r
608         dispatch = 0;\r
609         workcount = workcnt;\r
610         oldf = -1;\r
611         pacifier = showpacifier;\r
612         start = I_FloatTime (); \r
613         func(0);\r
614 \r
615         end = I_FloatTime ();\r
616         if (pacifier)\r
617                 Sys_Printf (" (%i)\n", end-start);\r
618 }\r
619 \r
620 #endif\r