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