threads.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "cmdlib.h"
  19. #include "threads.h"
  20. #define MAX_THREADS 64
  21. int dispatch;
  22. int workcount;
  23. int oldf;
  24. qboolean pacifier;
  25. qboolean threaded;
  26. /*
  27. =============
  28. GetThreadWork
  29. =============
  30. */
  31. int GetThreadWork (void)
  32. {
  33. int r;
  34. int f;
  35. ThreadLock ();
  36. if (dispatch == workcount)
  37. {
  38. ThreadUnlock ();
  39. return -1;
  40. }
  41. f = 10*dispatch / workcount;
  42. if (f != oldf)
  43. {
  44. oldf = f;
  45. if (pacifier)
  46. _printf ("%i...", f);
  47. }
  48. r = dispatch;
  49. dispatch++;
  50. ThreadUnlock ();
  51. return r;
  52. }
  53. void (*workfunction) (int);
  54. void ThreadWorkerFunction (int threadnum)
  55. {
  56. int work;
  57. while (1)
  58. {
  59. work = GetThreadWork ();
  60. if (work == -1)
  61. break;
  62. //_printf ("thread %i, work %i\n", threadnum, work);
  63. workfunction(work);
  64. }
  65. }
  66. void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int))
  67. {
  68. if (numthreads == -1)
  69. ThreadSetDefault ();
  70. workfunction = func;
  71. RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
  72. }
  73. /*
  74. ===================================================================
  75. WIN32
  76. ===================================================================
  77. */
  78. #ifdef WIN32
  79. #define USED
  80. #include <windows.h>
  81. int numthreads = -1;
  82. CRITICAL_SECTION crit;
  83. static int enter;
  84. void ThreadSetDefault (void)
  85. {
  86. SYSTEM_INFO info;
  87. if (numthreads == -1) // not set manually
  88. {
  89. GetSystemInfo (&info);
  90. numthreads = info.dwNumberOfProcessors;
  91. if (numthreads < 1 || numthreads > 32)
  92. numthreads = 1;
  93. }
  94. qprintf ("%i threads\n", numthreads);
  95. }
  96. void ThreadLock (void)
  97. {
  98. if (!threaded)
  99. return;
  100. EnterCriticalSection (&crit);
  101. if (enter)
  102. Error ("Recursive ThreadLock\n");
  103. enter = 1;
  104. }
  105. void ThreadUnlock (void)
  106. {
  107. if (!threaded)
  108. return;
  109. if (!enter)
  110. Error ("ThreadUnlock without lock\n");
  111. enter = 0;
  112. LeaveCriticalSection (&crit);
  113. }
  114. /*
  115. =============
  116. RunThreadsOn
  117. =============
  118. */
  119. void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
  120. {
  121. int threadid[MAX_THREADS];
  122. HANDLE threadhandle[MAX_THREADS];
  123. int i;
  124. int start, end;
  125. start = I_FloatTime ();
  126. dispatch = 0;
  127. workcount = workcnt;
  128. oldf = -1;
  129. pacifier = showpacifier;
  130. threaded = qtrue;
  131. //
  132. // run threads in parallel
  133. //
  134. InitializeCriticalSection (&crit);
  135. if (numthreads == 1)
  136. { // use same thread
  137. func (0);
  138. }
  139. else
  140. {
  141. for (i=0 ; i<numthreads ; i++)
  142. {
  143. threadhandle[i] = CreateThread(
  144. NULL, // LPSECURITY_ATTRIBUTES lpsa,
  145. 0, // DWORD cbStack,
  146. (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr,
  147. (LPVOID)i, // LPVOID lpvThreadParm,
  148. 0, // DWORD fdwCreate,
  149. &threadid[i]);
  150. }
  151. for (i=0 ; i<numthreads ; i++)
  152. WaitForSingleObject (threadhandle[i], INFINITE);
  153. }
  154. DeleteCriticalSection (&crit);
  155. threaded = qfalse;
  156. end = I_FloatTime ();
  157. if (pacifier)
  158. _printf (" (%i)\n", end-start);
  159. }
  160. #endif
  161. /*
  162. ===================================================================
  163. OSF1
  164. ===================================================================
  165. */
  166. #ifdef __osf__
  167. #define USED
  168. int numthreads = 4;
  169. void ThreadSetDefault (void)
  170. {
  171. if (numthreads == -1) // not set manually
  172. {
  173. numthreads = 4;
  174. }
  175. }
  176. #include <pthread.h>
  177. pthread_mutex_t *my_mutex;
  178. void ThreadLock (void)
  179. {
  180. if (my_mutex)
  181. pthread_mutex_lock (my_mutex);
  182. }
  183. void ThreadUnlock (void)
  184. {
  185. if (my_mutex)
  186. pthread_mutex_unlock (my_mutex);
  187. }
  188. /*
  189. =============
  190. RunThreadsOn
  191. =============
  192. */
  193. void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
  194. {
  195. int i;
  196. pthread_t work_threads[MAX_THREADS];
  197. pthread_addr_t status;
  198. pthread_attr_t attrib;
  199. pthread_mutexattr_t mattrib;
  200. int start, end;
  201. start = I_FloatTime ();
  202. dispatch = 0;
  203. workcount = workcnt;
  204. oldf = -1;
  205. pacifier = showpacifier;
  206. threaded = qtrue;
  207. if (pacifier)
  208. setbuf (stdout, NULL);
  209. if (!my_mutex)
  210. {
  211. my_mutex = malloc (sizeof(*my_mutex));
  212. if (pthread_mutexattr_create (&mattrib) == -1)
  213. Error ("pthread_mutex_attr_create failed");
  214. if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1)
  215. Error ("pthread_mutexattr_setkind_np failed");
  216. if (pthread_mutex_init (my_mutex, mattrib) == -1)
  217. Error ("pthread_mutex_init failed");
  218. }
  219. if (pthread_attr_create (&attrib) == -1)
  220. Error ("pthread_attr_create failed");
  221. if (pthread_attr_setstacksize (&attrib, 0x100000) == -1)
  222. Error ("pthread_attr_setstacksize failed");
  223. for (i=0 ; i<numthreads ; i++)
  224. {
  225. if (pthread_create(&work_threads[i], attrib
  226. , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1)
  227. Error ("pthread_create failed");
  228. }
  229. for (i=0 ; i<numthreads ; i++)
  230. {
  231. if (pthread_join (work_threads[i], &status) == -1)
  232. Error ("pthread_join failed");
  233. }
  234. threaded = qfalse;
  235. end = I_FloatTime ();
  236. if (pacifier)
  237. _printf (" (%i)\n", end-start);
  238. }
  239. #endif
  240. /*
  241. ===================================================================
  242. IRIX
  243. ===================================================================
  244. */
  245. #ifdef _MIPS_ISA
  246. #define USED
  247. #include <task.h>
  248. #include <abi_mutex.h>
  249. #include <sys/types.h>
  250. #include <sys/prctl.h>
  251. int numthreads = -1;
  252. abilock_t lck;
  253. void ThreadSetDefault (void)
  254. {
  255. if (numthreads == -1)
  256. numthreads = prctl(PR_MAXPPROCS);
  257. _printf ("%i threads\n", numthreads);
  258. usconfig (CONF_INITUSERS, numthreads);
  259. }
  260. void ThreadLock (void)
  261. {
  262. spin_lock (&lck);
  263. }
  264. void ThreadUnlock (void)
  265. {
  266. release_lock (&lck);
  267. }
  268. /*
  269. =============
  270. RunThreadsOn
  271. =============
  272. */
  273. void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
  274. {
  275. int i;
  276. int pid[MAX_THREADS];
  277. int start, end;
  278. start = I_FloatTime ();
  279. dispatch = 0;
  280. workcount = workcnt;
  281. oldf = -1;
  282. pacifier = showpacifier;
  283. threaded = qtrue;
  284. if (pacifier)
  285. setbuf (stdout, NULL);
  286. init_lock (&lck);
  287. for (i=0 ; i<numthreads-1 ; i++)
  288. {
  289. pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i
  290. , NULL, 0x200000); // 2 meg stacks
  291. if (pid[i] == -1)
  292. {
  293. perror ("sproc");
  294. Error ("sproc failed");
  295. }
  296. }
  297. func(i);
  298. for (i=0 ; i<numthreads-1 ; i++)
  299. wait (NULL);
  300. threaded = qfalse;
  301. end = I_FloatTime ();
  302. if (pacifier)
  303. _printf (" (%i)\n", end-start);
  304. }
  305. #endif
  306. /*
  307. =======================================================================
  308. SINGLE THREAD
  309. =======================================================================
  310. */
  311. #ifndef USED
  312. int numthreads = 1;
  313. void ThreadSetDefault (void)
  314. {
  315. numthreads = 1;
  316. }
  317. void ThreadLock (void)
  318. {
  319. }
  320. void ThreadUnlock (void)
  321. {
  322. }
  323. /*
  324. =============
  325. RunThreadsOn
  326. =============
  327. */
  328. void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int))
  329. {
  330. int i;
  331. int start, end;
  332. dispatch = 0;
  333. workcount = workcnt;
  334. oldf = -1;
  335. pacifier = showpacifier;
  336. start = I_FloatTime ();
  337. func(0);
  338. end = I_FloatTime ();
  339. if (pacifier)
  340. _printf (" (%i)\n", end-start);
  341. }
  342. #endif