1 /* Copyright (C) 2007-2021 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 maintenance of tasks in response to task
27 creation and termination. */
33 #include "gomp-constants.h"
35 typedef struct gomp_task_depend_entry
*hash_entry_type
;
38 htab_alloc (size_t size
)
40 return gomp_malloc (size
);
51 static inline hashval_t
52 htab_hash (hash_entry_type element
)
54 return hash_pointer (element
->addr
);
58 htab_eq (hash_entry_type x
, hash_entry_type y
)
60 return x
->addr
== y
->addr
;
63 /* Create a new task data structure. */
66 gomp_init_task (struct gomp_task
*task
, struct gomp_task
*parent_task
,
67 struct gomp_task_icv
*prev_icv
)
69 /* It would seem that using memset here would be a win, but it turns
70 out that partially filling gomp_task allows us to keep the
71 overhead of task creation low. In the nqueens-1.c test, for a
72 sufficiently large N, we drop the overhead from 5-6% to 1%.
74 Note, the nqueens-1.c test in serial mode is a good test to
75 benchmark the overhead of creating tasks as there are millions of
76 tiny tasks created that all run undeferred. */
77 task
->parent
= parent_task
;
78 priority_queue_init (&task
->children_queue
);
79 task
->taskgroup
= NULL
;
80 task
->dependers
= NULL
;
81 task
->depend_hash
= NULL
;
82 task
->taskwait
= NULL
;
83 task
->depend_count
= 0;
84 task
->completion_sem
= NULL
;
85 task
->deferred_p
= false;
86 task
->icv
= *prev_icv
;
87 task
->kind
= GOMP_TASK_IMPLICIT
;
88 task
->in_tied_task
= false;
89 task
->final_task
= false;
90 task
->copy_ctors_done
= false;
91 task
->parent_depends_on
= false;
94 /* Clean up a task, after completing it. */
99 struct gomp_thread
*thr
= gomp_thread ();
100 struct gomp_task
*task
= thr
->task
;
102 gomp_finish_task (task
);
103 thr
->task
= task
->parent
;
106 /* Clear the parent field of every task in LIST. */
109 gomp_clear_parent_in_list (struct priority_list
*list
)
111 struct priority_node
*p
= list
->tasks
;
115 priority_node_to_task (PQ_CHILDREN
, p
)->parent
= NULL
;
118 while (p
!= list
->tasks
);
121 /* Splay tree version of gomp_clear_parent_in_list.
123 Clear the parent field of every task in NODE within SP, and free
124 the node when done. */
127 gomp_clear_parent_in_tree (prio_splay_tree sp
, prio_splay_tree_node node
)
131 prio_splay_tree_node left
= node
->left
, right
= node
->right
;
132 gomp_clear_parent_in_list (&node
->key
.l
);
133 #if _LIBGOMP_CHECKING_
134 memset (node
, 0xaf, sizeof (*node
));
136 /* No need to remove the node from the tree. We're nuking
137 everything, so just free the nodes and our caller can clear the
138 entire splay tree. */
140 gomp_clear_parent_in_tree (sp
, left
);
141 gomp_clear_parent_in_tree (sp
, right
);
144 /* Clear the parent field of every task in Q and remove every task
148 gomp_clear_parent (struct priority_queue
*q
)
150 if (priority_queue_multi_p (q
))
152 gomp_clear_parent_in_tree (&q
->t
, q
->t
.root
);
153 /* All the nodes have been cleared in gomp_clear_parent_in_tree.
154 No need to remove anything. We can just nuke everything. */
158 gomp_clear_parent_in_list (&q
->l
);
161 /* Helper function for GOMP_task and gomp_create_target_task.
163 For a TASK with in/out dependencies, fill in the various dependency
164 queues. PARENT is the parent of said task. DEPEND is as in
168 gomp_task_handle_depend (struct gomp_task
*task
, struct gomp_task
*parent
,
171 size_t ndepend
= (uintptr_t) depend
[0];
177 /* depend[0] is total # */
178 size_t nout
= (uintptr_t) depend
[1]; /* # of out: and inout: */
179 /* ndepend - nout is # of in: */
180 for (i
= 0; i
< ndepend
; i
++)
182 task
->depend
[i
].addr
= depend
[2 + i
];
183 task
->depend
[i
].is_in
= i
>= nout
;
188 ndepend
= (uintptr_t) depend
[1]; /* total # */
189 size_t nout
= (uintptr_t) depend
[2]; /* # of out: and inout: */
190 size_t nmutexinoutset
= (uintptr_t) depend
[3]; /* # of mutexinoutset: */
191 /* For now we treat mutexinoutset like out, which is compliant, but
193 size_t nin
= (uintptr_t) depend
[4]; /* # of in: */
194 /* ndepend - nout - nmutexinoutset - nin is # of depobjs */
195 size_t normal
= nout
+ nmutexinoutset
+ nin
;
197 for (i
= normal
; i
< ndepend
; i
++)
199 void **d
= (void **) (uintptr_t) depend
[5 + i
];
200 switch ((uintptr_t) d
[1])
202 case GOMP_DEPEND_OUT
:
203 case GOMP_DEPEND_INOUT
:
204 case GOMP_DEPEND_MUTEXINOUTSET
:
209 gomp_fatal ("unknown omp_depend_t dependence type %d",
210 (int) (uintptr_t) d
[1]);
212 task
->depend
[n
].addr
= d
[0];
213 task
->depend
[n
++].is_in
= 0;
215 for (i
= 0; i
< normal
; i
++)
217 task
->depend
[n
].addr
= depend
[5 + i
];
218 task
->depend
[n
++].is_in
= i
>= nout
+ nmutexinoutset
;
220 for (i
= normal
; i
< ndepend
; i
++)
222 void **d
= (void **) (uintptr_t) depend
[5 + i
];
223 if ((uintptr_t) d
[1] != GOMP_DEPEND_IN
)
225 task
->depend
[n
].addr
= d
[0];
226 task
->depend
[n
++].is_in
= 1;
229 task
->depend_count
= ndepend
;
230 task
->num_dependees
= 0;
231 if (parent
->depend_hash
== NULL
)
232 parent
->depend_hash
= htab_create (2 * ndepend
> 12 ? 2 * ndepend
: 12);
233 for (i
= 0; i
< ndepend
; i
++)
235 task
->depend
[i
].next
= NULL
;
236 task
->depend
[i
].prev
= NULL
;
237 task
->depend
[i
].task
= task
;
238 task
->depend
[i
].redundant
= false;
239 task
->depend
[i
].redundant_out
= false;
241 hash_entry_type
*slot
= htab_find_slot (&parent
->depend_hash
,
242 &task
->depend
[i
], INSERT
);
243 hash_entry_type out
= NULL
, last
= NULL
;
246 /* If multiple depends on the same task are the same, all but the
247 first one are redundant. As inout/out come first, if any of them
248 is inout/out, it will win, which is the right semantics. */
249 if ((*slot
)->task
== task
)
251 task
->depend
[i
].redundant
= true;
254 for (ent
= *slot
; ent
; ent
= ent
->next
)
256 if (ent
->redundant_out
)
261 /* depend(in:...) doesn't depend on earlier depend(in:...). */
262 if (task
->depend
[i
].is_in
&& ent
->is_in
)
268 struct gomp_task
*tsk
= ent
->task
;
269 if (tsk
->dependers
== NULL
)
272 = gomp_malloc (sizeof (struct gomp_dependers_vec
)
273 + 6 * sizeof (struct gomp_task
*));
274 tsk
->dependers
->n_elem
= 1;
275 tsk
->dependers
->allocated
= 6;
276 tsk
->dependers
->elem
[0] = task
;
277 task
->num_dependees
++;
280 /* We already have some other dependency on tsk from earlier
282 else if (tsk
->dependers
->n_elem
283 && (tsk
->dependers
->elem
[tsk
->dependers
->n_elem
- 1]
286 else if (tsk
->dependers
->n_elem
== tsk
->dependers
->allocated
)
288 tsk
->dependers
->allocated
289 = tsk
->dependers
->allocated
* 2 + 2;
291 = gomp_realloc (tsk
->dependers
,
292 sizeof (struct gomp_dependers_vec
)
293 + (tsk
->dependers
->allocated
294 * sizeof (struct gomp_task
*)));
296 tsk
->dependers
->elem
[tsk
->dependers
->n_elem
++] = task
;
297 task
->num_dependees
++;
299 task
->depend
[i
].next
= *slot
;
300 (*slot
)->prev
= &task
->depend
[i
];
302 *slot
= &task
->depend
[i
];
304 /* There is no need to store more than one depend({,in}out:) task per
305 address in the hash table chain for the purpose of creation of
306 deferred tasks, because each out depends on all earlier outs, thus it
307 is enough to record just the last depend({,in}out:). For depend(in:),
308 we need to keep all of the previous ones not terminated yet, because
309 a later depend({,in}out:) might need to depend on all of them. So, if
310 the new task's clause is depend({,in}out:), we know there is at most
311 one other depend({,in}out:) clause in the list (out). For
312 non-deferred tasks we want to see all outs, so they are moved to the
313 end of the chain, after first redundant_out entry all following
314 entries should be redundant_out. */
315 if (!task
->depend
[i
].is_in
&& out
)
319 out
->next
->prev
= out
->prev
;
320 out
->prev
->next
= out
->next
;
321 out
->next
= last
->next
;
325 out
->next
->prev
= out
;
327 out
->redundant_out
= true;
332 /* Called when encountering an explicit task directive. If IF_CLAUSE is
333 false, then we must not delay in executing the task. If UNTIED is true,
334 then the task may be executed by any member of the team.
336 DEPEND is an array containing:
337 if depend[0] is non-zero, then:
338 depend[0]: number of depend elements.
339 depend[1]: number of depend elements of type "out/inout".
340 depend[2..N+1]: address of [1..N]th depend element.
341 otherwise, when depend[0] is zero, then:
342 depend[1]: number of depend elements.
343 depend[2]: number of depend elements of type "out/inout".
344 depend[3]: number of depend elements of type "mutexinoutset".
345 depend[4]: number of depend elements of type "in".
346 depend[5..4+depend[2]+depend[3]+depend[4]]: address of depend elements
347 depend[5+depend[2]+depend[3]+depend[4]..4+depend[1]]: address of
348 omp_depend_t objects. */
351 GOMP_task (void (*fn
) (void *), void *data
, void (*cpyfn
) (void *, void *),
352 long arg_size
, long arg_align
, bool if_clause
, unsigned flags
,
353 void **depend
, int priority_arg
, void *detach
)
355 struct gomp_thread
*thr
= gomp_thread ();
356 struct gomp_team
*team
= thr
->ts
.team
;
359 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
360 /* If pthread_mutex_* is used for omp_*lock*, then each task must be
361 tied to one thread all the time. This means UNTIED tasks must be
362 tied and if CPYFN is non-NULL IF(0) must be forced, as CPYFN
363 might be running on different thread than FN. */
366 flags
&= ~GOMP_TASK_FLAG_UNTIED
;
369 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
370 if (__builtin_expect (gomp_cancel_var
, 0) && team
)
372 if (gomp_team_barrier_cancelled (&team
->barrier
))
374 if (thr
->task
->taskgroup
)
376 if (thr
->task
->taskgroup
->cancelled
)
378 if (thr
->task
->taskgroup
->workshare
379 && thr
->task
->taskgroup
->prev
380 && thr
->task
->taskgroup
->prev
->cancelled
)
385 if (__builtin_expect ((flags
& GOMP_TASK_FLAG_PRIORITY
) != 0, 0))
387 priority
= priority_arg
;
388 if (priority
> gomp_max_task_priority_var
)
389 priority
= gomp_max_task_priority_var
;
392 if (!if_clause
|| team
== NULL
393 || (thr
->task
&& thr
->task
->final_task
)
394 || team
->task_count
> 64 * team
->nthreads
)
396 struct gomp_task task
;
397 gomp_sem_t completion_sem
;
399 /* If there are depend clauses and earlier deferred sibling tasks
400 with depend clauses, check if there isn't a dependency. If there
401 is, we need to wait for them. There is no need to handle
402 depend clauses for non-deferred tasks other than this, because
403 the parent task is suspended until the child task finishes and thus
404 it can't start further child tasks. */
405 if ((flags
& GOMP_TASK_FLAG_DEPEND
)
406 && thr
->task
&& thr
->task
->depend_hash
)
407 gomp_task_maybe_wait_for_dependencies (depend
);
409 gomp_init_task (&task
, thr
->task
, gomp_icv (false));
410 task
.kind
= GOMP_TASK_UNDEFERRED
;
411 task
.final_task
= (thr
->task
&& thr
->task
->final_task
)
412 || (flags
& GOMP_TASK_FLAG_FINAL
);
413 task
.priority
= priority
;
415 if ((flags
& GOMP_TASK_FLAG_DETACH
) != 0)
417 gomp_sem_init (&completion_sem
, 0);
418 task
.completion_sem
= &completion_sem
;
419 *(void **) detach
= &task
;
421 *(void **) data
= &task
;
423 gomp_debug (0, "Thread %d: new event: %p\n",
424 thr
->ts
.team_id
, &task
);
429 task
.in_tied_task
= thr
->task
->in_tied_task
;
430 task
.taskgroup
= thr
->task
->taskgroup
;
433 if (__builtin_expect (cpyfn
!= NULL
, 0))
435 char buf
[arg_size
+ arg_align
- 1];
436 char *arg
= (char *) (((uintptr_t) buf
+ arg_align
- 1)
437 & ~(uintptr_t) (arg_align
- 1));
444 if ((flags
& GOMP_TASK_FLAG_DETACH
) != 0)
446 gomp_sem_wait (&completion_sem
);
447 gomp_sem_destroy (&completion_sem
);
450 /* Access to "children" is normally done inside a task_lock
451 mutex region, but the only way this particular task.children
452 can be set is if this thread's task work function (fn)
453 creates children. So since the setter is *this* thread, we
454 need no barriers here when testing for non-NULL. We can have
455 task.children set by the current thread then changed by a
456 child thread, but seeing a stale non-NULL value is not a
457 problem. Once past the task_lock acquisition, this thread
458 will see the real value of task.children. */
459 if (!priority_queue_empty_p (&task
.children_queue
, MEMMODEL_RELAXED
))
461 gomp_mutex_lock (&team
->task_lock
);
462 gomp_clear_parent (&task
.children_queue
);
463 gomp_mutex_unlock (&team
->task_lock
);
469 struct gomp_task
*task
;
470 struct gomp_task
*parent
= thr
->task
;
471 struct gomp_taskgroup
*taskgroup
= parent
->taskgroup
;
474 size_t depend_size
= 0;
476 if (flags
& GOMP_TASK_FLAG_DEPEND
)
477 depend_size
= ((uintptr_t) (depend
[0] ? depend
[0] : depend
[1])
478 * sizeof (struct gomp_task_depend_entry
));
479 task
= gomp_malloc (sizeof (*task
) + depend_size
480 + arg_size
+ arg_align
- 1);
481 arg
= (char *) (((uintptr_t) (task
+ 1) + depend_size
+ arg_align
- 1)
482 & ~(uintptr_t) (arg_align
- 1));
483 gomp_init_task (task
, parent
, gomp_icv (false));
484 task
->priority
= priority
;
485 task
->kind
= GOMP_TASK_UNDEFERRED
;
486 task
->in_tied_task
= parent
->in_tied_task
;
487 task
->taskgroup
= taskgroup
;
488 task
->deferred_p
= true;
489 if ((flags
& GOMP_TASK_FLAG_DETACH
) != 0)
491 task
->detach_team
= team
;
493 *(void **) detach
= task
;
495 *(void **) data
= task
;
497 gomp_debug (0, "Thread %d: new event: %p\n", thr
->ts
.team_id
, task
);
503 task
->copy_ctors_done
= true;
506 memcpy (arg
, data
, arg_size
);
508 task
->kind
= GOMP_TASK_WAITING
;
511 task
->final_task
= (flags
& GOMP_TASK_FLAG_FINAL
) >> 1;
512 gomp_mutex_lock (&team
->task_lock
);
513 /* If parallel or taskgroup has been cancelled, don't start new
515 if (__builtin_expect (gomp_cancel_var
, 0)
516 && !task
->copy_ctors_done
)
518 if (gomp_team_barrier_cancelled (&team
->barrier
))
521 gomp_mutex_unlock (&team
->task_lock
);
522 gomp_finish_task (task
);
528 if (taskgroup
->cancelled
)
530 if (taskgroup
->workshare
532 && taskgroup
->prev
->cancelled
)
537 taskgroup
->num_children
++;
540 gomp_task_handle_depend (task
, parent
, depend
);
541 if (task
->num_dependees
)
543 /* Tasks that depend on other tasks are not put into the
544 various waiting queues, so we are done for now. Said
545 tasks are instead put into the queues via
546 gomp_task_run_post_handle_dependers() after their
547 dependencies have been satisfied. After which, they
548 can be picked up by the various scheduling
550 gomp_mutex_unlock (&team
->task_lock
);
555 priority_queue_insert (PQ_CHILDREN
, &parent
->children_queue
,
557 PRIORITY_INSERT_BEGIN
,
558 /*adjust_parent_depends_on=*/false,
559 task
->parent_depends_on
);
561 priority_queue_insert (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
563 PRIORITY_INSERT_BEGIN
,
564 /*adjust_parent_depends_on=*/false,
565 task
->parent_depends_on
);
567 priority_queue_insert (PQ_TEAM
, &team
->task_queue
,
570 /*adjust_parent_depends_on=*/false,
571 task
->parent_depends_on
);
574 ++team
->task_queued_count
;
575 gomp_team_barrier_set_task_pending (&team
->barrier
);
576 do_wake
= team
->task_running_count
+ !parent
->in_tied_task
578 gomp_mutex_unlock (&team
->task_lock
);
580 gomp_team_barrier_wake (&team
->barrier
, 1);
584 ialias (GOMP_taskgroup_start
)
585 ialias (GOMP_taskgroup_end
)
586 ialias (GOMP_taskgroup_reduction_register
)
589 #define UTYPE unsigned long
590 #define TYPE_is_long 1
591 #include "taskloop.c"
596 #define TYPE unsigned long long
598 #define GOMP_taskloop GOMP_taskloop_ull
599 #include "taskloop.c"
605 priority_queue_move_task_first (enum priority_queue_type type
,
606 struct priority_queue
*head
,
607 struct gomp_task
*task
)
609 #if _LIBGOMP_CHECKING_
610 if (!priority_queue_task_in_queue_p (type
, head
, task
))
611 gomp_fatal ("Attempt to move first missing task %p", task
);
613 struct priority_list
*list
;
614 if (priority_queue_multi_p (head
))
616 list
= priority_queue_lookup_priority (head
, task
->priority
);
617 #if _LIBGOMP_CHECKING_
619 gomp_fatal ("Unable to find priority %d", task
->priority
);
624 priority_list_remove (list
, task_to_priority_node (type
, task
), 0);
625 priority_list_insert (type
, list
, task
, task
->priority
,
626 PRIORITY_INSERT_BEGIN
, type
== PQ_CHILDREN
,
627 task
->parent_depends_on
);
630 /* Actual body of GOMP_PLUGIN_target_task_completion that is executed
631 with team->task_lock held, or is executed in the thread that called
632 gomp_target_task_fn if GOMP_PLUGIN_target_task_completion has been
633 run before it acquires team->task_lock. */
636 gomp_target_task_completion (struct gomp_team
*team
, struct gomp_task
*task
)
638 struct gomp_task
*parent
= task
->parent
;
640 priority_queue_move_task_first (PQ_CHILDREN
, &parent
->children_queue
,
643 struct gomp_taskgroup
*taskgroup
= task
->taskgroup
;
645 priority_queue_move_task_first (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
648 priority_queue_insert (PQ_TEAM
, &team
->task_queue
, task
, task
->priority
,
649 PRIORITY_INSERT_BEGIN
, false,
650 task
->parent_depends_on
);
651 task
->kind
= GOMP_TASK_WAITING
;
652 if (parent
&& parent
->taskwait
)
654 if (parent
->taskwait
->in_taskwait
)
656 /* One more task has had its dependencies met.
657 Inform any waiters. */
658 parent
->taskwait
->in_taskwait
= false;
659 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
661 else if (parent
->taskwait
->in_depend_wait
)
663 /* One more task has had its dependencies met.
664 Inform any waiters. */
665 parent
->taskwait
->in_depend_wait
= false;
666 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
669 if (taskgroup
&& taskgroup
->in_taskgroup_wait
)
671 /* One more task has had its dependencies met.
672 Inform any waiters. */
673 taskgroup
->in_taskgroup_wait
= false;
674 gomp_sem_post (&taskgroup
->taskgroup_sem
);
677 ++team
->task_queued_count
;
678 gomp_team_barrier_set_task_pending (&team
->barrier
);
679 /* I'm afraid this can't be done after releasing team->task_lock,
680 as gomp_target_task_completion is run from unrelated thread and
681 therefore in between gomp_mutex_unlock and gomp_team_barrier_wake
682 the team could be gone already. */
683 if (team
->nthreads
> team
->task_running_count
)
684 gomp_team_barrier_wake (&team
->barrier
, 1);
687 /* Signal that a target task TTASK has completed the asynchronously
688 running phase and should be requeued as a task to handle the
689 variable unmapping. */
692 GOMP_PLUGIN_target_task_completion (void *data
)
694 struct gomp_target_task
*ttask
= (struct gomp_target_task
*) data
;
695 struct gomp_task
*task
= ttask
->task
;
696 struct gomp_team
*team
= ttask
->team
;
698 gomp_mutex_lock (&team
->task_lock
);
699 if (ttask
->state
== GOMP_TARGET_TASK_READY_TO_RUN
)
701 ttask
->state
= GOMP_TARGET_TASK_FINISHED
;
702 gomp_mutex_unlock (&team
->task_lock
);
705 ttask
->state
= GOMP_TARGET_TASK_FINISHED
;
706 gomp_target_task_completion (team
, task
);
707 gomp_mutex_unlock (&team
->task_lock
);
710 static void gomp_task_run_post_handle_depend_hash (struct gomp_task
*);
712 /* Called for nowait target tasks. */
715 gomp_create_target_task (struct gomp_device_descr
*devicep
,
716 void (*fn
) (void *), size_t mapnum
, void **hostaddrs
,
717 size_t *sizes
, unsigned short *kinds
,
718 unsigned int flags
, void **depend
, void **args
,
719 enum gomp_target_task_state state
)
721 struct gomp_thread
*thr
= gomp_thread ();
722 struct gomp_team
*team
= thr
->ts
.team
;
724 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
725 if (__builtin_expect (gomp_cancel_var
, 0) && team
)
727 if (gomp_team_barrier_cancelled (&team
->barrier
))
729 if (thr
->task
->taskgroup
)
731 if (thr
->task
->taskgroup
->cancelled
)
733 if (thr
->task
->taskgroup
->workshare
734 && thr
->task
->taskgroup
->prev
735 && thr
->task
->taskgroup
->prev
->cancelled
)
740 struct gomp_target_task
*ttask
;
741 struct gomp_task
*task
;
742 struct gomp_task
*parent
= thr
->task
;
743 struct gomp_taskgroup
*taskgroup
= parent
->taskgroup
;
745 size_t depend_size
= 0;
746 uintptr_t depend_cnt
= 0;
747 size_t tgt_align
= 0, tgt_size
= 0;
748 uintptr_t args_cnt
= 0;
752 depend_cnt
= (uintptr_t) (depend
[0] ? depend
[0] : depend
[1]);
753 depend_size
= depend_cnt
* sizeof (struct gomp_task_depend_entry
);
757 /* GOMP_MAP_FIRSTPRIVATE need to be copied first, as they are
758 firstprivate on the target task. */
760 for (i
= 0; i
< mapnum
; i
++)
761 if ((kinds
[i
] & 0xff) == GOMP_MAP_FIRSTPRIVATE
)
763 size_t align
= (size_t) 1 << (kinds
[i
] >> 8);
764 if (tgt_align
< align
)
766 tgt_size
= (tgt_size
+ align
- 1) & ~(align
- 1);
767 tgt_size
+= sizes
[i
];
770 tgt_size
+= tgt_align
- 1;
778 intptr_t id
= (intptr_t) *cargs
++;
779 if (id
& GOMP_TARGET_ARG_SUBSEQUENT_PARAM
)
782 args_cnt
= cargs
+ 1 - args
;
786 task
= gomp_malloc (sizeof (*task
) + depend_size
788 + args_cnt
* sizeof (void *)
789 + mapnum
* (sizeof (void *) + sizeof (size_t)
790 + sizeof (unsigned short))
792 gomp_init_task (task
, parent
, gomp_icv (false));
794 task
->kind
= GOMP_TASK_WAITING
;
795 task
->in_tied_task
= parent
->in_tied_task
;
796 task
->taskgroup
= taskgroup
;
797 ttask
= (struct gomp_target_task
*) &task
->depend
[depend_cnt
];
798 ttask
->devicep
= devicep
;
800 ttask
->mapnum
= mapnum
;
801 memcpy (ttask
->hostaddrs
, hostaddrs
, mapnum
* sizeof (void *));
804 ttask
->args
= (void **) &ttask
->hostaddrs
[mapnum
];
805 memcpy (ttask
->args
, args
, args_cnt
* sizeof (void *));
806 ttask
->sizes
= (size_t *) &ttask
->args
[args_cnt
];
811 ttask
->sizes
= (size_t *) &ttask
->hostaddrs
[mapnum
];
813 memcpy (ttask
->sizes
, sizes
, mapnum
* sizeof (size_t));
814 ttask
->kinds
= (unsigned short *) &ttask
->sizes
[mapnum
];
815 memcpy (ttask
->kinds
, kinds
, mapnum
* sizeof (unsigned short));
818 char *tgt
= (char *) &ttask
->kinds
[mapnum
];
820 uintptr_t al
= (uintptr_t) tgt
& (tgt_align
- 1);
822 tgt
+= tgt_align
- al
;
824 for (i
= 0; i
< mapnum
; i
++)
825 if ((kinds
[i
] & 0xff) == GOMP_MAP_FIRSTPRIVATE
)
827 size_t align
= (size_t) 1 << (kinds
[i
] >> 8);
828 tgt_size
= (tgt_size
+ align
- 1) & ~(align
- 1);
829 memcpy (tgt
+ tgt_size
, hostaddrs
[i
], sizes
[i
]);
830 ttask
->hostaddrs
[i
] = tgt
+ tgt_size
;
831 tgt_size
= tgt_size
+ sizes
[i
];
834 ttask
->flags
= flags
;
835 ttask
->state
= state
;
839 task
->fn_data
= ttask
;
840 task
->final_task
= 0;
841 gomp_mutex_lock (&team
->task_lock
);
842 /* If parallel or taskgroup has been cancelled, don't start new tasks. */
843 if (__builtin_expect (gomp_cancel_var
, 0))
845 if (gomp_team_barrier_cancelled (&team
->barrier
))
848 gomp_mutex_unlock (&team
->task_lock
);
849 gomp_finish_task (task
);
855 if (taskgroup
->cancelled
)
857 if (taskgroup
->workshare
859 && taskgroup
->prev
->cancelled
)
865 gomp_task_handle_depend (task
, parent
, depend
);
866 if (task
->num_dependees
)
869 taskgroup
->num_children
++;
870 gomp_mutex_unlock (&team
->task_lock
);
874 if (state
== GOMP_TARGET_TASK_DATA
)
876 gomp_task_run_post_handle_depend_hash (task
);
877 gomp_mutex_unlock (&team
->task_lock
);
878 gomp_finish_task (task
);
883 taskgroup
->num_children
++;
884 /* For async offloading, if we don't need to wait for dependencies,
885 run the gomp_target_task_fn right away, essentially schedule the
886 mapping part of the task in the current thread. */
888 && (devicep
->capabilities
& GOMP_OFFLOAD_CAP_OPENMP_400
))
890 priority_queue_insert (PQ_CHILDREN
, &parent
->children_queue
, task
, 0,
892 /*adjust_parent_depends_on=*/false,
893 task
->parent_depends_on
);
895 priority_queue_insert (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
896 task
, 0, PRIORITY_INSERT_END
,
897 /*adjust_parent_depends_on=*/false,
898 task
->parent_depends_on
);
899 task
->pnode
[PQ_TEAM
].next
= NULL
;
900 task
->pnode
[PQ_TEAM
].prev
= NULL
;
901 task
->kind
= GOMP_TASK_TIED
;
903 gomp_mutex_unlock (&team
->task_lock
);
906 gomp_target_task_fn (task
->fn_data
);
909 gomp_mutex_lock (&team
->task_lock
);
910 task
->kind
= GOMP_TASK_ASYNC_RUNNING
;
911 /* If GOMP_PLUGIN_target_task_completion has run already
912 in between gomp_target_task_fn and the mutex lock,
913 perform the requeuing here. */
914 if (ttask
->state
== GOMP_TARGET_TASK_FINISHED
)
915 gomp_target_task_completion (team
, task
);
917 ttask
->state
= GOMP_TARGET_TASK_RUNNING
;
918 gomp_mutex_unlock (&team
->task_lock
);
921 priority_queue_insert (PQ_CHILDREN
, &parent
->children_queue
, task
, 0,
922 PRIORITY_INSERT_BEGIN
,
923 /*adjust_parent_depends_on=*/false,
924 task
->parent_depends_on
);
926 priority_queue_insert (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
, task
, 0,
927 PRIORITY_INSERT_BEGIN
,
928 /*adjust_parent_depends_on=*/false,
929 task
->parent_depends_on
);
930 priority_queue_insert (PQ_TEAM
, &team
->task_queue
, task
, 0,
932 /*adjust_parent_depends_on=*/false,
933 task
->parent_depends_on
);
935 ++team
->task_queued_count
;
936 gomp_team_barrier_set_task_pending (&team
->barrier
);
937 do_wake
= team
->task_running_count
+ !parent
->in_tied_task
939 gomp_mutex_unlock (&team
->task_lock
);
941 gomp_team_barrier_wake (&team
->barrier
, 1);
945 /* Given a parent_depends_on task in LIST, move it to the front of its
946 priority so it is run as soon as possible.
948 Care is taken to update the list's LAST_PARENT_DEPENDS_ON field.
950 We rearrange the queue such that all parent_depends_on tasks are
951 first, and last_parent_depends_on points to the last such task we
952 rearranged. For example, given the following tasks in a queue
953 where PD[123] are the parent_depends_on tasks:
958 C1 -> C2 -> C3 -> PD1 -> PD2 -> PD3 -> C4
960 We rearrange such that:
963 | +--- last_parent_depends_on
966 PD1 -> PD2 -> PD3 -> C1 -> C2 -> C3 -> C4. */
969 priority_list_upgrade_task (struct priority_list
*list
,
970 struct priority_node
*node
)
972 struct priority_node
*last_parent_depends_on
973 = list
->last_parent_depends_on
;
974 if (last_parent_depends_on
)
976 node
->prev
->next
= node
->next
;
977 node
->next
->prev
= node
->prev
;
978 node
->prev
= last_parent_depends_on
;
979 node
->next
= last_parent_depends_on
->next
;
980 node
->prev
->next
= node
;
981 node
->next
->prev
= node
;
983 else if (node
!= list
->tasks
)
985 node
->prev
->next
= node
->next
;
986 node
->next
->prev
= node
->prev
;
987 node
->prev
= list
->tasks
->prev
;
988 node
->next
= list
->tasks
;
990 node
->prev
->next
= node
;
991 node
->next
->prev
= node
;
993 list
->last_parent_depends_on
= node
;
996 /* Given a parent_depends_on TASK in its parent's children_queue, move
997 it to the front of its priority so it is run as soon as possible.
999 PARENT is passed as an optimization.
1001 (This function could be defined in priority_queue.c, but we want it
1002 inlined, and putting it in priority_queue.h is not an option, given
1003 that gomp_task has not been properly defined at that point). */
1006 priority_queue_upgrade_task (struct gomp_task
*task
,
1007 struct gomp_task
*parent
)
1009 struct priority_queue
*head
= &parent
->children_queue
;
1010 struct priority_node
*node
= &task
->pnode
[PQ_CHILDREN
];
1011 #if _LIBGOMP_CHECKING_
1012 if (!task
->parent_depends_on
)
1013 gomp_fatal ("priority_queue_upgrade_task: task must be a "
1014 "parent_depends_on task");
1015 if (!priority_queue_task_in_queue_p (PQ_CHILDREN
, head
, task
))
1016 gomp_fatal ("priority_queue_upgrade_task: cannot find task=%p", task
);
1018 if (priority_queue_multi_p (head
))
1020 struct priority_list
*list
1021 = priority_queue_lookup_priority (head
, task
->priority
);
1022 priority_list_upgrade_task (list
, node
);
1025 priority_list_upgrade_task (&head
->l
, node
);
1028 /* Given a CHILD_TASK in LIST that is about to be executed, move it out of
1029 the way in LIST so that other tasks can be considered for
1030 execution. LIST contains tasks of type TYPE.
1032 Care is taken to update the queue's LAST_PARENT_DEPENDS_ON field
1036 priority_list_downgrade_task (enum priority_queue_type type
,
1037 struct priority_list
*list
,
1038 struct gomp_task
*child_task
)
1040 struct priority_node
*node
= task_to_priority_node (type
, child_task
);
1041 if (list
->tasks
== node
)
1042 list
->tasks
= node
->next
;
1043 else if (node
->next
!= list
->tasks
)
1045 /* The task in NODE is about to become TIED and TIED tasks
1046 cannot come before WAITING tasks. If we're about to
1047 leave the queue in such an indeterminate state, rewire
1048 things appropriately. However, a TIED task at the end is
1050 struct gomp_task
*next_task
= priority_node_to_task (type
, node
->next
);
1051 if (next_task
->kind
== GOMP_TASK_WAITING
)
1053 /* Remove from list. */
1054 node
->prev
->next
= node
->next
;
1055 node
->next
->prev
= node
->prev
;
1056 /* Rewire at the end. */
1057 node
->next
= list
->tasks
;
1058 node
->prev
= list
->tasks
->prev
;
1059 list
->tasks
->prev
->next
= node
;
1060 list
->tasks
->prev
= node
;
1064 /* If the current task is the last_parent_depends_on for its
1065 priority, adjust last_parent_depends_on appropriately. */
1066 if (__builtin_expect (child_task
->parent_depends_on
, 0)
1067 && list
->last_parent_depends_on
== node
)
1069 struct gomp_task
*prev_child
= priority_node_to_task (type
, node
->prev
);
1070 if (node
->prev
!= node
1071 && prev_child
->kind
== GOMP_TASK_WAITING
1072 && prev_child
->parent_depends_on
)
1073 list
->last_parent_depends_on
= node
->prev
;
1076 /* There are no more parent_depends_on entries waiting
1077 to run, clear the list. */
1078 list
->last_parent_depends_on
= NULL
;
1083 /* Given a TASK in HEAD that is about to be executed, move it out of
1084 the way so that other tasks can be considered for execution. HEAD
1085 contains tasks of type TYPE.
1087 Care is taken to update the queue's LAST_PARENT_DEPENDS_ON field
1090 (This function could be defined in priority_queue.c, but we want it
1091 inlined, and putting it in priority_queue.h is not an option, given
1092 that gomp_task has not been properly defined at that point). */
1095 priority_queue_downgrade_task (enum priority_queue_type type
,
1096 struct priority_queue
*head
,
1097 struct gomp_task
*task
)
1099 #if _LIBGOMP_CHECKING_
1100 if (!priority_queue_task_in_queue_p (type
, head
, task
))
1101 gomp_fatal ("Attempt to downgrade missing task %p", task
);
1103 if (priority_queue_multi_p (head
))
1105 struct priority_list
*list
1106 = priority_queue_lookup_priority (head
, task
->priority
);
1107 priority_list_downgrade_task (type
, list
, task
);
1110 priority_list_downgrade_task (type
, &head
->l
, task
);
1113 /* Setup CHILD_TASK to execute. This is done by setting the task to
1114 TIED, and updating all relevant queues so that CHILD_TASK is no
1115 longer chosen for scheduling. Also, remove CHILD_TASK from the
1116 overall team task queue entirely.
1118 Return TRUE if task or its containing taskgroup has been
1122 gomp_task_run_pre (struct gomp_task
*child_task
, struct gomp_task
*parent
,
1123 struct gomp_team
*team
)
1125 #if _LIBGOMP_CHECKING_
1126 if (child_task
->parent
)
1127 priority_queue_verify (PQ_CHILDREN
,
1128 &child_task
->parent
->children_queue
, true);
1129 if (child_task
->taskgroup
)
1130 priority_queue_verify (PQ_TASKGROUP
,
1131 &child_task
->taskgroup
->taskgroup_queue
, false);
1132 priority_queue_verify (PQ_TEAM
, &team
->task_queue
, false);
1135 /* Task is about to go tied, move it out of the way. */
1137 priority_queue_downgrade_task (PQ_CHILDREN
, &parent
->children_queue
,
1140 /* Task is about to go tied, move it out of the way. */
1141 struct gomp_taskgroup
*taskgroup
= child_task
->taskgroup
;
1143 priority_queue_downgrade_task (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
1146 priority_queue_remove (PQ_TEAM
, &team
->task_queue
, child_task
,
1148 child_task
->pnode
[PQ_TEAM
].next
= NULL
;
1149 child_task
->pnode
[PQ_TEAM
].prev
= NULL
;
1150 child_task
->kind
= GOMP_TASK_TIED
;
1152 if (--team
->task_queued_count
== 0)
1153 gomp_team_barrier_clear_task_pending (&team
->barrier
);
1154 if (__builtin_expect (gomp_cancel_var
, 0)
1155 && !child_task
->copy_ctors_done
)
1157 if (gomp_team_barrier_cancelled (&team
->barrier
))
1161 if (taskgroup
->cancelled
)
1163 if (taskgroup
->workshare
1165 && taskgroup
->prev
->cancelled
)
1173 gomp_task_run_post_handle_depend_hash (struct gomp_task
*child_task
)
1175 struct gomp_task
*parent
= child_task
->parent
;
1178 for (i
= 0; i
< child_task
->depend_count
; i
++)
1179 if (!child_task
->depend
[i
].redundant
)
1181 if (child_task
->depend
[i
].next
)
1182 child_task
->depend
[i
].next
->prev
= child_task
->depend
[i
].prev
;
1183 if (child_task
->depend
[i
].prev
)
1184 child_task
->depend
[i
].prev
->next
= child_task
->depend
[i
].next
;
1187 hash_entry_type
*slot
1188 = htab_find_slot (&parent
->depend_hash
, &child_task
->depend
[i
],
1190 if (*slot
!= &child_task
->depend
[i
])
1192 if (child_task
->depend
[i
].next
)
1193 *slot
= child_task
->depend
[i
].next
;
1195 htab_clear_slot (parent
->depend_hash
, slot
);
1200 /* After a CHILD_TASK has been run, adjust the dependency queue for
1201 each task that depends on CHILD_TASK, to record the fact that there
1202 is one less dependency to worry about. If a task that depended on
1203 CHILD_TASK now has no dependencies, place it in the various queues
1204 so it gets scheduled to run.
1206 TEAM is the team to which CHILD_TASK belongs to. */
1209 gomp_task_run_post_handle_dependers (struct gomp_task
*child_task
,
1210 struct gomp_team
*team
)
1212 struct gomp_task
*parent
= child_task
->parent
;
1213 size_t i
, count
= child_task
->dependers
->n_elem
, ret
= 0;
1214 for (i
= 0; i
< count
; i
++)
1216 struct gomp_task
*task
= child_task
->dependers
->elem
[i
];
1218 /* CHILD_TASK satisfies a dependency for TASK. Keep track of
1219 TASK's remaining dependencies. Once TASK has no other
1220 dependencies, put it into the various queues so it will get
1221 scheduled for execution. */
1222 if (--task
->num_dependees
!= 0)
1225 struct gomp_taskgroup
*taskgroup
= task
->taskgroup
;
1228 priority_queue_insert (PQ_CHILDREN
, &parent
->children_queue
,
1229 task
, task
->priority
,
1230 PRIORITY_INSERT_BEGIN
,
1231 /*adjust_parent_depends_on=*/true,
1232 task
->parent_depends_on
);
1233 if (parent
->taskwait
)
1235 if (parent
->taskwait
->in_taskwait
)
1237 /* One more task has had its dependencies met.
1238 Inform any waiters. */
1239 parent
->taskwait
->in_taskwait
= false;
1240 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
1242 else if (parent
->taskwait
->in_depend_wait
)
1244 /* One more task has had its dependencies met.
1245 Inform any waiters. */
1246 parent
->taskwait
->in_depend_wait
= false;
1247 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
1253 priority_queue_insert (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
1254 task
, task
->priority
,
1255 PRIORITY_INSERT_BEGIN
,
1256 /*adjust_parent_depends_on=*/false,
1257 task
->parent_depends_on
);
1258 if (taskgroup
->in_taskgroup_wait
)
1260 /* One more task has had its dependencies met.
1261 Inform any waiters. */
1262 taskgroup
->in_taskgroup_wait
= false;
1263 gomp_sem_post (&taskgroup
->taskgroup_sem
);
1266 priority_queue_insert (PQ_TEAM
, &team
->task_queue
,
1267 task
, task
->priority
,
1268 PRIORITY_INSERT_END
,
1269 /*adjust_parent_depends_on=*/false,
1270 task
->parent_depends_on
);
1272 ++team
->task_queued_count
;
1275 free (child_task
->dependers
);
1276 child_task
->dependers
= NULL
;
1278 gomp_team_barrier_set_task_pending (&team
->barrier
);
1282 static inline size_t
1283 gomp_task_run_post_handle_depend (struct gomp_task
*child_task
,
1284 struct gomp_team
*team
)
1286 if (child_task
->depend_count
== 0)
1289 /* If parent is gone already, the hash table is freed and nothing
1290 will use the hash table anymore, no need to remove anything from it. */
1291 if (child_task
->parent
!= NULL
)
1292 gomp_task_run_post_handle_depend_hash (child_task
);
1294 if (child_task
->dependers
== NULL
)
1297 return gomp_task_run_post_handle_dependers (child_task
, team
);
1300 /* Remove CHILD_TASK from its parent. */
1303 gomp_task_run_post_remove_parent (struct gomp_task
*child_task
)
1305 struct gomp_task
*parent
= child_task
->parent
;
1309 /* If this was the last task the parent was depending on,
1310 synchronize with gomp_task_maybe_wait_for_dependencies so it can
1311 clean up and return. */
1312 if (__builtin_expect (child_task
->parent_depends_on
, 0)
1313 && --parent
->taskwait
->n_depend
== 0
1314 && parent
->taskwait
->in_depend_wait
)
1316 parent
->taskwait
->in_depend_wait
= false;
1317 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
1320 if (priority_queue_remove (PQ_CHILDREN
, &parent
->children_queue
,
1321 child_task
, MEMMODEL_RELEASE
)
1322 && parent
->taskwait
&& parent
->taskwait
->in_taskwait
)
1324 parent
->taskwait
->in_taskwait
= false;
1325 gomp_sem_post (&parent
->taskwait
->taskwait_sem
);
1327 child_task
->pnode
[PQ_CHILDREN
].next
= NULL
;
1328 child_task
->pnode
[PQ_CHILDREN
].prev
= NULL
;
1331 /* Remove CHILD_TASK from its taskgroup. */
1334 gomp_task_run_post_remove_taskgroup (struct gomp_task
*child_task
)
1336 struct gomp_taskgroup
*taskgroup
= child_task
->taskgroup
;
1337 if (taskgroup
== NULL
)
1339 bool empty
= priority_queue_remove (PQ_TASKGROUP
,
1340 &taskgroup
->taskgroup_queue
,
1341 child_task
, MEMMODEL_RELAXED
);
1342 child_task
->pnode
[PQ_TASKGROUP
].next
= NULL
;
1343 child_task
->pnode
[PQ_TASKGROUP
].prev
= NULL
;
1344 if (taskgroup
->num_children
> 1)
1345 --taskgroup
->num_children
;
1348 /* We access taskgroup->num_children in GOMP_taskgroup_end
1349 outside of the task lock mutex region, so
1350 need a release barrier here to ensure memory
1351 written by child_task->fn above is flushed
1352 before the NULL is written. */
1353 __atomic_store_n (&taskgroup
->num_children
, 0, MEMMODEL_RELEASE
);
1355 if (empty
&& taskgroup
->in_taskgroup_wait
)
1357 taskgroup
->in_taskgroup_wait
= false;
1358 gomp_sem_post (&taskgroup
->taskgroup_sem
);
1363 gomp_barrier_handle_tasks (gomp_barrier_state_t state
)
1365 struct gomp_thread
*thr
= gomp_thread ();
1366 struct gomp_team
*team
= thr
->ts
.team
;
1367 struct gomp_task
*task
= thr
->task
;
1368 struct gomp_task
*child_task
= NULL
;
1369 struct gomp_task
*to_free
= NULL
;
1372 gomp_mutex_lock (&team
->task_lock
);
1373 if (gomp_barrier_last_thread (state
))
1375 if (team
->task_count
== 0)
1377 gomp_team_barrier_done (&team
->barrier
, state
);
1378 gomp_mutex_unlock (&team
->task_lock
);
1379 gomp_team_barrier_wake (&team
->barrier
, 0);
1382 gomp_team_barrier_set_waiting_for_tasks (&team
->barrier
);
1387 bool cancelled
= false;
1389 if (!priority_queue_empty_p (&team
->task_queue
, MEMMODEL_RELAXED
))
1393 = priority_queue_next_task (PQ_TEAM
, &team
->task_queue
,
1396 cancelled
= gomp_task_run_pre (child_task
, child_task
->parent
,
1398 if (__builtin_expect (cancelled
, 0))
1402 gomp_finish_task (to_free
);
1406 goto finish_cancelled
;
1408 team
->task_running_count
++;
1409 child_task
->in_tied_task
= true;
1411 else if (team
->task_count
== 0
1412 && gomp_team_barrier_waiting_for_tasks (&team
->barrier
))
1414 gomp_team_barrier_done (&team
->barrier
, state
);
1415 gomp_mutex_unlock (&team
->task_lock
);
1416 gomp_team_barrier_wake (&team
->barrier
, 0);
1419 gomp_finish_task (to_free
);
1424 gomp_mutex_unlock (&team
->task_lock
);
1427 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
1432 gomp_finish_task (to_free
);
1438 thr
->task
= child_task
;
1439 if (__builtin_expect (child_task
->fn
== NULL
, 0))
1441 if (gomp_target_task_fn (child_task
->fn_data
))
1444 gomp_mutex_lock (&team
->task_lock
);
1445 child_task
->kind
= GOMP_TASK_ASYNC_RUNNING
;
1446 team
->task_running_count
--;
1447 struct gomp_target_task
*ttask
1448 = (struct gomp_target_task
*) child_task
->fn_data
;
1449 /* If GOMP_PLUGIN_target_task_completion has run already
1450 in between gomp_target_task_fn and the mutex lock,
1451 perform the requeuing here. */
1452 if (ttask
->state
== GOMP_TARGET_TASK_FINISHED
)
1453 gomp_target_task_completion (team
, child_task
);
1455 ttask
->state
= GOMP_TARGET_TASK_RUNNING
;
1461 child_task
->fn (child_task
->fn_data
);
1466 gomp_mutex_lock (&team
->task_lock
);
1469 if (child_task
->detach_team
)
1471 assert (child_task
->detach_team
== team
);
1472 child_task
->kind
= GOMP_TASK_DETACHED
;
1473 ++team
->task_detach_count
;
1474 --team
->task_running_count
;
1476 "thread %d: task with event %p finished without "
1477 "completion event fulfilled in team barrier\n",
1478 thr
->ts
.team_id
, child_task
);
1485 = gomp_task_run_post_handle_depend (child_task
, team
);
1486 gomp_task_run_post_remove_parent (child_task
);
1487 gomp_clear_parent (&child_task
->children_queue
);
1488 gomp_task_run_post_remove_taskgroup (child_task
);
1489 to_free
= child_task
;
1491 team
->task_running_count
--;
1495 do_wake
= team
->nthreads
- team
->task_running_count
;
1496 if (do_wake
> new_tasks
)
1497 do_wake
= new_tasks
;
1504 /* Called when encountering a taskwait directive.
1506 Wait for all children of the current task. */
1509 GOMP_taskwait (void)
1511 struct gomp_thread
*thr
= gomp_thread ();
1512 struct gomp_team
*team
= thr
->ts
.team
;
1513 struct gomp_task
*task
= thr
->task
;
1514 struct gomp_task
*child_task
= NULL
;
1515 struct gomp_task
*to_free
= NULL
;
1516 struct gomp_taskwait taskwait
;
1519 /* The acquire barrier on load of task->children here synchronizes
1520 with the write of a NULL in gomp_task_run_post_remove_parent. It is
1521 not necessary that we synchronize with other non-NULL writes at
1522 this point, but we must ensure that all writes to memory by a
1523 child thread task work function are seen before we exit from
1526 || priority_queue_empty_p (&task
->children_queue
, MEMMODEL_ACQUIRE
))
1529 memset (&taskwait
, 0, sizeof (taskwait
));
1530 bool child_q
= false;
1531 gomp_mutex_lock (&team
->task_lock
);
1534 bool cancelled
= false;
1535 if (priority_queue_empty_p (&task
->children_queue
, MEMMODEL_RELAXED
))
1537 bool destroy_taskwait
= task
->taskwait
!= NULL
;
1538 task
->taskwait
= NULL
;
1539 gomp_mutex_unlock (&team
->task_lock
);
1542 gomp_finish_task (to_free
);
1545 if (destroy_taskwait
)
1546 gomp_sem_destroy (&taskwait
.taskwait_sem
);
1549 struct gomp_task
*next_task
1550 = priority_queue_next_task (PQ_CHILDREN
, &task
->children_queue
,
1551 PQ_TEAM
, &team
->task_queue
, &child_q
);
1552 if (next_task
->kind
== GOMP_TASK_WAITING
)
1554 child_task
= next_task
;
1556 = gomp_task_run_pre (child_task
, task
, team
);
1557 if (__builtin_expect (cancelled
, 0))
1561 gomp_finish_task (to_free
);
1565 goto finish_cancelled
;
1570 /* All tasks we are waiting for are either running in other
1571 threads, are detached and waiting for the completion event to be
1572 fulfilled, or they are tasks that have not had their
1573 dependencies met (so they're not even in the queue). Wait
1575 if (task
->taskwait
== NULL
)
1577 taskwait
.in_depend_wait
= false;
1578 gomp_sem_init (&taskwait
.taskwait_sem
, 0);
1579 task
->taskwait
= &taskwait
;
1581 taskwait
.in_taskwait
= true;
1583 gomp_mutex_unlock (&team
->task_lock
);
1586 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
1591 gomp_finish_task (to_free
);
1597 thr
->task
= child_task
;
1598 if (__builtin_expect (child_task
->fn
== NULL
, 0))
1600 if (gomp_target_task_fn (child_task
->fn_data
))
1603 gomp_mutex_lock (&team
->task_lock
);
1604 child_task
->kind
= GOMP_TASK_ASYNC_RUNNING
;
1605 struct gomp_target_task
*ttask
1606 = (struct gomp_target_task
*) child_task
->fn_data
;
1607 /* If GOMP_PLUGIN_target_task_completion has run already
1608 in between gomp_target_task_fn and the mutex lock,
1609 perform the requeuing here. */
1610 if (ttask
->state
== GOMP_TARGET_TASK_FINISHED
)
1611 gomp_target_task_completion (team
, child_task
);
1613 ttask
->state
= GOMP_TARGET_TASK_RUNNING
;
1619 child_task
->fn (child_task
->fn_data
);
1623 gomp_sem_wait (&taskwait
.taskwait_sem
);
1624 gomp_mutex_lock (&team
->task_lock
);
1627 if (child_task
->detach_team
)
1629 assert (child_task
->detach_team
== team
);
1630 child_task
->kind
= GOMP_TASK_DETACHED
;
1631 ++team
->task_detach_count
;
1633 "thread %d: task with event %p finished without "
1634 "completion event fulfilled in taskwait\n",
1635 thr
->ts
.team_id
, child_task
);
1642 = gomp_task_run_post_handle_depend (child_task
, team
);
1646 priority_queue_remove (PQ_CHILDREN
, &task
->children_queue
,
1647 child_task
, MEMMODEL_RELAXED
);
1648 child_task
->pnode
[PQ_CHILDREN
].next
= NULL
;
1649 child_task
->pnode
[PQ_CHILDREN
].prev
= NULL
;
1652 gomp_clear_parent (&child_task
->children_queue
);
1654 gomp_task_run_post_remove_taskgroup (child_task
);
1656 to_free
= child_task
;
1661 do_wake
= team
->nthreads
- team
->task_running_count
1662 - !task
->in_tied_task
;
1663 if (do_wake
> new_tasks
)
1664 do_wake
= new_tasks
;
1670 /* Called when encountering a taskwait directive with depend clause(s).
1671 Wait as if it was an mergeable included task construct with empty body. */
1674 GOMP_taskwait_depend (void **depend
)
1676 struct gomp_thread
*thr
= gomp_thread ();
1677 struct gomp_team
*team
= thr
->ts
.team
;
1679 /* If parallel or taskgroup has been cancelled, return early. */
1680 if (__builtin_expect (gomp_cancel_var
, 0) && team
)
1682 if (gomp_team_barrier_cancelled (&team
->barrier
))
1684 if (thr
->task
->taskgroup
)
1686 if (thr
->task
->taskgroup
->cancelled
)
1688 if (thr
->task
->taskgroup
->workshare
1689 && thr
->task
->taskgroup
->prev
1690 && thr
->task
->taskgroup
->prev
->cancelled
)
1695 if (thr
->task
&& thr
->task
->depend_hash
)
1696 gomp_task_maybe_wait_for_dependencies (depend
);
1699 /* An undeferred task is about to run. Wait for all tasks that this
1700 undeferred task depends on.
1702 This is done by first putting all known ready dependencies
1703 (dependencies that have their own dependencies met) at the top of
1704 the scheduling queues. Then we iterate through these imminently
1705 ready tasks (and possibly other high priority tasks), and run them.
1706 If we run out of ready dependencies to execute, we either wait for
1707 the remaining dependencies to finish, or wait for them to get
1708 scheduled so we can run them.
1710 DEPEND is as in GOMP_task. */
1713 gomp_task_maybe_wait_for_dependencies (void **depend
)
1715 struct gomp_thread
*thr
= gomp_thread ();
1716 struct gomp_task
*task
= thr
->task
;
1717 struct gomp_team
*team
= thr
->ts
.team
;
1718 struct gomp_task_depend_entry elem
, *ent
= NULL
;
1719 struct gomp_taskwait taskwait
;
1720 size_t orig_ndepend
= (uintptr_t) depend
[0];
1721 size_t nout
= (uintptr_t) depend
[1];
1722 size_t ndepend
= orig_ndepend
;
1723 size_t normal
= ndepend
;
1726 size_t num_awaited
= 0;
1727 struct gomp_task
*child_task
= NULL
;
1728 struct gomp_task
*to_free
= NULL
;
1734 nout
= (uintptr_t) depend
[2] + (uintptr_t) depend
[3];
1735 normal
= nout
+ (uintptr_t) depend
[4];
1738 gomp_mutex_lock (&team
->task_lock
);
1739 for (i
= 0; i
< ndepend
; i
++)
1741 elem
.addr
= depend
[i
+ n
];
1742 elem
.is_in
= i
>= nout
;
1743 if (__builtin_expect (i
>= normal
, 0))
1745 void **d
= (void **) elem
.addr
;
1746 switch ((uintptr_t) d
[1])
1748 case GOMP_DEPEND_IN
:
1750 case GOMP_DEPEND_OUT
:
1751 case GOMP_DEPEND_INOUT
:
1752 case GOMP_DEPEND_MUTEXINOUTSET
:
1756 gomp_fatal ("unknown omp_depend_t dependence type %d",
1757 (int) (uintptr_t) d
[1]);
1761 ent
= htab_find (task
->depend_hash
, &elem
);
1762 for (; ent
; ent
= ent
->next
)
1763 if (elem
.is_in
&& ent
->is_in
)
1767 struct gomp_task
*tsk
= ent
->task
;
1768 if (!tsk
->parent_depends_on
)
1770 tsk
->parent_depends_on
= true;
1772 /* If dependency TSK itself has no dependencies and is
1773 ready to run, move it up front so that we run it as
1774 soon as possible. */
1775 if (tsk
->num_dependees
== 0 && tsk
->kind
== GOMP_TASK_WAITING
)
1776 priority_queue_upgrade_task (tsk
, task
);
1780 if (num_awaited
== 0)
1782 gomp_mutex_unlock (&team
->task_lock
);
1786 memset (&taskwait
, 0, sizeof (taskwait
));
1787 taskwait
.n_depend
= num_awaited
;
1788 gomp_sem_init (&taskwait
.taskwait_sem
, 0);
1789 task
->taskwait
= &taskwait
;
1793 bool cancelled
= false;
1794 if (taskwait
.n_depend
== 0)
1796 task
->taskwait
= NULL
;
1797 gomp_mutex_unlock (&team
->task_lock
);
1800 gomp_finish_task (to_free
);
1803 gomp_sem_destroy (&taskwait
.taskwait_sem
);
1807 /* Theoretically when we have multiple priorities, we should
1808 chose between the highest priority item in
1809 task->children_queue and team->task_queue here, so we should
1810 use priority_queue_next_task(). However, since we are
1811 running an undeferred task, perhaps that makes all tasks it
1812 depends on undeferred, thus a priority of INF? This would
1813 make it unnecessary to take anything into account here,
1814 but the dependencies.
1816 On the other hand, if we want to use priority_queue_next_task(),
1817 care should be taken to only use priority_queue_remove()
1818 below if the task was actually removed from the children
1821 struct gomp_task
*next_task
1822 = priority_queue_next_task (PQ_CHILDREN
, &task
->children_queue
,
1823 PQ_IGNORED
, NULL
, &ignored
);
1825 if (next_task
->kind
== GOMP_TASK_WAITING
)
1827 child_task
= next_task
;
1829 = gomp_task_run_pre (child_task
, task
, team
);
1830 if (__builtin_expect (cancelled
, 0))
1834 gomp_finish_task (to_free
);
1838 goto finish_cancelled
;
1842 /* All tasks we are waiting for are either running in other
1843 threads, or they are tasks that have not had their
1844 dependencies met (so they're not even in the queue). Wait
1846 taskwait
.in_depend_wait
= true;
1847 gomp_mutex_unlock (&team
->task_lock
);
1850 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
1855 gomp_finish_task (to_free
);
1861 thr
->task
= child_task
;
1862 if (__builtin_expect (child_task
->fn
== NULL
, 0))
1864 if (gomp_target_task_fn (child_task
->fn_data
))
1867 gomp_mutex_lock (&team
->task_lock
);
1868 child_task
->kind
= GOMP_TASK_ASYNC_RUNNING
;
1869 struct gomp_target_task
*ttask
1870 = (struct gomp_target_task
*) child_task
->fn_data
;
1871 /* If GOMP_PLUGIN_target_task_completion has run already
1872 in between gomp_target_task_fn and the mutex lock,
1873 perform the requeuing here. */
1874 if (ttask
->state
== GOMP_TARGET_TASK_FINISHED
)
1875 gomp_target_task_completion (team
, child_task
);
1877 ttask
->state
= GOMP_TARGET_TASK_RUNNING
;
1883 child_task
->fn (child_task
->fn_data
);
1887 gomp_sem_wait (&taskwait
.taskwait_sem
);
1888 gomp_mutex_lock (&team
->task_lock
);
1893 = gomp_task_run_post_handle_depend (child_task
, team
);
1894 if (child_task
->parent_depends_on
)
1895 --taskwait
.n_depend
;
1897 priority_queue_remove (PQ_CHILDREN
, &task
->children_queue
,
1898 child_task
, MEMMODEL_RELAXED
);
1899 child_task
->pnode
[PQ_CHILDREN
].next
= NULL
;
1900 child_task
->pnode
[PQ_CHILDREN
].prev
= NULL
;
1902 gomp_clear_parent (&child_task
->children_queue
);
1903 gomp_task_run_post_remove_taskgroup (child_task
);
1904 to_free
= child_task
;
1909 do_wake
= team
->nthreads
- team
->task_running_count
1910 - !task
->in_tied_task
;
1911 if (do_wake
> new_tasks
)
1912 do_wake
= new_tasks
;
1918 /* Called when encountering a taskyield directive. */
1921 GOMP_taskyield (void)
1923 /* Nothing at the moment. */
1926 static inline struct gomp_taskgroup
*
1927 gomp_taskgroup_init (struct gomp_taskgroup
*prev
)
1929 struct gomp_taskgroup
*taskgroup
1930 = gomp_malloc (sizeof (struct gomp_taskgroup
));
1931 taskgroup
->prev
= prev
;
1932 priority_queue_init (&taskgroup
->taskgroup_queue
);
1933 taskgroup
->reductions
= prev
? prev
->reductions
: NULL
;
1934 taskgroup
->in_taskgroup_wait
= false;
1935 taskgroup
->cancelled
= false;
1936 taskgroup
->workshare
= false;
1937 taskgroup
->num_children
= 0;
1938 gomp_sem_init (&taskgroup
->taskgroup_sem
, 0);
1943 GOMP_taskgroup_start (void)
1945 struct gomp_thread
*thr
= gomp_thread ();
1946 struct gomp_team
*team
= thr
->ts
.team
;
1947 struct gomp_task
*task
= thr
->task
;
1949 /* If team is NULL, all tasks are executed as
1950 GOMP_TASK_UNDEFERRED tasks and thus all children tasks of
1951 taskgroup and their descendant tasks will be finished
1952 by the time GOMP_taskgroup_end is called. */
1955 task
->taskgroup
= gomp_taskgroup_init (task
->taskgroup
);
1959 GOMP_taskgroup_end (void)
1961 struct gomp_thread
*thr
= gomp_thread ();
1962 struct gomp_team
*team
= thr
->ts
.team
;
1963 struct gomp_task
*task
= thr
->task
;
1964 struct gomp_taskgroup
*taskgroup
;
1965 struct gomp_task
*child_task
= NULL
;
1966 struct gomp_task
*to_free
= NULL
;
1971 taskgroup
= task
->taskgroup
;
1972 if (__builtin_expect (taskgroup
== NULL
, 0)
1973 && thr
->ts
.level
== 0)
1975 /* This can happen if GOMP_taskgroup_start is called when
1976 thr->ts.team == NULL, but inside of the taskgroup there
1977 is #pragma omp target nowait that creates an implicit
1978 team with a single thread. In this case, we want to wait
1979 for all outstanding tasks in this team. */
1980 gomp_team_barrier_wait (&team
->barrier
);
1984 /* The acquire barrier on load of taskgroup->num_children here
1985 synchronizes with the write of 0 in gomp_task_run_post_remove_taskgroup.
1986 It is not necessary that we synchronize with other non-0 writes at
1987 this point, but we must ensure that all writes to memory by a
1988 child thread task work function are seen before we exit from
1989 GOMP_taskgroup_end. */
1990 if (__atomic_load_n (&taskgroup
->num_children
, MEMMODEL_ACQUIRE
) == 0)
1994 gomp_mutex_lock (&team
->task_lock
);
1997 bool cancelled
= false;
1998 if (priority_queue_empty_p (&taskgroup
->taskgroup_queue
,
2001 if (taskgroup
->num_children
)
2003 if (priority_queue_empty_p (&task
->children_queue
,
2007 = priority_queue_next_task (PQ_CHILDREN
, &task
->children_queue
,
2008 PQ_TEAM
, &team
->task_queue
,
2013 gomp_mutex_unlock (&team
->task_lock
);
2016 gomp_finish_task (to_free
);
2024 = priority_queue_next_task (PQ_TASKGROUP
, &taskgroup
->taskgroup_queue
,
2025 PQ_TEAM
, &team
->task_queue
, &unused
);
2026 if (child_task
->kind
== GOMP_TASK_WAITING
)
2029 = gomp_task_run_pre (child_task
, child_task
->parent
, team
);
2030 if (__builtin_expect (cancelled
, 0))
2034 gomp_finish_task (to_free
);
2038 goto finish_cancelled
;
2045 /* All tasks we are waiting for are either running in other
2046 threads, or they are tasks that have not had their
2047 dependencies met (so they're not even in the queue). Wait
2049 taskgroup
->in_taskgroup_wait
= true;
2051 gomp_mutex_unlock (&team
->task_lock
);
2054 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
2059 gomp_finish_task (to_free
);
2065 thr
->task
= child_task
;
2066 if (__builtin_expect (child_task
->fn
== NULL
, 0))
2068 if (gomp_target_task_fn (child_task
->fn_data
))
2071 gomp_mutex_lock (&team
->task_lock
);
2072 child_task
->kind
= GOMP_TASK_ASYNC_RUNNING
;
2073 struct gomp_target_task
*ttask
2074 = (struct gomp_target_task
*) child_task
->fn_data
;
2075 /* If GOMP_PLUGIN_target_task_completion has run already
2076 in between gomp_target_task_fn and the mutex lock,
2077 perform the requeuing here. */
2078 if (ttask
->state
== GOMP_TARGET_TASK_FINISHED
)
2079 gomp_target_task_completion (team
, child_task
);
2081 ttask
->state
= GOMP_TARGET_TASK_RUNNING
;
2087 child_task
->fn (child_task
->fn_data
);
2091 gomp_sem_wait (&taskgroup
->taskgroup_sem
);
2092 gomp_mutex_lock (&team
->task_lock
);
2095 if (child_task
->detach_team
)
2097 assert (child_task
->detach_team
== team
);
2098 child_task
->kind
= GOMP_TASK_DETACHED
;
2099 ++team
->task_detach_count
;
2101 "thread %d: task with event %p finished without "
2102 "completion event fulfilled in taskgroup\n",
2103 thr
->ts
.team_id
, child_task
);
2110 = gomp_task_run_post_handle_depend (child_task
, team
);
2111 gomp_task_run_post_remove_parent (child_task
);
2112 gomp_clear_parent (&child_task
->children_queue
);
2113 gomp_task_run_post_remove_taskgroup (child_task
);
2114 to_free
= child_task
;
2119 do_wake
= team
->nthreads
- team
->task_running_count
2120 - !task
->in_tied_task
;
2121 if (do_wake
> new_tasks
)
2122 do_wake
= new_tasks
;
2128 task
->taskgroup
= taskgroup
->prev
;
2129 gomp_sem_destroy (&taskgroup
->taskgroup_sem
);
2133 static inline __attribute__((always_inline
)) void
2134 gomp_reduction_register (uintptr_t *data
, uintptr_t *old
, uintptr_t *orig
,
2137 size_t total_cnt
= 0;
2138 uintptr_t *d
= data
;
2139 struct htab
*old_htab
= NULL
, *new_htab
;
2142 if (__builtin_expect (orig
!= NULL
, 0))
2144 /* For worksharing task reductions, memory has been allocated
2145 already by some other thread that encountered the construct
2149 orig
= (uintptr_t *) orig
[4];
2153 size_t sz
= d
[1] * nthreads
;
2154 /* Should use omp_alloc if d[3] is not -1. */
2155 void *ptr
= gomp_aligned_alloc (d
[2], sz
);
2156 memset (ptr
, '\0', sz
);
2157 d
[2] = (uintptr_t) ptr
;
2164 d
[4] = (uintptr_t) old
;
2168 d
= (uintptr_t *) d
[4];
2173 old_htab
= (struct htab
*) old
[5];
2174 total_cnt
+= htab_elements (old_htab
);
2176 new_htab
= htab_create (total_cnt
);
2179 /* Copy old hash table, like in htab_expand. */
2180 hash_entry_type
*p
, *olimit
;
2181 new_htab
->n_elements
= htab_elements (old_htab
);
2182 olimit
= old_htab
->entries
+ old_htab
->size
;
2183 p
= old_htab
->entries
;
2186 hash_entry_type x
= *p
;
2187 if (x
!= HTAB_EMPTY_ENTRY
&& x
!= HTAB_DELETED_ENTRY
)
2188 *find_empty_slot_for_expand (new_htab
, htab_hash (x
)) = x
;
2197 for (j
= 0; j
< d
[0]; ++j
)
2199 uintptr_t *p
= d
+ 7 + j
* 3;
2200 p
[2] = (uintptr_t) d
;
2201 /* Ugly hack, hash_entry_type is defined for the task dependencies,
2202 which hash on the first element which is a pointer. We need
2203 to hash also on the first sizeof (uintptr_t) bytes which contain
2204 a pointer. Hide the cast from the compiler. */
2206 __asm ("" : "=g" (n
) : "0" (p
));
2207 *htab_find_slot (&new_htab
, n
, INSERT
) = n
;
2209 if (d
[4] == (uintptr_t) old
)
2212 d
= (uintptr_t *) d
[4];
2215 d
[5] = (uintptr_t) new_htab
;
2219 gomp_create_artificial_team (void)
2221 struct gomp_thread
*thr
= gomp_thread ();
2222 struct gomp_task_icv
*icv
;
2223 struct gomp_team
*team
= gomp_new_team (1);
2224 struct gomp_task
*task
= thr
->task
;
2225 icv
= task
? &task
->icv
: &gomp_global_icv
;
2226 team
->prev_ts
= thr
->ts
;
2227 thr
->ts
.team
= team
;
2228 thr
->ts
.team_id
= 0;
2229 thr
->ts
.work_share
= &team
->work_shares
[0];
2230 thr
->ts
.last_work_share
= NULL
;
2231 #ifdef HAVE_SYNC_BUILTINS
2232 thr
->ts
.single_count
= 0;
2234 thr
->ts
.static_trip
= 0;
2235 thr
->task
= &team
->implicit_task
[0];
2236 gomp_init_task (thr
->task
, NULL
, icv
);
2242 thr
->task
= &team
->implicit_task
[0];
2244 #ifdef LIBGOMP_USE_PTHREADS
2246 pthread_setspecific (gomp_thread_destructor
, thr
);
2250 /* The format of data is:
2253 data[2] alignment (on output array pointer)
2254 data[3] allocator (-1 if malloc allocator)
2255 data[4] next pointer
2256 data[5] used internally (htab pointer)
2257 data[6] used internally (end of array)
2261 ent[2] used internally (pointer to data[0])
2262 The entries are sorted by increasing offset, so that a binary
2263 search can be performed. Normally, data[8] is 0, exception is
2264 for worksharing construct task reductions in cancellable parallel,
2265 where at offset 0 there should be space for a pointer and an integer
2266 which are used internally. */
2269 GOMP_taskgroup_reduction_register (uintptr_t *data
)
2271 struct gomp_thread
*thr
= gomp_thread ();
2272 struct gomp_team
*team
= thr
->ts
.team
;
2273 struct gomp_task
*task
;
2275 if (__builtin_expect (team
== NULL
, 0))
2277 /* The task reduction code needs a team and task, so for
2278 orphaned taskgroups just create the implicit team. */
2279 gomp_create_artificial_team ();
2280 ialias_call (GOMP_taskgroup_start
) ();
2281 team
= thr
->ts
.team
;
2283 nthreads
= team
->nthreads
;
2285 gomp_reduction_register (data
, task
->taskgroup
->reductions
, NULL
, nthreads
);
2286 task
->taskgroup
->reductions
= data
;
2290 GOMP_taskgroup_reduction_unregister (uintptr_t *data
)
2292 uintptr_t *d
= data
;
2293 htab_free ((struct htab
*) data
[5]);
2296 gomp_aligned_free ((void *) d
[2]);
2297 d
= (uintptr_t *) d
[4];
2301 ialias (GOMP_taskgroup_reduction_unregister
)
2303 /* For i = 0 to cnt-1, remap ptrs[i] which is either address of the
2304 original list item or address of previously remapped original list
2305 item to address of the private copy, store that to ptrs[i].
2306 For i < cntorig, additionally set ptrs[cnt+i] to the address of
2307 the original list item. */
2310 GOMP_task_reduction_remap (size_t cnt
, size_t cntorig
, void **ptrs
)
2312 struct gomp_thread
*thr
= gomp_thread ();
2313 struct gomp_task
*task
= thr
->task
;
2314 unsigned id
= thr
->ts
.team_id
;
2315 uintptr_t *data
= task
->taskgroup
->reductions
;
2317 struct htab
*reduction_htab
= (struct htab
*) data
[5];
2319 for (i
= 0; i
< cnt
; ++i
)
2321 hash_entry_type ent
, n
;
2322 __asm ("" : "=g" (ent
) : "0" (ptrs
+ i
));
2323 n
= htab_find (reduction_htab
, ent
);
2327 __asm ("" : "=g" (p
) : "0" (n
));
2328 /* At this point, p[0] should be equal to (uintptr_t) ptrs[i],
2329 p[1] is the offset within the allocated chunk for each
2330 thread, p[2] is the array registered with
2331 GOMP_taskgroup_reduction_register, d[2] is the base of the
2332 allocated memory and d[1] is the size of the allocated chunk
2334 d
= (uintptr_t *) p
[2];
2335 ptrs
[i
] = (void *) (d
[2] + id
* d
[1] + p
[1]);
2336 if (__builtin_expect (i
< cntorig
, 0))
2337 ptrs
[cnt
+ i
] = (void *) p
[0];
2343 if ((uintptr_t) ptrs
[i
] >= d
[2] && (uintptr_t) ptrs
[i
] < d
[6])
2345 d
= (uintptr_t *) d
[4];
2348 gomp_fatal ("couldn't find matching task_reduction or reduction with "
2349 "task modifier for %p", ptrs
[i
]);
2350 uintptr_t off
= ((uintptr_t) ptrs
[i
] - d
[2]) % d
[1];
2351 ptrs
[i
] = (void *) (d
[2] + id
* d
[1] + off
);
2352 if (__builtin_expect (i
< cntorig
, 0))
2354 size_t lo
= 0, hi
= d
[0] - 1;
2357 size_t m
= (lo
+ hi
) / 2;
2358 if (d
[7 + 3 * m
+ 1] < off
)
2360 else if (d
[7 + 3 * m
+ 1] == off
)
2362 ptrs
[cnt
+ i
] = (void *) d
[7 + 3 * m
];
2369 gomp_fatal ("couldn't find matching task_reduction or reduction "
2370 "with task modifier for %p", ptrs
[i
]);
2375 struct gomp_taskgroup
*
2376 gomp_parallel_reduction_register (uintptr_t *data
, unsigned nthreads
)
2378 struct gomp_taskgroup
*taskgroup
= gomp_taskgroup_init (NULL
);
2379 gomp_reduction_register (data
, NULL
, NULL
, nthreads
);
2380 taskgroup
->reductions
= data
;
2385 gomp_workshare_task_reduction_register (uintptr_t *data
, uintptr_t *orig
)
2387 struct gomp_thread
*thr
= gomp_thread ();
2388 struct gomp_team
*team
= thr
->ts
.team
;
2389 struct gomp_task
*task
= thr
->task
;
2390 unsigned nthreads
= team
->nthreads
;
2391 gomp_reduction_register (data
, task
->taskgroup
->reductions
, orig
, nthreads
);
2392 task
->taskgroup
->reductions
= data
;
2396 gomp_workshare_taskgroup_start (void)
2398 struct gomp_thread
*thr
= gomp_thread ();
2399 struct gomp_team
*team
= thr
->ts
.team
;
2400 struct gomp_task
*task
;
2404 gomp_create_artificial_team ();
2405 team
= thr
->ts
.team
;
2408 task
->taskgroup
= gomp_taskgroup_init (task
->taskgroup
);
2409 task
->taskgroup
->workshare
= true;
2413 GOMP_workshare_task_reduction_unregister (bool cancelled
)
2415 struct gomp_thread
*thr
= gomp_thread ();
2416 struct gomp_task
*task
= thr
->task
;
2417 struct gomp_team
*team
= thr
->ts
.team
;
2418 uintptr_t *data
= task
->taskgroup
->reductions
;
2419 ialias_call (GOMP_taskgroup_end
) ();
2420 if (thr
->ts
.team_id
== 0)
2421 ialias_call (GOMP_taskgroup_reduction_unregister
) (data
);
2423 htab_free ((struct htab
*) data
[5]);
2426 gomp_team_barrier_wait (&team
->barrier
);
2432 struct gomp_thread
*thr
= gomp_thread ();
2433 return thr
->task
&& thr
->task
->final_task
;
2436 ialias (omp_in_final
)
2439 omp_fulfill_event (omp_event_handle_t event
)
2441 struct gomp_task
*task
= (struct gomp_task
*) event
;
2442 if (!task
->deferred_p
)
2444 if (gomp_sem_getcount (task
->completion_sem
) > 0)
2445 gomp_fatal ("omp_fulfill_event: %p event already fulfilled!\n", task
);
2447 gomp_debug (0, "omp_fulfill_event: %p event for undeferred task\n",
2449 gomp_sem_post (task
->completion_sem
);
2453 struct gomp_team
*team
= __atomic_load_n (&task
->detach_team
,
2456 gomp_fatal ("omp_fulfill_event: %p event is invalid or has already "
2457 "been fulfilled!\n", task
);
2459 gomp_mutex_lock (&team
->task_lock
);
2460 if (task
->kind
!= GOMP_TASK_DETACHED
)
2462 /* The task has not finished running yet. */
2464 "omp_fulfill_event: %p event fulfilled for unfinished "
2466 __atomic_store_n (&task
->detach_team
, NULL
, MEMMODEL_RELAXED
);
2467 gomp_mutex_unlock (&team
->task_lock
);
2471 gomp_debug (0, "omp_fulfill_event: %p event fulfilled for finished task\n",
2473 size_t new_tasks
= gomp_task_run_post_handle_depend (task
, team
);
2474 gomp_task_run_post_remove_parent (task
);
2475 gomp_clear_parent (&task
->children_queue
);
2476 gomp_task_run_post_remove_taskgroup (task
);
2478 team
->task_detach_count
--;
2481 bool shackled_thread_p
= team
== gomp_thread ()->ts
.team
;
2484 /* Wake up threads to run new tasks. */
2485 gomp_team_barrier_set_task_pending (&team
->barrier
);
2486 do_wake
= team
->nthreads
- team
->task_running_count
;
2487 if (do_wake
> new_tasks
)
2488 do_wake
= new_tasks
;
2491 if (!shackled_thread_p
2493 && team
->task_detach_count
== 0
2494 && gomp_team_barrier_waiting_for_tasks (&team
->barrier
))
2495 /* Ensure that at least one thread is woken up to signal that the
2496 barrier can finish. */
2499 /* If we are running in an unshackled thread, the team might vanish before
2500 gomp_team_barrier_wake is run if we release the lock first, so keep the
2501 lock for the call in that case. */
2502 if (shackled_thread_p
)
2503 gomp_mutex_unlock (&team
->task_lock
);
2505 gomp_team_barrier_wake (&team
->barrier
, do_wake
);
2506 if (!shackled_thread_p
)
2507 gomp_mutex_unlock (&team
->task_lock
);
2509 gomp_finish_task (task
);
2513 ialias (omp_fulfill_event
)