task.c 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515
  1. /* Copyright (C) 2007-2022 Free Software Foundation, Inc.
  2. Contributed by Richard Henderson <rth@redhat.com>.
  3. This file is part of the GNU Offloading and Multi Processing Library
  4. (libgomp).
  5. Libgomp is free software; you can redistribute it and/or modify it
  6. under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3, or (at your option)
  8. any later version.
  9. Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. /* This file handles the maintenance of tasks in response to task
  21. creation and termination. */
  22. #include "libgomp.h"
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <assert.h>
  26. #include "gomp-constants.h"
  27. typedef struct gomp_task_depend_entry *hash_entry_type;
  28. static inline void *
  29. htab_alloc (size_t size)
  30. {
  31. return gomp_malloc (size);
  32. }
  33. static inline void
  34. htab_free (void *ptr)
  35. {
  36. free (ptr);
  37. }
  38. #include "hashtab.h"
  39. static inline hashval_t
  40. htab_hash (hash_entry_type element)
  41. {
  42. return hash_pointer (element->addr);
  43. }
  44. static inline bool
  45. htab_eq (hash_entry_type x, hash_entry_type y)
  46. {
  47. return x->addr == y->addr;
  48. }
  49. /* Create a new task data structure. */
  50. void
  51. gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
  52. struct gomp_task_icv *prev_icv)
  53. {
  54. /* It would seem that using memset here would be a win, but it turns
  55. out that partially filling gomp_task allows us to keep the
  56. overhead of task creation low. In the nqueens-1.c test, for a
  57. sufficiently large N, we drop the overhead from 5-6% to 1%.
  58. Note, the nqueens-1.c test in serial mode is a good test to
  59. benchmark the overhead of creating tasks as there are millions of
  60. tiny tasks created that all run undeferred. */
  61. task->parent = parent_task;
  62. priority_queue_init (&task->children_queue);
  63. task->taskgroup = NULL;
  64. task->dependers = NULL;
  65. task->depend_hash = NULL;
  66. task->taskwait = NULL;
  67. task->depend_count = 0;
  68. task->completion_sem = NULL;
  69. task->deferred_p = false;
  70. task->icv = *prev_icv;
  71. task->kind = GOMP_TASK_IMPLICIT;
  72. task->in_tied_task = false;
  73. task->final_task = false;
  74. task->copy_ctors_done = false;
  75. task->parent_depends_on = false;
  76. }
  77. /* Clean up a task, after completing it. */
  78. void
  79. gomp_end_task (void)
  80. {
  81. struct gomp_thread *thr = gomp_thread ();
  82. struct gomp_task *task = thr->task;
  83. gomp_finish_task (task);
  84. thr->task = task->parent;
  85. }
  86. /* Clear the parent field of every task in LIST. */
  87. static inline void
  88. gomp_clear_parent_in_list (struct priority_list *list)
  89. {
  90. struct priority_node *p = list->tasks;
  91. if (p)
  92. do
  93. {
  94. priority_node_to_task (PQ_CHILDREN, p)->parent = NULL;
  95. p = p->next;
  96. }
  97. while (p != list->tasks);
  98. }
  99. /* Splay tree version of gomp_clear_parent_in_list.
  100. Clear the parent field of every task in NODE within SP, and free
  101. the node when done. */
  102. static void
  103. gomp_clear_parent_in_tree (prio_splay_tree sp, prio_splay_tree_node node)
  104. {
  105. if (!node)
  106. return;
  107. prio_splay_tree_node left = node->left, right = node->right;
  108. gomp_clear_parent_in_list (&node->key.l);
  109. #if _LIBGOMP_CHECKING_
  110. memset (node, 0xaf, sizeof (*node));
  111. #endif
  112. /* No need to remove the node from the tree. We're nuking
  113. everything, so just free the nodes and our caller can clear the
  114. entire splay tree. */
  115. free (node);
  116. gomp_clear_parent_in_tree (sp, left);
  117. gomp_clear_parent_in_tree (sp, right);
  118. }
  119. /* Clear the parent field of every task in Q and remove every task
  120. from Q. */
  121. static inline void
  122. gomp_clear_parent (struct priority_queue *q)
  123. {
  124. if (priority_queue_multi_p (q))
  125. {
  126. gomp_clear_parent_in_tree (&q->t, q->t.root);
  127. /* All the nodes have been cleared in gomp_clear_parent_in_tree.
  128. No need to remove anything. We can just nuke everything. */
  129. q->t.root = NULL;
  130. }
  131. else
  132. gomp_clear_parent_in_list (&q->l);
  133. }
  134. /* Helper function for GOMP_task and gomp_create_target_task.
  135. For a TASK with in/out dependencies, fill in the various dependency
  136. queues. PARENT is the parent of said task. DEPEND is as in
  137. GOMP_task. */
  138. static void
  139. gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
  140. void **depend)
  141. {
  142. size_t ndepend = (uintptr_t) depend[0];
  143. size_t i;
  144. hash_entry_type ent;
  145. if (ndepend)
  146. {
  147. /* depend[0] is total # */
  148. size_t nout = (uintptr_t) depend[1]; /* # of out: and inout: */
  149. /* ndepend - nout is # of in: */
  150. for (i = 0; i < ndepend; i++)
  151. {
  152. task->depend[i].addr = depend[2 + i];
  153. task->depend[i].is_in = i >= nout;
  154. }
  155. }
  156. else
  157. {
  158. ndepend = (uintptr_t) depend[1]; /* total # */
  159. size_t nout = (uintptr_t) depend[2]; /* # of out: and inout: */
  160. size_t nmutexinoutset = (uintptr_t) depend[3]; /* # of mutexinoutset: */
  161. /* For now we treat mutexinoutset like out, which is compliant, but
  162. inefficient. */
  163. size_t nin = (uintptr_t) depend[4]; /* # of in: */
  164. /* ndepend - nout - nmutexinoutset - nin is # of depobjs */
  165. size_t normal = nout + nmutexinoutset + nin;
  166. size_t n = 0;
  167. for (i = normal; i < ndepend; i++)
  168. {
  169. void **d = (void **) (uintptr_t) depend[5 + i];
  170. switch ((uintptr_t) d[1])
  171. {
  172. case GOMP_DEPEND_OUT:
  173. case GOMP_DEPEND_INOUT:
  174. case GOMP_DEPEND_MUTEXINOUTSET:
  175. break;
  176. case GOMP_DEPEND_IN:
  177. continue;
  178. default:
  179. gomp_fatal ("unknown omp_depend_t dependence type %d",
  180. (int) (uintptr_t) d[1]);
  181. }
  182. task->depend[n].addr = d[0];
  183. task->depend[n++].is_in = 0;
  184. }
  185. for (i = 0; i < normal; i++)
  186. {
  187. task->depend[n].addr = depend[5 + i];
  188. task->depend[n++].is_in = i >= nout + nmutexinoutset;
  189. }
  190. for (i = normal; i < ndepend; i++)
  191. {
  192. void **d = (void **) (uintptr_t) depend[5 + i];
  193. if ((uintptr_t) d[1] != GOMP_DEPEND_IN)
  194. continue;
  195. task->depend[n].addr = d[0];
  196. task->depend[n++].is_in = 1;
  197. }
  198. }
  199. task->depend_count = ndepend;
  200. task->num_dependees = 0;
  201. if (parent->depend_hash == NULL)
  202. parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
  203. for (i = 0; i < ndepend; i++)
  204. {
  205. task->depend[i].next = NULL;
  206. task->depend[i].prev = NULL;
  207. task->depend[i].task = task;
  208. task->depend[i].redundant = false;
  209. task->depend[i].redundant_out = false;
  210. hash_entry_type *slot = htab_find_slot (&parent->depend_hash,
  211. &task->depend[i], INSERT);
  212. hash_entry_type out = NULL, last = NULL;
  213. if (*slot)
  214. {
  215. /* If multiple depends on the same task are the same, all but the
  216. first one are redundant. As inout/out come first, if any of them
  217. is inout/out, it will win, which is the right semantics. */
  218. if ((*slot)->task == task)
  219. {
  220. task->depend[i].redundant = true;
  221. continue;
  222. }
  223. for (ent = *slot; ent; ent = ent->next)
  224. {
  225. if (ent->redundant_out)
  226. break;
  227. last = ent;
  228. /* depend(in:...) doesn't depend on earlier depend(in:...). */
  229. if (task->depend[i].is_in && ent->is_in)
  230. continue;
  231. if (!ent->is_in)
  232. out = ent;
  233. struct gomp_task *tsk = ent->task;
  234. if (tsk->dependers == NULL)
  235. {
  236. tsk->dependers
  237. = gomp_malloc (sizeof (struct gomp_dependers_vec)
  238. + 6 * sizeof (struct gomp_task *));
  239. tsk->dependers->n_elem = 1;
  240. tsk->dependers->allocated = 6;
  241. tsk->dependers->elem[0] = task;
  242. task->num_dependees++;
  243. continue;
  244. }
  245. /* We already have some other dependency on tsk from earlier
  246. depend clause. */
  247. else if (tsk->dependers->n_elem
  248. && (tsk->dependers->elem[tsk->dependers->n_elem - 1]
  249. == task))
  250. continue;
  251. else if (tsk->dependers->n_elem == tsk->dependers->allocated)
  252. {
  253. tsk->dependers->allocated
  254. = tsk->dependers->allocated * 2 + 2;
  255. tsk->dependers
  256. = gomp_realloc (tsk->dependers,
  257. sizeof (struct gomp_dependers_vec)
  258. + (tsk->dependers->allocated
  259. * sizeof (struct gomp_task *)));
  260. }
  261. tsk->dependers->elem[tsk->dependers->n_elem++] = task;
  262. task->num_dependees++;
  263. }
  264. task->depend[i].next = *slot;
  265. (*slot)->prev = &task->depend[i];
  266. }
  267. *slot = &task->depend[i];
  268. /* There is no need to store more than one depend({,in}out:) task per
  269. address in the hash table chain for the purpose of creation of
  270. deferred tasks, because each out depends on all earlier outs, thus it
  271. is enough to record just the last depend({,in}out:). For depend(in:),
  272. we need to keep all of the previous ones not terminated yet, because
  273. a later depend({,in}out:) might need to depend on all of them. So, if
  274. the new task's clause is depend({,in}out:), we know there is at most
  275. one other depend({,in}out:) clause in the list (out). For
  276. non-deferred tasks we want to see all outs, so they are moved to the
  277. end of the chain, after first redundant_out entry all following
  278. entries should be redundant_out. */
  279. if (!task->depend[i].is_in && out)
  280. {
  281. if (out != last)
  282. {
  283. out->next->prev = out->prev;
  284. out->prev->next = out->next;
  285. out->next = last->next;
  286. out->prev = last;
  287. last->next = out;
  288. if (out->next)
  289. out->next->prev = out;
  290. }
  291. out->redundant_out = true;
  292. }
  293. }
  294. }
  295. /* Called when encountering an explicit task directive. If IF_CLAUSE is
  296. false, then we must not delay in executing the task. If UNTIED is true,
  297. then the task may be executed by any member of the team.
  298. DEPEND is an array containing:
  299. if depend[0] is non-zero, then:
  300. depend[0]: number of depend elements.
  301. depend[1]: number of depend elements of type "out/inout".
  302. depend[2..N+1]: address of [1..N]th depend element.
  303. otherwise, when depend[0] is zero, then:
  304. depend[1]: number of depend elements.
  305. depend[2]: number of depend elements of type "out/inout".
  306. depend[3]: number of depend elements of type "mutexinoutset".
  307. depend[4]: number of depend elements of type "in".
  308. depend[5..4+depend[2]+depend[3]+depend[4]]: address of depend elements
  309. depend[5+depend[2]+depend[3]+depend[4]..4+depend[1]]: address of
  310. omp_depend_t objects. */
  311. void
  312. GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
  313. long arg_size, long arg_align, bool if_clause, unsigned flags,
  314. void **depend, int priority_arg, void *detach)
  315. {
  316. struct gomp_thread *thr = gomp_thread ();
  317. struct gomp_team *team = thr->ts.team;
  318. int priority = 0;
  319. #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
  320. /* If pthread_mutex_* is used for omp_*lock*, then each task must be
  321. tied to one thread all the time. This means UNTIED tasks must be
  322. tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
  323. might be running on different thread than FN. */
  324. if (cpyfn)
  325. if_clause = false;
  326. flags &= ~GOMP_TASK_FLAG_UNTIED;
  327. #endif
  328. /* If parallel or taskgroup has been cancelled, don't start new tasks. */
  329. if (__builtin_expect (gomp_cancel_var, 0) && team)
  330. {
  331. if (gomp_team_barrier_cancelled (&team->barrier))
  332. return;
  333. if (thr->task->taskgroup)
  334. {
  335. if (thr->task->taskgroup->cancelled)
  336. return;
  337. if (thr->task->taskgroup->workshare
  338. && thr->task->taskgroup->prev
  339. && thr->task->taskgroup->prev->cancelled)
  340. return;
  341. }
  342. }
  343. if (__builtin_expect ((flags & GOMP_TASK_FLAG_PRIORITY) != 0, 0))
  344. {
  345. priority = priority_arg;
  346. if (priority > gomp_max_task_priority_var)
  347. priority = gomp_max_task_priority_var;
  348. }
  349. if (!if_clause || team == NULL
  350. || (thr->task && thr->task->final_task)
  351. || team->task_count > 64 * team->nthreads)
  352. {
  353. struct gomp_task task;
  354. gomp_sem_t completion_sem;
  355. /* If there are depend clauses and earlier deferred sibling tasks
  356. with depend clauses, check if there isn't a dependency. If there
  357. is, we need to wait for them. There is no need to handle
  358. depend clauses for non-deferred tasks other than this, because
  359. the parent task is suspended until the child task finishes and thus
  360. it can't start further child tasks. */
  361. if ((flags & GOMP_TASK_FLAG_DEPEND)
  362. && thr->task && thr->task->depend_hash)
  363. gomp_task_maybe_wait_for_dependencies (depend);
  364. gomp_init_task (&task, thr->task, gomp_icv (false));
  365. task.kind = GOMP_TASK_UNDEFERRED;
  366. task.final_task = (thr->task && thr->task->final_task)
  367. || (flags & GOMP_TASK_FLAG_FINAL);
  368. task.priority = priority;
  369. if ((flags & GOMP_TASK_FLAG_DETACH) != 0)
  370. {
  371. gomp_sem_init (&completion_sem, 0);
  372. task.completion_sem = &completion_sem;
  373. *(void **) detach = &task;
  374. if (data)
  375. *(void **) data = &task;
  376. gomp_debug (0, "Thread %d: new event: %p\n",
  377. thr->ts.team_id, &task);
  378. }
  379. if (thr->task)
  380. {
  381. task.in_tied_task = thr->task->in_tied_task;
  382. task.taskgroup = thr->task->taskgroup;
  383. }
  384. thr->task = &task;
  385. if (__builtin_expect (cpyfn != NULL, 0))
  386. {
  387. char buf[arg_size + arg_align - 1];
  388. char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
  389. & ~(uintptr_t) (arg_align - 1));
  390. cpyfn (arg, data);
  391. fn (arg);
  392. }
  393. else
  394. fn (data);
  395. if ((flags & GOMP_TASK_FLAG_DETACH) != 0)
  396. {
  397. gomp_sem_wait (&completion_sem);
  398. gomp_sem_destroy (&completion_sem);
  399. }
  400. /* Access to "children" is normally done inside a task_lock
  401. mutex region, but the only way this particular task.children
  402. can be set is if this thread's task work function (fn)
  403. creates children. So since the setter is *this* thread, we
  404. need no barriers here when testing for non-NULL. We can have
  405. task.children set by the current thread then changed by a
  406. child thread, but seeing a stale non-NULL value is not a
  407. problem. Once past the task_lock acquisition, this thread
  408. will see the real value of task.children. */
  409. if (!priority_queue_empty_p (&task.children_queue, MEMMODEL_RELAXED))
  410. {
  411. gomp_mutex_lock (&team->task_lock);
  412. gomp_clear_parent (&task.children_queue);
  413. gomp_mutex_unlock (&team->task_lock);
  414. }
  415. gomp_end_task ();
  416. }
  417. else
  418. {
  419. struct gomp_task *task;
  420. struct gomp_task *parent = thr->task;
  421. struct gomp_taskgroup *taskgroup = parent->taskgroup;
  422. char *arg;
  423. bool do_wake;
  424. size_t depend_size = 0;
  425. if (flags & GOMP_TASK_FLAG_DEPEND)
  426. depend_size = ((uintptr_t) (depend[0] ? depend[0] : depend[1])
  427. * sizeof (struct gomp_task_depend_entry));
  428. task = gomp_malloc (sizeof (*task) + depend_size
  429. + arg_size + arg_align - 1);
  430. arg = (char *) (((uintptr_t) (task + 1) + depend_size + arg_align - 1)
  431. & ~(uintptr_t) (arg_align - 1));
  432. gomp_init_task (task, parent, gomp_icv (false));
  433. task->priority = priority;
  434. task->kind = GOMP_TASK_UNDEFERRED;
  435. task->in_tied_task = parent->in_tied_task;
  436. task->taskgroup = taskgroup;
  437. task->deferred_p = true;
  438. if ((flags & GOMP_TASK_FLAG_DETACH) != 0)
  439. {
  440. task->detach_team = team;
  441. *(void **) detach = task;
  442. if (data)
  443. *(void **) data = task;
  444. gomp_debug (0, "Thread %d: new event: %p\n", thr->ts.team_id, task);
  445. }
  446. thr->task = task;
  447. if (cpyfn)
  448. {
  449. cpyfn (arg, data);
  450. task->copy_ctors_done = true;
  451. }
  452. else
  453. memcpy (arg, data, arg_size);
  454. thr->task = parent;
  455. task->kind = GOMP_TASK_WAITING;
  456. task->fn = fn;
  457. task->fn_data = arg;
  458. task->final_task = (flags & GOMP_TASK_FLAG_FINAL) >> 1;
  459. gomp_mutex_lock (&team->task_lock);
  460. /* If parallel or taskgroup has been cancelled, don't start new
  461. tasks. */
  462. if (__builtin_expect (gomp_cancel_var, 0)
  463. && !task->copy_ctors_done)
  464. {
  465. if (gomp_team_barrier_cancelled (&team->barrier))
  466. {
  467. do_cancel:
  468. gomp_mutex_unlock (&team->task_lock);
  469. gomp_finish_task (task);
  470. free (task);
  471. return;
  472. }
  473. if (taskgroup)
  474. {
  475. if (taskgroup->cancelled)
  476. goto do_cancel;
  477. if (taskgroup->workshare
  478. && taskgroup->prev
  479. && taskgroup->prev->cancelled)
  480. goto do_cancel;
  481. }
  482. }
  483. if (taskgroup)
  484. taskgroup->num_children++;
  485. if (depend_size)
  486. {
  487. gomp_task_handle_depend (task, parent, depend);
  488. if (task->num_dependees)
  489. {
  490. /* Tasks that depend on other tasks are not put into the
  491. various waiting queues, so we are done for now. Said
  492. tasks are instead put into the queues via
  493. gomp_task_run_post_handle_dependers() after their
  494. dependencies have been satisfied. After which, they
  495. can be picked up by the various scheduling
  496. points. */
  497. gomp_mutex_unlock (&team->task_lock);
  498. return;
  499. }
  500. }
  501. priority_queue_insert (PQ_CHILDREN, &parent->children_queue,
  502. task, priority,
  503. PRIORITY_INSERT_BEGIN,
  504. /*adjust_parent_depends_on=*/false,
  505. task->parent_depends_on);
  506. if (taskgroup)
  507. priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
  508. task, priority,
  509. PRIORITY_INSERT_BEGIN,
  510. /*adjust_parent_depends_on=*/false,
  511. task->parent_depends_on);
  512. priority_queue_insert (PQ_TEAM, &team->task_queue,
  513. task, priority,
  514. PRIORITY_INSERT_END,
  515. /*adjust_parent_depends_on=*/false,
  516. task->parent_depends_on);
  517. ++team->task_count;
  518. ++team->task_queued_count;
  519. gomp_team_barrier_set_task_pending (&team->barrier);
  520. do_wake = team->task_running_count + !parent->in_tied_task
  521. < team->nthreads;
  522. gomp_mutex_unlock (&team->task_lock);
  523. if (do_wake)
  524. gomp_team_barrier_wake (&team->barrier, 1);
  525. }
  526. }
  527. ialias (GOMP_taskgroup_start)
  528. ialias (GOMP_taskgroup_end)
  529. ialias (GOMP_taskgroup_reduction_register)
  530. #define TYPE long
  531. #define UTYPE unsigned long
  532. #define TYPE_is_long 1
  533. #include "taskloop.c"
  534. #undef TYPE
  535. #undef UTYPE
  536. #undef TYPE_is_long
  537. #define TYPE unsigned long long
  538. #define UTYPE TYPE
  539. #define GOMP_taskloop GOMP_taskloop_ull
  540. #include "taskloop.c"
  541. #undef TYPE
  542. #undef UTYPE
  543. #undef GOMP_taskloop
  544. static void inline
  545. priority_queue_move_task_first (enum priority_queue_type type,
  546. struct priority_queue *head,
  547. struct gomp_task *task)
  548. {
  549. #if _LIBGOMP_CHECKING_
  550. if (!priority_queue_task_in_queue_p (type, head, task))
  551. gomp_fatal ("Attempt to move first missing task %p", task);
  552. #endif
  553. struct priority_list *list;
  554. if (priority_queue_multi_p (head))
  555. {
  556. list = priority_queue_lookup_priority (head, task->priority);
  557. #if _LIBGOMP_CHECKING_
  558. if (!list)
  559. gomp_fatal ("Unable to find priority %d", task->priority);
  560. #endif
  561. }
  562. else
  563. list = &head->l;
  564. priority_list_remove (list, task_to_priority_node (type, task), 0);
  565. priority_list_insert (type, list, task, task->priority,
  566. PRIORITY_INSERT_BEGIN, type == PQ_CHILDREN,
  567. task->parent_depends_on);
  568. }
  569. /* Actual body of GOMP_PLUGIN_target_task_completion that is executed
  570. with team->task_lock held, or is executed in the thread that called
  571. gomp_target_task_fn if GOMP_PLUGIN_target_task_completion has been
  572. run before it acquires team->task_lock. */
  573. static void
  574. gomp_target_task_completion (struct gomp_team *team, struct gomp_task *task)
  575. {
  576. struct gomp_task *parent = task->parent;
  577. if (parent)
  578. priority_queue_move_task_first (PQ_CHILDREN, &parent->children_queue,
  579. task);
  580. struct gomp_taskgroup *taskgroup = task->taskgroup;
  581. if (taskgroup)
  582. priority_queue_move_task_first (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
  583. task);
  584. priority_queue_insert (PQ_TEAM, &team->task_queue, task, task->priority,
  585. PRIORITY_INSERT_BEGIN, false,
  586. task->parent_depends_on);
  587. task->kind = GOMP_TASK_WAITING;
  588. if (parent && parent->taskwait)
  589. {
  590. if (parent->taskwait->in_taskwait)
  591. {
  592. /* One more task has had its dependencies met.
  593. Inform any waiters. */
  594. parent->taskwait->in_taskwait = false;
  595. gomp_sem_post (&parent->taskwait->taskwait_sem);
  596. }
  597. else if (parent->taskwait->in_depend_wait)
  598. {
  599. /* One more task has had its dependencies met.
  600. Inform any waiters. */
  601. parent->taskwait->in_depend_wait = false;
  602. gomp_sem_post (&parent->taskwait->taskwait_sem);
  603. }
  604. }
  605. if (taskgroup && taskgroup->in_taskgroup_wait)
  606. {
  607. /* One more task has had its dependencies met.
  608. Inform any waiters. */
  609. taskgroup->in_taskgroup_wait = false;
  610. gomp_sem_post (&taskgroup->taskgroup_sem);
  611. }
  612. ++team->task_queued_count;
  613. gomp_team_barrier_set_task_pending (&team->barrier);
  614. /* I'm afraid this can't be done after releasing team->task_lock,
  615. as gomp_target_task_completion is run from unrelated thread and
  616. therefore in between gomp_mutex_unlock and gomp_team_barrier_wake
  617. the team could be gone already. */
  618. if (team->nthreads > team->task_running_count)
  619. gomp_team_barrier_wake (&team->barrier, 1);
  620. }
  621. /* Signal that a target task TTASK has completed the asynchronously
  622. running phase and should be requeued as a task to handle the
  623. variable unmapping. */
  624. void
  625. GOMP_PLUGIN_target_task_completion (void *data)
  626. {
  627. struct gomp_target_task *ttask = (struct gomp_target_task *) data;
  628. struct gomp_task *task = ttask->task;
  629. struct gomp_team *team = ttask->team;
  630. gomp_mutex_lock (&team->task_lock);
  631. if (ttask->state == GOMP_TARGET_TASK_READY_TO_RUN)
  632. {
  633. ttask->state = GOMP_TARGET_TASK_FINISHED;
  634. gomp_mutex_unlock (&team->task_lock);
  635. return;
  636. }
  637. ttask->state = GOMP_TARGET_TASK_FINISHED;
  638. gomp_target_task_completion (team, task);
  639. gomp_mutex_unlock (&team->task_lock);
  640. }
  641. static void gomp_task_run_post_handle_depend_hash (struct gomp_task *);
  642. /* Called for nowait target tasks. */
  643. bool
  644. gomp_create_target_task (struct gomp_device_descr *devicep,
  645. void (*fn) (void *), size_t mapnum, void **hostaddrs,
  646. size_t *sizes, unsigned short *kinds,
  647. unsigned int flags, void **depend, void **args,
  648. enum gomp_target_task_state state)
  649. {
  650. struct gomp_thread *thr = gomp_thread ();
  651. struct gomp_team *team = thr->ts.team;
  652. /* If parallel or taskgroup has been cancelled, don't start new tasks. */
  653. if (__builtin_expect (gomp_cancel_var, 0) && team)
  654. {
  655. if (gomp_team_barrier_cancelled (&team->barrier))
  656. return true;
  657. if (thr->task->taskgroup)
  658. {
  659. if (thr->task->taskgroup->cancelled)
  660. return true;
  661. if (thr->task->taskgroup->workshare
  662. && thr->task->taskgroup->prev
  663. && thr->task->taskgroup->prev->cancelled)
  664. return true;
  665. }
  666. }
  667. struct gomp_target_task *ttask;
  668. struct gomp_task *task;
  669. struct gomp_task *parent = thr->task;
  670. struct gomp_taskgroup *taskgroup = parent->taskgroup;
  671. bool do_wake;
  672. size_t depend_size = 0;
  673. uintptr_t depend_cnt = 0;
  674. size_t tgt_align = 0, tgt_size = 0;
  675. uintptr_t args_cnt = 0;
  676. if (depend != NULL)
  677. {
  678. depend_cnt = (uintptr_t) (depend[0] ? depend[0] : depend[1]);
  679. depend_size = depend_cnt * sizeof (struct gomp_task_depend_entry);
  680. }
  681. if (fn)
  682. {
  683. /* GOMP_MAP_FIRSTPRIVATE need to be copied first, as they are
  684. firstprivate on the target task. */
  685. size_t i;
  686. for (i = 0; i < mapnum; i++)
  687. if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
  688. {
  689. size_t align = (size_t) 1 << (kinds[i] >> 8);
  690. if (tgt_align < align)
  691. tgt_align = align;
  692. tgt_size = (tgt_size + align - 1) & ~(align - 1);
  693. tgt_size += sizes[i];
  694. }
  695. if (tgt_align)
  696. tgt_size += tgt_align - 1;
  697. else
  698. tgt_size = 0;
  699. if (args)
  700. {
  701. void **cargs = args;
  702. while (*cargs)
  703. {
  704. intptr_t id = (intptr_t) *cargs++;
  705. if (id & GOMP_TARGET_ARG_SUBSEQUENT_PARAM)
  706. cargs++;
  707. }
  708. args_cnt = cargs + 1 - args;
  709. }
  710. }
  711. task = gomp_malloc (sizeof (*task) + depend_size
  712. + sizeof (*ttask)
  713. + args_cnt * sizeof (void *)
  714. + mapnum * (sizeof (void *) + sizeof (size_t)
  715. + sizeof (unsigned short))
  716. + tgt_size);
  717. gomp_init_task (task, parent, gomp_icv (false));
  718. task->priority = 0;
  719. task->kind = GOMP_TASK_WAITING;
  720. task->in_tied_task = parent->in_tied_task;
  721. task->taskgroup = taskgroup;
  722. ttask = (struct gomp_target_task *) &task->depend[depend_cnt];
  723. ttask->devicep = devicep;
  724. ttask->fn = fn;
  725. ttask->mapnum = mapnum;
  726. memcpy (ttask->hostaddrs, hostaddrs, mapnum * sizeof (void *));
  727. if (args_cnt)
  728. {
  729. ttask->args = (void **) &ttask->hostaddrs[mapnum];
  730. memcpy (ttask->args, args, args_cnt * sizeof (void *));
  731. ttask->sizes = (size_t *) &ttask->args[args_cnt];
  732. }
  733. else
  734. {
  735. ttask->args = args;
  736. ttask->sizes = (size_t *) &ttask->hostaddrs[mapnum];
  737. }
  738. memcpy (ttask->sizes, sizes, mapnum * sizeof (size_t));
  739. ttask->kinds = (unsigned short *) &ttask->sizes[mapnum];
  740. memcpy (ttask->kinds, kinds, mapnum * sizeof (unsigned short));
  741. if (tgt_align)
  742. {
  743. char *tgt = (char *) &ttask->kinds[mapnum];
  744. size_t i;
  745. uintptr_t al = (uintptr_t) tgt & (tgt_align - 1);
  746. if (al)
  747. tgt += tgt_align - al;
  748. tgt_size = 0;
  749. for (i = 0; i < mapnum; i++)
  750. if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
  751. {
  752. size_t align = (size_t) 1 << (kinds[i] >> 8);
  753. tgt_size = (tgt_size + align - 1) & ~(align - 1);
  754. memcpy (tgt + tgt_size, hostaddrs[i], sizes[i]);
  755. ttask->hostaddrs[i] = tgt + tgt_size;
  756. tgt_size = tgt_size + sizes[i];
  757. }
  758. }
  759. ttask->flags = flags;
  760. ttask->state = state;
  761. ttask->task = task;
  762. ttask->team = team;
  763. task->fn = NULL;
  764. task->fn_data = ttask;
  765. task->final_task = 0;
  766. gomp_mutex_lock (&team->task_lock);
  767. /* If parallel or taskgroup has been cancelled, don't start new tasks. */
  768. if (__builtin_expect (gomp_cancel_var, 0))
  769. {
  770. if (gomp_team_barrier_cancelled (&team->barrier))
  771. {
  772. do_cancel:
  773. gomp_mutex_unlock (&team->task_lock);
  774. gomp_finish_task (task);
  775. free (task);
  776. return true;
  777. }
  778. if (taskgroup)
  779. {
  780. if (taskgroup->cancelled)
  781. goto do_cancel;
  782. if (taskgroup->workshare
  783. && taskgroup->prev
  784. && taskgroup->prev->cancelled)
  785. goto do_cancel;
  786. }
  787. }
  788. if (depend_size)
  789. {
  790. gomp_task_handle_depend (task, parent, depend);
  791. if (task->num_dependees)
  792. {
  793. if (taskgroup)
  794. taskgroup->num_children++;
  795. gomp_mutex_unlock (&team->task_lock);
  796. return true;
  797. }
  798. }
  799. if (state == GOMP_TARGET_TASK_DATA)
  800. {
  801. gomp_task_run_post_handle_depend_hash (task);
  802. gomp_mutex_unlock (&team->task_lock);
  803. gomp_finish_task (task);
  804. free (task);
  805. return false;
  806. }
  807. if (taskgroup)
  808. taskgroup->num_children++;
  809. /* For async offloading, if we don't need to wait for dependencies,
  810. run the gomp_target_task_fn right away, essentially schedule the
  811. mapping part of the task in the current thread. */
  812. if (devicep != NULL
  813. && (devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
  814. {
  815. priority_queue_insert (PQ_CHILDREN, &parent->children_queue, task, 0,
  816. PRIORITY_INSERT_END,
  817. /*adjust_parent_depends_on=*/false,
  818. task->parent_depends_on);
  819. if (taskgroup)
  820. priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
  821. task, 0, PRIORITY_INSERT_END,
  822. /*adjust_parent_depends_on=*/false,
  823. task->parent_depends_on);
  824. task->pnode[PQ_TEAM].next = NULL;
  825. task->pnode[PQ_TEAM].prev = NULL;
  826. task->kind = GOMP_TASK_TIED;
  827. ++team->task_count;
  828. gomp_mutex_unlock (&team->task_lock);
  829. thr->task = task;
  830. gomp_target_task_fn (task->fn_data);
  831. thr->task = parent;
  832. gomp_mutex_lock (&team->task_lock);
  833. task->kind = GOMP_TASK_ASYNC_RUNNING;
  834. /* If GOMP_PLUGIN_target_task_completion has run already
  835. in between gomp_target_task_fn and the mutex lock,
  836. perform the requeuing here. */
  837. if (ttask->state == GOMP_TARGET_TASK_FINISHED)
  838. gomp_target_task_completion (team, task);
  839. else
  840. ttask->state = GOMP_TARGET_TASK_RUNNING;
  841. gomp_mutex_unlock (&team->task_lock);
  842. return true;
  843. }
  844. priority_queue_insert (PQ_CHILDREN, &parent->children_queue, task, 0,
  845. PRIORITY_INSERT_BEGIN,
  846. /*adjust_parent_depends_on=*/false,
  847. task->parent_depends_on);
  848. if (taskgroup)
  849. priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue, task, 0,
  850. PRIORITY_INSERT_BEGIN,
  851. /*adjust_parent_depends_on=*/false,
  852. task->parent_depends_on);
  853. priority_queue_insert (PQ_TEAM, &team->task_queue, task, 0,
  854. PRIORITY_INSERT_END,
  855. /*adjust_parent_depends_on=*/false,
  856. task->parent_depends_on);
  857. ++team->task_count;
  858. ++team->task_queued_count;
  859. gomp_team_barrier_set_task_pending (&team->barrier);
  860. do_wake = team->task_running_count + !parent->in_tied_task
  861. < team->nthreads;
  862. gomp_mutex_unlock (&team->task_lock);
  863. if (do_wake)
  864. gomp_team_barrier_wake (&team->barrier, 1);
  865. return true;
  866. }
  867. /* Given a parent_depends_on task in LIST, move it to the front of its
  868. priority so it is run as soon as possible.
  869. Care is taken to update the list's LAST_PARENT_DEPENDS_ON field.
  870. We rearrange the queue such that all parent_depends_on tasks are
  871. first, and last_parent_depends_on points to the last such task we
  872. rearranged. For example, given the following tasks in a queue
  873. where PD[123] are the parent_depends_on tasks:
  874. task->children
  875. |
  876. V
  877. C1 -> C2 -> C3 -> PD1 -> PD2 -> PD3 -> C4
  878. We rearrange such that:
  879. task->children
  880. | +--- last_parent_depends_on
  881. | |
  882. V V
  883. PD1 -> PD2 -> PD3 -> C1 -> C2 -> C3 -> C4. */
  884. static void inline
  885. priority_list_upgrade_task (struct priority_list *list,
  886. struct priority_node *node)
  887. {
  888. struct priority_node *last_parent_depends_on
  889. = list->last_parent_depends_on;
  890. if (last_parent_depends_on)
  891. {
  892. node->prev->next = node->next;
  893. node->next->prev = node->prev;
  894. node->prev = last_parent_depends_on;
  895. node->next = last_parent_depends_on->next;
  896. node->prev->next = node;
  897. node->next->prev = node;
  898. }
  899. else if (node != list->tasks)
  900. {
  901. node->prev->next = node->next;
  902. node->next->prev = node->prev;
  903. node->prev = list->tasks->prev;
  904. node->next = list->tasks;
  905. list->tasks = node;
  906. node->prev->next = node;
  907. node->next->prev = node;
  908. }
  909. list->last_parent_depends_on = node;
  910. }
  911. /* Given a parent_depends_on TASK in its parent's children_queue, move
  912. it to the front of its priority so it is run as soon as possible.
  913. PARENT is passed as an optimization.
  914. (This function could be defined in priority_queue.c, but we want it
  915. inlined, and putting it in priority_queue.h is not an option, given
  916. that gomp_task has not been properly defined at that point). */
  917. static void inline
  918. priority_queue_upgrade_task (struct gomp_task *task,
  919. struct gomp_task *parent)
  920. {
  921. struct priority_queue *head = &parent->children_queue;
  922. struct priority_node *node = &task->pnode[PQ_CHILDREN];
  923. #if _LIBGOMP_CHECKING_
  924. if (!task->parent_depends_on)
  925. gomp_fatal ("priority_queue_upgrade_task: task must be a "
  926. "parent_depends_on task");
  927. if (!priority_queue_task_in_queue_p (PQ_CHILDREN, head, task))
  928. gomp_fatal ("priority_queue_upgrade_task: cannot find task=%p", task);
  929. #endif
  930. if (priority_queue_multi_p (head))
  931. {
  932. struct priority_list *list
  933. = priority_queue_lookup_priority (head, task->priority);
  934. priority_list_upgrade_task (list, node);
  935. }
  936. else
  937. priority_list_upgrade_task (&head->l, node);
  938. }
  939. /* Given a CHILD_TASK in LIST that is about to be executed, move it out of
  940. the way in LIST so that other tasks can be considered for
  941. execution. LIST contains tasks of type TYPE.
  942. Care is taken to update the queue's LAST_PARENT_DEPENDS_ON field
  943. if applicable. */
  944. static void inline
  945. priority_list_downgrade_task (enum priority_queue_type type,
  946. struct priority_list *list,
  947. struct gomp_task *child_task)
  948. {
  949. struct priority_node *node = task_to_priority_node (type, child_task);
  950. if (list->tasks == node)
  951. list->tasks = node->next;
  952. else if (node->next != list->tasks)
  953. {
  954. /* The task in NODE is about to become TIED and TIED tasks
  955. cannot come before WAITING tasks. If we're about to
  956. leave the queue in such an indeterminate state, rewire
  957. things appropriately. However, a TIED task at the end is
  958. perfectly fine. */
  959. struct gomp_task *next_task = priority_node_to_task (type, node->next);
  960. if (next_task->kind == GOMP_TASK_WAITING)
  961. {
  962. /* Remove from list. */
  963. node->prev->next = node->next;
  964. node->next->prev = node->prev;
  965. /* Rewire at the end. */
  966. node->next = list->tasks;
  967. node->prev = list->tasks->prev;
  968. list->tasks->prev->next = node;
  969. list->tasks->prev = node;
  970. }
  971. }
  972. /* If the current task is the last_parent_depends_on for its
  973. priority, adjust last_parent_depends_on appropriately. */
  974. if (__builtin_expect (child_task->parent_depends_on, 0)
  975. && list->last_parent_depends_on == node)
  976. {
  977. struct gomp_task *prev_child = priority_node_to_task (type, node->prev);
  978. if (node->prev != node
  979. && prev_child->kind == GOMP_TASK_WAITING
  980. && prev_child->parent_depends_on)
  981. list->last_parent_depends_on = node->prev;
  982. else
  983. {
  984. /* There are no more parent_depends_on entries waiting
  985. to run, clear the list. */
  986. list->last_parent_depends_on = NULL;
  987. }
  988. }
  989. }
  990. /* Given a TASK in HEAD that is about to be executed, move it out of
  991. the way so that other tasks can be considered for execution. HEAD
  992. contains tasks of type TYPE.
  993. Care is taken to update the queue's LAST_PARENT_DEPENDS_ON field
  994. if applicable.
  995. (This function could be defined in priority_queue.c, but we want it
  996. inlined, and putting it in priority_queue.h is not an option, given
  997. that gomp_task has not been properly defined at that point). */
  998. static void inline
  999. priority_queue_downgrade_task (enum priority_queue_type type,
  1000. struct priority_queue *head,
  1001. struct gomp_task *task)
  1002. {
  1003. #if _LIBGOMP_CHECKING_
  1004. if (!priority_queue_task_in_queue_p (type, head, task))
  1005. gomp_fatal ("Attempt to downgrade missing task %p", task);
  1006. #endif
  1007. if (priority_queue_multi_p (head))
  1008. {
  1009. struct priority_list *list
  1010. = priority_queue_lookup_priority (head, task->priority);
  1011. priority_list_downgrade_task (type, list, task);
  1012. }
  1013. else
  1014. priority_list_downgrade_task (type, &head->l, task);
  1015. }
  1016. /* Setup CHILD_TASK to execute. This is done by setting the task to
  1017. TIED, and updating all relevant queues so that CHILD_TASK is no
  1018. longer chosen for scheduling. Also, remove CHILD_TASK from the
  1019. overall team task queue entirely.
  1020. Return TRUE if task or its containing taskgroup has been
  1021. cancelled. */
  1022. static inline bool
  1023. gomp_task_run_pre (struct gomp_task *child_task, struct gomp_task *parent,
  1024. struct gomp_team *team)
  1025. {
  1026. #if _LIBGOMP_CHECKING_
  1027. if (child_task->parent)
  1028. priority_queue_verify (PQ_CHILDREN,
  1029. &child_task->parent->children_queue, true);
  1030. if (child_task->taskgroup)
  1031. priority_queue_verify (PQ_TASKGROUP,
  1032. &child_task->taskgroup->taskgroup_queue, false);
  1033. priority_queue_verify (PQ_TEAM, &team->task_queue, false);
  1034. #endif
  1035. /* Task is about to go tied, move it out of the way. */
  1036. if (parent)
  1037. priority_queue_downgrade_task (PQ_CHILDREN, &parent->children_queue,
  1038. child_task);
  1039. /* Task is about to go tied, move it out of the way. */
  1040. struct gomp_taskgroup *taskgroup = child_task->taskgroup;
  1041. if (taskgroup)
  1042. priority_queue_downgrade_task (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
  1043. child_task);
  1044. priority_queue_remove (PQ_TEAM, &team->task_queue, child_task,
  1045. MEMMODEL_RELAXED);
  1046. child_task->pnode[PQ_TEAM].next = NULL;
  1047. child_task->pnode[PQ_TEAM].prev = NULL;
  1048. child_task->kind = GOMP_TASK_TIED;
  1049. if (--team->task_queued_count == 0)
  1050. gomp_team_barrier_clear_task_pending (&team->barrier);
  1051. if (__builtin_expect (gomp_cancel_var, 0)
  1052. && !child_task->copy_ctors_done)
  1053. {
  1054. if (gomp_team_barrier_cancelled (&team->barrier))
  1055. return true;
  1056. if (taskgroup)
  1057. {
  1058. if (taskgroup->cancelled)
  1059. return true;
  1060. if (taskgroup->workshare
  1061. && taskgroup->prev
  1062. && taskgroup->prev->cancelled)
  1063. return true;
  1064. }
  1065. }
  1066. return false;
  1067. }
  1068. static void
  1069. gomp_task_run_post_handle_depend_hash (struct gomp_task *child_task)
  1070. {
  1071. struct gomp_task *parent = child_task->parent;
  1072. size_t i;
  1073. for (i = 0; i < child_task->depend_count; i++)
  1074. if (!child_task->depend[i].redundant)
  1075. {
  1076. if (child_task->depend[i].next)
  1077. child_task->depend[i].next->prev = child_task->depend[i].prev;
  1078. if (child_task->depend[i].prev)
  1079. child_task->depend[i].prev->next = child_task->depend[i].next;
  1080. else
  1081. {
  1082. hash_entry_type *slot
  1083. = htab_find_slot (&parent->depend_hash, &child_task->depend[i],
  1084. NO_INSERT);
  1085. if (*slot != &child_task->depend[i])
  1086. abort ();
  1087. if (child_task->depend[i].next)
  1088. *slot = child_task->depend[i].next;
  1089. else
  1090. htab_clear_slot (parent->depend_hash, slot);
  1091. }
  1092. }
  1093. }
  1094. /* After a CHILD_TASK has been run, adjust the dependency queue for
  1095. each task that depends on CHILD_TASK, to record the fact that there
  1096. is one less dependency to worry about. If a task that depended on
  1097. CHILD_TASK now has no dependencies, place it in the various queues
  1098. so it gets scheduled to run.
  1099. TEAM is the team to which CHILD_TASK belongs to. */
  1100. static size_t
  1101. gomp_task_run_post_handle_dependers (struct gomp_task *child_task,
  1102. struct gomp_team *team)
  1103. {
  1104. struct gomp_task *parent = child_task->parent;
  1105. size_t i, count = child_task->dependers->n_elem, ret = 0;
  1106. for (i = 0; i < count; i++)
  1107. {
  1108. struct gomp_task *task = child_task->dependers->elem[i];
  1109. /* CHILD_TASK satisfies a dependency for TASK. Keep track of
  1110. TASK's remaining dependencies. Once TASK has no other
  1111. dependencies, put it into the various queues so it will get
  1112. scheduled for execution. */
  1113. if (--task->num_dependees != 0)
  1114. continue;
  1115. struct gomp_taskgroup *taskgroup = task->taskgroup;
  1116. if (parent)
  1117. {
  1118. priority_queue_insert (PQ_CHILDREN, &parent->children_queue,
  1119. task, task->priority,
  1120. PRIORITY_INSERT_BEGIN,
  1121. /*adjust_parent_depends_on=*/true,
  1122. task->parent_depends_on);
  1123. if (parent->taskwait)
  1124. {
  1125. if (parent->taskwait->in_taskwait)
  1126. {
  1127. /* One more task has had its dependencies met.
  1128. Inform any waiters. */
  1129. parent->taskwait->in_taskwait = false;
  1130. gomp_sem_post (&parent->taskwait->taskwait_sem);
  1131. }
  1132. else if (parent->taskwait->in_depend_wait)
  1133. {
  1134. /* One more task has had its dependencies met.
  1135. Inform any waiters. */
  1136. parent->taskwait->in_depend_wait = false;
  1137. gomp_sem_post (&parent->taskwait->taskwait_sem);
  1138. }
  1139. }
  1140. }
  1141. else
  1142. task->parent = NULL;
  1143. if (taskgroup)
  1144. {
  1145. priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
  1146. task, task->priority,
  1147. PRIORITY_INSERT_BEGIN,
  1148. /*adjust_parent_depends_on=*/false,
  1149. task->parent_depends_on);
  1150. if (taskgroup->in_taskgroup_wait)
  1151. {
  1152. /* One more task has had its dependencies met.
  1153. Inform any waiters. */
  1154. taskgroup->in_taskgroup_wait = false;
  1155. gomp_sem_post (&taskgroup->taskgroup_sem);
  1156. }
  1157. }
  1158. priority_queue_insert (PQ_TEAM, &team->task_queue,
  1159. task, task->priority,
  1160. PRIORITY_INSERT_END,
  1161. /*adjust_parent_depends_on=*/false,
  1162. task->parent_depends_on);
  1163. ++team->task_count;
  1164. ++team->task_queued_count;
  1165. ++ret;
  1166. }
  1167. free (child_task->dependers);
  1168. child_task->dependers = NULL;
  1169. if (ret > 1)
  1170. gomp_team_barrier_set_task_pending (&team->barrier);
  1171. return ret;
  1172. }
  1173. static inline size_t
  1174. gomp_task_run_post_handle_depend (struct gomp_task *child_task,
  1175. struct gomp_team *team)
  1176. {
  1177. if (child_task->depend_count == 0)
  1178. return 0;
  1179. /* If parent is gone already, the hash table is freed and nothing
  1180. will use the hash table anymore, no need to remove anything from it. */
  1181. if (child_task->parent != NULL)
  1182. gomp_task_run_post_handle_depend_hash (child_task);
  1183. if (child_task->dependers == NULL)
  1184. return 0;
  1185. return gomp_task_run_post_handle_dependers (child_task, team);
  1186. }
  1187. /* Remove CHILD_TASK from its parent. */
  1188. static inline void
  1189. gomp_task_run_post_remove_parent (struct gomp_task *child_task)
  1190. {
  1191. struct gomp_task *parent = child_task->parent;
  1192. if (parent == NULL)
  1193. return;
  1194. /* If this was the last task the parent was depending on,
  1195. synchronize with gomp_task_maybe_wait_for_dependencies so it can
  1196. clean up and return. */
  1197. if (__builtin_expect (child_task->parent_depends_on, 0)
  1198. && --parent->taskwait->n_depend == 0
  1199. && parent->taskwait->in_depend_wait)
  1200. {
  1201. parent->taskwait->in_depend_wait = false;
  1202. gomp_sem_post (&parent->taskwait->taskwait_sem);
  1203. }
  1204. if (priority_queue_remove (PQ_CHILDREN, &parent->children_queue,
  1205. child_task, MEMMODEL_RELEASE)
  1206. && parent->taskwait && parent->taskwait->in_taskwait)
  1207. {
  1208. parent->taskwait->in_taskwait = false;
  1209. gomp_sem_post (&parent->taskwait->taskwait_sem);
  1210. }
  1211. child_task->pnode[PQ_CHILDREN].next = NULL;
  1212. child_task->pnode[PQ_CHILDREN].prev = NULL;
  1213. }
  1214. /* Remove CHILD_TASK from its taskgroup. */
  1215. static inline void
  1216. gomp_task_run_post_remove_taskgroup (struct gomp_task *child_task)
  1217. {
  1218. struct gomp_taskgroup *taskgroup = child_task->taskgroup;
  1219. if (taskgroup == NULL)
  1220. return;
  1221. bool empty = priority_queue_remove (PQ_TASKGROUP,
  1222. &taskgroup->taskgroup_queue,
  1223. child_task, MEMMODEL_RELAXED);
  1224. child_task->pnode[PQ_TASKGROUP].next = NULL;
  1225. child_task->pnode[PQ_TASKGROUP].prev = NULL;
  1226. if (taskgroup->num_children > 1)
  1227. --taskgroup->num_children;
  1228. else
  1229. {
  1230. /* We access taskgroup->num_children in GOMP_taskgroup_end
  1231. outside of the task lock mutex region, so
  1232. need a release barrier here to ensure memory
  1233. written by child_task->fn above is flushed
  1234. before the NULL is written. */
  1235. __atomic_store_n (&taskgroup->num_children, 0, MEMMODEL_RELEASE);
  1236. }
  1237. if (empty && taskgroup->in_taskgroup_wait)
  1238. {
  1239. taskgroup->in_taskgroup_wait = false;
  1240. gomp_sem_post (&taskgroup->taskgroup_sem);
  1241. }
  1242. }
  1243. void
  1244. gomp_barrier_handle_tasks (gomp_barrier_state_t state)
  1245. {
  1246. struct gomp_thread *thr = gomp_thread ();
  1247. struct gomp_team *team = thr->ts.team;
  1248. struct gomp_task *task = thr->task;
  1249. struct gomp_task *child_task = NULL;
  1250. struct gomp_task *to_free = NULL;
  1251. int do_wake = 0;
  1252. gomp_mutex_lock (&team->task_lock);
  1253. if (gomp_barrier_last_thread (state))
  1254. {
  1255. if (team->task_count == 0)
  1256. {
  1257. gomp_team_barrier_done (&team->barrier, state);
  1258. gomp_mutex_unlock (&team->task_lock);
  1259. gomp_team_barrier_wake (&team->barrier, 0);
  1260. return;
  1261. }
  1262. gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
  1263. }
  1264. while (1)
  1265. {
  1266. bool cancelled = false;
  1267. if (!priority_queue_empty_p (&team->task_queue, MEMMODEL_RELAXED))
  1268. {
  1269. bool ignored;
  1270. child_task
  1271. = priority_queue_next_task (PQ_TEAM, &team->task_queue,
  1272. PQ_IGNORED, NULL,
  1273. &ignored);
  1274. cancelled = gomp_task_run_pre (child_task, child_task->parent,
  1275. team);
  1276. if (__builtin_expect (cancelled, 0))
  1277. {
  1278. if (to_free)
  1279. {
  1280. gomp_finish_task (to_free);
  1281. free (to_free);
  1282. to_free = NULL;
  1283. }
  1284. goto finish_cancelled;
  1285. }
  1286. team->task_running_count++;
  1287. child_task->in_tied_task = true;
  1288. }
  1289. else if (team->task_count == 0
  1290. && gomp_team_barrier_waiting_for_tasks (&team->barrier))
  1291. {
  1292. gomp_team_barrier_done (&team->barrier, state);
  1293. gomp_mutex_unlock (&team->task_lock);
  1294. gomp_team_barrier_wake (&team->barrier, 0);
  1295. if (to_free)
  1296. {
  1297. gomp_finish_task (to_free);
  1298. free (to_free);
  1299. }
  1300. return;
  1301. }
  1302. gomp_mutex_unlock (&team->task_lock);
  1303. if (do_wake)
  1304. {
  1305. gomp_team_barrier_wake (&team->barrier, do_wake);
  1306. do_wake = 0;
  1307. }
  1308. if (to_free)
  1309. {
  1310. gomp_finish_task (to_free);
  1311. free (to_free);
  1312. to_free = NULL;
  1313. }
  1314. if (child_task)
  1315. {
  1316. thr->task = child_task;
  1317. if (__builtin_expect (child_task->fn == NULL, 0))
  1318. {
  1319. if (gomp_target_task_fn (child_task->fn_data))
  1320. {
  1321. thr->task = task;
  1322. gomp_mutex_lock (&team->task_lock);
  1323. child_task->kind = GOMP_TASK_ASYNC_RUNNING;
  1324. team->task_running_count--;
  1325. struct gomp_target_task *ttask
  1326. = (struct gomp_target_task *) child_task->fn_data;
  1327. /* If GOMP_PLUGIN_target_task_completion has run already
  1328. in between gomp_target_task_fn and the mutex lock,
  1329. perform the requeuing here. */
  1330. if (ttask->state == GOMP_TARGET_TASK_FINISHED)
  1331. gomp_target_task_completion (team, child_task);
  1332. else
  1333. ttask->state = GOMP_TARGET_TASK_RUNNING;
  1334. child_task = NULL;
  1335. continue;
  1336. }
  1337. }
  1338. else
  1339. child_task->fn (child_task->fn_data);
  1340. thr->task = task;
  1341. }
  1342. else
  1343. return;
  1344. gomp_mutex_lock (&team->task_lock);
  1345. if (child_task)
  1346. {
  1347. if (child_task->detach_team)
  1348. {
  1349. assert (child_task->detach_team == team);
  1350. child_task->kind = GOMP_TASK_DETACHED;
  1351. ++team->task_detach_count;
  1352. --team->task_running_count;
  1353. gomp_debug (0,
  1354. "thread %d: task with event %p finished without "
  1355. "completion event fulfilled in team barrier\n",
  1356. thr->ts.team_id, child_task);
  1357. child_task = NULL;
  1358. continue;
  1359. }
  1360. finish_cancelled:;
  1361. size_t new_tasks
  1362. = gomp_task_run_post_handle_depend (child_task, team);
  1363. gomp_task_run_post_remove_parent (child_task);
  1364. gomp_clear_parent (&child_task->children_queue);
  1365. gomp_task_run_post_remove_taskgroup (child_task);
  1366. to_free = child_task;
  1367. if (!cancelled)
  1368. team->task_running_count--;
  1369. child_task = NULL;
  1370. if (new_tasks > 1)
  1371. {
  1372. do_wake = team->nthreads - team->task_running_count;
  1373. if (do_wake > new_tasks)
  1374. do_wake = new_tasks;
  1375. }
  1376. --team->task_count;
  1377. }
  1378. }
  1379. }
  1380. /* Called when encountering a taskwait directive.
  1381. Wait for all children of the current task. */
  1382. void
  1383. GOMP_taskwait (void)
  1384. {
  1385. struct gomp_thread *thr = gomp_thread ();
  1386. struct gomp_team *team = thr->ts.team;
  1387. struct gomp_task *task = thr->task;
  1388. struct gomp_task *child_task = NULL;
  1389. struct gomp_task *to_free = NULL;
  1390. struct gomp_taskwait taskwait;
  1391. int do_wake = 0;
  1392. /* The acquire barrier on load of task->children here synchronizes
  1393. with the write of a NULL in gomp_task_run_post_remove_parent. It is
  1394. not necessary that we synchronize with other non-NULL writes at
  1395. this point, but we must ensure that all writes to memory by a
  1396. child thread task work function are seen before we exit from
  1397. GOMP_taskwait. */
  1398. if (task == NULL
  1399. || priority_queue_empty_p (&task->children_queue, MEMMODEL_ACQUIRE))
  1400. return;
  1401. memset (&taskwait, 0, sizeof (taskwait));
  1402. bool child_q = false;
  1403. gomp_mutex_lock (&team->task_lock);
  1404. while (1)
  1405. {
  1406. bool cancelled = false;
  1407. if (priority_queue_empty_p (&task->children_queue, MEMMODEL_RELAXED))
  1408. {
  1409. bool destroy_taskwait = task->taskwait != NULL;
  1410. task->taskwait = NULL;
  1411. gomp_mutex_unlock (&team->task_lock);
  1412. if (to_free)
  1413. {
  1414. gomp_finish_task (to_free);
  1415. free (to_free);
  1416. }
  1417. if (destroy_taskwait)
  1418. gomp_sem_destroy (&taskwait.taskwait_sem);
  1419. return;
  1420. }
  1421. struct gomp_task *next_task
  1422. = priority_queue_next_task (PQ_CHILDREN, &task->children_queue,
  1423. PQ_TEAM, &team->task_queue, &child_q);
  1424. if (next_task->kind == GOMP_TASK_WAITING)
  1425. {
  1426. child_task = next_task;
  1427. cancelled
  1428. = gomp_task_run_pre (child_task, task, team);
  1429. if (__builtin_expect (cancelled, 0))
  1430. {
  1431. if (to_free)
  1432. {
  1433. gomp_finish_task (to_free);
  1434. free (to_free);
  1435. to_free = NULL;
  1436. }
  1437. goto finish_cancelled;
  1438. }
  1439. }
  1440. else
  1441. {
  1442. /* All tasks we are waiting for are either running in other
  1443. threads, are detached and waiting for the completion event to be
  1444. fulfilled, or they are tasks that have not had their
  1445. dependencies met (so they're not even in the queue). Wait
  1446. for them. */
  1447. if (task->taskwait == NULL)
  1448. {
  1449. taskwait.in_depend_wait = false;
  1450. gomp_sem_init (&taskwait.taskwait_sem, 0);
  1451. task->taskwait = &taskwait;
  1452. }
  1453. taskwait.in_taskwait = true;
  1454. }
  1455. gomp_mutex_unlock (&team->task_lock);
  1456. if (do_wake)
  1457. {
  1458. gomp_team_barrier_wake (&team->barrier, do_wake);
  1459. do_wake = 0;
  1460. }
  1461. if (to_free)
  1462. {
  1463. gomp_finish_task (to_free);
  1464. free (to_free);
  1465. to_free = NULL;
  1466. }
  1467. if (child_task)
  1468. {
  1469. thr->task = child_task;
  1470. if (__builtin_expect (child_task->fn == NULL, 0))
  1471. {
  1472. if (gomp_target_task_fn (child_task->fn_data))
  1473. {
  1474. thr->task = task;
  1475. gomp_mutex_lock (&team->task_lock);
  1476. child_task->kind = GOMP_TASK_ASYNC_RUNNING;
  1477. struct gomp_target_task *ttask
  1478. = (struct gomp_target_task *) child_task->fn_data;
  1479. /* If GOMP_PLUGIN_target_task_completion has run already
  1480. in between gomp_target_task_fn and the mutex lock,
  1481. perform the requeuing here. */
  1482. if (ttask->state == GOMP_TARGET_TASK_FINISHED)
  1483. gomp_target_task_completion (team, child_task);
  1484. else
  1485. ttask->state = GOMP_TARGET_TASK_RUNNING;
  1486. child_task = NULL;
  1487. continue;
  1488. }
  1489. }
  1490. else
  1491. child_task->fn (child_task->fn_data);
  1492. thr->task = task;
  1493. }
  1494. else
  1495. gomp_sem_wait (&taskwait.taskwait_sem);
  1496. gomp_mutex_lock (&team->task_lock);
  1497. if (child_task)
  1498. {
  1499. if (child_task->detach_team)
  1500. {
  1501. assert (child_task->detach_team == team);
  1502. child_task->kind = GOMP_TASK_DETACHED;
  1503. ++team->task_detach_count;
  1504. gomp_debug (0,
  1505. "thread %d: task with event %p finished without "
  1506. "completion event fulfilled in taskwait\n",
  1507. thr->ts.team_id, child_task);
  1508. child_task = NULL;
  1509. continue;
  1510. }
  1511. finish_cancelled:;
  1512. size_t new_tasks
  1513. = gomp_task_run_post_handle_depend (child_task, team);
  1514. if (child_q)
  1515. {
  1516. priority_queue_remove (PQ_CHILDREN, &task->children_queue,
  1517. child_task, MEMMODEL_RELAXED);
  1518. child_task->pnode[PQ_CHILDREN].next = NULL;
  1519. child_task->pnode[PQ_CHILDREN].prev = NULL;
  1520. }
  1521. gomp_clear_parent (&child_task->children_queue);
  1522. gomp_task_run_post_remove_taskgroup (child_task);
  1523. to_free = child_task;
  1524. child_task = NULL;
  1525. team->task_count--;
  1526. if (new_tasks > 1)
  1527. {
  1528. do_wake = team->nthreads - team->task_running_count
  1529. - !task->in_tied_task;
  1530. if (do_wake > new_tasks)
  1531. do_wake = new_tasks;
  1532. }
  1533. }
  1534. }
  1535. }
  1536. /* Called when encountering a taskwait directive with depend clause(s).
  1537. Wait as if it was an mergeable included task construct with empty body. */
  1538. void
  1539. GOMP_taskwait_depend (void **depend)
  1540. {
  1541. struct gomp_thread *thr = gomp_thread ();
  1542. struct gomp_team *team = thr->ts.team;
  1543. /* If parallel or taskgroup has been cancelled, return early. */
  1544. if (__builtin_expect (gomp_cancel_var, 0) && team)
  1545. {
  1546. if (gomp_team_barrier_cancelled (&team->barrier))
  1547. return;
  1548. if (thr->task->taskgroup)
  1549. {
  1550. if (thr->task->taskgroup->cancelled)
  1551. return;
  1552. if (thr->task->taskgroup->workshare
  1553. && thr->task->taskgroup->prev
  1554. && thr->task->taskgroup->prev->cancelled)
  1555. return;
  1556. }
  1557. }
  1558. if (thr->task && thr->task->depend_hash)
  1559. gomp_task_maybe_wait_for_dependencies (depend);
  1560. }
  1561. /* An undeferred task is about to run. Wait for all tasks that this
  1562. undeferred task depends on.
  1563. This is done by first putting all known ready dependencies
  1564. (dependencies that have their own dependencies met) at the top of
  1565. the scheduling queues. Then we iterate through these imminently
  1566. ready tasks (and possibly other high priority tasks), and run them.
  1567. If we run out of ready dependencies to execute, we either wait for
  1568. the remaining dependencies to finish, or wait for them to get
  1569. scheduled so we can run them.
  1570. DEPEND is as in GOMP_task. */
  1571. void
  1572. gomp_task_maybe_wait_for_dependencies (void **depend)
  1573. {
  1574. struct gomp_thread *thr = gomp_thread ();
  1575. struct gomp_task *task = thr->task;
  1576. struct gomp_team *team = thr->ts.team;
  1577. struct gomp_task_depend_entry elem, *ent = NULL;
  1578. struct gomp_taskwait taskwait;
  1579. size_t orig_ndepend = (uintptr_t) depend[0];
  1580. size_t nout = (uintptr_t) depend[1];
  1581. size_t ndepend = orig_ndepend;
  1582. size_t normal = ndepend;
  1583. size_t n = 2;
  1584. size_t i;
  1585. size_t num_awaited = 0;
  1586. struct gomp_task *child_task = NULL;
  1587. struct gomp_task *to_free = NULL;
  1588. int do_wake = 0;
  1589. if (ndepend == 0)
  1590. {
  1591. ndepend = nout;
  1592. nout = (uintptr_t) depend[2] + (uintptr_t) depend[3];
  1593. normal = nout + (uintptr_t) depend[4];
  1594. n = 5;
  1595. }
  1596. gomp_mutex_lock (&team->task_lock);
  1597. for (i = 0; i < ndepend; i++)
  1598. {
  1599. elem.addr = depend[i + n];
  1600. elem.is_in = i >= nout;
  1601. if (__builtin_expect (i >= normal, 0))
  1602. {
  1603. void **d = (void **) elem.addr;
  1604. switch ((uintptr_t) d[1])
  1605. {
  1606. case GOMP_DEPEND_IN:
  1607. break;
  1608. case GOMP_DEPEND_OUT:
  1609. case GOMP_DEPEND_INOUT:
  1610. case GOMP_DEPEND_MUTEXINOUTSET:
  1611. elem.is_in = 0;
  1612. break;
  1613. default:
  1614. gomp_fatal ("unknown omp_depend_t dependence type %d",
  1615. (int) (uintptr_t) d[1]);
  1616. }
  1617. elem.addr = d[0];
  1618. }
  1619. ent = htab_find (task->depend_hash, &elem);
  1620. for (; ent; ent = ent->next)
  1621. if (elem.is_in && ent->is_in)
  1622. continue;
  1623. else
  1624. {
  1625. struct gomp_task *tsk = ent->task;
  1626. if (!tsk->parent_depends_on)
  1627. {
  1628. tsk->parent_depends_on = true;
  1629. ++num_awaited;
  1630. /* If dependency TSK itself has no dependencies and is
  1631. ready to run, move it up front so that we run it as
  1632. soon as possible. */
  1633. if (tsk->num_dependees == 0 && tsk->kind == GOMP_TASK_WAITING)
  1634. priority_queue_upgrade_task (tsk, task);
  1635. }
  1636. }
  1637. }
  1638. if (num_awaited == 0)
  1639. {
  1640. gomp_mutex_unlock (&team->task_lock);
  1641. return;
  1642. }
  1643. memset (&taskwait, 0, sizeof (taskwait));
  1644. taskwait.n_depend = num_awaited;
  1645. gomp_sem_init (&taskwait.taskwait_sem, 0);
  1646. task->taskwait = &taskwait;
  1647. while (1)
  1648. {
  1649. bool cancelled = false;
  1650. if (taskwait.n_depend == 0)
  1651. {
  1652. task->taskwait = NULL;
  1653. gomp_mutex_unlock (&team->task_lock);
  1654. if (to_free)
  1655. {
  1656. gomp_finish_task (to_free);
  1657. free (to_free);
  1658. }
  1659. gomp_sem_destroy (&taskwait.taskwait_sem);
  1660. return;
  1661. }
  1662. /* Theoretically when we have multiple priorities, we should
  1663. chose between the highest priority item in
  1664. task->children_queue and team->task_queue here, so we should
  1665. use priority_queue_next_task(). However, since we are
  1666. running an undeferred task, perhaps that makes all tasks it
  1667. depends on undeferred, thus a priority of INF? This would
  1668. make it unnecessary to take anything into account here,
  1669. but the dependencies.
  1670. On the other hand, if we want to use priority_queue_next_task(),
  1671. care should be taken to only use priority_queue_remove()
  1672. below if the task was actually removed from the children
  1673. queue. */
  1674. bool ignored;
  1675. struct gomp_task *next_task
  1676. = priority_queue_next_task (PQ_CHILDREN, &task->children_queue,
  1677. PQ_IGNORED, NULL, &ignored);
  1678. if (next_task->kind == GOMP_TASK_WAITING)
  1679. {
  1680. child_task = next_task;
  1681. cancelled
  1682. = gomp_task_run_pre (child_task, task, team);
  1683. if (__builtin_expect (cancelled, 0))
  1684. {
  1685. if (to_free)
  1686. {
  1687. gomp_finish_task (to_free);
  1688. free (to_free);
  1689. to_free = NULL;
  1690. }
  1691. goto finish_cancelled;
  1692. }
  1693. }
  1694. else
  1695. /* All tasks we are waiting for are either running in other
  1696. threads, or they are tasks that have not had their
  1697. dependencies met (so they're not even in the queue). Wait
  1698. for them. */
  1699. taskwait.in_depend_wait = true;
  1700. gomp_mutex_unlock (&team->task_lock);
  1701. if (do_wake)
  1702. {
  1703. gomp_team_barrier_wake (&team->barrier, do_wake);
  1704. do_wake = 0;
  1705. }
  1706. if (to_free)
  1707. {
  1708. gomp_finish_task (to_free);
  1709. free (to_free);
  1710. to_free = NULL;
  1711. }
  1712. if (child_task)
  1713. {
  1714. thr->task = child_task;
  1715. if (__builtin_expect (child_task->fn == NULL, 0))
  1716. {
  1717. if (gomp_target_task_fn (child_task->fn_data))
  1718. {
  1719. thr->task = task;
  1720. gomp_mutex_lock (&team->task_lock);
  1721. child_task->kind = GOMP_TASK_ASYNC_RUNNING;
  1722. struct gomp_target_task *ttask
  1723. = (struct gomp_target_task *) child_task->fn_data;
  1724. /* If GOMP_PLUGIN_target_task_completion has run already
  1725. in between gomp_target_task_fn and the mutex lock,
  1726. perform the requeuing here. */
  1727. if (ttask->state == GOMP_TARGET_TASK_FINISHED)
  1728. gomp_target_task_completion (team, child_task);
  1729. else
  1730. ttask->state = GOMP_TARGET_TASK_RUNNING;
  1731. child_task = NULL;
  1732. continue;
  1733. }
  1734. }
  1735. else
  1736. child_task->fn (child_task->fn_data);
  1737. thr->task = task;
  1738. }
  1739. else
  1740. gomp_sem_wait (&taskwait.taskwait_sem);
  1741. gomp_mutex_lock (&team->task_lock);
  1742. if (child_task)
  1743. {
  1744. finish_cancelled:;
  1745. size_t new_tasks
  1746. = gomp_task_run_post_handle_depend (child_task, team);
  1747. if (child_task->parent_depends_on)
  1748. --taskwait.n_depend;
  1749. priority_queue_remove (PQ_CHILDREN, &task->children_queue,
  1750. child_task, MEMMODEL_RELAXED);
  1751. child_task->pnode[PQ_CHILDREN].next = NULL;
  1752. child_task->pnode[PQ_CHILDREN].prev = NULL;
  1753. gomp_clear_parent (&child_task->children_queue);
  1754. gomp_task_run_post_remove_taskgroup (child_task);
  1755. to_free = child_task;
  1756. child_task = NULL;
  1757. team->task_count--;
  1758. if (new_tasks > 1)
  1759. {
  1760. do_wake = team->nthreads - team->task_running_count
  1761. - !task->in_tied_task;
  1762. if (do_wake > new_tasks)
  1763. do_wake = new_tasks;
  1764. }
  1765. }
  1766. }
  1767. }
  1768. /* Called when encountering a taskyield directive. */
  1769. void
  1770. GOMP_taskyield (void)
  1771. {
  1772. /* Nothing at the moment. */
  1773. }
  1774. static inline struct gomp_taskgroup *
  1775. gomp_taskgroup_init (struct gomp_taskgroup *prev)
  1776. {
  1777. struct gomp_taskgroup *taskgroup
  1778. = gomp_malloc (sizeof (struct gomp_taskgroup));
  1779. taskgroup->prev = prev;
  1780. priority_queue_init (&taskgroup->taskgroup_queue);
  1781. taskgroup->reductions = prev ? prev->reductions : NULL;
  1782. taskgroup->in_taskgroup_wait = false;
  1783. taskgroup->cancelled = false;
  1784. taskgroup->workshare = false;
  1785. taskgroup->num_children = 0;
  1786. gomp_sem_init (&taskgroup->taskgroup_sem, 0);
  1787. return taskgroup;
  1788. }
  1789. void
  1790. GOMP_taskgroup_start (void)
  1791. {
  1792. struct gomp_thread *thr = gomp_thread ();
  1793. struct gomp_team *team = thr->ts.team;
  1794. struct gomp_task *task = thr->task;
  1795. /* If team is NULL, all tasks are executed as
  1796. GOMP_TASK_UNDEFERRED tasks and thus all children tasks of
  1797. taskgroup and their descendant tasks will be finished
  1798. by the time GOMP_taskgroup_end is called. */
  1799. if (team == NULL)
  1800. return;
  1801. task->taskgroup = gomp_taskgroup_init (task->taskgroup);
  1802. }
  1803. void
  1804. GOMP_taskgroup_end (void)
  1805. {
  1806. struct gomp_thread *thr = gomp_thread ();
  1807. struct gomp_team *team = thr->ts.team;
  1808. struct gomp_task *task = thr->task;
  1809. struct gomp_taskgroup *taskgroup;
  1810. struct gomp_task *child_task = NULL;
  1811. struct gomp_task *to_free = NULL;
  1812. int do_wake = 0;
  1813. if (team == NULL)
  1814. return;
  1815. taskgroup = task->taskgroup;
  1816. if (__builtin_expect (taskgroup == NULL, 0)
  1817. && thr->ts.level == 0)
  1818. {
  1819. /* This can happen if GOMP_taskgroup_start is called when
  1820. thr->ts.team == NULL, but inside of the taskgroup there
  1821. is #pragma omp target nowait that creates an implicit
  1822. team with a single thread. In this case, we want to wait
  1823. for all outstanding tasks in this team. */
  1824. gomp_team_barrier_wait (&team->barrier);
  1825. return;
  1826. }
  1827. /* The acquire barrier on load of taskgroup->num_children here
  1828. synchronizes with the write of 0 in gomp_task_run_post_remove_taskgroup.
  1829. It is not necessary that we synchronize with other non-0 writes at
  1830. this point, but we must ensure that all writes to memory by a
  1831. child thread task work function are seen before we exit from
  1832. GOMP_taskgroup_end. */
  1833. if (__atomic_load_n (&taskgroup->num_children, MEMMODEL_ACQUIRE) == 0)
  1834. goto finish;
  1835. bool unused;
  1836. gomp_mutex_lock (&team->task_lock);
  1837. while (1)
  1838. {
  1839. bool cancelled = false;
  1840. if (priority_queue_empty_p (&taskgroup->taskgroup_queue,
  1841. MEMMODEL_RELAXED))
  1842. {
  1843. if (taskgroup->num_children)
  1844. {
  1845. if (priority_queue_empty_p (&task->children_queue,
  1846. MEMMODEL_RELAXED))
  1847. goto do_wait;
  1848. child_task
  1849. = priority_queue_next_task (PQ_CHILDREN, &task->children_queue,
  1850. PQ_TEAM, &team->task_queue,
  1851. &unused);
  1852. }
  1853. else
  1854. {
  1855. gomp_mutex_unlock (&team->task_lock);
  1856. if (to_free)
  1857. {
  1858. gomp_finish_task (to_free);
  1859. free (to_free);
  1860. }
  1861. goto finish;
  1862. }
  1863. }
  1864. else
  1865. child_task
  1866. = priority_queue_next_task (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
  1867. PQ_TEAM, &team->task_queue, &unused);
  1868. if (child_task->kind == GOMP_TASK_WAITING)
  1869. {
  1870. cancelled
  1871. = gomp_task_run_pre (child_task, child_task->parent, team);
  1872. if (__builtin_expect (cancelled, 0))
  1873. {
  1874. if (to_free)
  1875. {
  1876. gomp_finish_task (to_free);
  1877. free (to_free);
  1878. to_free = NULL;
  1879. }
  1880. goto finish_cancelled;
  1881. }
  1882. }
  1883. else
  1884. {
  1885. child_task = NULL;
  1886. do_wait:
  1887. /* All tasks we are waiting for are either running in other
  1888. threads, or they are tasks that have not had their
  1889. dependencies met (so they're not even in the queue). Wait
  1890. for them. */
  1891. taskgroup->in_taskgroup_wait = true;
  1892. }
  1893. gomp_mutex_unlock (&team->task_lock);
  1894. if (do_wake)
  1895. {
  1896. gomp_team_barrier_wake (&team->barrier, do_wake);
  1897. do_wake = 0;
  1898. }
  1899. if (to_free)
  1900. {
  1901. gomp_finish_task (to_free);
  1902. free (to_free);
  1903. to_free = NULL;
  1904. }
  1905. if (child_task)
  1906. {
  1907. thr->task = child_task;
  1908. if (__builtin_expect (child_task->fn == NULL, 0))
  1909. {
  1910. if (gomp_target_task_fn (child_task->fn_data))
  1911. {
  1912. thr->task = task;
  1913. gomp_mutex_lock (&team->task_lock);
  1914. child_task->kind = GOMP_TASK_ASYNC_RUNNING;
  1915. struct gomp_target_task *ttask
  1916. = (struct gomp_target_task *) child_task->fn_data;
  1917. /* If GOMP_PLUGIN_target_task_completion has run already
  1918. in between gomp_target_task_fn and the mutex lock,
  1919. perform the requeuing here. */
  1920. if (ttask->state == GOMP_TARGET_TASK_FINISHED)
  1921. gomp_target_task_completion (team, child_task);
  1922. else
  1923. ttask->state = GOMP_TARGET_TASK_RUNNING;
  1924. child_task = NULL;
  1925. continue;
  1926. }
  1927. }
  1928. else
  1929. child_task->fn (child_task->fn_data);
  1930. thr->task = task;
  1931. }
  1932. else
  1933. gomp_sem_wait (&taskgroup->taskgroup_sem);
  1934. gomp_mutex_lock (&team->task_lock);
  1935. if (child_task)
  1936. {
  1937. if (child_task->detach_team)
  1938. {
  1939. assert (child_task->detach_team == team);
  1940. child_task->kind = GOMP_TASK_DETACHED;
  1941. ++team->task_detach_count;
  1942. gomp_debug (0,
  1943. "thread %d: task with event %p finished without "
  1944. "completion event fulfilled in taskgroup\n",
  1945. thr->ts.team_id, child_task);
  1946. child_task = NULL;
  1947. continue;
  1948. }
  1949. finish_cancelled:;
  1950. size_t new_tasks
  1951. = gomp_task_run_post_handle_depend (child_task, team);
  1952. gomp_task_run_post_remove_parent (child_task);
  1953. gomp_clear_parent (&child_task->children_queue);
  1954. gomp_task_run_post_remove_taskgroup (child_task);
  1955. to_free = child_task;
  1956. child_task = NULL;
  1957. team->task_count--;
  1958. if (new_tasks > 1)
  1959. {
  1960. do_wake = team->nthreads - team->task_running_count
  1961. - !task->in_tied_task;
  1962. if (do_wake > new_tasks)
  1963. do_wake = new_tasks;
  1964. }
  1965. }
  1966. }
  1967. finish:
  1968. task->taskgroup = taskgroup->prev;
  1969. gomp_sem_destroy (&taskgroup->taskgroup_sem);
  1970. free (taskgroup);
  1971. }
  1972. static inline __attribute__((always_inline)) void
  1973. gomp_reduction_register (uintptr_t *data, uintptr_t *old, uintptr_t *orig,
  1974. unsigned nthreads)
  1975. {
  1976. size_t total_cnt = 0;
  1977. uintptr_t *d = data;
  1978. struct htab *old_htab = NULL, *new_htab;
  1979. do
  1980. {
  1981. if (__builtin_expect (orig != NULL, 0))
  1982. {
  1983. /* For worksharing task reductions, memory has been allocated
  1984. already by some other thread that encountered the construct
  1985. earlier. */
  1986. d[2] = orig[2];
  1987. d[6] = orig[6];
  1988. orig = (uintptr_t *) orig[4];
  1989. }
  1990. else
  1991. {
  1992. size_t sz = d[1] * nthreads;
  1993. /* Should use omp_alloc if d[3] is not -1. */
  1994. void *ptr = gomp_aligned_alloc (d[2], sz);
  1995. memset (ptr, '\0', sz);
  1996. d[2] = (uintptr_t) ptr;
  1997. d[6] = d[2] + sz;
  1998. }
  1999. d[5] = 0;
  2000. total_cnt += d[0];
  2001. if (d[4] == 0)
  2002. {
  2003. d[4] = (uintptr_t) old;
  2004. break;
  2005. }
  2006. else
  2007. d = (uintptr_t *) d[4];
  2008. }
  2009. while (1);
  2010. if (old && old[5])
  2011. {
  2012. old_htab = (struct htab *) old[5];
  2013. total_cnt += htab_elements (old_htab);
  2014. }
  2015. new_htab = htab_create (total_cnt);
  2016. if (old_htab)
  2017. {
  2018. /* Copy old hash table, like in htab_expand. */
  2019. hash_entry_type *p, *olimit;
  2020. new_htab->n_elements = htab_elements (old_htab);
  2021. olimit = old_htab->entries + old_htab->size;
  2022. p = old_htab->entries;
  2023. do
  2024. {
  2025. hash_entry_type x = *p;
  2026. if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
  2027. *find_empty_slot_for_expand (new_htab, htab_hash (x)) = x;
  2028. p++;
  2029. }
  2030. while (p < olimit);
  2031. }
  2032. d = data;
  2033. do
  2034. {
  2035. size_t j;
  2036. for (j = 0; j < d[0]; ++j)
  2037. {
  2038. uintptr_t *p = d + 7 + j * 3;
  2039. p[2] = (uintptr_t) d;
  2040. /* Ugly hack, hash_entry_type is defined for the task dependencies,
  2041. which hash on the first element which is a pointer. We need
  2042. to hash also on the first sizeof (uintptr_t) bytes which contain
  2043. a pointer. Hide the cast from the compiler. */
  2044. hash_entry_type n;
  2045. __asm ("" : "=g" (n) : "0" (p));
  2046. *htab_find_slot (&new_htab, n, INSERT) = n;
  2047. }
  2048. if (d[4] == (uintptr_t) old)
  2049. break;
  2050. else
  2051. d = (uintptr_t *) d[4];
  2052. }
  2053. while (1);
  2054. d[5] = (uintptr_t) new_htab;
  2055. }
  2056. static void
  2057. gomp_create_artificial_team (void)
  2058. {
  2059. struct gomp_thread *thr = gomp_thread ();
  2060. struct gomp_task_icv *icv;
  2061. struct gomp_team *team = gomp_new_team (1);
  2062. struct gomp_task *task = thr->task;
  2063. icv = task ? &task->icv : &gomp_global_icv;
  2064. team->prev_ts = thr->ts;
  2065. thr->ts.team = team;
  2066. thr->ts.team_id = 0;
  2067. thr->ts.work_share = &team->work_shares[0];
  2068. thr->ts.last_work_share = NULL;
  2069. #ifdef HAVE_SYNC_BUILTINS
  2070. thr->ts.single_count = 0;
  2071. #endif
  2072. thr->ts.static_trip = 0;
  2073. thr->task = &team->implicit_task[0];
  2074. gomp_init_task (thr->task, NULL, icv);
  2075. if (task)
  2076. {
  2077. thr->task = task;
  2078. gomp_end_task ();
  2079. free (task);
  2080. thr->task = &team->implicit_task[0];
  2081. }
  2082. #ifdef LIBGOMP_USE_PTHREADS
  2083. else
  2084. pthread_setspecific (gomp_thread_destructor, thr);
  2085. #endif
  2086. }
  2087. /* The format of data is:
  2088. data[0] cnt
  2089. data[1] size
  2090. data[2] alignment (on output array pointer)
  2091. data[3] allocator (-1 if malloc allocator)
  2092. data[4] next pointer
  2093. data[5] used internally (htab pointer)
  2094. data[6] used internally (end of array)
  2095. cnt times
  2096. ent[0] address
  2097. ent[1] offset
  2098. ent[2] used internally (pointer to data[0])
  2099. The entries are sorted by increasing offset, so that a binary
  2100. search can be performed. Normally, data[8] is 0, exception is
  2101. for worksharing construct task reductions in cancellable parallel,
  2102. where at offset 0 there should be space for a pointer and an integer
  2103. which are used internally. */
  2104. void
  2105. GOMP_taskgroup_reduction_register (uintptr_t *data)
  2106. {
  2107. struct gomp_thread *thr = gomp_thread ();
  2108. struct gomp_team *team = thr->ts.team;
  2109. struct gomp_task *task;
  2110. unsigned nthreads;
  2111. if (__builtin_expect (team == NULL, 0))
  2112. {
  2113. /* The task reduction code needs a team and task, so for
  2114. orphaned taskgroups just create the implicit team. */
  2115. gomp_create_artificial_team ();
  2116. ialias_call (GOMP_taskgroup_start) ();
  2117. team = thr->ts.team;
  2118. }
  2119. nthreads = team->nthreads;
  2120. task = thr->task;
  2121. gomp_reduction_register (data, task->taskgroup->reductions, NULL, nthreads);
  2122. task->taskgroup->reductions = data;
  2123. }
  2124. void
  2125. GOMP_taskgroup_reduction_unregister (uintptr_t *data)
  2126. {
  2127. uintptr_t *d = data;
  2128. htab_free ((struct htab *) data[5]);
  2129. do
  2130. {
  2131. gomp_aligned_free ((void *) d[2]);
  2132. d = (uintptr_t *) d[4];
  2133. }
  2134. while (d && !d[5]);
  2135. }
  2136. ialias (GOMP_taskgroup_reduction_unregister)
  2137. /* For i = 0 to cnt-1, remap ptrs[i] which is either address of the
  2138. original list item or address of previously remapped original list
  2139. item to address of the private copy, store that to ptrs[i].
  2140. For i < cntorig, additionally set ptrs[cnt+i] to the address of
  2141. the original list item. */
  2142. void
  2143. GOMP_task_reduction_remap (size_t cnt, size_t cntorig, void **ptrs)
  2144. {
  2145. struct gomp_thread *thr = gomp_thread ();
  2146. struct gomp_task *task = thr->task;
  2147. unsigned id = thr->ts.team_id;
  2148. uintptr_t *data = task->taskgroup->reductions;
  2149. uintptr_t *d;
  2150. struct htab *reduction_htab = (struct htab *) data[5];
  2151. size_t i;
  2152. for (i = 0; i < cnt; ++i)
  2153. {
  2154. hash_entry_type ent, n;
  2155. __asm ("" : "=g" (ent) : "0" (ptrs + i));
  2156. n = htab_find (reduction_htab, ent);
  2157. if (n)
  2158. {
  2159. uintptr_t *p;
  2160. __asm ("" : "=g" (p) : "0" (n));
  2161. /* At this point, p[0] should be equal to (uintptr_t) ptrs[i],
  2162. p[1] is the offset within the allocated chunk for each
  2163. thread, p[2] is the array registered with
  2164. GOMP_taskgroup_reduction_register, d[2] is the base of the
  2165. allocated memory and d[1] is the size of the allocated chunk
  2166. for one thread. */
  2167. d = (uintptr_t *) p[2];
  2168. ptrs[i] = (void *) (d[2] + id * d[1] + p[1]);
  2169. if (__builtin_expect (i < cntorig, 0))
  2170. ptrs[cnt + i] = (void *) p[0];
  2171. continue;
  2172. }
  2173. d = data;
  2174. while (d != NULL)
  2175. {
  2176. if ((uintptr_t) ptrs[i] >= d[2] && (uintptr_t) ptrs[i] < d[6])
  2177. break;
  2178. d = (uintptr_t *) d[4];
  2179. }
  2180. if (d == NULL)
  2181. gomp_fatal ("couldn't find matching task_reduction or reduction with "
  2182. "task modifier for %p", ptrs[i]);
  2183. uintptr_t off = ((uintptr_t) ptrs[i] - d[2]) % d[1];
  2184. ptrs[i] = (void *) (d[2] + id * d[1] + off);
  2185. if (__builtin_expect (i < cntorig, 0))
  2186. {
  2187. size_t lo = 0, hi = d[0] - 1;
  2188. while (lo <= hi)
  2189. {
  2190. size_t m = (lo + hi) / 2;
  2191. if (d[7 + 3 * m + 1] < off)
  2192. lo = m + 1;
  2193. else if (d[7 + 3 * m + 1] == off)
  2194. {
  2195. ptrs[cnt + i] = (void *) d[7 + 3 * m];
  2196. break;
  2197. }
  2198. else
  2199. hi = m - 1;
  2200. }
  2201. if (lo > hi)
  2202. gomp_fatal ("couldn't find matching task_reduction or reduction "
  2203. "with task modifier for %p", ptrs[i]);
  2204. }
  2205. }
  2206. }
  2207. struct gomp_taskgroup *
  2208. gomp_parallel_reduction_register (uintptr_t *data, unsigned nthreads)
  2209. {
  2210. struct gomp_taskgroup *taskgroup = gomp_taskgroup_init (NULL);
  2211. gomp_reduction_register (data, NULL, NULL, nthreads);
  2212. taskgroup->reductions = data;
  2213. return taskgroup;
  2214. }
  2215. void
  2216. gomp_workshare_task_reduction_register (uintptr_t *data, uintptr_t *orig)
  2217. {
  2218. struct gomp_thread *thr = gomp_thread ();
  2219. struct gomp_team *team = thr->ts.team;
  2220. struct gomp_task *task = thr->task;
  2221. unsigned nthreads = team->nthreads;
  2222. gomp_reduction_register (data, task->taskgroup->reductions, orig, nthreads);
  2223. task->taskgroup->reductions = data;
  2224. }
  2225. void
  2226. gomp_workshare_taskgroup_start (void)
  2227. {
  2228. struct gomp_thread *thr = gomp_thread ();
  2229. struct gomp_team *team = thr->ts.team;
  2230. struct gomp_task *task;
  2231. if (team == NULL)
  2232. {
  2233. gomp_create_artificial_team ();
  2234. team = thr->ts.team;
  2235. }
  2236. task = thr->task;
  2237. task->taskgroup = gomp_taskgroup_init (task->taskgroup);
  2238. task->taskgroup->workshare = true;
  2239. }
  2240. void
  2241. GOMP_workshare_task_reduction_unregister (bool cancelled)
  2242. {
  2243. struct gomp_thread *thr = gomp_thread ();
  2244. struct gomp_task *task = thr->task;
  2245. struct gomp_team *team = thr->ts.team;
  2246. uintptr_t *data = task->taskgroup->reductions;
  2247. ialias_call (GOMP_taskgroup_end) ();
  2248. if (thr->ts.team_id == 0)
  2249. ialias_call (GOMP_taskgroup_reduction_unregister) (data);
  2250. else
  2251. htab_free ((struct htab *) data[5]);
  2252. if (!cancelled)
  2253. gomp_team_barrier_wait (&team->barrier);
  2254. }
  2255. int
  2256. omp_in_final (void)
  2257. {
  2258. struct gomp_thread *thr = gomp_thread ();
  2259. return thr->task && thr->task->final_task;
  2260. }
  2261. ialias (omp_in_final)
  2262. void
  2263. omp_fulfill_event (omp_event_handle_t event)
  2264. {
  2265. struct gomp_task *task = (struct gomp_task *) event;
  2266. if (!task->deferred_p)
  2267. {
  2268. if (gomp_sem_getcount (task->completion_sem) > 0)
  2269. gomp_fatal ("omp_fulfill_event: %p event already fulfilled!\n", task);
  2270. gomp_debug (0, "omp_fulfill_event: %p event for undeferred task\n",
  2271. task);
  2272. gomp_sem_post (task->completion_sem);
  2273. return;
  2274. }
  2275. struct gomp_team *team = __atomic_load_n (&task->detach_team,
  2276. MEMMODEL_RELAXED);
  2277. if (!team)
  2278. gomp_fatal ("omp_fulfill_event: %p event is invalid or has already "
  2279. "been fulfilled!\n", task);
  2280. gomp_mutex_lock (&team->task_lock);
  2281. if (task->kind != GOMP_TASK_DETACHED)
  2282. {
  2283. /* The task has not finished running yet. */
  2284. gomp_debug (0,
  2285. "omp_fulfill_event: %p event fulfilled for unfinished "
  2286. "task\n", task);
  2287. __atomic_store_n (&task->detach_team, NULL, MEMMODEL_RELAXED);
  2288. gomp_mutex_unlock (&team->task_lock);
  2289. return;
  2290. }
  2291. gomp_debug (0, "omp_fulfill_event: %p event fulfilled for finished task\n",
  2292. task);
  2293. size_t new_tasks = gomp_task_run_post_handle_depend (task, team);
  2294. gomp_task_run_post_remove_parent (task);
  2295. gomp_clear_parent (&task->children_queue);
  2296. gomp_task_run_post_remove_taskgroup (task);
  2297. team->task_count--;
  2298. team->task_detach_count--;
  2299. int do_wake = 0;
  2300. bool shackled_thread_p = team == gomp_thread ()->ts.team;
  2301. if (new_tasks > 0)
  2302. {
  2303. /* Wake up threads to run new tasks. */
  2304. gomp_team_barrier_set_task_pending (&team->barrier);
  2305. do_wake = team->nthreads - team->task_running_count;
  2306. if (do_wake > new_tasks)
  2307. do_wake = new_tasks;
  2308. }
  2309. if (!shackled_thread_p
  2310. && !do_wake
  2311. && team->task_detach_count == 0
  2312. && gomp_team_barrier_waiting_for_tasks (&team->barrier))
  2313. /* Ensure that at least one thread is woken up to signal that the
  2314. barrier can finish. */
  2315. do_wake = 1;
  2316. /* If we are running in an unshackled thread, the team might vanish before
  2317. gomp_team_barrier_wake is run if we release the lock first, so keep the
  2318. lock for the call in that case. */
  2319. if (shackled_thread_p)
  2320. gomp_mutex_unlock (&team->task_lock);
  2321. if (do_wake)
  2322. gomp_team_barrier_wake (&team->barrier, do_wake);
  2323. if (!shackled_thread_p)
  2324. gomp_mutex_unlock (&team->task_lock);
  2325. gomp_finish_task (task);
  2326. free (task);
  2327. }
  2328. ialias (omp_fulfill_event)