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