1 /* Copyright (C) 2007-2013 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This file handles the maintainence of tasks in response to task
26 creation and termination. */
32 typedef struct gomp_task_depend_entry
*hash_entry_type
;
35 htab_alloc (size_t size
)
37 return gomp_malloc (size
);
48 static inline hashval_t
49 htab_hash (hash_entry_type element
)
51 return hash_pointer (element
->addr
);
55 htab_eq (hash_entry_type x
, hash_entry_type y
)
57 return x
->addr
== y
->addr
;
60 /* Create a new task data structure. */
63 gomp_init_task (struct gomp_task
*task
, struct gomp_task
*parent_task
,
64 struct gomp_task_icv
*prev_icv
)
66 task
->parent
= parent_task
;
67 task
->icv
= *prev_icv
;
68 task
->kind
= GOMP_TASK_IMPLICIT
;
69 task
->in_taskwait
= false;
70 task
->in_tied_task
= false;
71 task
->final_task
= false;
72 task
->copy_ctors_done
= false;
73 task
->children
= NULL
;
74 task
->taskgroup
= NULL
;
75 task
->dependers
= NULL
;
76 task
->depend_hash
= NULL
;
77 task
->depend_count
= 0;
78 gomp_sem_init (&task
->taskwait_sem
, 0);
81 /* Clean up a task, after completing it. */
86 struct gomp_thread
*thr
= gomp_thread ();
87 struct gomp_task
*task
= thr
->task
;
89 gomp_finish_task (task
);
90 thr
->task
= task
->parent
;
94 gomp_clear_parent (struct gomp_task
*children
)
96 struct gomp_task
*task
= children
;
102 task
= task
->next_child
;
104 while (task
!= children
);
107 /* Called when encountering an explicit task directive. If IF_CLAUSE is
108 false, then we must not delay in executing the task. If UNTIED is true,
109 then the task may be executed by any member of the team. */
112 GOMP_task (void (*fn
) (void *), void *data
, void (*cpyfn
) (void *, void *),
113 long arg_size
, long arg_align
, bool if_clause
, unsigned flags
,
116 struct gomp_thread
*thr
= gomp_thread ();
117 struct gomp_team
*team
= thr
->ts
.team
;
119 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
120 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
121 tied to one thread all the time. This means UNTIED tasks must be
122 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
123 might be running on different thread than FN. */
130 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
132 && (gomp_team_barrier_cancelled (&team
->barrier
)
133 || (thr
->task
->taskgroup
&& thr
->task
->taskgroup
->cancelled
)))
136 if (!if_clause
|| team
== NULL
137 || (thr
->task
&& thr
->task
->final_task
)
138 || team
->task_count
> 64 * team
->nthreads
)
140 struct gomp_task task
;
142 /* If there are depend clauses and earlier deferred sibling tasks
143 with depend clauses, check if there isn't a dependency. If there
144 is, fall through to the deferred task handling, as we can't
145 schedule such tasks right away. There is no need to handle
146 depend clauses for non-deferred tasks other than this, because
147 the parent task is suspended until the child task finishes and thus
148 it can't start further child tasks. */
149 if ((flags
& 8) && thr
->task
&& thr
->task
->depend_hash
)
151 struct gomp_task
*parent
= thr
->task
;
152 struct gomp_task_depend_entry elem
, *ent
= NULL
;
153 size_t ndepend
= (uintptr_t) depend
[0];
154 size_t nout
= (uintptr_t) depend
[1];
156 gomp_mutex_lock (&team
->task_lock
);
157 for (i
= 0; i
< ndepend
; i
++)
159 elem
.addr
= depend
[i
+ 2];
160 ent
= htab_find (parent
->depend_hash
, &elem
);
161 for (; ent
; ent
= ent
->next
)
162 if (i
>= nout
&& ent
->is_in
)
169 gomp_mutex_unlock (&team
->task_lock
);
174 gomp_init_task (&task
, thr
->task
, gomp_icv (false));
175 task
.kind
= GOMP_TASK_IFFALSE
;
176 task
.final_task
= (thr
->task
&& thr
->task
->final_task
) || (flags
& 2);
179 task
.in_tied_task
= thr
->task
->in_tied_task
;
180 task
.taskgroup
= thr
->task
->taskgroup
;
183 if (__builtin_expect (cpyfn
!= NULL
, 0))
185 char buf
[arg_size
+ arg_align
- 1];
186 char *arg
= (char *) (((uintptr_t) buf
+ arg_align
- 1)
187 & ~(uintptr_t) (arg_align
- 1));
193 /* Access to "children" is normally done inside a task_lock
194 mutex region, but the only way this particular task.children
195 can be set is if this thread's task work function (fn)
196 creates children. So since the setter is *this* thread, we
197 need no barriers here when testing for non-NULL. We can have
198 task.children set by the current thread then changed by a
199 child thread, but seeing a stale non-NULL value is not a
200 problem. Once past the task_lock acquisition, this thread
201 will see the real value of task.children. */
202 if (task
.children
!= NULL
)
204 gomp_mutex_lock (&team
->task_lock
);
205 gomp_clear_parent (task
.children
);
206 gomp_mutex_unlock (&team
->task_lock
);
213 struct gomp_task
*task
;
214 struct gomp_task
*parent
= thr
->task
;
215 struct gomp_taskgroup
*taskgroup
= parent
->taskgroup
;
218 size_t depend_size
= 0;
221 depend_size
= ((uintptr_t) depend
[0]
222 * sizeof (struct gomp_task_depend_entry
));
223 task
= gomp_malloc (sizeof (*task
) + depend_size
224 + arg_size
+ arg_align
- 1);
225 arg
= (char *) (((uintptr_t) (task
+ 1) + depend_size
+ arg_align
- 1)
226 & ~(uintptr_t) (arg_align
- 1));
227 gomp_init_task (task
, parent
, gomp_icv (false));
228 task
->kind
= GOMP_TASK_IFFALSE
;
229 task
->in_tied_task
= parent
->in_tied_task
;
230 task
->taskgroup
= taskgroup
;
235 task
->copy_ctors_done
= true;
238 memcpy (arg
, data
, arg_size
);
240 task
->kind
= GOMP_TASK_WAITING
;
243 task
->final_task
= (flags
& 2) >> 1;
244 gomp_mutex_lock (&team
->task_lock
);
245 /* If parallel or taskgroup has been cancelled, don't start new
247 if (__builtin_expect ((gomp_team_barrier_cancelled (&team
->barrier
)
248 || (taskgroup
&& taskgroup
->cancelled
))
249 && !task
->copy_ctors_done
, 0))
251 gomp_mutex_unlock (&team
->task_lock
);
252 gomp_finish_task (task
);
257 taskgroup
->num_children
++;
260 size_t ndepend
= (uintptr_t) depend
[0];
261 size_t nout
= (uintptr_t) depend
[1];
265 task
->depend_count
= ndepend
;
266 task
->num_dependees
= 0;
267 if (parent
->depend_hash
== NULL
)
269 = htab_create (2 * ndepend
> 12 ? 2 * ndepend
: 12);
270 for (i
= 0; i
< ndepend
; i
++)
272 task
->depend
[i
].addr
= depend
[2 + i
];
273 task
->depend
[i
].next
= NULL
;
274 task
->depend
[i
].prev
= NULL
;
275 task
->depend
[i
].task
= task
;
276 task
->depend
[i
].is_in
= i
>= nout
;
277 task
->depend
[i
].redundant
= false;
279 hash_entry_type
*slot
280 = htab_find_slot (&parent
->depend_hash
, &task
->depend
[i
],
282 hash_entry_type out
= NULL
;
285 /* If multiple depends on the same task are the
286 same, all but the first one are redundant.
287 As inout/out come first, if any of them is
288 inout/out, it will win, which is the right
290 if ((*slot
)->task
== task
)
292 task
->depend
[i
].redundant
= true;
295 for (ent
= *slot
; ent
; ent
= ent
->next
)
297 /* depend(in:...) doesn't depend on earlier
299 if (i
>= nout
&& ent
->is_in
)
305 struct gomp_task
*tsk
= ent
->task
;
306 if (tsk
->dependers
== NULL
)
309 = gomp_malloc (sizeof (struct gomp_dependers_vec
)
310 + 6 * sizeof (struct gomp_task
*));
311 tsk
->dependers
->n_elem
= 1;
312 tsk
->dependers
->allocated
= 6;
313 tsk
->dependers
->elem
[0] = task
;
314 task
->num_dependees
++;
317 /* We already have some other dependency on tsk
318 from earlier depend clause. */
319 else if (tsk
->dependers
->n_elem
320 && (tsk
->dependers
->elem
[tsk
->dependers
->n_elem
324 else if (tsk
->dependers
->n_elem
325 == tsk
->dependers
->allocated
)
327 tsk
->dependers
->allocated
328 = tsk
->dependers
->allocated
* 2 + 2;
330 = gomp_realloc (tsk
->dependers
,
331 sizeof (struct gomp_dependers_vec
)
332 + (tsk
->dependers
->allocated
333 * sizeof (struct gomp_task
*)));
335 tsk
->dependers
->elem
[tsk
->dependers
->n_elem
++] = task
;
336 task
->num_dependees
++;
338 task
->depend
[i
].next
= *slot
;
339 (*slot
)->prev
= &task
->depend
[i
];
341 *slot
= &task
->depend
[i
];
343 /* There is no need to store more than one depend({,in}out:)
344 task per address in the hash table chain, because each out
345 depends on all earlier outs, thus it is enough to record
346 just the last depend({,in}out:). For depend(in:), we need
347 to keep all of the previous ones not terminated yet, because
348 a later depend({,in}out:) might need to depend on all of
349 them. So, if the new task's clause is depend({,in}out:),
350 we know there is at most one other depend({,in}out:) clause
351 in the list (out) and to maintain the invariant we now
352 need to remove it from the list. */
353 if (!task
->depend
[i
].is_in
&& out
)
356 out
->next
->prev
= out
->prev
;
357 out
->prev
->next
= out
->next
;
358 out
->redundant
= true;
361 if (task
->num_dependees
)
363 gomp_mutex_unlock (&team
->task_lock
);
367 if (parent
->children
)
369 task
->next_child
= parent
->children
;
370 task
->prev_child
= parent
->children
->prev_child
;
371 task
->next_child
->prev_child
= task
;
372 task
->prev_child
->next_child
= task
;
376 task
->next_child
= task
;
377 task
->prev_child
= task
;
379 parent
->children
= task
;
382 if (taskgroup
->children
)
384 task
->next_taskgroup
= taskgroup
->children
;
385 task
->prev_taskgroup
= taskgroup
->children
->prev_taskgroup
;
386 task
->next_taskgroup
->prev_taskgroup
= task
;
387 task
->prev_taskgroup
->next_taskgroup
= task
;
391 task
->next_taskgroup
= task
;
392 task
->prev_taskgroup
= task
;
394 taskgroup
->children
= task
;
396 if (team
->task_queue
)
398 task
->next_queue
= team
->task_queue
;
399 task
->prev_queue
= team
->task_queue
->prev_queue
;
400 task
->next_queue
->prev_queue
= task
;
401 task
->prev_queue
->next_queue
= task
;
405 task
->next_queue
= task
;
406 task
->prev_queue
= task
;
407 team
->task_queue
= task
;
410 ++team
->task_queued_count
;
411 gomp_team_barrier_set_task_pending (&team
->barrier
);
412 do_wake
= team
->task_running_count
+ !parent
->in_tied_task
414 gomp_mutex_unlock (&team
->task_lock
);
416 gomp_team_barrier_wake (&team
->barrier
, 1);
421 gomp_task_run_pre (struct gomp_task
*child_task
, struct gomp_task
*parent
,
422 struct gomp_taskgroup
*taskgroup
, struct gomp_team
*team
)
424 if (parent
&& parent
->children
== child_task
)
425 parent
->children
= child_task
->next_child
;
426 if (taskgroup
&& taskgroup
->children
== child_task
)
427 taskgroup
->children
= child_task
->next_taskgroup
;
428 child_task
->prev_queue
->next_queue
= child_task
->next_queue
;
429 child_task
->next_queue
->prev_queue
= child_task
->prev_queue
;
430 if (team
->task_queue
== child_task
)
432 if (child_task
->next_queue
!= child_task
)
433 team
->task_queue
= child_task
->next_queue
;
435 team
->task_queue
= NULL
;
437 child_task
->kind
= GOMP_TASK_TIED
;
438 if (--team
->task_queued_count
== 0)
439 gomp_team_barrier_clear_task_pending (&team
->barrier
);
440 if ((gomp_team_barrier_cancelled (&team
->barrier
)
441 || (taskgroup
&& taskgroup
->cancelled
))
442 && !child_task
->copy_ctors_done
)
448 gomp_task_run_post_handle_depend_hash (struct gomp_task
*child_task
)
450 struct gomp_task
*parent
= child_task
->parent
;
453 for (i
= 0; i
< child_task
->depend_count
; i
++)
454 if (!child_task
->depend
[i
].redundant
)
456 if (child_task
->depend
[i
].next
)
457 child_task
->depend
[i
].next
->prev
= child_task
->depend
[i
].prev
;
458 if (child_task
->depend
[i
].prev
)
459 child_task
->depend
[i
].prev
->next
= child_task
->depend
[i
].next
;
462 hash_entry_type
*slot
463 = htab_find_slot (&parent
->depend_hash
, &child_task
->depend
[i
],
465 if (*slot
!= &child_task
->depend
[i
])
467 if (child_task
->depend
[i
].next
)
468 *slot
= child_task
->depend
[i
].next
;
470 htab_clear_slot (parent
->depend_hash
, slot
);
476 gomp_task_run_post_handle_dependers (struct gomp_task
*child_task
,
477 struct gomp_team
*team
)
479 struct gomp_task
*parent
= child_task
->parent
;
480 size_t i
, count
= child_task
->dependers
->n_elem
, ret
= 0;
481 for (i
= 0; i
< count
; i
++)
483 struct gomp_task
*task
= child_task
->dependers
->elem
[i
];
484 if (--task
->num_dependees
!= 0)
487 struct gomp_taskgroup
*taskgroup
= task
->taskgroup
;
490 if (parent
->children
)
492 task
->next_child
= parent
->children
;
493 task
->prev_child
= parent
->children
->prev_child
;
494 task
->next_child
->prev_child
= task
;
495 task
->prev_child
->next_child
= task
;
499 task
->next_child
= task
;
500 task
->prev_child
= task
;
502 parent
->children
= task
;
503 if (parent
->in_taskwait
)
505 parent
->in_taskwait
= false;
506 gomp_sem_post (&parent
->taskwait_sem
);
511 if (taskgroup
->children
)
513 task
->next_taskgroup
= taskgroup
->children
;
514 task
->prev_taskgroup
= taskgroup
->children
->prev_taskgroup
;
515 task
->next_taskgroup
->prev_taskgroup
= task
;
516 task
->prev_taskgroup
->next_taskgroup
= task
;
520 task
->next_taskgroup
= task
;
521 task
->prev_taskgroup
= task
;
523 taskgroup
->children
= task
;
524 if (taskgroup
->in_taskgroup_wait
)
526 taskgroup
->in_taskgroup_wait
= false;
527 gomp_sem_post (&taskgroup
->taskgroup_sem
);
530 if (team
->task_queue
)
532 task
->next_queue
= team
->task_queue
;
533 task
->prev_queue
= team
->task_queue
->prev_queue
;
534 task
->next_queue
->prev_queue
= task
;
535 task
->prev_queue
->next_queue
= task
;
539 task
->next_queue
= task
;
540 task
->prev_queue
= task
;
541 team
->task_queue
= task
;
544 ++team
->task_queued_count
;
547 free (child_task
->dependers
);
548 child_task
->dependers
= NULL
;
550 gomp_team_barrier_set_task_pending (&team
->barrier
);
555 gomp_task_run_post_handle_depend (struct gomp_task
*child_task
,
556 struct gomp_team
*team
)
558 if (child_task
->depend_count
== 0)
561 /* If parent is gone already, the hash table is freed and nothing
562 will use the hash table anymore, no need to remove anything from it. */
563 if (child_task
->parent
!= NULL
)
564 gomp_task_run_post_handle_depend_hash (child_task
);
566 if (child_task
->dependers
== NULL
)
569 return gomp_task_run_post_handle_dependers (child_task
, team
);
573 gomp_task_run_post_remove_parent (struct gomp_task
*child_task
)
575 struct gomp_task
*parent
= child_task
->parent
;
578 child_task
->prev_child
->next_child
= child_task
->next_child
;
579 child_task
->next_child
->prev_child
= child_task
->prev_child
;
580 if (parent
->children
!= child_task
)
582 if (child_task
->next_child
!= child_task
)
583 parent
->children
= child_task
->next_child
;
586 /* We access task->children in GOMP_taskwait
587 outside of the task lock mutex region, so
588 need a release barrier here to ensure memory
589 written by child_task->fn above is flushed
590 before the NULL is written. */
591 __atomic_store_n (&parent
->children
, NULL
, MEMMODEL_RELEASE
);
592 if (parent
->in_taskwait
)
594 parent
->in_taskwait
= false;
595 gomp_sem_post (&parent
->taskwait_sem
);
601 gomp_task_run_post_remove_taskgroup (struct gomp_task
*child_task
)
603 struct gomp_taskgroup
*taskgroup
= child_task
->taskgroup
;
604 if (taskgroup
== NULL
)
606 child_task
->prev_taskgroup
->next_taskgroup
= child_task
->next_taskgroup
;
607 child_task
->next_taskgroup
->prev_taskgroup
= child_task
->prev_taskgroup
;
608 if (taskgroup
->num_children
> 1)
609 --taskgroup
->num_children
;
612 /* We access taskgroup->num_children in GOMP_taskgroup_end
613 outside of the task lock mutex region, so
614 need a release barrier here to ensure memory
615 written by child_task->fn above is flushed
616 before the NULL is written. */
617 __atomic_store_n (&taskgroup
->num_children
, 0, MEMMODEL_RELEASE
);
619 if (taskgroup
->children
!= child_task
)
621 if (child_task
->next_taskgroup
!= child_task
)
622 taskgroup
->children
= child_task
->next_taskgroup
;
625 taskgroup
->children
= NULL
;
626 if (taskgroup
->in_taskgroup_wait
)
628 taskgroup
->in_taskgroup_wait
= false;
629 gomp_sem_post (&taskgroup
->taskgroup_sem
);
635 gomp_barrier_handle_tasks (gomp_barrier_state_t state
)
637 struct gomp_thread
*thr
= gomp_thread ();
638 struct gomp_team
*team
= thr
->ts
.team
;
639 struct gomp_task
*task
= thr
->task
;
640 struct gomp_task
*child_task
= NULL
;
641 struct gomp_task
*to_free
= NULL
;
644 gomp_mutex_lock (&team
->task_lock
);
645 if (gomp_barrier_last_thread (state
))
647 if (team
->task_count
== 0)
649 gomp_team_barrier_done (&team
->barrier
, state
);
650 gomp_mutex_unlock (&team
->task_lock
);
651 gomp_team_barrier_wake (&team
->barrier
, 0);
654 gomp_team_barrier_set_waiting_for_tasks (&team
->barrier
);
659 bool cancelled
= false;
660 if (team
->task_queue
!= NULL
)
662 child_task
= team
->task_queue
;
663 cancelled
= gomp_task_run_pre (child_task
, child_task
->parent
,
664 child_task
->taskgroup
, team
);
665 if (__builtin_expect (cancelled
, 0))
669 gomp_finish_task (to_free
);
673 goto finish_cancelled
;
675 team
->task_running_count
++;
676 child_task
->in_tied_task
= true;
678 gomp_mutex_unlock (&team
->task_lock
);
681 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
686 gomp_finish_task (to_free
);
692 thr
->task
= child_task
;
693 child_task
->fn (child_task
->fn_data
);
698 gomp_mutex_lock (&team
->task_lock
);
703 = gomp_task_run_post_handle_depend (child_task
, team
);
704 gomp_task_run_post_remove_parent (child_task
);
705 gomp_clear_parent (child_task
->children
);
706 gomp_task_run_post_remove_taskgroup (child_task
);
707 to_free
= child_task
;
710 team
->task_running_count
--;
713 do_wake
= team
->nthreads
- team
->task_running_count
;
714 if (do_wake
> new_tasks
)
717 if (--team
->task_count
== 0
718 && gomp_team_barrier_waiting_for_tasks (&team
->barrier
))
720 gomp_team_barrier_done (&team
->barrier
, state
);
721 gomp_mutex_unlock (&team
->task_lock
);
722 gomp_team_barrier_wake (&team
->barrier
, 0);
723 gomp_mutex_lock (&team
->task_lock
);
729 /* Called when encountering a taskwait directive. */
734 struct gomp_thread
*thr
= gomp_thread ();
735 struct gomp_team
*team
= thr
->ts
.team
;
736 struct gomp_task
*task
= thr
->task
;
737 struct gomp_task
*child_task
= NULL
;
738 struct gomp_task
*to_free
= NULL
;
741 /* The acquire barrier on load of task->children here synchronizes
742 with the write of a NULL in gomp_task_run_post_remove_parent. It is
743 not necessary that we synchronize with other non-NULL writes at
744 this point, but we must ensure that all writes to memory by a
745 child thread task work function are seen before we exit from
748 || __atomic_load_n (&task
->children
, MEMMODEL_ACQUIRE
) == NULL
)
751 gomp_mutex_lock (&team
->task_lock
);
754 bool cancelled
= false;
755 if (task
->children
== NULL
)
757 gomp_mutex_unlock (&team
->task_lock
);
760 gomp_finish_task (to_free
);
765 if (task
->children
->kind
== GOMP_TASK_WAITING
)
767 child_task
= task
->children
;
769 = gomp_task_run_pre (child_task
, task
, child_task
->taskgroup
,
771 if (__builtin_expect (cancelled
, 0))
775 gomp_finish_task (to_free
);
779 goto finish_cancelled
;
783 /* All tasks we are waiting for are already running
784 in other threads. Wait for them. */
785 task
->in_taskwait
= true;
786 gomp_mutex_unlock (&team
->task_lock
);
789 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
794 gomp_finish_task (to_free
);
800 thr
->task
= child_task
;
801 child_task
->fn (child_task
->fn_data
);
805 gomp_sem_wait (&task
->taskwait_sem
);
806 gomp_mutex_lock (&team
->task_lock
);
811 = gomp_task_run_post_handle_depend (child_task
, team
);
812 child_task
->prev_child
->next_child
= child_task
->next_child
;
813 child_task
->next_child
->prev_child
= child_task
->prev_child
;
814 if (task
->children
== child_task
)
816 if (child_task
->next_child
!= child_task
)
817 task
->children
= child_task
->next_child
;
819 task
->children
= NULL
;
821 gomp_clear_parent (child_task
->children
);
822 gomp_task_run_post_remove_taskgroup (child_task
);
823 to_free
= child_task
;
828 do_wake
= team
->nthreads
- team
->task_running_count
829 - !task
->in_tied_task
;
830 if (do_wake
> new_tasks
)
837 /* Called when encountering a taskyield directive. */
840 GOMP_taskyield (void)
842 /* Nothing at the moment. */
846 GOMP_taskgroup_start (void)
848 struct gomp_thread
*thr
= gomp_thread ();
849 struct gomp_team
*team
= thr
->ts
.team
;
850 struct gomp_task
*task
= thr
->task
;
851 struct gomp_taskgroup
*taskgroup
;
853 /* If team is NULL, all tasks are executed as
854 GOMP_TASK_IFFALSE tasks and thus all children tasks of
855 taskgroup and their descendant tasks will be finished
856 by the time GOMP_taskgroup_end is called. */
859 taskgroup
= gomp_malloc (sizeof (struct gomp_taskgroup
));
860 taskgroup
->prev
= task
->taskgroup
;
861 taskgroup
->children
= NULL
;
862 taskgroup
->in_taskgroup_wait
= false;
863 taskgroup
->cancelled
= false;
864 taskgroup
->num_children
= 0;
865 gomp_sem_init (&taskgroup
->taskgroup_sem
, 0);
866 task
->taskgroup
= taskgroup
;
870 GOMP_taskgroup_end (void)
872 struct gomp_thread
*thr
= gomp_thread ();
873 struct gomp_team
*team
= thr
->ts
.team
;
874 struct gomp_task
*task
= thr
->task
;
875 struct gomp_taskgroup
*taskgroup
;
876 struct gomp_task
*child_task
= NULL
;
877 struct gomp_task
*to_free
= NULL
;
882 taskgroup
= task
->taskgroup
;
884 /* The acquire barrier on load of taskgroup->num_children here
885 synchronizes with the write of 0 in gomp_task_run_post_remove_taskgroup.
886 It is not necessary that we synchronize with other non-0 writes at
887 this point, but we must ensure that all writes to memory by a
888 child thread task work function are seen before we exit from
889 GOMP_taskgroup_end. */
890 if (__atomic_load_n (&taskgroup
->num_children
, MEMMODEL_ACQUIRE
) == 0)
893 gomp_mutex_lock (&team
->task_lock
);
896 bool cancelled
= false;
897 if (taskgroup
->children
== NULL
)
899 if (taskgroup
->num_children
)
901 gomp_mutex_unlock (&team
->task_lock
);
904 gomp_finish_task (to_free
);
909 if (taskgroup
->children
->kind
== GOMP_TASK_WAITING
)
911 child_task
= taskgroup
->children
;
913 = gomp_task_run_pre (child_task
, child_task
->parent
, taskgroup
,
915 if (__builtin_expect (cancelled
, 0))
919 gomp_finish_task (to_free
);
923 goto finish_cancelled
;
929 /* All tasks we are waiting for are already running
930 in other threads. Wait for them. */
931 taskgroup
->in_taskgroup_wait
= true;
933 gomp_mutex_unlock (&team
->task_lock
);
936 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
941 gomp_finish_task (to_free
);
947 thr
->task
= child_task
;
948 child_task
->fn (child_task
->fn_data
);
952 gomp_sem_wait (&taskgroup
->taskgroup_sem
);
953 gomp_mutex_lock (&team
->task_lock
);
958 = gomp_task_run_post_handle_depend (child_task
, team
);
959 child_task
->prev_taskgroup
->next_taskgroup
960 = child_task
->next_taskgroup
;
961 child_task
->next_taskgroup
->prev_taskgroup
962 = child_task
->prev_taskgroup
;
963 --taskgroup
->num_children
;
964 if (taskgroup
->children
== child_task
)
966 if (child_task
->next_taskgroup
!= child_task
)
967 taskgroup
->children
= child_task
->next_taskgroup
;
969 taskgroup
->children
= NULL
;
971 gomp_task_run_post_remove_parent (child_task
);
972 gomp_clear_parent (child_task
->children
);
973 to_free
= child_task
;
978 do_wake
= team
->nthreads
- team
->task_running_count
979 - !task
->in_tied_task
;
980 if (do_wake
> new_tasks
)
987 task
->taskgroup
= taskgroup
->prev
;
988 gomp_sem_destroy (&taskgroup
->taskgroup_sem
);
995 struct gomp_thread
*thr
= gomp_thread ();
996 return thr
->task
&& thr
->task
->final_task
;
999 ialias (omp_in_final
)