1 /* Copyright (C) 2007-2015 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
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)
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
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. */
33 typedef struct gomp_task_depend_entry
*hash_entry_type
;
36 htab_alloc (size_t size
)
38 return gomp_malloc (size
);
49 static inline hashval_t
50 htab_hash (hash_entry_type element
)
52 return hash_pointer (element
->addr
);
56 htab_eq (hash_entry_type x
, hash_entry_type y
)
58 return x
->addr
== y
->addr
;
61 /* Create a new task data structure. */
64 gomp_init_task (struct gomp_task
*task
, struct gomp_task
*parent_task
,
65 struct gomp_task_icv
*prev_icv
)
67 task
->parent
= parent_task
;
68 task
->icv
= *prev_icv
;
69 task
->kind
= GOMP_TASK_IMPLICIT
;
70 task
->taskwait
= NULL
;
71 task
->in_tied_task
= false;
72 task
->final_task
= false;
73 task
->copy_ctors_done
= false;
74 task
->parent_depends_on
= false;
75 task
->children
= NULL
;
76 task
->taskgroup
= NULL
;
77 task
->dependers
= NULL
;
78 task
->depend_hash
= NULL
;
79 task
->depend_count
= 0;
82 /* Clean up a task, after completing it. */
87 struct gomp_thread
*thr
= gomp_thread ();
88 struct gomp_task
*task
= thr
->task
;
90 gomp_finish_task (task
);
91 thr
->task
= task
->parent
;
95 gomp_clear_parent (struct gomp_task
*children
)
97 struct gomp_task
*task
= children
;
103 task
= task
->next_child
;
105 while (task
!= children
);
108 static void gomp_task_maybe_wait_for_dependencies (void **depend
);
110 /* Called when encountering an explicit task directive. If IF_CLAUSE is
111 false, then we must not delay in executing the task. If UNTIED is true,
112 then the task may be executed by any member of the team. */
115 GOMP_task (void (*fn
) (void *), void *data
, void (*cpyfn
) (void *, void *),
116 long arg_size
, long arg_align
, bool if_clause
, unsigned flags
,
119 struct gomp_thread
*thr
= gomp_thread ();
120 struct gomp_team
*team
= thr
->ts
.team
;
122 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
123 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
124 tied to one thread all the time. This means UNTIED tasks must be
125 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
126 might be running on different thread than FN. */
133 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
135 && (gomp_team_barrier_cancelled (&team
->barrier
)
136 || (thr
->task
->taskgroup
&& thr
->task
->taskgroup
->cancelled
)))
139 if (!if_clause
|| team
== NULL
140 || (thr
->task
&& thr
->task
->final_task
)
141 || team
->task_count
> 64 * team
->nthreads
)
143 struct gomp_task task
;
145 /* If there are depend clauses and earlier deferred sibling tasks
146 with depend clauses, check if there isn't a dependency. If there
147 is, we need to wait for them. There is no need to handle
148 depend clauses for non-deferred tasks other than this, because
149 the parent task is suspended until the child task finishes and thus
150 it can't start further child tasks. */
151 if ((flags
& 8) && thr
->task
&& thr
->task
->depend_hash
)
152 gomp_task_maybe_wait_for_dependencies (depend
);
154 gomp_init_task (&task
, thr
->task
, gomp_icv (false));
155 task
.kind
= GOMP_TASK_IFFALSE
;
156 task
.final_task
= (thr
->task
&& thr
->task
->final_task
) || (flags
& 2);
159 task
.in_tied_task
= thr
->task
->in_tied_task
;
160 task
.taskgroup
= thr
->task
->taskgroup
;
163 if (__builtin_expect (cpyfn
!= NULL
, 0))
165 char buf
[arg_size
+ arg_align
- 1];
166 char *arg
= (char *) (((uintptr_t) buf
+ arg_align
- 1)
167 & ~(uintptr_t) (arg_align
- 1));
173 /* Access to "children" is normally done inside a task_lock
174 mutex region, but the only way this particular task.children
175 can be set is if this thread's task work function (fn)
176 creates children. So since the setter is *this* thread, we
177 need no barriers here when testing for non-NULL. We can have
178 task.children set by the current thread then changed by a
179 child thread, but seeing a stale non-NULL value is not a
180 problem. Once past the task_lock acquisition, this thread
181 will see the real value of task.children. */
182 if (task
.children
!= NULL
)
184 gomp_mutex_lock (&team
->task_lock
);
185 gomp_clear_parent (task
.children
);
186 gomp_mutex_unlock (&team
->task_lock
);
192 struct gomp_task
*task
;
193 struct gomp_task
*parent
= thr
->task
;
194 struct gomp_taskgroup
*taskgroup
= parent
->taskgroup
;
197 size_t depend_size
= 0;
200 depend_size
= ((uintptr_t) depend
[0]
201 * sizeof (struct gomp_task_depend_entry
));
202 task
= gomp_malloc (sizeof (*task
) + depend_size
203 + arg_size
+ arg_align
- 1);
204 arg
= (char *) (((uintptr_t) (task
+ 1) + depend_size
+ arg_align
- 1)
205 & ~(uintptr_t) (arg_align
- 1));
206 gomp_init_task (task
, parent
, gomp_icv (false));
207 task
->kind
= GOMP_TASK_IFFALSE
;
208 task
->in_tied_task
= parent
->in_tied_task
;
209 task
->taskgroup
= taskgroup
;
214 task
->copy_ctors_done
= true;
217 memcpy (arg
, data
, arg_size
);
219 task
->kind
= GOMP_TASK_WAITING
;
222 task
->final_task
= (flags
& 2) >> 1;
223 gomp_mutex_lock (&team
->task_lock
);
224 /* If parallel or taskgroup has been cancelled, don't start new
226 if (__builtin_expect ((gomp_team_barrier_cancelled (&team
->barrier
)
227 || (taskgroup
&& taskgroup
->cancelled
))
228 && !task
->copy_ctors_done
, 0))
230 gomp_mutex_unlock (&team
->task_lock
);
231 gomp_finish_task (task
);
236 taskgroup
->num_children
++;
239 size_t ndepend
= (uintptr_t) depend
[0];
240 size_t nout
= (uintptr_t) depend
[1];
244 task
->depend_count
= ndepend
;
245 task
->num_dependees
= 0;
246 if (parent
->depend_hash
== NULL
)
248 = htab_create (2 * ndepend
> 12 ? 2 * ndepend
: 12);
249 for (i
= 0; i
< ndepend
; i
++)
251 task
->depend
[i
].addr
= depend
[2 + i
];
252 task
->depend
[i
].next
= NULL
;
253 task
->depend
[i
].prev
= NULL
;
254 task
->depend
[i
].task
= task
;
255 task
->depend
[i
].is_in
= i
>= nout
;
256 task
->depend
[i
].redundant
= false;
257 task
->depend
[i
].redundant_out
= false;
259 hash_entry_type
*slot
260 = htab_find_slot (&parent
->depend_hash
, &task
->depend
[i
],
262 hash_entry_type out
= NULL
, last
= NULL
;
265 /* If multiple depends on the same task are the
266 same, all but the first one are redundant.
267 As inout/out come first, if any of them is
268 inout/out, it will win, which is the right
270 if ((*slot
)->task
== task
)
272 task
->depend
[i
].redundant
= true;
275 for (ent
= *slot
; ent
; ent
= ent
->next
)
277 if (ent
->redundant_out
)
282 /* depend(in:...) doesn't depend on earlier
284 if (i
>= nout
&& ent
->is_in
)
290 struct gomp_task
*tsk
= ent
->task
;
291 if (tsk
->dependers
== NULL
)
294 = gomp_malloc (sizeof (struct gomp_dependers_vec
)
295 + 6 * sizeof (struct gomp_task
*));
296 tsk
->dependers
->n_elem
= 1;
297 tsk
->dependers
->allocated
= 6;
298 tsk
->dependers
->elem
[0] = task
;
299 task
->num_dependees
++;
302 /* We already have some other dependency on tsk
303 from earlier depend clause. */
304 else if (tsk
->dependers
->n_elem
305 && (tsk
->dependers
->elem
[tsk
->dependers
->n_elem
309 else if (tsk
->dependers
->n_elem
310 == tsk
->dependers
->allocated
)
312 tsk
->dependers
->allocated
313 = tsk
->dependers
->allocated
* 2 + 2;
315 = gomp_realloc (tsk
->dependers
,
316 sizeof (struct gomp_dependers_vec
)
317 + (tsk
->dependers
->allocated
318 * sizeof (struct gomp_task
*)));
320 tsk
->dependers
->elem
[tsk
->dependers
->n_elem
++] = task
;
321 task
->num_dependees
++;
323 task
->depend
[i
].next
= *slot
;
324 (*slot
)->prev
= &task
->depend
[i
];
326 *slot
= &task
->depend
[i
];
328 /* There is no need to store more than one depend({,in}out:)
329 task per address in the hash table chain for the purpose
330 of creation of deferred tasks, because each out
331 depends on all earlier outs, thus it is enough to record
332 just the last depend({,in}out:). For depend(in:), we need
333 to keep all of the previous ones not terminated yet, because
334 a later depend({,in}out:) might need to depend on all of
335 them. So, if the new task's clause is depend({,in}out:),
336 we know there is at most one other depend({,in}out:) clause
337 in the list (out). For non-deferred tasks we want to see
338 all outs, so they are moved to the end of the chain,
339 after first redundant_out entry all following entries
340 should be redundant_out. */
341 if (!task
->depend
[i
].is_in
&& out
)
345 out
->next
->prev
= out
->prev
;
346 out
->prev
->next
= out
->next
;
347 out
->next
= last
->next
;
351 out
->next
->prev
= out
;
353 out
->redundant_out
= true;
356 if (task
->num_dependees
)
358 gomp_mutex_unlock (&team
->task_lock
);
362 if (parent
->children
)
364 task
->next_child
= parent
->children
;
365 task
->prev_child
= parent
->children
->prev_child
;
366 task
->next_child
->prev_child
= task
;
367 task
->prev_child
->next_child
= task
;
371 task
->next_child
= task
;
372 task
->prev_child
= task
;
374 parent
->children
= task
;
377 if (taskgroup
->children
)
379 task
->next_taskgroup
= taskgroup
->children
;
380 task
->prev_taskgroup
= taskgroup
->children
->prev_taskgroup
;
381 task
->next_taskgroup
->prev_taskgroup
= task
;
382 task
->prev_taskgroup
->next_taskgroup
= task
;
386 task
->next_taskgroup
= task
;
387 task
->prev_taskgroup
= task
;
389 taskgroup
->children
= task
;
391 if (team
->task_queue
)
393 task
->next_queue
= team
->task_queue
;
394 task
->prev_queue
= team
->task_queue
->prev_queue
;
395 task
->next_queue
->prev_queue
= task
;
396 task
->prev_queue
->next_queue
= task
;
400 task
->next_queue
= task
;
401 task
->prev_queue
= task
;
402 team
->task_queue
= task
;
405 ++team
->task_queued_count
;
406 gomp_team_barrier_set_task_pending (&team
->barrier
);
407 do_wake
= team
->task_running_count
+ !parent
->in_tied_task
409 gomp_mutex_unlock (&team
->task_lock
);
411 gomp_team_barrier_wake (&team
->barrier
, 1);
416 gomp_task_run_pre (struct gomp_task
*child_task
, struct gomp_task
*parent
,
417 struct gomp_taskgroup
*taskgroup
, struct gomp_team
*team
)
421 if (parent
->children
== child_task
)
422 parent
->children
= child_task
->next_child
;
423 if (__builtin_expect (child_task
->parent_depends_on
, 0)
424 && parent
->taskwait
->last_parent_depends_on
== child_task
)
426 if (child_task
->prev_child
->kind
== GOMP_TASK_WAITING
427 && child_task
->prev_child
->parent_depends_on
)
428 parent
->taskwait
->last_parent_depends_on
= child_task
->prev_child
;
430 parent
->taskwait
->last_parent_depends_on
= NULL
;
433 if (taskgroup
&& taskgroup
->children
== child_task
)
434 taskgroup
->children
= child_task
->next_taskgroup
;
435 child_task
->prev_queue
->next_queue
= child_task
->next_queue
;
436 child_task
->next_queue
->prev_queue
= child_task
->prev_queue
;
437 if (team
->task_queue
== child_task
)
439 if (child_task
->next_queue
!= child_task
)
440 team
->task_queue
= child_task
->next_queue
;
442 team
->task_queue
= NULL
;
444 child_task
->kind
= GOMP_TASK_TIED
;
445 if (--team
->task_queued_count
== 0)
446 gomp_team_barrier_clear_task_pending (&team
->barrier
);
447 if ((gomp_team_barrier_cancelled (&team
->barrier
)
448 || (taskgroup
&& taskgroup
->cancelled
))
449 && !child_task
->copy_ctors_done
)
455 gomp_task_run_post_handle_depend_hash (struct gomp_task
*child_task
)
457 struct gomp_task
*parent
= child_task
->parent
;
460 for (i
= 0; i
< child_task
->depend_count
; i
++)
461 if (!child_task
->depend
[i
].redundant
)
463 if (child_task
->depend
[i
].next
)
464 child_task
->depend
[i
].next
->prev
= child_task
->depend
[i
].prev
;
465 if (child_task
->depend
[i
].prev
)
466 child_task
->depend
[i
].prev
->next
= child_task
->depend
[i
].next
;
469 hash_entry_type
*slot
470 = htab_find_slot (&parent
->depend_hash
, &child_task
->depend
[i
],
472 if (*slot
!= &child_task
->depend
[i
])
474 if (child_task
->depend
[i
].next
)
475 *slot
= child_task
->depend
[i
].next
;
477 htab_clear_slot (parent
->depend_hash
, slot
);
483 gomp_task_run_post_handle_dependers (struct gomp_task
*child_task
,
484 struct gomp_team
*team
)
486 struct gomp_task
*parent
= child_task
->parent
;
487 size_t i
, count
= child_task
->dependers
->n_elem
, ret
= 0;
488 for (i
= 0; i
< count
; i
++)
490 struct gomp_task
*task
= child_task
->dependers
->elem
[i
];
491 if (--task
->num_dependees
!= 0)
494 struct gomp_taskgroup
*taskgroup
= task
->taskgroup
;
497 if (parent
->children
)
499 /* If parent is in gomp_task_maybe_wait_for_dependencies
500 and it doesn't need to wait for this task, put it after
501 all ready to run tasks it needs to wait for. */
502 if (parent
->taskwait
&& parent
->taskwait
->last_parent_depends_on
503 && !task
->parent_depends_on
)
505 struct gomp_task
*last_parent_depends_on
506 = parent
->taskwait
->last_parent_depends_on
;
507 task
->next_child
= last_parent_depends_on
->next_child
;
508 task
->prev_child
= last_parent_depends_on
;
512 task
->next_child
= parent
->children
;
513 task
->prev_child
= parent
->children
->prev_child
;
514 parent
->children
= task
;
516 task
->next_child
->prev_child
= task
;
517 task
->prev_child
->next_child
= task
;
521 task
->next_child
= task
;
522 task
->prev_child
= task
;
523 parent
->children
= task
;
525 if (parent
->taskwait
)
527 if (parent
->taskwait
->in_taskwait
)
529 parent
->taskwait
->in_taskwait
= false;
530 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
532 else if (parent
->taskwait
->in_depend_wait
)
534 parent
->taskwait
->in_depend_wait
= false;
535 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
537 if (parent
->taskwait
->last_parent_depends_on
== NULL
538 && task
->parent_depends_on
)
539 parent
->taskwait
->last_parent_depends_on
= task
;
544 if (taskgroup
->children
)
546 task
->next_taskgroup
= taskgroup
->children
;
547 task
->prev_taskgroup
= taskgroup
->children
->prev_taskgroup
;
548 task
->next_taskgroup
->prev_taskgroup
= task
;
549 task
->prev_taskgroup
->next_taskgroup
= task
;
553 task
->next_taskgroup
= task
;
554 task
->prev_taskgroup
= task
;
556 taskgroup
->children
= task
;
557 if (taskgroup
->in_taskgroup_wait
)
559 taskgroup
->in_taskgroup_wait
= false;
560 gomp_sem_post (&taskgroup
->taskgroup_sem
);
563 if (team
->task_queue
)
565 task
->next_queue
= team
->task_queue
;
566 task
->prev_queue
= team
->task_queue
->prev_queue
;
567 task
->next_queue
->prev_queue
= task
;
568 task
->prev_queue
->next_queue
= task
;
572 task
->next_queue
= task
;
573 task
->prev_queue
= task
;
574 team
->task_queue
= task
;
577 ++team
->task_queued_count
;
580 free (child_task
->dependers
);
581 child_task
->dependers
= NULL
;
583 gomp_team_barrier_set_task_pending (&team
->barrier
);
588 gomp_task_run_post_handle_depend (struct gomp_task
*child_task
,
589 struct gomp_team
*team
)
591 if (child_task
->depend_count
== 0)
594 /* If parent is gone already, the hash table is freed and nothing
595 will use the hash table anymore, no need to remove anything from it. */
596 if (child_task
->parent
!= NULL
)
597 gomp_task_run_post_handle_depend_hash (child_task
);
599 if (child_task
->dependers
== NULL
)
602 return gomp_task_run_post_handle_dependers (child_task
, team
);
606 gomp_task_run_post_remove_parent (struct gomp_task
*child_task
)
608 struct gomp_task
*parent
= child_task
->parent
;
611 if (__builtin_expect (child_task
->parent_depends_on
, 0)
612 && --parent
->taskwait
->n_depend
== 0
613 && parent
->taskwait
->in_depend_wait
)
615 parent
->taskwait
->in_depend_wait
= false;
616 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
618 child_task
->prev_child
->next_child
= child_task
->next_child
;
619 child_task
->next_child
->prev_child
= child_task
->prev_child
;
620 if (parent
->children
!= child_task
)
622 if (child_task
->next_child
!= child_task
)
623 parent
->children
= child_task
->next_child
;
626 /* We access task->children in GOMP_taskwait
627 outside of the task lock mutex region, so
628 need a release barrier here to ensure memory
629 written by child_task->fn above is flushed
630 before the NULL is written. */
631 __atomic_store_n (&parent
->children
, NULL
, MEMMODEL_RELEASE
);
632 if (parent
->taskwait
&& parent
->taskwait
->in_taskwait
)
634 parent
->taskwait
->in_taskwait
= false;
635 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
641 gomp_task_run_post_remove_taskgroup (struct gomp_task
*child_task
)
643 struct gomp_taskgroup
*taskgroup
= child_task
->taskgroup
;
644 if (taskgroup
== NULL
)
646 child_task
->prev_taskgroup
->next_taskgroup
= child_task
->next_taskgroup
;
647 child_task
->next_taskgroup
->prev_taskgroup
= child_task
->prev_taskgroup
;
648 if (taskgroup
->num_children
> 1)
649 --taskgroup
->num_children
;
652 /* We access taskgroup->num_children in GOMP_taskgroup_end
653 outside of the task lock mutex region, so
654 need a release barrier here to ensure memory
655 written by child_task->fn above is flushed
656 before the NULL is written. */
657 __atomic_store_n (&taskgroup
->num_children
, 0, MEMMODEL_RELEASE
);
659 if (taskgroup
->children
!= child_task
)
661 if (child_task
->next_taskgroup
!= child_task
)
662 taskgroup
->children
= child_task
->next_taskgroup
;
665 taskgroup
->children
= NULL
;
666 if (taskgroup
->in_taskgroup_wait
)
668 taskgroup
->in_taskgroup_wait
= false;
669 gomp_sem_post (&taskgroup
->taskgroup_sem
);
675 gomp_barrier_handle_tasks (gomp_barrier_state_t state
)
677 struct gomp_thread
*thr
= gomp_thread ();
678 struct gomp_team
*team
= thr
->ts
.team
;
679 struct gomp_task
*task
= thr
->task
;
680 struct gomp_task
*child_task
= NULL
;
681 struct gomp_task
*to_free
= NULL
;
684 gomp_mutex_lock (&team
->task_lock
);
685 if (gomp_barrier_last_thread (state
))
687 if (team
->task_count
== 0)
689 gomp_team_barrier_done (&team
->barrier
, state
);
690 gomp_mutex_unlock (&team
->task_lock
);
691 gomp_team_barrier_wake (&team
->barrier
, 0);
694 gomp_team_barrier_set_waiting_for_tasks (&team
->barrier
);
699 bool cancelled
= false;
700 if (team
->task_queue
!= NULL
)
702 child_task
= team
->task_queue
;
703 cancelled
= gomp_task_run_pre (child_task
, child_task
->parent
,
704 child_task
->taskgroup
, team
);
705 if (__builtin_expect (cancelled
, 0))
709 gomp_finish_task (to_free
);
713 goto finish_cancelled
;
715 team
->task_running_count
++;
716 child_task
->in_tied_task
= true;
718 gomp_mutex_unlock (&team
->task_lock
);
721 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
726 gomp_finish_task (to_free
);
732 thr
->task
= child_task
;
733 child_task
->fn (child_task
->fn_data
);
738 gomp_mutex_lock (&team
->task_lock
);
743 = gomp_task_run_post_handle_depend (child_task
, team
);
744 gomp_task_run_post_remove_parent (child_task
);
745 gomp_clear_parent (child_task
->children
);
746 gomp_task_run_post_remove_taskgroup (child_task
);
747 to_free
= child_task
;
750 team
->task_running_count
--;
753 do_wake
= team
->nthreads
- team
->task_running_count
;
754 if (do_wake
> new_tasks
)
757 if (--team
->task_count
== 0
758 && gomp_team_barrier_waiting_for_tasks (&team
->barrier
))
760 gomp_team_barrier_done (&team
->barrier
, state
);
761 gomp_mutex_unlock (&team
->task_lock
);
762 gomp_team_barrier_wake (&team
->barrier
, 0);
763 gomp_mutex_lock (&team
->task_lock
);
769 /* Called when encountering a taskwait directive. */
774 struct gomp_thread
*thr
= gomp_thread ();
775 struct gomp_team
*team
= thr
->ts
.team
;
776 struct gomp_task
*task
= thr
->task
;
777 struct gomp_task
*child_task
= NULL
;
778 struct gomp_task
*to_free
= NULL
;
779 struct gomp_taskwait taskwait
;
782 /* The acquire barrier on load of task->children here synchronizes
783 with the write of a NULL in gomp_task_run_post_remove_parent. It is
784 not necessary that we synchronize with other non-NULL writes at
785 this point, but we must ensure that all writes to memory by a
786 child thread task work function are seen before we exit from
789 || __atomic_load_n (&task
->children
, MEMMODEL_ACQUIRE
) == NULL
)
792 memset (&taskwait
, 0, sizeof (taskwait
));
793 gomp_mutex_lock (&team
->task_lock
);
796 bool cancelled
= false;
797 if (task
->children
== NULL
)
799 bool destroy_taskwait
= task
->taskwait
!= NULL
;
800 task
->taskwait
= NULL
;
801 gomp_mutex_unlock (&team
->task_lock
);
804 gomp_finish_task (to_free
);
807 if (destroy_taskwait
)
808 gomp_sem_destroy (&taskwait
.taskwait_sem
);
811 if (task
->children
->kind
== GOMP_TASK_WAITING
)
813 child_task
= task
->children
;
815 = gomp_task_run_pre (child_task
, task
, child_task
->taskgroup
,
817 if (__builtin_expect (cancelled
, 0))
821 gomp_finish_task (to_free
);
825 goto finish_cancelled
;
830 /* All tasks we are waiting for are already running
831 in other threads. Wait for them. */
832 if (task
->taskwait
== NULL
)
834 taskwait
.in_depend_wait
= false;
835 gomp_sem_init (&taskwait
.taskwait_sem
, 0);
836 task
->taskwait
= &taskwait
;
838 taskwait
.in_taskwait
= true;
840 gomp_mutex_unlock (&team
->task_lock
);
843 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
848 gomp_finish_task (to_free
);
854 thr
->task
= child_task
;
855 child_task
->fn (child_task
->fn_data
);
859 gomp_sem_wait (&taskwait
.taskwait_sem
);
860 gomp_mutex_lock (&team
->task_lock
);
865 = gomp_task_run_post_handle_depend (child_task
, team
);
866 child_task
->prev_child
->next_child
= child_task
->next_child
;
867 child_task
->next_child
->prev_child
= child_task
->prev_child
;
868 if (task
->children
== child_task
)
870 if (child_task
->next_child
!= child_task
)
871 task
->children
= child_task
->next_child
;
873 task
->children
= NULL
;
875 gomp_clear_parent (child_task
->children
);
876 gomp_task_run_post_remove_taskgroup (child_task
);
877 to_free
= child_task
;
882 do_wake
= team
->nthreads
- team
->task_running_count
883 - !task
->in_tied_task
;
884 if (do_wake
> new_tasks
)
891 /* This is like GOMP_taskwait, but we only wait for tasks that the
892 upcoming task depends on. */
895 gomp_task_maybe_wait_for_dependencies (void **depend
)
897 struct gomp_thread
*thr
= gomp_thread ();
898 struct gomp_task
*task
= thr
->task
;
899 struct gomp_team
*team
= thr
->ts
.team
;
900 struct gomp_task_depend_entry elem
, *ent
= NULL
;
901 struct gomp_taskwait taskwait
;
902 struct gomp_task
*last_parent_depends_on
= NULL
;
903 size_t ndepend
= (uintptr_t) depend
[0];
904 size_t nout
= (uintptr_t) depend
[1];
906 size_t num_awaited
= 0;
907 struct gomp_task
*child_task
= NULL
;
908 struct gomp_task
*to_free
= NULL
;
911 gomp_mutex_lock (&team
->task_lock
);
912 for (i
= 0; i
< ndepend
; i
++)
914 elem
.addr
= depend
[i
+ 2];
915 ent
= htab_find (task
->depend_hash
, &elem
);
916 for (; ent
; ent
= ent
->next
)
917 if (i
>= nout
&& ent
->is_in
)
921 struct gomp_task
*tsk
= ent
->task
;
922 if (!tsk
->parent_depends_on
)
924 tsk
->parent_depends_on
= true;
926 if (tsk
->num_dependees
== 0 && tsk
->kind
== GOMP_TASK_WAITING
)
928 /* If a task we need to wait for is not already
929 running and is ready to be scheduled, move it
930 to front, so that we run it as soon as possible. */
931 if (last_parent_depends_on
)
933 tsk
->prev_child
->next_child
= tsk
->next_child
;
934 tsk
->next_child
->prev_child
= tsk
->prev_child
;
935 tsk
->prev_child
= last_parent_depends_on
;
936 tsk
->next_child
= last_parent_depends_on
->next_child
;
937 tsk
->prev_child
->next_child
= tsk
;
938 tsk
->next_child
->prev_child
= tsk
;
940 else if (tsk
!= task
->children
)
942 tsk
->prev_child
->next_child
= tsk
->next_child
;
943 tsk
->next_child
->prev_child
= tsk
->prev_child
;
944 tsk
->prev_child
= task
->children
;
945 tsk
->next_child
= task
->children
->next_child
;
946 task
->children
= tsk
;
947 tsk
->prev_child
->next_child
= tsk
;
948 tsk
->next_child
->prev_child
= tsk
;
950 last_parent_depends_on
= tsk
;
955 if (num_awaited
== 0)
957 gomp_mutex_unlock (&team
->task_lock
);
961 memset (&taskwait
, 0, sizeof (taskwait
));
962 taskwait
.n_depend
= num_awaited
;
963 taskwait
.last_parent_depends_on
= last_parent_depends_on
;
964 gomp_sem_init (&taskwait
.taskwait_sem
, 0);
965 task
->taskwait
= &taskwait
;
969 bool cancelled
= false;
970 if (taskwait
.n_depend
== 0)
972 task
->taskwait
= NULL
;
973 gomp_mutex_unlock (&team
->task_lock
);
976 gomp_finish_task (to_free
);
979 gomp_sem_destroy (&taskwait
.taskwait_sem
);
982 if (task
->children
->kind
== GOMP_TASK_WAITING
)
984 child_task
= task
->children
;
986 = gomp_task_run_pre (child_task
, task
, child_task
->taskgroup
,
988 if (__builtin_expect (cancelled
, 0))
992 gomp_finish_task (to_free
);
996 goto finish_cancelled
;
1000 /* All tasks we are waiting for are already running
1001 in other threads. Wait for them. */
1002 taskwait
.in_depend_wait
= true;
1003 gomp_mutex_unlock (&team
->task_lock
);
1006 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
1011 gomp_finish_task (to_free
);
1017 thr
->task
= child_task
;
1018 child_task
->fn (child_task
->fn_data
);
1022 gomp_sem_wait (&taskwait
.taskwait_sem
);
1023 gomp_mutex_lock (&team
->task_lock
);
1028 = gomp_task_run_post_handle_depend (child_task
, team
);
1029 if (child_task
->parent_depends_on
)
1030 --taskwait
.n_depend
;
1031 child_task
->prev_child
->next_child
= child_task
->next_child
;
1032 child_task
->next_child
->prev_child
= child_task
->prev_child
;
1033 if (task
->children
== child_task
)
1035 if (child_task
->next_child
!= child_task
)
1036 task
->children
= child_task
->next_child
;
1038 task
->children
= NULL
;
1040 gomp_clear_parent (child_task
->children
);
1041 gomp_task_run_post_remove_taskgroup (child_task
);
1042 to_free
= child_task
;
1047 do_wake
= team
->nthreads
- team
->task_running_count
1048 - !task
->in_tied_task
;
1049 if (do_wake
> new_tasks
)
1050 do_wake
= new_tasks
;
1056 /* Called when encountering a taskyield directive. */
1059 GOMP_taskyield (void)
1061 /* Nothing at the moment. */
1065 GOMP_taskgroup_start (void)
1067 struct gomp_thread
*thr
= gomp_thread ();
1068 struct gomp_team
*team
= thr
->ts
.team
;
1069 struct gomp_task
*task
= thr
->task
;
1070 struct gomp_taskgroup
*taskgroup
;
1072 /* If team is NULL, all tasks are executed as
1073 GOMP_TASK_IFFALSE tasks and thus all children tasks of
1074 taskgroup and their descendant tasks will be finished
1075 by the time GOMP_taskgroup_end is called. */
1078 taskgroup
= gomp_malloc (sizeof (struct gomp_taskgroup
));
1079 taskgroup
->prev
= task
->taskgroup
;
1080 taskgroup
->children
= NULL
;
1081 taskgroup
->in_taskgroup_wait
= false;
1082 taskgroup
->cancelled
= false;
1083 taskgroup
->num_children
= 0;
1084 gomp_sem_init (&taskgroup
->taskgroup_sem
, 0);
1085 task
->taskgroup
= taskgroup
;
1089 GOMP_taskgroup_end (void)
1091 struct gomp_thread
*thr
= gomp_thread ();
1092 struct gomp_team
*team
= thr
->ts
.team
;
1093 struct gomp_task
*task
= thr
->task
;
1094 struct gomp_taskgroup
*taskgroup
;
1095 struct gomp_task
*child_task
= NULL
;
1096 struct gomp_task
*to_free
= NULL
;
1101 taskgroup
= task
->taskgroup
;
1103 /* The acquire barrier on load of taskgroup->num_children here
1104 synchronizes with the write of 0 in gomp_task_run_post_remove_taskgroup.
1105 It is not necessary that we synchronize with other non-0 writes at
1106 this point, but we must ensure that all writes to memory by a
1107 child thread task work function are seen before we exit from
1108 GOMP_taskgroup_end. */
1109 if (__atomic_load_n (&taskgroup
->num_children
, MEMMODEL_ACQUIRE
) == 0)
1112 gomp_mutex_lock (&team
->task_lock
);
1115 bool cancelled
= false;
1116 if (taskgroup
->children
== NULL
)
1118 if (taskgroup
->num_children
)
1120 if (task
->children
== NULL
)
1122 child_task
= task
->children
;
1126 gomp_mutex_unlock (&team
->task_lock
);
1129 gomp_finish_task (to_free
);
1136 child_task
= taskgroup
->children
;
1137 if (child_task
->kind
== GOMP_TASK_WAITING
)
1140 = gomp_task_run_pre (child_task
, child_task
->parent
, taskgroup
,
1142 if (__builtin_expect (cancelled
, 0))
1146 gomp_finish_task (to_free
);
1150 goto finish_cancelled
;
1157 /* All tasks we are waiting for are already running
1158 in other threads. Wait for them. */
1159 taskgroup
->in_taskgroup_wait
= true;
1161 gomp_mutex_unlock (&team
->task_lock
);
1164 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
1169 gomp_finish_task (to_free
);
1175 thr
->task
= child_task
;
1176 child_task
->fn (child_task
->fn_data
);
1180 gomp_sem_wait (&taskgroup
->taskgroup_sem
);
1181 gomp_mutex_lock (&team
->task_lock
);
1186 = gomp_task_run_post_handle_depend (child_task
, team
);
1187 gomp_task_run_post_remove_parent (child_task
);
1188 gomp_clear_parent (child_task
->children
);
1189 gomp_task_run_post_remove_taskgroup (child_task
);
1190 to_free
= child_task
;
1195 do_wake
= team
->nthreads
- team
->task_running_count
1196 - !task
->in_tied_task
;
1197 if (do_wake
> new_tasks
)
1198 do_wake
= new_tasks
;
1204 task
->taskgroup
= taskgroup
->prev
;
1205 gomp_sem_destroy (&taskgroup
->taskgroup_sem
);
1212 struct gomp_thread
*thr
= gomp_thread ();
1213 return thr
->task
&& thr
->task
->final_task
;
1216 ialias (omp_in_final
)