thread.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2013,2015,2017 Inria
  4. * Copyright (C) 2010-2017 CNRS
  5. * Copyright (C) 2010,2012-2019 Université de Bordeaux
  6. *
  7. * StarPU is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation; either version 2.1 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * StarPU is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. *
  16. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  17. */
  18. #include <starpu.h>
  19. #include <core/simgrid.h>
  20. #ifdef STARPU_DEBUG
  21. #include <core/workers.h>
  22. #endif
  23. #include <common/thread.h>
  24. #include <common/fxt.h>
  25. #include <common/timing.h>
  26. #include <errno.h>
  27. #include <limits.h>
  28. #ifdef STARPU_SIMGRID
  29. #ifdef STARPU_HAVE_XBT_SYNCHRO_H
  30. #include <xbt/synchro.h>
  31. #else
  32. #include <xbt/synchro_core.h>
  33. #endif
  34. #include <smpi/smpi.h>
  35. #include <simgrid/simix.h>
  36. #else
  37. #if defined(STARPU_LINUX_SYS) && defined(STARPU_HAVE_XCHG)
  38. #include <linux/futex.h>
  39. #include <sys/syscall.h>
  40. /* Private futexes are not so old, cope with old kernels. */
  41. #ifdef FUTEX_WAIT_PRIVATE
  42. static int _starpu_futex_wait = FUTEX_WAIT_PRIVATE;
  43. static int _starpu_futex_wake = FUTEX_WAKE_PRIVATE;
  44. #else
  45. static int _starpu_futex_wait = FUTEX_WAIT;
  46. static int _starpu_futex_wake = FUTEX_WAKE;
  47. #endif
  48. #endif
  49. #endif /* !STARPU_SIMGRID */
  50. #ifdef STARPU_SIMGRID
  51. extern int _starpu_simgrid_thread_start(int argc, char *argv[]);
  52. int starpu_pthread_equal(starpu_pthread_t t1, starpu_pthread_t t2)
  53. {
  54. return t1 == t2;
  55. }
  56. starpu_pthread_t starpu_pthread_self(void)
  57. {
  58. #ifdef HAVE_SG_ACTOR_SELF
  59. return sg_actor_self();
  60. #else
  61. return MSG_process_self();
  62. #endif
  63. }
  64. int starpu_pthread_create_on(char *name, starpu_pthread_t *thread, const starpu_pthread_attr_t *attr STARPU_ATTRIBUTE_UNUSED, void *(*start_routine) (void *), void *arg, starpu_sg_host_t host)
  65. {
  66. char **_args;
  67. _STARPU_MALLOC(_args, 3*sizeof(char*));
  68. asprintf(&_args[0], "%p", start_routine);
  69. asprintf(&_args[1], "%p", arg);
  70. _args[2] = NULL;
  71. if (!host)
  72. #ifdef STARPU_HAVE_SIMGRID_HOST_H
  73. host = sg_host_by_name("MAIN");
  74. #else
  75. host = MSG_get_host_by_name("MAIN");
  76. #endif
  77. void *tsd;
  78. _STARPU_CALLOC(tsd, MAX_TSD+1, sizeof(void*));
  79. *thread = MSG_process_create_with_arguments(name, _starpu_simgrid_thread_start, tsd, host, 2, _args);
  80. #if SIMGRID_VERSION >= 31500 && SIMGRID_VERSION != 31559
  81. # ifdef HAVE_SG_ACTOR_REF
  82. sg_actor_ref(*thread);
  83. # else
  84. MSG_process_ref(*thread);
  85. # endif
  86. #endif
  87. return 0;
  88. }
  89. int starpu_pthread_create(starpu_pthread_t *thread, const starpu_pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)
  90. {
  91. return starpu_pthread_create_on("", thread, attr, start_routine, arg, NULL);
  92. }
  93. int starpu_pthread_join(starpu_pthread_t thread STARPU_ATTRIBUTE_UNUSED, void **retval STARPU_ATTRIBUTE_UNUSED)
  94. {
  95. #if SIMGRID_VERSION >= 31400
  96. # ifdef STARPU_HAVE_SIMGRID_ACTOR_H
  97. sg_actor_join(thread, 1000000);
  98. # else
  99. MSG_process_join(thread, 1000000);
  100. # endif
  101. #if SIMGRID_VERSION >= 31500 && SIMGRID_VERSION != 31559
  102. # ifdef HAVE_SG_ACTOR_REF
  103. sg_actor_unref(thread);
  104. # else
  105. MSG_process_unref(thread);
  106. # endif
  107. #endif
  108. #else
  109. starpu_sleep(1);
  110. #endif
  111. return 0;
  112. }
  113. int starpu_pthread_exit(void *retval STARPU_ATTRIBUTE_UNUSED)
  114. {
  115. #ifdef HAVE_SG_ACTOR_SELF
  116. sg_actor_kill(sg_actor_self());
  117. #else
  118. MSG_process_kill(MSG_process_self());
  119. #endif
  120. STARPU_ABORT_MSG("MSG_process_kill(MSG_process_self()) returned?!");
  121. }
  122. int starpu_pthread_attr_init(starpu_pthread_attr_t *attr STARPU_ATTRIBUTE_UNUSED)
  123. {
  124. return 0;
  125. }
  126. int starpu_pthread_attr_destroy(starpu_pthread_attr_t *attr STARPU_ATTRIBUTE_UNUSED)
  127. {
  128. return 0;
  129. }
  130. int starpu_pthread_attr_setdetachstate(starpu_pthread_attr_t *attr STARPU_ATTRIBUTE_UNUSED, int detachstate STARPU_ATTRIBUTE_UNUSED)
  131. {
  132. return 0;
  133. }
  134. int starpu_pthread_mutex_init(starpu_pthread_mutex_t *mutex, const starpu_pthread_mutexattr_t *mutexattr STARPU_ATTRIBUTE_UNUSED)
  135. {
  136. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  137. *mutex = sg_mutex_init();
  138. #else
  139. *mutex = xbt_mutex_init();
  140. #endif
  141. return 0;
  142. }
  143. int starpu_pthread_mutex_destroy(starpu_pthread_mutex_t *mutex)
  144. {
  145. if (*mutex)
  146. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  147. sg_mutex_destroy(*mutex);
  148. #else
  149. xbt_mutex_destroy(*mutex);
  150. #endif
  151. return 0;
  152. }
  153. int starpu_pthread_mutex_lock(starpu_pthread_mutex_t *mutex)
  154. {
  155. _STARPU_TRACE_LOCKING_MUTEX();
  156. /* Note: this is actually safe, because simgrid only preempts within
  157. * simgrid functions */
  158. if (!*mutex)
  159. {
  160. /* Here we may get preempted */
  161. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  162. sg_mutex_t new_mutex = sg_mutex_init();
  163. #else
  164. xbt_mutex_t new_mutex = xbt_mutex_init();
  165. #endif
  166. if (!*mutex)
  167. *mutex = new_mutex;
  168. else
  169. /* Somebody already initialized it while we were
  170. * calling sg_mutex_init, this one is now useless */
  171. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  172. sg_mutex_destroy(new_mutex);
  173. #else
  174. xbt_mutex_destroy(new_mutex);
  175. #endif
  176. }
  177. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  178. sg_mutex_lock(*mutex);
  179. #else
  180. xbt_mutex_acquire(*mutex);
  181. #endif
  182. _STARPU_TRACE_MUTEX_LOCKED();
  183. return 0;
  184. }
  185. int starpu_pthread_mutex_unlock(starpu_pthread_mutex_t *mutex)
  186. {
  187. _STARPU_TRACE_UNLOCKING_MUTEX();
  188. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  189. sg_mutex_unlock(*mutex);
  190. #else
  191. xbt_mutex_release(*mutex);
  192. #endif
  193. _STARPU_TRACE_MUTEX_UNLOCKED();
  194. return 0;
  195. }
  196. int starpu_pthread_mutex_trylock(starpu_pthread_mutex_t *mutex)
  197. {
  198. int ret;
  199. _STARPU_TRACE_TRYLOCK_MUTEX();
  200. #ifdef STARPU_HAVE_SIMGRID_MUTEX_H
  201. ret = sg_mutex_try_lock(*mutex);
  202. #elif defined(HAVE_XBT_MUTEX_TRY_ACQUIRE) || defined(xbt_mutex_try_acquire)
  203. ret = xbt_mutex_try_acquire(*mutex);
  204. #else
  205. ret = simcall_mutex_trylock((smx_mutex_t)*mutex);
  206. #endif
  207. ret = ret ? 0 : EBUSY;
  208. _STARPU_TRACE_MUTEX_LOCKED();
  209. return ret;
  210. }
  211. int starpu_pthread_mutexattr_gettype(const starpu_pthread_mutexattr_t *attr STARPU_ATTRIBUTE_UNUSED, int *type STARPU_ATTRIBUTE_UNUSED)
  212. {
  213. return 0;
  214. }
  215. int starpu_pthread_mutexattr_settype(starpu_pthread_mutexattr_t *attr STARPU_ATTRIBUTE_UNUSED, int type STARPU_ATTRIBUTE_UNUSED)
  216. {
  217. return 0;
  218. }
  219. int starpu_pthread_mutexattr_destroy(starpu_pthread_mutexattr_t *attr STARPU_ATTRIBUTE_UNUSED)
  220. {
  221. return 0;
  222. }
  223. int starpu_pthread_mutexattr_init(starpu_pthread_mutexattr_t *attr STARPU_ATTRIBUTE_UNUSED)
  224. {
  225. return 0;
  226. }
  227. /* Indexed by key-1 */
  228. static int used_key[MAX_TSD];
  229. int starpu_pthread_key_create(starpu_pthread_key_t *key, void (*destr_function) (void *) STARPU_ATTRIBUTE_UNUSED)
  230. {
  231. unsigned i;
  232. /* Note: no synchronization here, we are actually monothreaded anyway. */
  233. for (i = 0; i < MAX_TSD; i++)
  234. {
  235. if (!used_key[i])
  236. {
  237. used_key[i] = 1;
  238. break;
  239. }
  240. }
  241. STARPU_ASSERT(i < MAX_TSD);
  242. /* key 0 is for process pointer argument */
  243. *key = i+1;
  244. return 0;
  245. }
  246. int starpu_pthread_key_delete(starpu_pthread_key_t key)
  247. {
  248. used_key[key-1] = 0;
  249. return 0;
  250. }
  251. /* We need it only when using smpi */
  252. #pragma weak smpi_process_get_user_data
  253. #if !HAVE_DECL_SMPI_PROCESS_SET_USER_DATA && !defined(smpi_process_get_user_data)
  254. extern void *smpi_process_get_user_data();
  255. #endif
  256. int starpu_pthread_setspecific(starpu_pthread_key_t key, const void *pointer)
  257. {
  258. void **array;
  259. #if defined(HAVE_SMPI_PROCESS_SET_USER_DATA) || defined(smpi_process_get_user_data)
  260. #if defined(HAVE_MSG_PROCESS_SELF_NAME) || defined(MSG_process_self_name)
  261. const char *process_name = MSG_process_self_name();
  262. #else
  263. const char *process_name = SIMIX_process_self_get_name();
  264. #endif
  265. char *end;
  266. /* Test whether it is an MPI rank */
  267. strtol(process_name, &end, 10);
  268. if (!*end || !strcmp(process_name, "wait for mpi transfer") ||
  269. (!strcmp(process_name, "main") && _starpu_simgrid_running_smpi()))
  270. /* Special-case the SMPI process */
  271. array = smpi_process_get_user_data();
  272. else
  273. #endif
  274. array = MSG_process_get_data(MSG_process_self());
  275. array[key] = (void*) pointer;
  276. return 0;
  277. }
  278. void* starpu_pthread_getspecific(starpu_pthread_key_t key)
  279. {
  280. void **array;
  281. #if defined(HAVE_SMPI_PROCESS_SET_USER_DATA) || defined(smpi_process_get_user_data)
  282. #if defined(HAVE_MSG_PROCESS_SELF_NAME) || defined(MSG_process_self_name)
  283. const char *process_name = MSG_process_self_name();
  284. #else
  285. const char *process_name = SIMIX_process_self_get_name();
  286. #endif
  287. char *end;
  288. /* Test whether it is an MPI rank */
  289. strtol(process_name, &end, 10);
  290. if (!*end || !strcmp(process_name, "wait for mpi transfer") ||
  291. (!strcmp(process_name, "main") && _starpu_simgrid_running_smpi()))
  292. /* Special-case the SMPI processes */
  293. array = smpi_process_get_user_data();
  294. else
  295. #endif
  296. array = MSG_process_get_data(MSG_process_self());
  297. if (!array)
  298. return NULL;
  299. return array[key];
  300. }
  301. int starpu_pthread_cond_init(starpu_pthread_cond_t *cond, starpu_pthread_condattr_t *cond_attr STARPU_ATTRIBUTE_UNUSED)
  302. {
  303. #ifdef STARPU_HAVE_SIMGRID_COND_H
  304. *cond = sg_cond_init();
  305. #else
  306. *cond = xbt_cond_init();
  307. #endif
  308. return 0;
  309. }
  310. static void _starpu_pthread_cond_auto_init(starpu_pthread_cond_t *cond)
  311. {
  312. /* Note: this is actually safe, because simgrid only preempts within
  313. * simgrid functions */
  314. if (!*cond)
  315. {
  316. /* Here we may get preempted */
  317. #ifdef STARPU_HAVE_SIMGRID_COND_H
  318. sg_cond_t new_cond = sg_cond_init();
  319. #else
  320. xbt_cond_t new_cond = xbt_cond_init();
  321. #endif
  322. if (!*cond)
  323. *cond = new_cond;
  324. else
  325. /* Somebody already initialized it while we were
  326. * calling xbt_cond_init, this one is now useless */
  327. #ifdef STARPU_HAVE_SIMGRID_COND_H
  328. sg_cond_destroy(new_cond);
  329. #else
  330. xbt_cond_destroy(new_cond);
  331. #endif
  332. }
  333. }
  334. int starpu_pthread_cond_signal(starpu_pthread_cond_t *cond)
  335. {
  336. _starpu_pthread_cond_auto_init(cond);
  337. #ifdef STARPU_HAVE_SIMGRID_COND_H
  338. sg_cond_notify_one(*cond);
  339. #else
  340. xbt_cond_signal(*cond);
  341. #endif
  342. return 0;
  343. }
  344. int starpu_pthread_cond_broadcast(starpu_pthread_cond_t *cond)
  345. {
  346. _starpu_pthread_cond_auto_init(cond);
  347. #ifdef STARPU_HAVE_SIMGRID_COND_H
  348. sg_cond_notify_all(*cond);
  349. #else
  350. xbt_cond_broadcast(*cond);
  351. #endif
  352. return 0;
  353. }
  354. int starpu_pthread_cond_wait(starpu_pthread_cond_t *cond, starpu_pthread_mutex_t *mutex)
  355. {
  356. _STARPU_TRACE_COND_WAIT_BEGIN();
  357. _starpu_pthread_cond_auto_init(cond);
  358. #ifdef STARPU_HAVE_SIMGRID_COND_H
  359. sg_cond_wait(*cond, *mutex);
  360. #else
  361. xbt_cond_wait(*cond, *mutex);
  362. #endif
  363. _STARPU_TRACE_COND_WAIT_END();
  364. return 0;
  365. }
  366. int starpu_pthread_cond_timedwait(starpu_pthread_cond_t *cond, starpu_pthread_mutex_t *mutex, const struct timespec *abstime)
  367. {
  368. #if SIMGRID_VERSION >= 31800
  369. struct timespec now, delta;
  370. double delay;
  371. int ret = 0;
  372. _starpu_clock_gettime(&now);
  373. delta.tv_sec = abstime->tv_sec - now.tv_sec;
  374. delta.tv_nsec = abstime->tv_nsec - now.tv_nsec;
  375. delay = (double) delta.tv_sec + (double) delta.tv_nsec / 1000000000.;
  376. _STARPU_TRACE_COND_WAIT_BEGIN();
  377. _starpu_pthread_cond_auto_init(cond);
  378. #ifdef STARPU_HAVE_SIMGRID_COND_H
  379. ret = sg_cond_wait_for(*cond, *mutex, delay) ? ETIMEDOUT : 0;
  380. #else
  381. ret = xbt_cond_timedwait(*cond, *mutex, delay) ? ETIMEDOUT : 0;
  382. #endif
  383. _STARPU_TRACE_COND_WAIT_END();
  384. return ret;
  385. #else
  386. STARPU_ASSERT_MSG(0, "simgrid version is too old for this");
  387. #endif
  388. }
  389. int starpu_pthread_cond_destroy(starpu_pthread_cond_t *cond)
  390. {
  391. if (*cond)
  392. #ifdef STARPU_HAVE_SIMGRID_COND_H
  393. sg_cond_destroy(*cond);
  394. #else
  395. xbt_cond_destroy(*cond);
  396. #endif
  397. return 0;
  398. }
  399. /* TODO: use rwlocks
  400. * https://gforge.inria.fr/tracker/index.php?func=detail&aid=17213&group_id=12&atid=165
  401. */
  402. int starpu_pthread_rwlock_init(starpu_pthread_rwlock_t *restrict rwlock, const starpu_pthread_rwlockattr_t *restrict attr STARPU_ATTRIBUTE_UNUSED)
  403. {
  404. return starpu_pthread_mutex_init(rwlock, NULL);
  405. }
  406. int starpu_pthread_rwlock_destroy(starpu_pthread_rwlock_t *rwlock)
  407. {
  408. return starpu_pthread_mutex_destroy(rwlock);
  409. }
  410. int starpu_pthread_rwlock_rdlock(starpu_pthread_rwlock_t *rwlock)
  411. {
  412. _STARPU_TRACE_RDLOCKING_RWLOCK();
  413. int p_ret = starpu_pthread_mutex_lock(rwlock);
  414. _STARPU_TRACE_RWLOCK_RDLOCKED();
  415. return p_ret;
  416. }
  417. int starpu_pthread_rwlock_tryrdlock(starpu_pthread_rwlock_t *rwlock)
  418. {
  419. int p_ret = starpu_pthread_mutex_trylock(rwlock);
  420. if (!p_ret)
  421. _STARPU_TRACE_RWLOCK_RDLOCKED();
  422. return p_ret;
  423. }
  424. int starpu_pthread_rwlock_wrlock(starpu_pthread_rwlock_t *rwlock)
  425. {
  426. _STARPU_TRACE_WRLOCKING_RWLOCK();
  427. int p_ret = starpu_pthread_mutex_lock(rwlock);
  428. _STARPU_TRACE_RWLOCK_WRLOCKED();
  429. return p_ret;
  430. }
  431. int starpu_pthread_rwlock_trywrlock(starpu_pthread_rwlock_t *rwlock)
  432. {
  433. int p_ret = starpu_pthread_mutex_trylock(rwlock);
  434. if (!p_ret)
  435. _STARPU_TRACE_RWLOCK_RDLOCKED();
  436. return p_ret;
  437. }
  438. int starpu_pthread_rwlock_unlock(starpu_pthread_rwlock_t *rwlock)
  439. {
  440. _STARPU_TRACE_UNLOCKING_RWLOCK();
  441. int p_ret = starpu_pthread_mutex_unlock(rwlock);
  442. _STARPU_TRACE_RWLOCK_UNLOCKED();
  443. return p_ret;
  444. }
  445. #ifdef STARPU_HAVE_SIMGRID_BARRIER_H
  446. int starpu_pthread_barrier_init(starpu_pthread_barrier_t *restrict barrier, const starpu_pthread_barrierattr_t *restrict attr STARPU_ATTRIBUTE_UNUSED, unsigned count)
  447. {
  448. *barrier = sg_barrier_init(count);
  449. return 0;
  450. }
  451. int starpu_pthread_barrier_destroy(starpu_pthread_barrier_t *barrier)
  452. {
  453. if (*barrier)
  454. sg_barrier_destroy(*barrier);
  455. return 0;
  456. }
  457. int starpu_pthread_barrier_wait(starpu_pthread_barrier_t *barrier)
  458. {
  459. int ret;
  460. _STARPU_TRACE_BARRIER_WAIT_BEGIN();
  461. ret = sg_barrier_wait(*barrier);
  462. _STARPU_TRACE_BARRIER_WAIT_END();
  463. return ret;
  464. }
  465. #elif defined(STARPU_SIMGRID_HAVE_XBT_BARRIER_INIT) || defined(xbt_barrier_init)
  466. int starpu_pthread_barrier_init(starpu_pthread_barrier_t *restrict barrier, const starpu_pthread_barrierattr_t *restrict attr STARPU_ATTRIBUTE_UNUSED, unsigned count)
  467. {
  468. *barrier = xbt_barrier_init(count);
  469. return 0;
  470. }
  471. int starpu_pthread_barrier_destroy(starpu_pthread_barrier_t *barrier)
  472. {
  473. if (*barrier)
  474. xbt_barrier_destroy(*barrier);
  475. return 0;
  476. }
  477. int starpu_pthread_barrier_wait(starpu_pthread_barrier_t *barrier)
  478. {
  479. int ret;
  480. _STARPU_TRACE_BARRIER_WAIT_BEGIN();
  481. ret = xbt_barrier_wait(*barrier);
  482. _STARPU_TRACE_BARRIER_WAIT_END();
  483. return ret;
  484. }
  485. #endif /* defined(STARPU_SIMGRID_HAVE_XBT_BARRIER_INIT) */
  486. int starpu_pthread_queue_init(starpu_pthread_queue_t *q)
  487. {
  488. STARPU_PTHREAD_MUTEX_INIT(&q->mutex, NULL);
  489. q->queue = NULL;
  490. q->allocqueue = 0;
  491. q->nqueue = 0;
  492. return 0;
  493. }
  494. int starpu_pthread_wait_init(starpu_pthread_wait_t *w)
  495. {
  496. STARPU_PTHREAD_MUTEX_INIT(&w->mutex, NULL);
  497. STARPU_PTHREAD_COND_INIT(&w->cond, NULL);
  498. w->block = 1;
  499. return 0;
  500. }
  501. int starpu_pthread_queue_register(starpu_pthread_wait_t *w, starpu_pthread_queue_t *q)
  502. {
  503. STARPU_PTHREAD_MUTEX_LOCK(&q->mutex);
  504. if (q->nqueue == q->allocqueue)
  505. {
  506. /* Make room for the new waiter */
  507. unsigned newalloc;
  508. newalloc = q->allocqueue * 2;
  509. if (!newalloc)
  510. newalloc = 1;
  511. _STARPU_REALLOC(q->queue, newalloc * sizeof(*(q->queue)));
  512. q->allocqueue = newalloc;
  513. }
  514. q->queue[q->nqueue++] = w;
  515. STARPU_PTHREAD_MUTEX_UNLOCK(&q->mutex);
  516. return 0;
  517. }
  518. int starpu_pthread_queue_unregister(starpu_pthread_wait_t *w, starpu_pthread_queue_t *q)
  519. {
  520. unsigned i;
  521. STARPU_PTHREAD_MUTEX_LOCK(&q->mutex);
  522. for (i = 0; i < q->nqueue; i++)
  523. {
  524. if (q->queue[i] == w)
  525. {
  526. memmove(&q->queue[i], &q->queue[i+1], (q->nqueue - i - 1) * sizeof(*(q->queue)));
  527. break;
  528. }
  529. }
  530. STARPU_ASSERT(i < q->nqueue);
  531. q->nqueue--;
  532. STARPU_PTHREAD_MUTEX_UNLOCK(&q->mutex);
  533. return 0;
  534. }
  535. int starpu_pthread_wait_reset(starpu_pthread_wait_t *w)
  536. {
  537. STARPU_PTHREAD_MUTEX_LOCK(&w->mutex);
  538. w->block = 1;
  539. STARPU_PTHREAD_MUTEX_UNLOCK(&w->mutex);
  540. return 0;
  541. }
  542. int starpu_pthread_wait_wait(starpu_pthread_wait_t *w)
  543. {
  544. STARPU_PTHREAD_MUTEX_LOCK(&w->mutex);
  545. while (w->block == 1)
  546. STARPU_PTHREAD_COND_WAIT(&w->cond, &w->mutex);
  547. STARPU_PTHREAD_MUTEX_UNLOCK(&w->mutex);
  548. return 0;
  549. }
  550. /* pthread_cond_timedwait not yet available on windows, but we don't run simgrid there anyway */
  551. #ifdef STARPU_SIMGRID
  552. int starpu_pthread_wait_timedwait(starpu_pthread_wait_t *w, const struct timespec *abstime)
  553. {
  554. STARPU_PTHREAD_MUTEX_LOCK(&w->mutex);
  555. while (w->block == 1)
  556. STARPU_PTHREAD_COND_TIMEDWAIT(&w->cond, &w->mutex, abstime);
  557. STARPU_PTHREAD_MUTEX_UNLOCK(&w->mutex);
  558. return 0;
  559. }
  560. #endif
  561. int starpu_pthread_queue_signal(starpu_pthread_queue_t *q)
  562. {
  563. starpu_pthread_wait_t *w;
  564. STARPU_PTHREAD_MUTEX_LOCK(&q->mutex);
  565. if (q->nqueue)
  566. {
  567. /* TODO: better try to wake a sleeping one if possible */
  568. w = q->queue[0];
  569. STARPU_PTHREAD_MUTEX_LOCK(&w->mutex);
  570. w->block = 0;
  571. STARPU_PTHREAD_COND_SIGNAL(&w->cond);
  572. STARPU_PTHREAD_MUTEX_UNLOCK(&w->mutex);
  573. }
  574. STARPU_PTHREAD_MUTEX_UNLOCK(&q->mutex);
  575. return 0;
  576. }
  577. int starpu_pthread_queue_broadcast(starpu_pthread_queue_t *q)
  578. {
  579. unsigned i;
  580. starpu_pthread_wait_t *w;
  581. STARPU_PTHREAD_MUTEX_LOCK(&q->mutex);
  582. for (i = 0; i < q->nqueue; i++)
  583. {
  584. w = q->queue[i];
  585. STARPU_PTHREAD_MUTEX_LOCK(&w->mutex);
  586. w->block = 0;
  587. STARPU_PTHREAD_COND_SIGNAL(&w->cond);
  588. STARPU_PTHREAD_MUTEX_UNLOCK(&w->mutex);
  589. }
  590. STARPU_PTHREAD_MUTEX_UNLOCK(&q->mutex);
  591. return 0;
  592. }
  593. int starpu_pthread_wait_destroy(starpu_pthread_wait_t *w)
  594. {
  595. STARPU_PTHREAD_MUTEX_LOCK(&w->mutex);
  596. STARPU_PTHREAD_MUTEX_UNLOCK(&w->mutex);
  597. STARPU_PTHREAD_MUTEX_DESTROY(&w->mutex);
  598. STARPU_PTHREAD_COND_DESTROY(&w->cond);
  599. return 0;
  600. }
  601. int starpu_pthread_queue_destroy(starpu_pthread_queue_t *q)
  602. {
  603. STARPU_ASSERT(!q->nqueue);
  604. STARPU_PTHREAD_MUTEX_LOCK(&q->mutex);
  605. STARPU_PTHREAD_MUTEX_UNLOCK(&q->mutex);
  606. STARPU_PTHREAD_MUTEX_DESTROY(&q->mutex);
  607. free(q->queue);
  608. return 0;
  609. }
  610. #endif /* STARPU_SIMGRID */
  611. #if (defined(STARPU_SIMGRID) && !defined(STARPU_HAVE_SIMGRID_BARRIER_H) && !defined(STARPU_SIMGRID_HAVE_XBT_BARRIER_INIT) && !defined(xbt_barrier_init)) || (!defined(STARPU_SIMGRID) && !defined(STARPU_HAVE_PTHREAD_BARRIER))
  612. int starpu_pthread_barrier_init(starpu_pthread_barrier_t *restrict barrier, const starpu_pthread_barrierattr_t *restrict attr STARPU_ATTRIBUTE_UNUSED, unsigned count)
  613. {
  614. int ret = starpu_pthread_mutex_init(&barrier->mutex, NULL);
  615. if (!ret)
  616. ret = starpu_pthread_cond_init(&barrier->cond, NULL);
  617. if (!ret)
  618. ret = starpu_pthread_cond_init(&barrier->cond_destroy, NULL);
  619. barrier->count = count;
  620. barrier->done = 0;
  621. barrier->busy = 0;
  622. return ret;
  623. }
  624. int starpu_pthread_barrier_destroy(starpu_pthread_barrier_t *barrier)
  625. {
  626. starpu_pthread_mutex_lock(&barrier->mutex);
  627. while (barrier->busy)
  628. {
  629. starpu_pthread_cond_wait(&barrier->cond_destroy, &barrier->mutex);
  630. }
  631. starpu_pthread_mutex_unlock(&barrier->mutex);
  632. int ret = starpu_pthread_mutex_destroy(&barrier->mutex);
  633. if (!ret)
  634. ret = starpu_pthread_cond_destroy(&barrier->cond);
  635. if (!ret)
  636. ret = starpu_pthread_cond_destroy(&barrier->cond_destroy);
  637. return ret;
  638. }
  639. int starpu_pthread_barrier_wait(starpu_pthread_barrier_t *barrier)
  640. {
  641. int ret = 0;
  642. _STARPU_TRACE_BARRIER_WAIT_BEGIN();
  643. starpu_pthread_mutex_lock(&barrier->mutex);
  644. barrier->done++;
  645. if (barrier->done == barrier->count)
  646. {
  647. barrier->done = 0;
  648. starpu_pthread_cond_broadcast(&barrier->cond);
  649. ret = STARPU_PTHREAD_BARRIER_SERIAL_THREAD;
  650. }
  651. else
  652. {
  653. barrier->busy++;
  654. starpu_pthread_cond_wait(&barrier->cond, &barrier->mutex);
  655. barrier->busy--;
  656. starpu_pthread_cond_broadcast(&barrier->cond_destroy);
  657. }
  658. starpu_pthread_mutex_unlock(&barrier->mutex);
  659. _STARPU_TRACE_BARRIER_WAIT_END();
  660. return ret;
  661. }
  662. #endif /* defined(STARPU_SIMGRID) || !defined(STARPU_HAVE_PTHREAD_BARRIER) */
  663. #ifdef STARPU_FXT_LOCK_TRACES
  664. #if !defined(STARPU_SIMGRID) && !defined(_MSC_VER) /* !STARPU_SIMGRID */
  665. int starpu_pthread_mutex_lock(starpu_pthread_mutex_t *mutex)
  666. {
  667. _STARPU_TRACE_LOCKING_MUTEX();
  668. int p_ret = pthread_mutex_lock(mutex);
  669. _STARPU_TRACE_MUTEX_LOCKED();
  670. return p_ret;
  671. }
  672. int starpu_pthread_mutex_unlock(starpu_pthread_mutex_t *mutex)
  673. {
  674. _STARPU_TRACE_UNLOCKING_MUTEX();
  675. int p_ret = pthread_mutex_unlock(mutex);
  676. _STARPU_TRACE_MUTEX_UNLOCKED();
  677. return p_ret;
  678. }
  679. int starpu_pthread_mutex_trylock(starpu_pthread_mutex_t *mutex)
  680. {
  681. int ret;
  682. _STARPU_TRACE_TRYLOCK_MUTEX();
  683. ret = pthread_mutex_trylock(mutex);
  684. if (!ret)
  685. _STARPU_TRACE_MUTEX_LOCKED();
  686. return ret;
  687. }
  688. int starpu_pthread_cond_wait(starpu_pthread_cond_t *cond, starpu_pthread_mutex_t *mutex)
  689. {
  690. _STARPU_TRACE_COND_WAIT_BEGIN();
  691. int p_ret = pthread_cond_wait(cond, mutex);
  692. _STARPU_TRACE_COND_WAIT_END();
  693. return p_ret;
  694. }
  695. int starpu_pthread_rwlock_rdlock(starpu_pthread_rwlock_t *rwlock)
  696. {
  697. _STARPU_TRACE_RDLOCKING_RWLOCK();
  698. int p_ret = pthread_rwlock_rdlock(rwlock);
  699. _STARPU_TRACE_RWLOCK_RDLOCKED();
  700. return p_ret;
  701. }
  702. int starpu_pthread_rwlock_tryrdlock(starpu_pthread_rwlock_t *rwlock)
  703. {
  704. _STARPU_TRACE_RDLOCKING_RWLOCK();
  705. int p_ret = pthread_rwlock_tryrdlock(rwlock);
  706. if (!p_ret)
  707. _STARPU_TRACE_RWLOCK_RDLOCKED();
  708. return p_ret;
  709. }
  710. int starpu_pthread_rwlock_wrlock(starpu_pthread_rwlock_t *rwlock)
  711. {
  712. _STARPU_TRACE_WRLOCKING_RWLOCK();
  713. int p_ret = pthread_rwlock_wrlock(rwlock);
  714. _STARPU_TRACE_RWLOCK_WRLOCKED();
  715. return p_ret;
  716. }
  717. int starpu_pthread_rwlock_trywrlock(starpu_pthread_rwlock_t *rwlock)
  718. {
  719. _STARPU_TRACE_WRLOCKING_RWLOCK();
  720. int p_ret = pthread_rwlock_trywrlock(rwlock);
  721. if (!p_ret)
  722. _STARPU_TRACE_RWLOCK_WRLOCKED();
  723. return p_ret;
  724. }
  725. int starpu_pthread_rwlock_unlock(starpu_pthread_rwlock_t *rwlock)
  726. {
  727. _STARPU_TRACE_UNLOCKING_RWLOCK();
  728. int p_ret = pthread_rwlock_unlock(rwlock);
  729. _STARPU_TRACE_RWLOCK_UNLOCKED();
  730. return p_ret;
  731. }
  732. #endif /* !defined(STARPU_SIMGRID) && !defined(_MSC_VER) */
  733. #if !defined(STARPU_SIMGRID) && !defined(_MSC_VER) && defined(STARPU_HAVE_PTHREAD_BARRIER)
  734. int starpu_pthread_barrier_wait(starpu_pthread_barrier_t *barrier)
  735. {
  736. int ret;
  737. _STARPU_TRACE_BARRIER_WAIT_BEGIN();
  738. ret = pthread_barrier_wait(barrier);
  739. _STARPU_TRACE_BARRIER_WAIT_END();
  740. return ret;
  741. }
  742. #endif /* STARPU_SIMGRID, _MSC_VER, STARPU_HAVE_PTHREAD_BARRIER */
  743. #endif /* STARPU_FXT_LOCK_TRACES */
  744. /* "sched" variants, to be used (through the STARPU_PTHREAD_MUTEX_*LOCK_SCHED
  745. * macros of course) which record when the mutex is held or not */
  746. int starpu_pthread_mutex_lock_sched(starpu_pthread_mutex_t *mutex)
  747. {
  748. return starpu_pthread_mutex_lock(mutex);
  749. }
  750. int starpu_pthread_mutex_unlock_sched(starpu_pthread_mutex_t *mutex)
  751. {
  752. return starpu_pthread_mutex_unlock(mutex);
  753. }
  754. int starpu_pthread_mutex_trylock_sched(starpu_pthread_mutex_t *mutex)
  755. {
  756. return starpu_pthread_mutex_trylock(mutex);
  757. }
  758. #ifdef STARPU_DEBUG
  759. void starpu_pthread_mutex_check_sched(starpu_pthread_mutex_t *mutex, char *file, int line)
  760. {
  761. int workerid = starpu_worker_get_id();
  762. STARPU_ASSERT_MSG(workerid == -1 || !_starpu_worker_mutex_is_sched_mutex(workerid, mutex), "%s:%d is locking/unlocking a sched mutex but not using STARPU_PTHREAD_MUTEX_LOCK_SCHED", file, line);
  763. }
  764. #endif
  765. #if defined(STARPU_SIMGRID) || (defined(STARPU_LINUX_SYS) && defined(STARPU_HAVE_XCHG)) || !defined(HAVE_PTHREAD_SPIN_LOCK)
  766. #undef starpu_pthread_spin_init
  767. int starpu_pthread_spin_init(starpu_pthread_spinlock_t *lock, int pshared)
  768. {
  769. return _starpu_pthread_spin_init(lock, pshared);
  770. }
  771. #undef starpu_pthread_spin_destroy
  772. int starpu_pthread_spin_destroy(starpu_pthread_spinlock_t *lock STARPU_ATTRIBUTE_UNUSED)
  773. {
  774. return _starpu_pthread_spin_destroy(lock);
  775. }
  776. #undef starpu_pthread_spin_lock
  777. int starpu_pthread_spin_lock(starpu_pthread_spinlock_t *lock)
  778. {
  779. return _starpu_pthread_spin_lock(lock);
  780. }
  781. #endif
  782. #if defined(STARPU_SIMGRID) || (defined(STARPU_LINUX_SYS) && defined(STARPU_HAVE_XCHG)) || !defined(STARPU_HAVE_PTHREAD_SPIN_LOCK)
  783. #if !defined(STARPU_SIMGRID) && defined(STARPU_LINUX_SYS) && defined(STARPU_HAVE_XCHG)
  784. int _starpu_pthread_spin_do_lock(starpu_pthread_spinlock_t *lock)
  785. {
  786. if (STARPU_VAL_COMPARE_AND_SWAP(&lock->taken, 0, 1) == 0)
  787. /* Got it on first try! */
  788. return 0;
  789. /* Busy, spin a bit. */
  790. unsigned i;
  791. for (i = 0; i < 128; i++)
  792. {
  793. /* Pause a bit before retrying */
  794. STARPU_UYIELD();
  795. /* And synchronize with other threads */
  796. STARPU_SYNCHRONIZE();
  797. if (!lock->taken)
  798. /* Holder released it, try again */
  799. if (STARPU_VAL_COMPARE_AND_SWAP(&lock->taken, 0, 1) == 0)
  800. /* Got it! */
  801. return 0;
  802. }
  803. /* We have spent enough time with spinning, let's block */
  804. /* This avoids typical 10ms pauses when the application thread tries to submit tasks. */
  805. while (1)
  806. {
  807. /* Tell releaser to wake us */
  808. unsigned prev = starpu_xchg(&lock->taken, 2);
  809. if (prev == 0)
  810. /* Ah, it just got released and we actually acquired
  811. * it!
  812. * Note: the sad thing is that we have just written 2,
  813. * so will spuriously try to wake a thread on unlock,
  814. * but we can not avoid it since we do not know whether
  815. * there are other threads sleeping or not.
  816. */
  817. return 0;
  818. /* Now start sleeping (unless it was released in between)
  819. * We are sure to get woken because either
  820. * - some thread has not released the lock yet, and lock->taken
  821. * is 2, so it will wake us.
  822. * - some other thread started blocking, and will set
  823. * lock->taken back to 2
  824. */
  825. if (syscall(SYS_futex, &lock->taken, _starpu_futex_wait, 2, NULL, NULL, 0))
  826. if (errno == ENOSYS)
  827. _starpu_futex_wait = FUTEX_WAIT;
  828. }
  829. }
  830. #endif
  831. #undef starpu_pthread_spin_trylock
  832. int starpu_pthread_spin_trylock(starpu_pthread_spinlock_t *lock)
  833. {
  834. return _starpu_pthread_spin_trylock(lock);
  835. }
  836. #undef starpu_pthread_spin_unlock
  837. int starpu_pthread_spin_unlock(starpu_pthread_spinlock_t *lock)
  838. {
  839. return _starpu_pthread_spin_unlock(lock);
  840. }
  841. #if !defined(STARPU_SIMGRID) && defined(STARPU_LINUX_SYS) && defined(STARPU_HAVE_XCHG)
  842. void _starpu_pthread_spin_do_unlock(starpu_pthread_spinlock_t *lock)
  843. {
  844. /*
  845. * Somebody to wake. Clear 'taken' and wake him.
  846. * Note that he may not be sleeping yet, but if he is not, we won't
  847. * since the value of 'taken' will have changed.
  848. */
  849. lock->taken = 0;
  850. STARPU_SYNCHRONIZE();
  851. if (syscall(SYS_futex, &lock->taken, _starpu_futex_wake, 1, NULL, NULL, 0) == -1)
  852. switch (errno)
  853. {
  854. case ENOSYS:
  855. _starpu_futex_wake = FUTEX_WAKE;
  856. if (syscall(SYS_futex, &lock->taken, _starpu_futex_wake, 1, NULL, NULL, 0) == -1)
  857. STARPU_ASSERT_MSG(0, "futex(wake) returned %d!", errno);
  858. break;
  859. case 0:
  860. break;
  861. default:
  862. STARPU_ASSERT_MSG(0, "futex returned %d!", errno);
  863. break;
  864. }
  865. }
  866. #endif
  867. #endif /* defined(STARPU_SIMGRID) || (defined(STARPU_LINUX_SYS) && defined(STARPU_HAVE_XCHG)) || !defined(STARPU_HAVE_PTHREAD_SPIN_LOCK) */
  868. #ifdef STARPU_SIMGRID
  869. int starpu_sem_destroy(starpu_sem_t *sem)
  870. {
  871. #ifdef STARPU_HAVE_SIMGRID_SEMAPHORE_H
  872. sg_sem_destroy(*sem);
  873. #else
  874. MSG_sem_destroy(*sem);
  875. #endif
  876. return 0;
  877. }
  878. int starpu_sem_init(starpu_sem_t *sem, int pshared, unsigned value)
  879. {
  880. STARPU_ASSERT_MSG(pshared == 0, "pshared semaphores not supported under simgrid");
  881. #ifdef STARPU_HAVE_SIMGRID_SEMAPHORE_H
  882. *sem = sg_sem_init(value);
  883. #else
  884. *sem = MSG_sem_init(value);
  885. #endif
  886. return 0;
  887. }
  888. int starpu_sem_post(starpu_sem_t *sem)
  889. {
  890. #ifdef STARPU_HAVE_SIMGRID_SEMAPHORE_H
  891. sg_sem_release(*sem);
  892. #else
  893. MSG_sem_release(*sem);
  894. #endif
  895. return 0;
  896. }
  897. int starpu_sem_wait(starpu_sem_t *sem)
  898. {
  899. #ifdef STARPU_HAVE_SIMGRID_SEMAPHORE_H
  900. sg_sem_acquire(*sem);
  901. #else
  902. MSG_sem_acquire(*sem);
  903. #endif
  904. return 0;
  905. }
  906. int starpu_sem_trywait(starpu_sem_t *sem)
  907. {
  908. #ifdef STARPU_HAVE_SIMGRID_SEMAPHORE_H
  909. if (sg_sem_would_block(*sem))
  910. #else
  911. if (MSG_sem_would_block(*sem))
  912. #endif
  913. return EAGAIN;
  914. starpu_sem_wait(sem);
  915. return 0;
  916. }
  917. int starpu_sem_getvalue(starpu_sem_t *sem, int *sval)
  918. {
  919. #if SIMGRID_VERSION > 31300
  920. # ifdef STARPU_HAVE_SIMGRID_SEMAPHORE_H
  921. *sval = sg_sem_get_capacity(*sem);
  922. # else
  923. *sval = MSG_sem_get_capacity(*sem);
  924. # endif
  925. return 0;
  926. #else
  927. (void) sem;
  928. (void) sval;
  929. STARPU_ABORT_MSG("sigmrid up to 3.13 did not have working MSG_sem_get_capacity");
  930. #endif
  931. }
  932. #elif !defined(_MSC_VER) || defined(BUILDING_STARPU) /* !STARPU_SIMGRID */
  933. int starpu_sem_wait(starpu_sem_t *sem)
  934. {
  935. int ret;
  936. while((ret = sem_wait(sem)) == -1 && errno == EINTR)
  937. ;
  938. return ret;
  939. }
  940. int starpu_sem_trywait(starpu_sem_t *sem)
  941. {
  942. int ret;
  943. while((ret = sem_trywait(sem)) == -1 && errno == EINTR)
  944. ;
  945. return ret;
  946. }
  947. #endif