1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4
5 This file is part of Quake 2 Tools source code.
6
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, 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 Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22
23 #include "cmdlib.h"
24 #include "threads.h"
25
26 #define MAX_THREADS 64
27
28 int dispatch;
29 int workcount;
30 int oldf;
31 qboolean pacifier;
32
33 qboolean threaded;
34
35 /*
36 =============
37 GetThreadWork
38
39 =============
40 */
GetThreadWork(void)41 int GetThreadWork (void)
42 {
43 int r;
44 int f;
45
46 ThreadLock ();
47
48 if (dispatch == workcount)
49 {
50 ThreadUnlock ();
51 return -1;
52 }
53
54 f = 10*dispatch / workcount;
55 if (f != oldf)
56 {
57 oldf = f;
58 if (pacifier)
59 printf ("%i...", f);
60 }
61
62 r = dispatch;
63 dispatch++;
64 ThreadUnlock ();
65
66 return r;
67 }
68
69
70 void (*workfunction) (int);
71
ThreadWorkerFunction(int threadnum)72 void ThreadWorkerFunction (int threadnum)
73 {
74 int work;
75
76 while (1)
77 {
78 work = GetThreadWork ();
79 if (work == -1)
80 break;
81 //printf ("thread %i, work %i\n", threadnum, work);
82 workfunction(work);
83 }
84 }
85
RunThreadsOnIndividual(int workcnt,qboolean showpacifier,void (* func)(int))86 void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
87 {
88 if (numthreads == -1)
89 ThreadSetDefault ();
90 workfunction = func;
91 RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
92 }
93
94
95 /*
96 ===================================================================
97
98 WIN32
99
100 ===================================================================
101 */
102 #ifdef WIN32
103
104 #define USED
105
106 #include <windows.h>
107
108 int numthreads = -1;
109 CRITICAL_SECTION crit;
110 static int enter;
111
ThreadSetDefault(void)112 void ThreadSetDefault (void)
113 {
114 SYSTEM_INFO info;
115
116 if (numthreads == -1) // not set manually
117 {
118 GetSystemInfo (&info);
119 numthreads = info.dwNumberOfProcessors;
120 if (numthreads < 1 || numthreads > 32)
121 numthreads = 1;
122 }
123
124 qprintf ("%i threads\n", numthreads);
125 }
126
127
ThreadLock(void)128 void ThreadLock (void)
129 {
130 if (!threaded)
131 return;
132 EnterCriticalSection (&crit);
133 if (enter)
134 Error ("Recursive ThreadLock\n");
135 enter = 1;
136 }
137
ThreadUnlock(void)138 void ThreadUnlock (void)
139 {
140 if (!threaded)
141 return;
142 if (!enter)
143 Error ("ThreadUnlock without lock\n");
144 enter = 0;
145 LeaveCriticalSection (&crit);
146 }
147
148 /*
149 =============
150 RunThreadsOn
151 =============
152 */
RunThreadsOn(int workcnt,qboolean showpacifier,void (* func)(int))153 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
154 {
155 int threadid[MAX_THREADS];
156 HANDLE threadhandle[MAX_THREADS];
157 int i;
158 int start, end;
159
160 start = I_FloatTime ();
161 dispatch = 0;
162 workcount = workcnt;
163 oldf = -1;
164 pacifier = showpacifier;
165 threaded = true;
166
167 //
168 // run threads in parallel
169 //
170 InitializeCriticalSection (&crit);
171
172 if (numthreads == 1)
173 { // use same thread
174 func (0);
175 }
176 else
177 {
178 for (i=0 ; i<numthreads ; i++)
179 {
180 threadhandle[i] = CreateThread(
181 NULL, // LPSECURITY_ATTRIBUTES lpsa,
182 0, // DWORD cbStack,
183 (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
184 (LPVOID)i, // LPVOID lpvThreadParm,
185 0, // DWORD fdwCreate,
186 &threadid[i]);
187 }
188
189 for (i=0 ; i<numthreads ; i++)
190 WaitForSingleObject (threadhandle[i], INFINITE);
191 }
192 DeleteCriticalSection (&crit);
193
194 threaded = false;
195 end = I_FloatTime ();
196 if (pacifier)
197 printf (" (%i)\n", end-start);
198 }
199
200
201 #endif
202
203 /*
204 ===================================================================
205
206 OSF1
207
208 ===================================================================
209 */
210
211 #ifdef __osf__
212 #define USED
213
214 int numthreads = 4;
215
ThreadSetDefault(void)216 void ThreadSetDefault (void)
217 {
218 if (numthreads == -1) // not set manually
219 {
220 numthreads = 4;
221 }
222 }
223
224
225 #include <pthread.h>
226
227 pthread_mutex_t *my_mutex;
228
ThreadLock(void)229 void ThreadLock (void)
230 {
231 if (my_mutex)
232 pthread_mutex_lock (my_mutex);
233 }
234
ThreadUnlock(void)235 void ThreadUnlock (void)
236 {
237 if (my_mutex)
238 pthread_mutex_unlock (my_mutex);
239 }
240
241
242 /*
243 =============
244 RunThreadsOn
245 =============
246 */
RunThreadsOn(int workcnt,qboolean showpacifier,void (* func)(int))247 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
248 {
249 int i;
250 pthread_t work_threads[MAX_THREADS];
251 pthread_addr_t status;
252 pthread_attr_t attrib;
253 pthread_mutexattr_t mattrib;
254 int start, end;
255
256 start = I_FloatTime ();
257 dispatch = 0;
258 workcount = workcnt;
259 oldf = -1;
260 pacifier = showpacifier;
261 threaded = true;
262
263 if (pacifier)
264 setbuf (stdout, NULL);
265
266 if (!my_mutex)
267 {
268 my_mutex = malloc (sizeof(*my_mutex));
269 if (pthread_mutexattr_create (&mattrib) == -1)
270 Error ("pthread_mutex_attr_create failed");
271 if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
272 Error ("pthread_mutexattr_setkind_np failed");
273 if (pthread_mutex_init (my_mutex, mattrib) == -1)
274 Error ("pthread_mutex_init failed");
275 }
276
277 if (pthread_attr_create (&attrib) == -1)
278 Error ("pthread_attr_create failed");
279 if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
280 Error ("pthread_attr_setstacksize failed");
281
282 for (i=0 ; i<numthreads ; i++)
283 {
284 if (pthread_create(&work_threads[i], attrib
285 , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
286 Error ("pthread_create failed");
287 }
288
289 for (i=0 ; i<numthreads ; i++)
290 {
291 if (pthread_join (work_threads[i], &status) == -1)
292 Error ("pthread_join failed");
293 }
294
295 threaded = false;
296
297 end = I_FloatTime ();
298 if (pacifier)
299 printf (" (%i)\n", end-start);
300 }
301
302
303 #endif
304
305 /*
306 ===================================================================
307
308 IRIX
309
310 ===================================================================
311 */
312
313 #ifdef _MIPS_ISA
314 #define USED
315
316 #include <task.h>
317 #include <abi_mutex.h>
318 #include <sys/types.h>
319 #include <sys/prctl.h>
320
321
322 int numthreads = -1;
323 abilock_t lck;
324
ThreadSetDefault(void)325 void ThreadSetDefault (void)
326 {
327 if (numthreads == -1)
328 numthreads = prctl(PR_MAXPPROCS);
329 printf ("%i threads\n", numthreads);
330 //@@
331 usconfig (CONF_INITUSERS, numthreads);
332 }
333
334
ThreadLock(void)335 void ThreadLock (void)
336 {
337 spin_lock (&lck);
338 }
339
ThreadUnlock(void)340 void ThreadUnlock (void)
341 {
342 release_lock (&lck);
343 }
344
345
346 /*
347 =============
348 RunThreadsOn
349 =============
350 */
RunThreadsOn(int workcnt,qboolean showpacifier,void (* func)(int))351 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
352 {
353 int i;
354 int pid[MAX_THREADS];
355 int start, end;
356
357 start = I_FloatTime ();
358 dispatch = 0;
359 workcount = workcnt;
360 oldf = -1;
361 pacifier = showpacifier;
362 threaded = true;
363
364 if (pacifier)
365 setbuf (stdout, NULL);
366
367 init_lock (&lck);
368
369 for (i=0 ; i<numthreads-1 ; i++)
370 {
371 pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
372 , NULL, 0x100000);
373 // pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
374 // , NULL, 0x80000);
375 if (pid[i] == -1)
376 {
377 perror ("sproc");
378 Error ("sproc failed");
379 }
380 }
381
382 func(i);
383
384 for (i=0 ; i<numthreads-1 ; i++)
385 wait (NULL);
386
387 threaded = false;
388
389 end = I_FloatTime ();
390 if (pacifier)
391 printf (" (%i)\n", end-start);
392 }
393
394
395 #endif
396
397 /*
398 =======================================================================
399
400 SINGLE THREAD
401
402 =======================================================================
403 */
404
405 #ifndef USED
406
407 int numthreads = 1;
408
ThreadSetDefault(void)409 void ThreadSetDefault (void)
410 {
411 numthreads = 1;
412 }
413
ThreadLock(void)414 void ThreadLock (void)
415 {
416 }
417
ThreadUnlock(void)418 void ThreadUnlock (void)
419 {
420 }
421
422 /*
423 =============
424 RunThreadsOn
425 =============
426 */
RunThreadsOn(int workcnt,qboolean showpacifier,void (* func)(int))427 void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
428 {
429 int i;
430 int start, end;
431
432 dispatch = 0;
433 workcount = workcnt;
434 oldf = -1;
435 pacifier = showpacifier;
436 start = I_FloatTime ();
437 #ifdef NeXT
438 if (pacifier)
439 setbuf (stdout, NULL);
440 #endif
441 func(0);
442
443 end = I_FloatTime ();
444 if (pacifier)
445 printf (" (%i)\n", end-start);
446 }
447
448 #endif
449