Clean up some minor white space issues in trans-decl.c and trans-expr.c
[official-gcc.git] / libgomp / task.c
blobb18b6e26b7d60c9fb121f21f27ffbcd6c52ef61a
1 /* Copyright (C) 2007-2016 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
5 (libgomp).
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* This file handles the maintainence of tasks in response to task
27 creation and termination. */
29 #include "libgomp.h"
30 #include <stdlib.h>
31 #include <string.h>
32 #include "gomp-constants.h"
34 typedef struct gomp_task_depend_entry *hash_entry_type;
36 static inline void *
37 htab_alloc (size_t size)
39 return gomp_malloc (size);
42 static inline void
43 htab_free (void *ptr)
45 free (ptr);
48 #include "hashtab.h"
50 static inline hashval_t
51 htab_hash (hash_entry_type element)
53 return hash_pointer (element->addr);
56 static inline bool
57 htab_eq (hash_entry_type x, hash_entry_type y)
59 return x->addr == y->addr;
62 /* Create a new task data structure. */
64 void
65 gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
66 struct gomp_task_icv *prev_icv)
68 /* It would seem that using memset here would be a win, but it turns
69 out that partially filling gomp_task allows us to keep the
70 overhead of task creation low. In the nqueens-1.c test, for a
71 sufficiently large N, we drop the overhead from 5-6% to 1%.
73 Note, the nqueens-1.c test in serial mode is a good test to
74 benchmark the overhead of creating tasks as there are millions of
75 tiny tasks created that all run undeferred. */
76 task->parent = parent_task;
77 task->icv = *prev_icv;
78 task->kind = GOMP_TASK_IMPLICIT;
79 task->taskwait = NULL;
80 task->in_tied_task = false;
81 task->final_task = false;
82 task->copy_ctors_done = false;
83 task->parent_depends_on = false;
84 priority_queue_init (&task->children_queue);
85 task->taskgroup = NULL;
86 task->dependers = NULL;
87 task->depend_hash = NULL;
88 task->depend_count = 0;
91 /* Clean up a task, after completing it. */
93 void
94 gomp_end_task (void)
96 struct gomp_thread *thr = gomp_thread ();
97 struct gomp_task *task = thr->task;
99 gomp_finish_task (task);
100 thr->task = task->parent;
103 /* Clear the parent field of every task in LIST. */
105 static inline void
106 gomp_clear_parent_in_list (struct priority_list *list)
108 struct priority_node *p = list->tasks;
109 if (p)
112 priority_node_to_task (PQ_CHILDREN, p)->parent = NULL;
113 p = p->next;
115 while (p != list->tasks);
118 /* Splay tree version of gomp_clear_parent_in_list.
120 Clear the parent field of every task in NODE within SP, and free
121 the node when done. */
123 static void
124 gomp_clear_parent_in_tree (prio_splay_tree sp, prio_splay_tree_node node)
126 if (!node)
127 return;
128 prio_splay_tree_node left = node->left, right = node->right;
129 gomp_clear_parent_in_list (&node->key.l);
130 #if _LIBGOMP_CHECKING_
131 memset (node, 0xaf, sizeof (*node));
132 #endif
133 /* No need to remove the node from the tree. We're nuking
134 everything, so just free the nodes and our caller can clear the
135 entire splay tree. */
136 free (node);
137 gomp_clear_parent_in_tree (sp, left);
138 gomp_clear_parent_in_tree (sp, right);
141 /* Clear the parent field of every task in Q and remove every task
142 from Q. */
144 static inline void
145 gomp_clear_parent (struct priority_queue *q)
147 if (priority_queue_multi_p (q))
149 gomp_clear_parent_in_tree (&q->t, q->t.root);
150 /* All the nodes have been cleared in gomp_clear_parent_in_tree.
151 No need to remove anything. We can just nuke everything. */
152 q->t.root = NULL;
154 else
155 gomp_clear_parent_in_list (&q->l);
158 /* Helper function for GOMP_task and gomp_create_target_task.
160 For a TASK with in/out dependencies, fill in the various dependency
161 queues. PARENT is the parent of said task. DEPEND is as in
162 GOMP_task. */
164 static void
165 gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
166 void **depend)
168 size_t ndepend = (uintptr_t) depend[0];
169 size_t nout = (uintptr_t) depend[1];
170 size_t i;
171 hash_entry_type ent;
173 task->depend_count = ndepend;
174 task->num_dependees = 0;
175 if (parent->depend_hash == NULL)
176 parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
177 for (i = 0; i < ndepend; i++)
179 task->depend[i].addr = depend[2 + i];
180 task->depend[i].next = NULL;
181 task->depend[i].prev = NULL;
182 task->depend[i].task = task;
183 task->depend[i].is_in = i >= nout;
184 task->depend[i].redundant = false;
185 task->depend[i].redundant_out = false;
187 hash_entry_type *slot = htab_find_slot (&parent->depend_hash,
188 &task->depend[i], INSERT);
189 hash_entry_type out = NULL, last = NULL;
190 if (*slot)
192 /* If multiple depends on the same task are the same, all but the
193 first one are redundant. As inout/out come first, if any of them
194 is inout/out, it will win, which is the right semantics. */
195 if ((*slot)->task == task)
197 task->depend[i].redundant = true;
198 continue;
200 for (ent = *slot; ent; ent = ent->next)
202 if (ent->redundant_out)
203 break;
205 last = ent;
207 /* depend(in:...) doesn't depend on earlier depend(in:...). */
208 if (i >= nout && ent->is_in)
209 continue;
211 if (!ent->is_in)
212 out = ent;
214 struct gomp_task *tsk = ent->task;
215 if (tsk->dependers == NULL)
217 tsk->dependers
218 = gomp_malloc (sizeof (struct gomp_dependers_vec)
219 + 6 * sizeof (struct gomp_task *));
220 tsk->dependers->n_elem = 1;
221 tsk->dependers->allocated = 6;
222 tsk->dependers->elem[0] = task;
223 task->num_dependees++;
224 continue;
226 /* We already have some other dependency on tsk from earlier
227 depend clause. */
228 else if (tsk->dependers->n_elem
229 && (tsk->dependers->elem[tsk->dependers->n_elem - 1]
230 == task))
231 continue;
232 else if (tsk->dependers->n_elem == tsk->dependers->allocated)
234 tsk->dependers->allocated
235 = tsk->dependers->allocated * 2 + 2;
236 tsk->dependers
237 = gomp_realloc (tsk->dependers,
238 sizeof (struct gomp_dependers_vec)
239 + (tsk->dependers->allocated
240 * sizeof (struct gomp_task *)));
242 tsk->dependers->elem[tsk->dependers->n_elem++] = task;
243 task->num_dependees++;
245 task->depend[i].next = *slot;
246 (*slot)->prev = &task->depend[i];
248 *slot = &task->depend[i];
250 /* There is no need to store more than one depend({,in}out:) task per
251 address in the hash table chain for the purpose of creation of
252 deferred tasks, because each out depends on all earlier outs, thus it
253 is enough to record just the last depend({,in}out:). For depend(in:),
254 we need to keep all of the previous ones not terminated yet, because
255 a later depend({,in}out:) might need to depend on all of them. So, if
256 the new task's clause is depend({,in}out:), we know there is at most
257 one other depend({,in}out:) clause in the list (out). For
258 non-deferred tasks we want to see all outs, so they are moved to the
259 end of the chain, after first redundant_out entry all following
260 entries should be redundant_out. */
261 if (!task->depend[i].is_in && out)
263 if (out != last)
265 out->next->prev = out->prev;
266 out->prev->next = out->next;
267 out->next = last->next;
268 out->prev = last;
269 last->next = out;
270 if (out->next)
271 out->next->prev = out;
273 out->redundant_out = true;
278 /* Called when encountering an explicit task directive. If IF_CLAUSE is
279 false, then we must not delay in executing the task. If UNTIED is true,
280 then the task may be executed by any member of the team.
282 DEPEND is an array containing:
283 depend[0]: number of depend elements.
284 depend[1]: number of depend elements of type "out".
285 depend[2..N+1]: address of [1..N]th depend element. */
287 void
288 GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
289 long arg_size, long arg_align, bool if_clause, unsigned flags,
290 void **depend, int priority)
292 struct gomp_thread *thr = gomp_thread ();
293 struct gomp_team *team = thr->ts.team;
295 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
296 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
297 tied to one thread all the time. This means UNTIED tasks must be
298 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
299 might be running on different thread than FN. */
300 if (cpyfn)
301 if_clause = false;
302 flags &= ~GOMP_TASK_FLAG_UNTIED;
303 #endif
305 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
306 if (team
307 && (gomp_team_barrier_cancelled (&team->barrier)
308 || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
309 return;
311 if ((flags & GOMP_TASK_FLAG_PRIORITY) == 0)
312 priority = 0;
313 else if (priority > gomp_max_task_priority_var)
314 priority = gomp_max_task_priority_var;
316 if (!if_clause || team == NULL
317 || (thr->task && thr->task->final_task)
318 || team->task_count > 64 * team->nthreads)
320 struct gomp_task task;
322 /* If there are depend clauses and earlier deferred sibling tasks
323 with depend clauses, check if there isn't a dependency. If there
324 is, we need to wait for them. There is no need to handle
325 depend clauses for non-deferred tasks other than this, because
326 the parent task is suspended until the child task finishes and thus
327 it can't start further child tasks. */
328 if ((flags & GOMP_TASK_FLAG_DEPEND)
329 && thr->task && thr->task->depend_hash)
330 gomp_task_maybe_wait_for_dependencies (depend);
332 gomp_init_task (&task, thr->task, gomp_icv (false));
333 task.kind = GOMP_TASK_UNDEFERRED;
334 task.final_task = (thr->task && thr->task->final_task)
335 || (flags & GOMP_TASK_FLAG_FINAL);
336 task.priority = priority;
337 if (thr->task)
339 task.in_tied_task = thr->task->in_tied_task;
340 task.taskgroup = thr->task->taskgroup;
342 thr->task = &task;
343 if (__builtin_expect (cpyfn != NULL, 0))
345 char buf[arg_size + arg_align - 1];
346 char *arg = (char *) (((uintptr_t) buf + arg_align - 1)
347 & ~(uintptr_t) (arg_align - 1));
348 cpyfn (arg, data);
349 fn (arg);
351 else
352 fn (data);
353 /* Access to "children" is normally done inside a task_lock
354 mutex region, but the only way this particular task.children
355 can be set is if this thread's task work function (fn)
356 creates children. So since the setter is *this* thread, we
357 need no barriers here when testing for non-NULL. We can have
358 task.children set by the current thread then changed by a
359 child thread, but seeing a stale non-NULL value is not a
360 problem. Once past the task_lock acquisition, this thread
361 will see the real value of task.children. */
362 if (!priority_queue_empty_p (&task.children_queue, MEMMODEL_RELAXED))
364 gomp_mutex_lock (&team->task_lock);
365 gomp_clear_parent (&task.children_queue);
366 gomp_mutex_unlock (&team->task_lock);
368 gomp_end_task ();
370 else
372 struct gomp_task *task;
373 struct gomp_task *parent = thr->task;
374 struct gomp_taskgroup *taskgroup = parent->taskgroup;
375 char *arg;
376 bool do_wake;
377 size_t depend_size = 0;
379 if (flags & GOMP_TASK_FLAG_DEPEND)
380 depend_size = ((uintptr_t) depend[0]
381 * sizeof (struct gomp_task_depend_entry));
382 task = gomp_malloc (sizeof (*task) + depend_size
383 + arg_size + arg_align - 1);
384 arg = (char *) (((uintptr_t) (task + 1) + depend_size + arg_align - 1)
385 & ~(uintptr_t) (arg_align - 1));
386 gomp_init_task (task, parent, gomp_icv (false));
387 task->priority = priority;
388 task->kind = GOMP_TASK_UNDEFERRED;
389 task->in_tied_task = parent->in_tied_task;
390 task->taskgroup = taskgroup;
391 thr->task = task;
392 if (cpyfn)
394 cpyfn (arg, data);
395 task->copy_ctors_done = true;
397 else
398 memcpy (arg, data, arg_size);
399 thr->task = parent;
400 task->kind = GOMP_TASK_WAITING;
401 task->fn = fn;
402 task->fn_data = arg;
403 task->final_task = (flags & GOMP_TASK_FLAG_FINAL) >> 1;
404 gomp_mutex_lock (&team->task_lock);
405 /* If parallel or taskgroup has been cancelled, don't start new
406 tasks. */
407 if (__builtin_expect ((gomp_team_barrier_cancelled (&team->barrier)
408 || (taskgroup && taskgroup->cancelled))
409 && !task->copy_ctors_done, 0))
411 gomp_mutex_unlock (&team->task_lock);
412 gomp_finish_task (task);
413 free (task);
414 return;
416 if (taskgroup)
417 taskgroup->num_children++;
418 if (depend_size)
420 gomp_task_handle_depend (task, parent, depend);
421 if (task->num_dependees)
423 /* Tasks that depend on other tasks are not put into the
424 various waiting queues, so we are done for now. Said
425 tasks are instead put into the queues via
426 gomp_task_run_post_handle_dependers() after their
427 dependencies have been satisfied. After which, they
428 can be picked up by the various scheduling
429 points. */
430 gomp_mutex_unlock (&team->task_lock);
431 return;
435 priority_queue_insert (PQ_CHILDREN, &parent->children_queue,
436 task, priority,
437 PRIORITY_INSERT_BEGIN,
438 /*adjust_parent_depends_on=*/false,
439 task->parent_depends_on);
440 if (taskgroup)
441 priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
442 task, priority,
443 PRIORITY_INSERT_BEGIN,
444 /*adjust_parent_depends_on=*/false,
445 task->parent_depends_on);
447 priority_queue_insert (PQ_TEAM, &team->task_queue,
448 task, priority,
449 PRIORITY_INSERT_END,
450 /*adjust_parent_depends_on=*/false,
451 task->parent_depends_on);
453 ++team->task_count;
454 ++team->task_queued_count;
455 gomp_team_barrier_set_task_pending (&team->barrier);
456 do_wake = team->task_running_count + !parent->in_tied_task
457 < team->nthreads;
458 gomp_mutex_unlock (&team->task_lock);
459 if (do_wake)
460 gomp_team_barrier_wake (&team->barrier, 1);
464 ialias (GOMP_taskgroup_start)
465 ialias (GOMP_taskgroup_end)
467 #define TYPE long
468 #define UTYPE unsigned long
469 #define TYPE_is_long 1
470 #include "taskloop.c"
471 #undef TYPE
472 #undef UTYPE
473 #undef TYPE_is_long
475 #define TYPE unsigned long long
476 #define UTYPE TYPE
477 #define GOMP_taskloop GOMP_taskloop_ull
478 #include "taskloop.c"
479 #undef TYPE
480 #undef UTYPE
481 #undef GOMP_taskloop
483 static void inline
484 priority_queue_move_task_first (enum priority_queue_type type,
485 struct priority_queue *head,
486 struct gomp_task *task)
488 #if _LIBGOMP_CHECKING_
489 if (!priority_queue_task_in_queue_p (type, head, task))
490 gomp_fatal ("Attempt to move first missing task %p", task);
491 #endif
492 struct priority_list *list;
493 if (priority_queue_multi_p (head))
495 list = priority_queue_lookup_priority (head, task->priority);
496 #if _LIBGOMP_CHECKING_
497 if (!list)
498 gomp_fatal ("Unable to find priority %d", task->priority);
499 #endif
501 else
502 list = &head->l;
503 priority_list_remove (list, task_to_priority_node (type, task), 0);
504 priority_list_insert (type, list, task, task->priority,
505 PRIORITY_INSERT_BEGIN, type == PQ_CHILDREN,
506 task->parent_depends_on);
509 /* Actual body of GOMP_PLUGIN_target_task_completion that is executed
510 with team->task_lock held, or is executed in the thread that called
511 gomp_target_task_fn if GOMP_PLUGIN_target_task_completion has been
512 run before it acquires team->task_lock. */
514 static void
515 gomp_target_task_completion (struct gomp_team *team, struct gomp_task *task)
517 struct gomp_task *parent = task->parent;
518 if (parent)
519 priority_queue_move_task_first (PQ_CHILDREN, &parent->children_queue,
520 task);
522 struct gomp_taskgroup *taskgroup = task->taskgroup;
523 if (taskgroup)
524 priority_queue_move_task_first (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
525 task);
527 priority_queue_insert (PQ_TEAM, &team->task_queue, task, task->priority,
528 PRIORITY_INSERT_BEGIN, false,
529 task->parent_depends_on);
530 task->kind = GOMP_TASK_WAITING;
531 if (parent && parent->taskwait)
533 if (parent->taskwait->in_taskwait)
535 /* One more task has had its dependencies met.
536 Inform any waiters. */
537 parent->taskwait->in_taskwait = false;
538 gomp_sem_post (&parent->taskwait->taskwait_sem);
540 else if (parent->taskwait->in_depend_wait)
542 /* One more task has had its dependencies met.
543 Inform any waiters. */
544 parent->taskwait->in_depend_wait = false;
545 gomp_sem_post (&parent->taskwait->taskwait_sem);
548 if (taskgroup && taskgroup->in_taskgroup_wait)
550 /* One more task has had its dependencies met.
551 Inform any waiters. */
552 taskgroup->in_taskgroup_wait = false;
553 gomp_sem_post (&taskgroup->taskgroup_sem);
556 ++team->task_queued_count;
557 gomp_team_barrier_set_task_pending (&team->barrier);
558 /* I'm afraid this can't be done after releasing team->task_lock,
559 as gomp_target_task_completion is run from unrelated thread and
560 therefore in between gomp_mutex_unlock and gomp_team_barrier_wake
561 the team could be gone already. */
562 if (team->nthreads > team->task_running_count)
563 gomp_team_barrier_wake (&team->barrier, 1);
566 /* Signal that a target task TTASK has completed the asynchronously
567 running phase and should be requeued as a task to handle the
568 variable unmapping. */
570 void
571 GOMP_PLUGIN_target_task_completion (void *data)
573 struct gomp_target_task *ttask = (struct gomp_target_task *) data;
574 struct gomp_task *task = ttask->task;
575 struct gomp_team *team = ttask->team;
577 gomp_mutex_lock (&team->task_lock);
578 if (ttask->state == GOMP_TARGET_TASK_READY_TO_RUN)
580 ttask->state = GOMP_TARGET_TASK_FINISHED;
581 gomp_mutex_unlock (&team->task_lock);
582 return;
584 ttask->state = GOMP_TARGET_TASK_FINISHED;
585 gomp_target_task_completion (team, task);
586 gomp_mutex_unlock (&team->task_lock);
589 static void gomp_task_run_post_handle_depend_hash (struct gomp_task *);
591 /* Called for nowait target tasks. */
593 bool
594 gomp_create_target_task (struct gomp_device_descr *devicep,
595 void (*fn) (void *), size_t mapnum, void **hostaddrs,
596 size_t *sizes, unsigned short *kinds,
597 unsigned int flags, void **depend,
598 enum gomp_target_task_state state)
600 struct gomp_thread *thr = gomp_thread ();
601 struct gomp_team *team = thr->ts.team;
603 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
604 if (team
605 && (gomp_team_barrier_cancelled (&team->barrier)
606 || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
607 return true;
609 struct gomp_target_task *ttask;
610 struct gomp_task *task;
611 struct gomp_task *parent = thr->task;
612 struct gomp_taskgroup *taskgroup = parent->taskgroup;
613 bool do_wake;
614 size_t depend_size = 0;
615 uintptr_t depend_cnt = 0;
616 size_t tgt_align = 0, tgt_size = 0;
618 if (depend != NULL)
620 depend_cnt = (uintptr_t) depend[0];
621 depend_size = depend_cnt * sizeof (struct gomp_task_depend_entry);
623 if (fn)
625 /* GOMP_MAP_FIRSTPRIVATE need to be copied first, as they are
626 firstprivate on the target task. */
627 size_t i;
628 for (i = 0; i < mapnum; i++)
629 if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
631 size_t align = (size_t) 1 << (kinds[i] >> 8);
632 if (tgt_align < align)
633 tgt_align = align;
634 tgt_size = (tgt_size + align - 1) & ~(align - 1);
635 tgt_size += sizes[i];
637 if (tgt_align)
638 tgt_size += tgt_align - 1;
639 else
640 tgt_size = 0;
643 task = gomp_malloc (sizeof (*task) + depend_size
644 + sizeof (*ttask)
645 + mapnum * (sizeof (void *) + sizeof (size_t)
646 + sizeof (unsigned short))
647 + tgt_size);
648 gomp_init_task (task, parent, gomp_icv (false));
649 task->priority = 0;
650 task->kind = GOMP_TASK_WAITING;
651 task->in_tied_task = parent->in_tied_task;
652 task->taskgroup = taskgroup;
653 ttask = (struct gomp_target_task *) &task->depend[depend_cnt];
654 ttask->devicep = devicep;
655 ttask->fn = fn;
656 ttask->mapnum = mapnum;
657 memcpy (ttask->hostaddrs, hostaddrs, mapnum * sizeof (void *));
658 ttask->sizes = (size_t *) &ttask->hostaddrs[mapnum];
659 memcpy (ttask->sizes, sizes, mapnum * sizeof (size_t));
660 ttask->kinds = (unsigned short *) &ttask->sizes[mapnum];
661 memcpy (ttask->kinds, kinds, mapnum * sizeof (unsigned short));
662 if (tgt_align)
664 char *tgt = (char *) &ttask->kinds[mapnum];
665 size_t i;
666 uintptr_t al = (uintptr_t) tgt & (tgt_align - 1);
667 if (al)
668 tgt += tgt_align - al;
669 tgt_size = 0;
670 for (i = 0; i < mapnum; i++)
671 if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
673 size_t align = (size_t) 1 << (kinds[i] >> 8);
674 tgt_size = (tgt_size + align - 1) & ~(align - 1);
675 memcpy (tgt + tgt_size, hostaddrs[i], sizes[i]);
676 ttask->hostaddrs[i] = tgt + tgt_size;
677 tgt_size = tgt_size + sizes[i];
680 ttask->flags = flags;
681 ttask->state = state;
682 ttask->task = task;
683 ttask->team = team;
684 task->fn = NULL;
685 task->fn_data = ttask;
686 task->final_task = 0;
687 gomp_mutex_lock (&team->task_lock);
688 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
689 if (__builtin_expect (gomp_team_barrier_cancelled (&team->barrier)
690 || (taskgroup && taskgroup->cancelled), 0))
692 gomp_mutex_unlock (&team->task_lock);
693 gomp_finish_task (task);
694 free (task);
695 return true;
697 if (depend_size)
699 gomp_task_handle_depend (task, parent, depend);
700 if (task->num_dependees)
702 if (taskgroup)
703 taskgroup->num_children++;
704 gomp_mutex_unlock (&team->task_lock);
705 return true;
708 if (state == GOMP_TARGET_TASK_DATA)
710 gomp_task_run_post_handle_depend_hash (task);
711 gomp_mutex_unlock (&team->task_lock);
712 gomp_finish_task (task);
713 free (task);
714 return false;
716 if (taskgroup)
717 taskgroup->num_children++;
718 /* For async offloading, if we don't need to wait for dependencies,
719 run the gomp_target_task_fn right away, essentially schedule the
720 mapping part of the task in the current thread. */
721 if (devicep != NULL
722 && (devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
724 priority_queue_insert (PQ_CHILDREN, &parent->children_queue, task, 0,
725 PRIORITY_INSERT_END,
726 /*adjust_parent_depends_on=*/false,
727 task->parent_depends_on);
728 if (taskgroup)
729 priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
730 task, 0, PRIORITY_INSERT_END,
731 /*adjust_parent_depends_on=*/false,
732 task->parent_depends_on);
733 task->pnode[PQ_TEAM].next = NULL;
734 task->pnode[PQ_TEAM].prev = NULL;
735 task->kind = GOMP_TASK_TIED;
736 ++team->task_count;
737 gomp_mutex_unlock (&team->task_lock);
739 thr->task = task;
740 gomp_target_task_fn (task->fn_data);
741 thr->task = parent;
743 gomp_mutex_lock (&team->task_lock);
744 task->kind = GOMP_TASK_ASYNC_RUNNING;
745 /* If GOMP_PLUGIN_target_task_completion has run already
746 in between gomp_target_task_fn and the mutex lock,
747 perform the requeuing here. */
748 if (ttask->state == GOMP_TARGET_TASK_FINISHED)
749 gomp_target_task_completion (team, task);
750 else
751 ttask->state = GOMP_TARGET_TASK_RUNNING;
752 gomp_mutex_unlock (&team->task_lock);
753 return true;
755 priority_queue_insert (PQ_CHILDREN, &parent->children_queue, task, 0,
756 PRIORITY_INSERT_BEGIN,
757 /*adjust_parent_depends_on=*/false,
758 task->parent_depends_on);
759 if (taskgroup)
760 priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue, task, 0,
761 PRIORITY_INSERT_BEGIN,
762 /*adjust_parent_depends_on=*/false,
763 task->parent_depends_on);
764 priority_queue_insert (PQ_TEAM, &team->task_queue, task, 0,
765 PRIORITY_INSERT_END,
766 /*adjust_parent_depends_on=*/false,
767 task->parent_depends_on);
768 ++team->task_count;
769 ++team->task_queued_count;
770 gomp_team_barrier_set_task_pending (&team->barrier);
771 do_wake = team->task_running_count + !parent->in_tied_task
772 < team->nthreads;
773 gomp_mutex_unlock (&team->task_lock);
774 if (do_wake)
775 gomp_team_barrier_wake (&team->barrier, 1);
776 return true;
779 /* Given a parent_depends_on task in LIST, move it to the front of its
780 priority so it is run as soon as possible.
782 Care is taken to update the list's LAST_PARENT_DEPENDS_ON field.
784 We rearrange the queue such that all parent_depends_on tasks are
785 first, and last_parent_depends_on points to the last such task we
786 rearranged. For example, given the following tasks in a queue
787 where PD[123] are the parent_depends_on tasks:
789 task->children
792 C1 -> C2 -> C3 -> PD1 -> PD2 -> PD3 -> C4
794 We rearrange such that:
796 task->children
797 | +--- last_parent_depends_on
800 PD1 -> PD2 -> PD3 -> C1 -> C2 -> C3 -> C4. */
802 static void inline
803 priority_list_upgrade_task (struct priority_list *list,
804 struct priority_node *node)
806 struct priority_node *last_parent_depends_on
807 = list->last_parent_depends_on;
808 if (last_parent_depends_on)
810 node->prev->next = node->next;
811 node->next->prev = node->prev;
812 node->prev = last_parent_depends_on;
813 node->next = last_parent_depends_on->next;
814 node->prev->next = node;
815 node->next->prev = node;
817 else if (node != list->tasks)
819 node->prev->next = node->next;
820 node->next->prev = node->prev;
821 node->prev = list->tasks->prev;
822 node->next = list->tasks;
823 list->tasks = node;
824 node->prev->next = node;
825 node->next->prev = node;
827 list->last_parent_depends_on = node;
830 /* Given a parent_depends_on TASK in its parent's children_queue, move
831 it to the front of its priority so it is run as soon as possible.
833 PARENT is passed as an optimization.
835 (This function could be defined in priority_queue.c, but we want it
836 inlined, and putting it in priority_queue.h is not an option, given
837 that gomp_task has not been properly defined at that point). */
839 static void inline
840 priority_queue_upgrade_task (struct gomp_task *task,
841 struct gomp_task *parent)
843 struct priority_queue *head = &parent->children_queue;
844 struct priority_node *node = &task->pnode[PQ_CHILDREN];
845 #if _LIBGOMP_CHECKING_
846 if (!task->parent_depends_on)
847 gomp_fatal ("priority_queue_upgrade_task: task must be a "
848 "parent_depends_on task");
849 if (!priority_queue_task_in_queue_p (PQ_CHILDREN, head, task))
850 gomp_fatal ("priority_queue_upgrade_task: cannot find task=%p", task);
851 #endif
852 if (priority_queue_multi_p (head))
854 struct priority_list *list
855 = priority_queue_lookup_priority (head, task->priority);
856 priority_list_upgrade_task (list, node);
858 else
859 priority_list_upgrade_task (&head->l, node);
862 /* Given a CHILD_TASK in LIST that is about to be executed, move it out of
863 the way in LIST so that other tasks can be considered for
864 execution. LIST contains tasks of type TYPE.
866 Care is taken to update the queue's LAST_PARENT_DEPENDS_ON field
867 if applicable. */
869 static void inline
870 priority_list_downgrade_task (enum priority_queue_type type,
871 struct priority_list *list,
872 struct gomp_task *child_task)
874 struct priority_node *node = task_to_priority_node (type, child_task);
875 if (list->tasks == node)
876 list->tasks = node->next;
877 else if (node->next != list->tasks)
879 /* The task in NODE is about to become TIED and TIED tasks
880 cannot come before WAITING tasks. If we're about to
881 leave the queue in such an indeterminate state, rewire
882 things appropriately. However, a TIED task at the end is
883 perfectly fine. */
884 struct gomp_task *next_task = priority_node_to_task (type, node->next);
885 if (next_task->kind == GOMP_TASK_WAITING)
887 /* Remove from list. */
888 node->prev->next = node->next;
889 node->next->prev = node->prev;
890 /* Rewire at the end. */
891 node->next = list->tasks;
892 node->prev = list->tasks->prev;
893 list->tasks->prev->next = node;
894 list->tasks->prev = node;
898 /* If the current task is the last_parent_depends_on for its
899 priority, adjust last_parent_depends_on appropriately. */
900 if (__builtin_expect (child_task->parent_depends_on, 0)
901 && list->last_parent_depends_on == node)
903 struct gomp_task *prev_child = priority_node_to_task (type, node->prev);
904 if (node->prev != node
905 && prev_child->kind == GOMP_TASK_WAITING
906 && prev_child->parent_depends_on)
907 list->last_parent_depends_on = node->prev;
908 else
910 /* There are no more parent_depends_on entries waiting
911 to run, clear the list. */
912 list->last_parent_depends_on = NULL;
917 /* Given a TASK in HEAD that is about to be executed, move it out of
918 the way so that other tasks can be considered for execution. HEAD
919 contains tasks of type TYPE.
921 Care is taken to update the queue's LAST_PARENT_DEPENDS_ON field
922 if applicable.
924 (This function could be defined in priority_queue.c, but we want it
925 inlined, and putting it in priority_queue.h is not an option, given
926 that gomp_task has not been properly defined at that point). */
928 static void inline
929 priority_queue_downgrade_task (enum priority_queue_type type,
930 struct priority_queue *head,
931 struct gomp_task *task)
933 #if _LIBGOMP_CHECKING_
934 if (!priority_queue_task_in_queue_p (type, head, task))
935 gomp_fatal ("Attempt to downgrade missing task %p", task);
936 #endif
937 if (priority_queue_multi_p (head))
939 struct priority_list *list
940 = priority_queue_lookup_priority (head, task->priority);
941 priority_list_downgrade_task (type, list, task);
943 else
944 priority_list_downgrade_task (type, &head->l, task);
947 /* Setup CHILD_TASK to execute. This is done by setting the task to
948 TIED, and updating all relevant queues so that CHILD_TASK is no
949 longer chosen for scheduling. Also, remove CHILD_TASK from the
950 overall team task queue entirely.
952 Return TRUE if task or its containing taskgroup has been
953 cancelled. */
955 static inline bool
956 gomp_task_run_pre (struct gomp_task *child_task, struct gomp_task *parent,
957 struct gomp_team *team)
959 #if _LIBGOMP_CHECKING_
960 if (child_task->parent)
961 priority_queue_verify (PQ_CHILDREN,
962 &child_task->parent->children_queue, true);
963 if (child_task->taskgroup)
964 priority_queue_verify (PQ_TASKGROUP,
965 &child_task->taskgroup->taskgroup_queue, false);
966 priority_queue_verify (PQ_TEAM, &team->task_queue, false);
967 #endif
969 /* Task is about to go tied, move it out of the way. */
970 if (parent)
971 priority_queue_downgrade_task (PQ_CHILDREN, &parent->children_queue,
972 child_task);
974 /* Task is about to go tied, move it out of the way. */
975 struct gomp_taskgroup *taskgroup = child_task->taskgroup;
976 if (taskgroup)
977 priority_queue_downgrade_task (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
978 child_task);
980 priority_queue_remove (PQ_TEAM, &team->task_queue, child_task,
981 MEMMODEL_RELAXED);
982 child_task->pnode[PQ_TEAM].next = NULL;
983 child_task->pnode[PQ_TEAM].prev = NULL;
984 child_task->kind = GOMP_TASK_TIED;
986 if (--team->task_queued_count == 0)
987 gomp_team_barrier_clear_task_pending (&team->barrier);
988 if ((gomp_team_barrier_cancelled (&team->barrier)
989 || (taskgroup && taskgroup->cancelled))
990 && !child_task->copy_ctors_done)
991 return true;
992 return false;
995 static void
996 gomp_task_run_post_handle_depend_hash (struct gomp_task *child_task)
998 struct gomp_task *parent = child_task->parent;
999 size_t i;
1001 for (i = 0; i < child_task->depend_count; i++)
1002 if (!child_task->depend[i].redundant)
1004 if (child_task->depend[i].next)
1005 child_task->depend[i].next->prev = child_task->depend[i].prev;
1006 if (child_task->depend[i].prev)
1007 child_task->depend[i].prev->next = child_task->depend[i].next;
1008 else
1010 hash_entry_type *slot
1011 = htab_find_slot (&parent->depend_hash, &child_task->depend[i],
1012 NO_INSERT);
1013 if (*slot != &child_task->depend[i])
1014 abort ();
1015 if (child_task->depend[i].next)
1016 *slot = child_task->depend[i].next;
1017 else
1018 htab_clear_slot (parent->depend_hash, slot);
1023 /* After a CHILD_TASK has been run, adjust the dependency queue for
1024 each task that depends on CHILD_TASK, to record the fact that there
1025 is one less dependency to worry about. If a task that depended on
1026 CHILD_TASK now has no dependencies, place it in the various queues
1027 so it gets scheduled to run.
1029 TEAM is the team to which CHILD_TASK belongs to. */
1031 static size_t
1032 gomp_task_run_post_handle_dependers (struct gomp_task *child_task,
1033 struct gomp_team *team)
1035 struct gomp_task *parent = child_task->parent;
1036 size_t i, count = child_task->dependers->n_elem, ret = 0;
1037 for (i = 0; i < count; i++)
1039 struct gomp_task *task = child_task->dependers->elem[i];
1041 /* CHILD_TASK satisfies a dependency for TASK. Keep track of
1042 TASK's remaining dependencies. Once TASK has no other
1043 depenencies, put it into the various queues so it will get
1044 scheduled for execution. */
1045 if (--task->num_dependees != 0)
1046 continue;
1048 struct gomp_taskgroup *taskgroup = task->taskgroup;
1049 if (parent)
1051 priority_queue_insert (PQ_CHILDREN, &parent->children_queue,
1052 task, task->priority,
1053 PRIORITY_INSERT_BEGIN,
1054 /*adjust_parent_depends_on=*/true,
1055 task->parent_depends_on);
1056 if (parent->taskwait)
1058 if (parent->taskwait->in_taskwait)
1060 /* One more task has had its dependencies met.
1061 Inform any waiters. */
1062 parent->taskwait->in_taskwait = false;
1063 gomp_sem_post (&parent->taskwait->taskwait_sem);
1065 else if (parent->taskwait->in_depend_wait)
1067 /* One more task has had its dependencies met.
1068 Inform any waiters. */
1069 parent->taskwait->in_depend_wait = false;
1070 gomp_sem_post (&parent->taskwait->taskwait_sem);
1074 if (taskgroup)
1076 priority_queue_insert (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
1077 task, task->priority,
1078 PRIORITY_INSERT_BEGIN,
1079 /*adjust_parent_depends_on=*/false,
1080 task->parent_depends_on);
1081 if (taskgroup->in_taskgroup_wait)
1083 /* One more task has had its dependencies met.
1084 Inform any waiters. */
1085 taskgroup->in_taskgroup_wait = false;
1086 gomp_sem_post (&taskgroup->taskgroup_sem);
1089 priority_queue_insert (PQ_TEAM, &team->task_queue,
1090 task, task->priority,
1091 PRIORITY_INSERT_END,
1092 /*adjust_parent_depends_on=*/false,
1093 task->parent_depends_on);
1094 ++team->task_count;
1095 ++team->task_queued_count;
1096 ++ret;
1098 free (child_task->dependers);
1099 child_task->dependers = NULL;
1100 if (ret > 1)
1101 gomp_team_barrier_set_task_pending (&team->barrier);
1102 return ret;
1105 static inline size_t
1106 gomp_task_run_post_handle_depend (struct gomp_task *child_task,
1107 struct gomp_team *team)
1109 if (child_task->depend_count == 0)
1110 return 0;
1112 /* If parent is gone already, the hash table is freed and nothing
1113 will use the hash table anymore, no need to remove anything from it. */
1114 if (child_task->parent != NULL)
1115 gomp_task_run_post_handle_depend_hash (child_task);
1117 if (child_task->dependers == NULL)
1118 return 0;
1120 return gomp_task_run_post_handle_dependers (child_task, team);
1123 /* Remove CHILD_TASK from its parent. */
1125 static inline void
1126 gomp_task_run_post_remove_parent (struct gomp_task *child_task)
1128 struct gomp_task *parent = child_task->parent;
1129 if (parent == NULL)
1130 return;
1132 /* If this was the last task the parent was depending on,
1133 synchronize with gomp_task_maybe_wait_for_dependencies so it can
1134 clean up and return. */
1135 if (__builtin_expect (child_task->parent_depends_on, 0)
1136 && --parent->taskwait->n_depend == 0
1137 && parent->taskwait->in_depend_wait)
1139 parent->taskwait->in_depend_wait = false;
1140 gomp_sem_post (&parent->taskwait->taskwait_sem);
1143 if (priority_queue_remove (PQ_CHILDREN, &parent->children_queue,
1144 child_task, MEMMODEL_RELEASE)
1145 && parent->taskwait && parent->taskwait->in_taskwait)
1147 parent->taskwait->in_taskwait = false;
1148 gomp_sem_post (&parent->taskwait->taskwait_sem);
1150 child_task->pnode[PQ_CHILDREN].next = NULL;
1151 child_task->pnode[PQ_CHILDREN].prev = NULL;
1154 /* Remove CHILD_TASK from its taskgroup. */
1156 static inline void
1157 gomp_task_run_post_remove_taskgroup (struct gomp_task *child_task)
1159 struct gomp_taskgroup *taskgroup = child_task->taskgroup;
1160 if (taskgroup == NULL)
1161 return;
1162 bool empty = priority_queue_remove (PQ_TASKGROUP,
1163 &taskgroup->taskgroup_queue,
1164 child_task, MEMMODEL_RELAXED);
1165 child_task->pnode[PQ_TASKGROUP].next = NULL;
1166 child_task->pnode[PQ_TASKGROUP].prev = NULL;
1167 if (taskgroup->num_children > 1)
1168 --taskgroup->num_children;
1169 else
1171 /* We access taskgroup->num_children in GOMP_taskgroup_end
1172 outside of the task lock mutex region, so
1173 need a release barrier here to ensure memory
1174 written by child_task->fn above is flushed
1175 before the NULL is written. */
1176 __atomic_store_n (&taskgroup->num_children, 0, MEMMODEL_RELEASE);
1178 if (empty && taskgroup->in_taskgroup_wait)
1180 taskgroup->in_taskgroup_wait = false;
1181 gomp_sem_post (&taskgroup->taskgroup_sem);
1185 void
1186 gomp_barrier_handle_tasks (gomp_barrier_state_t state)
1188 struct gomp_thread *thr = gomp_thread ();
1189 struct gomp_team *team = thr->ts.team;
1190 struct gomp_task *task = thr->task;
1191 struct gomp_task *child_task = NULL;
1192 struct gomp_task *to_free = NULL;
1193 int do_wake = 0;
1195 gomp_mutex_lock (&team->task_lock);
1196 if (gomp_barrier_last_thread (state))
1198 if (team->task_count == 0)
1200 gomp_team_barrier_done (&team->barrier, state);
1201 gomp_mutex_unlock (&team->task_lock);
1202 gomp_team_barrier_wake (&team->barrier, 0);
1203 return;
1205 gomp_team_barrier_set_waiting_for_tasks (&team->barrier);
1208 while (1)
1210 bool cancelled = false;
1211 if (!priority_queue_empty_p (&team->task_queue, MEMMODEL_RELAXED))
1213 bool ignored;
1214 child_task
1215 = priority_queue_next_task (PQ_TEAM, &team->task_queue,
1216 PQ_IGNORED, NULL,
1217 &ignored);
1218 cancelled = gomp_task_run_pre (child_task, child_task->parent,
1219 team);
1220 if (__builtin_expect (cancelled, 0))
1222 if (to_free)
1224 gomp_finish_task (to_free);
1225 free (to_free);
1226 to_free = NULL;
1228 goto finish_cancelled;
1230 team->task_running_count++;
1231 child_task->in_tied_task = true;
1233 gomp_mutex_unlock (&team->task_lock);
1234 if (do_wake)
1236 gomp_team_barrier_wake (&team->barrier, do_wake);
1237 do_wake = 0;
1239 if (to_free)
1241 gomp_finish_task (to_free);
1242 free (to_free);
1243 to_free = NULL;
1245 if (child_task)
1247 thr->task = child_task;
1248 if (__builtin_expect (child_task->fn == NULL, 0))
1250 if (gomp_target_task_fn (child_task->fn_data))
1252 thr->task = task;
1253 gomp_mutex_lock (&team->task_lock);
1254 child_task->kind = GOMP_TASK_ASYNC_RUNNING;
1255 team->task_running_count--;
1256 struct gomp_target_task *ttask
1257 = (struct gomp_target_task *) child_task->fn_data;
1258 /* If GOMP_PLUGIN_target_task_completion has run already
1259 in between gomp_target_task_fn and the mutex lock,
1260 perform the requeuing here. */
1261 if (ttask->state == GOMP_TARGET_TASK_FINISHED)
1262 gomp_target_task_completion (team, child_task);
1263 else
1264 ttask->state = GOMP_TARGET_TASK_RUNNING;
1265 child_task = NULL;
1266 continue;
1269 else
1270 child_task->fn (child_task->fn_data);
1271 thr->task = task;
1273 else
1274 return;
1275 gomp_mutex_lock (&team->task_lock);
1276 if (child_task)
1278 finish_cancelled:;
1279 size_t new_tasks
1280 = gomp_task_run_post_handle_depend (child_task, team);
1281 gomp_task_run_post_remove_parent (child_task);
1282 gomp_clear_parent (&child_task->children_queue);
1283 gomp_task_run_post_remove_taskgroup (child_task);
1284 to_free = child_task;
1285 child_task = NULL;
1286 if (!cancelled)
1287 team->task_running_count--;
1288 if (new_tasks > 1)
1290 do_wake = team->nthreads - team->task_running_count;
1291 if (do_wake > new_tasks)
1292 do_wake = new_tasks;
1294 if (--team->task_count == 0
1295 && gomp_team_barrier_waiting_for_tasks (&team->barrier))
1297 gomp_team_barrier_done (&team->barrier, state);
1298 gomp_mutex_unlock (&team->task_lock);
1299 gomp_team_barrier_wake (&team->barrier, 0);
1300 gomp_mutex_lock (&team->task_lock);
1306 /* Called when encountering a taskwait directive.
1308 Wait for all children of the current task. */
1310 void
1311 GOMP_taskwait (void)
1313 struct gomp_thread *thr = gomp_thread ();
1314 struct gomp_team *team = thr->ts.team;
1315 struct gomp_task *task = thr->task;
1316 struct gomp_task *child_task = NULL;
1317 struct gomp_task *to_free = NULL;
1318 struct gomp_taskwait taskwait;
1319 int do_wake = 0;
1321 /* The acquire barrier on load of task->children here synchronizes
1322 with the write of a NULL in gomp_task_run_post_remove_parent. It is
1323 not necessary that we synchronize with other non-NULL writes at
1324 this point, but we must ensure that all writes to memory by a
1325 child thread task work function are seen before we exit from
1326 GOMP_taskwait. */
1327 if (task == NULL
1328 || priority_queue_empty_p (&task->children_queue, MEMMODEL_ACQUIRE))
1329 return;
1331 memset (&taskwait, 0, sizeof (taskwait));
1332 bool child_q = false;
1333 gomp_mutex_lock (&team->task_lock);
1334 while (1)
1336 bool cancelled = false;
1337 if (priority_queue_empty_p (&task->children_queue, MEMMODEL_RELAXED))
1339 bool destroy_taskwait = task->taskwait != NULL;
1340 task->taskwait = NULL;
1341 gomp_mutex_unlock (&team->task_lock);
1342 if (to_free)
1344 gomp_finish_task (to_free);
1345 free (to_free);
1347 if (destroy_taskwait)
1348 gomp_sem_destroy (&taskwait.taskwait_sem);
1349 return;
1351 struct gomp_task *next_task
1352 = priority_queue_next_task (PQ_CHILDREN, &task->children_queue,
1353 PQ_TEAM, &team->task_queue, &child_q);
1354 if (next_task->kind == GOMP_TASK_WAITING)
1356 child_task = next_task;
1357 cancelled
1358 = gomp_task_run_pre (child_task, task, team);
1359 if (__builtin_expect (cancelled, 0))
1361 if (to_free)
1363 gomp_finish_task (to_free);
1364 free (to_free);
1365 to_free = NULL;
1367 goto finish_cancelled;
1370 else
1372 /* All tasks we are waiting for are either running in other
1373 threads, or they are tasks that have not had their
1374 dependencies met (so they're not even in the queue). Wait
1375 for them. */
1376 if (task->taskwait == NULL)
1378 taskwait.in_depend_wait = false;
1379 gomp_sem_init (&taskwait.taskwait_sem, 0);
1380 task->taskwait = &taskwait;
1382 taskwait.in_taskwait = true;
1384 gomp_mutex_unlock (&team->task_lock);
1385 if (do_wake)
1387 gomp_team_barrier_wake (&team->barrier, do_wake);
1388 do_wake = 0;
1390 if (to_free)
1392 gomp_finish_task (to_free);
1393 free (to_free);
1394 to_free = NULL;
1396 if (child_task)
1398 thr->task = child_task;
1399 if (__builtin_expect (child_task->fn == NULL, 0))
1401 if (gomp_target_task_fn (child_task->fn_data))
1403 thr->task = task;
1404 gomp_mutex_lock (&team->task_lock);
1405 child_task->kind = GOMP_TASK_ASYNC_RUNNING;
1406 struct gomp_target_task *ttask
1407 = (struct gomp_target_task *) child_task->fn_data;
1408 /* If GOMP_PLUGIN_target_task_completion has run already
1409 in between gomp_target_task_fn and the mutex lock,
1410 perform the requeuing here. */
1411 if (ttask->state == GOMP_TARGET_TASK_FINISHED)
1412 gomp_target_task_completion (team, child_task);
1413 else
1414 ttask->state = GOMP_TARGET_TASK_RUNNING;
1415 child_task = NULL;
1416 continue;
1419 else
1420 child_task->fn (child_task->fn_data);
1421 thr->task = task;
1423 else
1424 gomp_sem_wait (&taskwait.taskwait_sem);
1425 gomp_mutex_lock (&team->task_lock);
1426 if (child_task)
1428 finish_cancelled:;
1429 size_t new_tasks
1430 = gomp_task_run_post_handle_depend (child_task, team);
1432 if (child_q)
1434 priority_queue_remove (PQ_CHILDREN, &task->children_queue,
1435 child_task, MEMMODEL_RELAXED);
1436 child_task->pnode[PQ_CHILDREN].next = NULL;
1437 child_task->pnode[PQ_CHILDREN].prev = NULL;
1440 gomp_clear_parent (&child_task->children_queue);
1442 gomp_task_run_post_remove_taskgroup (child_task);
1444 to_free = child_task;
1445 child_task = NULL;
1446 team->task_count--;
1447 if (new_tasks > 1)
1449 do_wake = team->nthreads - team->task_running_count
1450 - !task->in_tied_task;
1451 if (do_wake > new_tasks)
1452 do_wake = new_tasks;
1458 /* An undeferred task is about to run. Wait for all tasks that this
1459 undeferred task depends on.
1461 This is done by first putting all known ready dependencies
1462 (dependencies that have their own dependencies met) at the top of
1463 the scheduling queues. Then we iterate through these imminently
1464 ready tasks (and possibly other high priority tasks), and run them.
1465 If we run out of ready dependencies to execute, we either wait for
1466 the reamining dependencies to finish, or wait for them to get
1467 scheduled so we can run them.
1469 DEPEND is as in GOMP_task. */
1471 void
1472 gomp_task_maybe_wait_for_dependencies (void **depend)
1474 struct gomp_thread *thr = gomp_thread ();
1475 struct gomp_task *task = thr->task;
1476 struct gomp_team *team = thr->ts.team;
1477 struct gomp_task_depend_entry elem, *ent = NULL;
1478 struct gomp_taskwait taskwait;
1479 size_t ndepend = (uintptr_t) depend[0];
1480 size_t nout = (uintptr_t) depend[1];
1481 size_t i;
1482 size_t num_awaited = 0;
1483 struct gomp_task *child_task = NULL;
1484 struct gomp_task *to_free = NULL;
1485 int do_wake = 0;
1487 gomp_mutex_lock (&team->task_lock);
1488 for (i = 0; i < ndepend; i++)
1490 elem.addr = depend[i + 2];
1491 ent = htab_find (task->depend_hash, &elem);
1492 for (; ent; ent = ent->next)
1493 if (i >= nout && ent->is_in)
1494 continue;
1495 else
1497 struct gomp_task *tsk = ent->task;
1498 if (!tsk->parent_depends_on)
1500 tsk->parent_depends_on = true;
1501 ++num_awaited;
1502 /* If depenency TSK itself has no dependencies and is
1503 ready to run, move it up front so that we run it as
1504 soon as possible. */
1505 if (tsk->num_dependees == 0 && tsk->kind == GOMP_TASK_WAITING)
1506 priority_queue_upgrade_task (tsk, task);
1510 if (num_awaited == 0)
1512 gomp_mutex_unlock (&team->task_lock);
1513 return;
1516 memset (&taskwait, 0, sizeof (taskwait));
1517 taskwait.n_depend = num_awaited;
1518 gomp_sem_init (&taskwait.taskwait_sem, 0);
1519 task->taskwait = &taskwait;
1521 while (1)
1523 bool cancelled = false;
1524 if (taskwait.n_depend == 0)
1526 task->taskwait = NULL;
1527 gomp_mutex_unlock (&team->task_lock);
1528 if (to_free)
1530 gomp_finish_task (to_free);
1531 free (to_free);
1533 gomp_sem_destroy (&taskwait.taskwait_sem);
1534 return;
1537 /* Theoretically when we have multiple priorities, we should
1538 chose between the highest priority item in
1539 task->children_queue and team->task_queue here, so we should
1540 use priority_queue_next_task(). However, since we are
1541 running an undeferred task, perhaps that makes all tasks it
1542 depends on undeferred, thus a priority of INF? This would
1543 make it unnecessary to take anything into account here,
1544 but the dependencies.
1546 On the other hand, if we want to use priority_queue_next_task(),
1547 care should be taken to only use priority_queue_remove()
1548 below if the task was actually removed from the children
1549 queue. */
1550 bool ignored;
1551 struct gomp_task *next_task
1552 = priority_queue_next_task (PQ_CHILDREN, &task->children_queue,
1553 PQ_IGNORED, NULL, &ignored);
1555 if (next_task->kind == GOMP_TASK_WAITING)
1557 child_task = next_task;
1558 cancelled
1559 = gomp_task_run_pre (child_task, task, team);
1560 if (__builtin_expect (cancelled, 0))
1562 if (to_free)
1564 gomp_finish_task (to_free);
1565 free (to_free);
1566 to_free = NULL;
1568 goto finish_cancelled;
1571 else
1572 /* All tasks we are waiting for are either running in other
1573 threads, or they are tasks that have not had their
1574 dependencies met (so they're not even in the queue). Wait
1575 for them. */
1576 taskwait.in_depend_wait = true;
1577 gomp_mutex_unlock (&team->task_lock);
1578 if (do_wake)
1580 gomp_team_barrier_wake (&team->barrier, do_wake);
1581 do_wake = 0;
1583 if (to_free)
1585 gomp_finish_task (to_free);
1586 free (to_free);
1587 to_free = NULL;
1589 if (child_task)
1591 thr->task = child_task;
1592 if (__builtin_expect (child_task->fn == NULL, 0))
1594 if (gomp_target_task_fn (child_task->fn_data))
1596 thr->task = task;
1597 gomp_mutex_lock (&team->task_lock);
1598 child_task->kind = GOMP_TASK_ASYNC_RUNNING;
1599 struct gomp_target_task *ttask
1600 = (struct gomp_target_task *) child_task->fn_data;
1601 /* If GOMP_PLUGIN_target_task_completion has run already
1602 in between gomp_target_task_fn and the mutex lock,
1603 perform the requeuing here. */
1604 if (ttask->state == GOMP_TARGET_TASK_FINISHED)
1605 gomp_target_task_completion (team, child_task);
1606 else
1607 ttask->state = GOMP_TARGET_TASK_RUNNING;
1608 child_task = NULL;
1609 continue;
1612 else
1613 child_task->fn (child_task->fn_data);
1614 thr->task = task;
1616 else
1617 gomp_sem_wait (&taskwait.taskwait_sem);
1618 gomp_mutex_lock (&team->task_lock);
1619 if (child_task)
1621 finish_cancelled:;
1622 size_t new_tasks
1623 = gomp_task_run_post_handle_depend (child_task, team);
1624 if (child_task->parent_depends_on)
1625 --taskwait.n_depend;
1627 priority_queue_remove (PQ_CHILDREN, &task->children_queue,
1628 child_task, MEMMODEL_RELAXED);
1629 child_task->pnode[PQ_CHILDREN].next = NULL;
1630 child_task->pnode[PQ_CHILDREN].prev = NULL;
1632 gomp_clear_parent (&child_task->children_queue);
1633 gomp_task_run_post_remove_taskgroup (child_task);
1634 to_free = child_task;
1635 child_task = NULL;
1636 team->task_count--;
1637 if (new_tasks > 1)
1639 do_wake = team->nthreads - team->task_running_count
1640 - !task->in_tied_task;
1641 if (do_wake > new_tasks)
1642 do_wake = new_tasks;
1648 /* Called when encountering a taskyield directive. */
1650 void
1651 GOMP_taskyield (void)
1653 /* Nothing at the moment. */
1656 void
1657 GOMP_taskgroup_start (void)
1659 struct gomp_thread *thr = gomp_thread ();
1660 struct gomp_team *team = thr->ts.team;
1661 struct gomp_task *task = thr->task;
1662 struct gomp_taskgroup *taskgroup;
1664 /* If team is NULL, all tasks are executed as
1665 GOMP_TASK_UNDEFERRED tasks and thus all children tasks of
1666 taskgroup and their descendant tasks will be finished
1667 by the time GOMP_taskgroup_end is called. */
1668 if (team == NULL)
1669 return;
1670 taskgroup = gomp_malloc (sizeof (struct gomp_taskgroup));
1671 taskgroup->prev = task->taskgroup;
1672 priority_queue_init (&taskgroup->taskgroup_queue);
1673 taskgroup->in_taskgroup_wait = false;
1674 taskgroup->cancelled = false;
1675 taskgroup->num_children = 0;
1676 gomp_sem_init (&taskgroup->taskgroup_sem, 0);
1677 task->taskgroup = taskgroup;
1680 void
1681 GOMP_taskgroup_end (void)
1683 struct gomp_thread *thr = gomp_thread ();
1684 struct gomp_team *team = thr->ts.team;
1685 struct gomp_task *task = thr->task;
1686 struct gomp_taskgroup *taskgroup;
1687 struct gomp_task *child_task = NULL;
1688 struct gomp_task *to_free = NULL;
1689 int do_wake = 0;
1691 if (team == NULL)
1692 return;
1693 taskgroup = task->taskgroup;
1694 if (__builtin_expect (taskgroup == NULL, 0)
1695 && thr->ts.level == 0)
1697 /* This can happen if GOMP_taskgroup_start is called when
1698 thr->ts.team == NULL, but inside of the taskgroup there
1699 is #pragma omp target nowait that creates an implicit
1700 team with a single thread. In this case, we want to wait
1701 for all outstanding tasks in this team. */
1702 gomp_team_barrier_wait (&team->barrier);
1703 return;
1706 /* The acquire barrier on load of taskgroup->num_children here
1707 synchronizes with the write of 0 in gomp_task_run_post_remove_taskgroup.
1708 It is not necessary that we synchronize with other non-0 writes at
1709 this point, but we must ensure that all writes to memory by a
1710 child thread task work function are seen before we exit from
1711 GOMP_taskgroup_end. */
1712 if (__atomic_load_n (&taskgroup->num_children, MEMMODEL_ACQUIRE) == 0)
1713 goto finish;
1715 bool unused;
1716 gomp_mutex_lock (&team->task_lock);
1717 while (1)
1719 bool cancelled = false;
1720 if (priority_queue_empty_p (&taskgroup->taskgroup_queue,
1721 MEMMODEL_RELAXED))
1723 if (taskgroup->num_children)
1725 if (priority_queue_empty_p (&task->children_queue,
1726 MEMMODEL_RELAXED))
1727 goto do_wait;
1728 child_task
1729 = priority_queue_next_task (PQ_CHILDREN, &task->children_queue,
1730 PQ_TEAM, &team->task_queue,
1731 &unused);
1733 else
1735 gomp_mutex_unlock (&team->task_lock);
1736 if (to_free)
1738 gomp_finish_task (to_free);
1739 free (to_free);
1741 goto finish;
1744 else
1745 child_task
1746 = priority_queue_next_task (PQ_TASKGROUP, &taskgroup->taskgroup_queue,
1747 PQ_TEAM, &team->task_queue, &unused);
1748 if (child_task->kind == GOMP_TASK_WAITING)
1750 cancelled
1751 = gomp_task_run_pre (child_task, child_task->parent, team);
1752 if (__builtin_expect (cancelled, 0))
1754 if (to_free)
1756 gomp_finish_task (to_free);
1757 free (to_free);
1758 to_free = NULL;
1760 goto finish_cancelled;
1763 else
1765 child_task = NULL;
1766 do_wait:
1767 /* All tasks we are waiting for are either running in other
1768 threads, or they are tasks that have not had their
1769 dependencies met (so they're not even in the queue). Wait
1770 for them. */
1771 taskgroup->in_taskgroup_wait = true;
1773 gomp_mutex_unlock (&team->task_lock);
1774 if (do_wake)
1776 gomp_team_barrier_wake (&team->barrier, do_wake);
1777 do_wake = 0;
1779 if (to_free)
1781 gomp_finish_task (to_free);
1782 free (to_free);
1783 to_free = NULL;
1785 if (child_task)
1787 thr->task = child_task;
1788 if (__builtin_expect (child_task->fn == NULL, 0))
1790 if (gomp_target_task_fn (child_task->fn_data))
1792 thr->task = task;
1793 gomp_mutex_lock (&team->task_lock);
1794 child_task->kind = GOMP_TASK_ASYNC_RUNNING;
1795 struct gomp_target_task *ttask
1796 = (struct gomp_target_task *) child_task->fn_data;
1797 /* If GOMP_PLUGIN_target_task_completion has run already
1798 in between gomp_target_task_fn and the mutex lock,
1799 perform the requeuing here. */
1800 if (ttask->state == GOMP_TARGET_TASK_FINISHED)
1801 gomp_target_task_completion (team, child_task);
1802 else
1803 ttask->state = GOMP_TARGET_TASK_RUNNING;
1804 child_task = NULL;
1805 continue;
1808 else
1809 child_task->fn (child_task->fn_data);
1810 thr->task = task;
1812 else
1813 gomp_sem_wait (&taskgroup->taskgroup_sem);
1814 gomp_mutex_lock (&team->task_lock);
1815 if (child_task)
1817 finish_cancelled:;
1818 size_t new_tasks
1819 = gomp_task_run_post_handle_depend (child_task, team);
1820 gomp_task_run_post_remove_parent (child_task);
1821 gomp_clear_parent (&child_task->children_queue);
1822 gomp_task_run_post_remove_taskgroup (child_task);
1823 to_free = child_task;
1824 child_task = NULL;
1825 team->task_count--;
1826 if (new_tasks > 1)
1828 do_wake = team->nthreads - team->task_running_count
1829 - !task->in_tied_task;
1830 if (do_wake > new_tasks)
1831 do_wake = new_tasks;
1836 finish:
1837 task->taskgroup = taskgroup->prev;
1838 gomp_sem_destroy (&taskgroup->taskgroup_sem);
1839 free (taskgroup);
1843 omp_in_final (void)
1845 struct gomp_thread *thr = gomp_thread ();
1846 return thr->task && thr->task->final_task;
1849 ialias (omp_in_final)