17cc577a4SJonathan Peyton /*
2de4749b7SJonathan Peyton  * kmp_tasking.cpp -- OpenMP 3.0 tasking support.
37cc577a4SJonathan Peyton  */
47cc577a4SJonathan Peyton 
57cc577a4SJonathan Peyton 
67cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
77cc577a4SJonathan Peyton //
87cc577a4SJonathan Peyton //                     The LLVM Compiler Infrastructure
97cc577a4SJonathan Peyton //
107cc577a4SJonathan Peyton // This file is dual licensed under the MIT and the University of Illinois Open
117cc577a4SJonathan Peyton // Source Licenses. See LICENSE.txt for details.
127cc577a4SJonathan Peyton //
137cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
147cc577a4SJonathan Peyton 
157cc577a4SJonathan Peyton 
167cc577a4SJonathan Peyton #include "kmp.h"
177cc577a4SJonathan Peyton #include "kmp_i18n.h"
187cc577a4SJonathan Peyton #include "kmp_itt.h"
197cc577a4SJonathan Peyton #include "kmp_stats.h"
20*3041982dSJonathan Peyton #include "kmp_wait_release.h"
217cc577a4SJonathan Peyton 
227cc577a4SJonathan Peyton #if OMPT_SUPPORT
237cc577a4SJonathan Peyton #include "ompt-specific.h"
247cc577a4SJonathan Peyton #endif
257cc577a4SJonathan Peyton 
267cc577a4SJonathan Peyton #include "tsan_annotations.h"
277cc577a4SJonathan Peyton 
287cc577a4SJonathan Peyton /* forward declaration */
29*3041982dSJonathan Peyton static void __kmp_enable_tasking(kmp_task_team_t *task_team,
30*3041982dSJonathan Peyton                                  kmp_info_t *this_thr);
31*3041982dSJonathan Peyton static void __kmp_alloc_task_deque(kmp_info_t *thread,
32*3041982dSJonathan Peyton                                    kmp_thread_data_t *thread_data);
33*3041982dSJonathan Peyton static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
34*3041982dSJonathan Peyton                                            kmp_task_team_t *task_team);
357cc577a4SJonathan Peyton 
367cc577a4SJonathan Peyton #ifdef OMP_45_ENABLED
377cc577a4SJonathan Peyton static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask);
387cc577a4SJonathan Peyton #endif
397cc577a4SJonathan Peyton 
407cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
417cc577a4SJonathan Peyton 
427cc577a4SJonathan Peyton //  __kmp_trace_task_stack: print the tied tasks from the task stack in order
437cc577a4SJonathan Peyton //  from top do bottom
447cc577a4SJonathan Peyton //
457cc577a4SJonathan Peyton //  gtid: global thread identifier for thread containing stack
467cc577a4SJonathan Peyton //  thread_data: thread data for task team thread containing stack
477cc577a4SJonathan Peyton //  threshold: value above which the trace statement triggers
487cc577a4SJonathan Peyton //  location: string identifying call site of this function (for trace)
49*3041982dSJonathan Peyton static void __kmp_trace_task_stack(kmp_int32 gtid,
50*3041982dSJonathan Peyton                                    kmp_thread_data_t *thread_data,
51*3041982dSJonathan Peyton                                    int threshold, char *location) {
527cc577a4SJonathan Peyton   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
537cc577a4SJonathan Peyton   kmp_taskdata_t **stack_top = task_stack->ts_top;
547cc577a4SJonathan Peyton   kmp_int32 entries = task_stack->ts_entries;
557cc577a4SJonathan Peyton   kmp_taskdata_t *tied_task;
567cc577a4SJonathan Peyton 
57*3041982dSJonathan Peyton   KA_TRACE(
58*3041982dSJonathan Peyton       threshold,
59*3041982dSJonathan Peyton       ("__kmp_trace_task_stack(start): location = %s, gtid = %d, entries = %d, "
607cc577a4SJonathan Peyton        "first_block = %p, stack_top = %p \n",
617cc577a4SJonathan Peyton        location, gtid, entries, task_stack->ts_first_block, stack_top));
627cc577a4SJonathan Peyton 
637cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(stack_top != NULL);
647cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(entries > 0);
657cc577a4SJonathan Peyton 
66*3041982dSJonathan Peyton   while (entries != 0) {
677cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(stack_top != &task_stack->ts_first_block.sb_block[0]);
687cc577a4SJonathan Peyton     // fix up ts_top if we need to pop from previous block
69*3041982dSJonathan Peyton     if (entries & TASK_STACK_INDEX_MASK == 0) {
707cc577a4SJonathan Peyton       kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(stack_top);
717cc577a4SJonathan Peyton 
727cc577a4SJonathan Peyton       stack_block = stack_block->sb_prev;
737cc577a4SJonathan Peyton       stack_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE];
747cc577a4SJonathan Peyton     }
757cc577a4SJonathan Peyton 
767cc577a4SJonathan Peyton     // finish bookkeeping
777cc577a4SJonathan Peyton     stack_top--;
787cc577a4SJonathan Peyton     entries--;
797cc577a4SJonathan Peyton 
807cc577a4SJonathan Peyton     tied_task = *stack_top;
817cc577a4SJonathan Peyton 
827cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(tied_task != NULL);
837cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED);
847cc577a4SJonathan Peyton 
85*3041982dSJonathan Peyton     KA_TRACE(threshold,
86*3041982dSJonathan Peyton              ("__kmp_trace_task_stack(%s):             gtid=%d, entry=%d, "
877cc577a4SJonathan Peyton               "stack_top=%p, tied_task=%p\n",
887cc577a4SJonathan Peyton               location, gtid, entries, stack_top, tied_task));
897cc577a4SJonathan Peyton   }
907cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(stack_top == &task_stack->ts_first_block.sb_block[0]);
917cc577a4SJonathan Peyton 
92*3041982dSJonathan Peyton   KA_TRACE(threshold,
93*3041982dSJonathan Peyton            ("__kmp_trace_task_stack(exit): location = %s, gtid = %d\n",
947cc577a4SJonathan Peyton             location, gtid));
957cc577a4SJonathan Peyton }
967cc577a4SJonathan Peyton 
977cc577a4SJonathan Peyton //  __kmp_init_task_stack: initialize the task stack for the first time
987cc577a4SJonathan Peyton //  after a thread_data structure is created.
997cc577a4SJonathan Peyton //  It should not be necessary to do this again (assuming the stack works).
1007cc577a4SJonathan Peyton //
1017cc577a4SJonathan Peyton //  gtid: global thread identifier of calling thread
1027cc577a4SJonathan Peyton //  thread_data: thread data for task team thread containing stack
103*3041982dSJonathan Peyton static void __kmp_init_task_stack(kmp_int32 gtid,
104*3041982dSJonathan Peyton                                   kmp_thread_data_t *thread_data) {
1057cc577a4SJonathan Peyton   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
1067cc577a4SJonathan Peyton   kmp_stack_block_t *first_block;
1077cc577a4SJonathan Peyton 
1087cc577a4SJonathan Peyton   // set up the first block of the stack
1097cc577a4SJonathan Peyton   first_block = &task_stack->ts_first_block;
1107cc577a4SJonathan Peyton   task_stack->ts_top = (kmp_taskdata_t **)first_block;
111*3041982dSJonathan Peyton   memset((void *)first_block, '\0',
112*3041982dSJonathan Peyton          TASK_STACK_BLOCK_SIZE * sizeof(kmp_taskdata_t *));
1137cc577a4SJonathan Peyton 
1147cc577a4SJonathan Peyton   // initialize the stack to be empty
1157cc577a4SJonathan Peyton   task_stack->ts_entries = TASK_STACK_EMPTY;
1167cc577a4SJonathan Peyton   first_block->sb_next = NULL;
1177cc577a4SJonathan Peyton   first_block->sb_prev = NULL;
1187cc577a4SJonathan Peyton }
1197cc577a4SJonathan Peyton 
1207cc577a4SJonathan Peyton //  __kmp_free_task_stack: free the task stack when thread_data is destroyed.
1217cc577a4SJonathan Peyton //
1227cc577a4SJonathan Peyton //  gtid: global thread identifier for calling thread
1237cc577a4SJonathan Peyton //  thread_data: thread info for thread containing stack
124*3041982dSJonathan Peyton static void __kmp_free_task_stack(kmp_int32 gtid,
125*3041982dSJonathan Peyton                                   kmp_thread_data_t *thread_data) {
1267cc577a4SJonathan Peyton   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
1277cc577a4SJonathan Peyton   kmp_stack_block_t *stack_block = &task_stack->ts_first_block;
1287cc577a4SJonathan Peyton 
1297cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_stack->ts_entries == TASK_STACK_EMPTY);
1307cc577a4SJonathan Peyton   // free from the second block of the stack
1317cc577a4SJonathan Peyton   while (stack_block != NULL) {
1327cc577a4SJonathan Peyton     kmp_stack_block_t *next_block = (stack_block) ? stack_block->sb_next : NULL;
1337cc577a4SJonathan Peyton 
1347cc577a4SJonathan Peyton     stack_block->sb_next = NULL;
1357cc577a4SJonathan Peyton     stack_block->sb_prev = NULL;
1367cc577a4SJonathan Peyton     if (stack_block != &task_stack->ts_first_block) {
137*3041982dSJonathan Peyton       __kmp_thread_free(thread,
138*3041982dSJonathan Peyton                         stack_block); // free the block, if not the first
1397cc577a4SJonathan Peyton     }
1407cc577a4SJonathan Peyton     stack_block = next_block;
1417cc577a4SJonathan Peyton   }
1427cc577a4SJonathan Peyton   // initialize the stack to be empty
1437cc577a4SJonathan Peyton   task_stack->ts_entries = 0;
1447cc577a4SJonathan Peyton   task_stack->ts_top = NULL;
1457cc577a4SJonathan Peyton }
1467cc577a4SJonathan Peyton 
1477cc577a4SJonathan Peyton //  __kmp_push_task_stack: Push the tied task onto the task stack.
1487cc577a4SJonathan Peyton //     Grow the stack if necessary by allocating another block.
1497cc577a4SJonathan Peyton //
1507cc577a4SJonathan Peyton //  gtid: global thread identifier for calling thread
1517cc577a4SJonathan Peyton //  thread: thread info for thread containing stack
1527cc577a4SJonathan Peyton //  tied_task: the task to push on the stack
153*3041982dSJonathan Peyton static void __kmp_push_task_stack(kmp_int32 gtid, kmp_info_t *thread,
154*3041982dSJonathan Peyton                                   kmp_taskdata_t *tied_task) {
1557cc577a4SJonathan Peyton   // GEH - need to consider what to do if tt_threads_data not allocated yet
156*3041982dSJonathan Peyton   kmp_thread_data_t *thread_data =
157*3041982dSJonathan Peyton       &thread->th.th_task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)];
1587cc577a4SJonathan Peyton   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
1597cc577a4SJonathan Peyton 
1607cc577a4SJonathan Peyton   if (tied_task->td_flags.team_serial || tied_task->td_flags.tasking_ser) {
1617cc577a4SJonathan Peyton     return; // Don't push anything on stack if team or team tasks are serialized
1627cc577a4SJonathan Peyton   }
1637cc577a4SJonathan Peyton 
1647cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED);
1657cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_stack->ts_top != NULL);
1667cc577a4SJonathan Peyton 
167*3041982dSJonathan Peyton   KA_TRACE(20,
168*3041982dSJonathan Peyton            ("__kmp_push_task_stack(enter): GTID: %d; THREAD: %p; TASK: %p\n",
1697cc577a4SJonathan Peyton             gtid, thread, tied_task));
1707cc577a4SJonathan Peyton   // Store entry
1717cc577a4SJonathan Peyton   *(task_stack->ts_top) = tied_task;
1727cc577a4SJonathan Peyton 
1737cc577a4SJonathan Peyton   // Do bookkeeping for next push
1747cc577a4SJonathan Peyton   task_stack->ts_top++;
1757cc577a4SJonathan Peyton   task_stack->ts_entries++;
1767cc577a4SJonathan Peyton 
177*3041982dSJonathan Peyton   if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) {
1787cc577a4SJonathan Peyton     // Find beginning of this task block
1797cc577a4SJonathan Peyton     kmp_stack_block_t *stack_block =
1807cc577a4SJonathan Peyton         (kmp_stack_block_t *)(task_stack->ts_top - TASK_STACK_BLOCK_SIZE);
1817cc577a4SJonathan Peyton 
1827cc577a4SJonathan Peyton     // Check if we already have a block
183*3041982dSJonathan Peyton     if (stack_block->sb_next !=
184*3041982dSJonathan Peyton         NULL) { // reset ts_top to beginning of next block
1857cc577a4SJonathan Peyton       task_stack->ts_top = &stack_block->sb_next->sb_block[0];
186*3041982dSJonathan Peyton     } else { // Alloc new block and link it up
187*3041982dSJonathan Peyton       kmp_stack_block_t *new_block = (kmp_stack_block_t *)__kmp_thread_calloc(
188*3041982dSJonathan Peyton           thread, sizeof(kmp_stack_block_t));
1897cc577a4SJonathan Peyton 
1907cc577a4SJonathan Peyton       task_stack->ts_top = &new_block->sb_block[0];
1917cc577a4SJonathan Peyton       stack_block->sb_next = new_block;
1927cc577a4SJonathan Peyton       new_block->sb_prev = stack_block;
1937cc577a4SJonathan Peyton       new_block->sb_next = NULL;
1947cc577a4SJonathan Peyton 
195*3041982dSJonathan Peyton       KA_TRACE(
196*3041982dSJonathan Peyton           30,
197*3041982dSJonathan Peyton           ("__kmp_push_task_stack(): GTID: %d; TASK: %p; Alloc new block: %p\n",
1987cc577a4SJonathan Peyton            gtid, tied_task, new_block));
1997cc577a4SJonathan Peyton     }
2007cc577a4SJonathan Peyton   }
201*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmp_push_task_stack(exit): GTID: %d; TASK: %p\n", gtid,
202*3041982dSJonathan Peyton                 tied_task));
2037cc577a4SJonathan Peyton }
2047cc577a4SJonathan Peyton 
2057cc577a4SJonathan Peyton //  __kmp_pop_task_stack: Pop the tied task from the task stack.  Don't return
2067cc577a4SJonathan Peyton //  the task, just check to make sure it matches the ending task passed in.
2077cc577a4SJonathan Peyton //
2087cc577a4SJonathan Peyton //  gtid: global thread identifier for the calling thread
2097cc577a4SJonathan Peyton //  thread: thread info structure containing stack
2107cc577a4SJonathan Peyton //  tied_task: the task popped off the stack
2117cc577a4SJonathan Peyton //  ending_task: the task that is ending (should match popped task)
212*3041982dSJonathan Peyton static void __kmp_pop_task_stack(kmp_int32 gtid, kmp_info_t *thread,
213*3041982dSJonathan Peyton                                  kmp_taskdata_t *ending_task) {
2147cc577a4SJonathan Peyton   // GEH - need to consider what to do if tt_threads_data not allocated yet
215*3041982dSJonathan Peyton   kmp_thread_data_t *thread_data =
216*3041982dSJonathan Peyton       &thread->th.th_task_team->tt_threads_data[__kmp_tid_from_gtid(gtid)];
2177cc577a4SJonathan Peyton   kmp_task_stack_t *task_stack = &thread_data->td.td_susp_tied_tasks;
2187cc577a4SJonathan Peyton   kmp_taskdata_t *tied_task;
2197cc577a4SJonathan Peyton 
2207cc577a4SJonathan Peyton   if (ending_task->td_flags.team_serial || ending_task->td_flags.tasking_ser) {
221*3041982dSJonathan Peyton     // Don't pop anything from stack if team or team tasks are serialized
222*3041982dSJonathan Peyton     return;
2237cc577a4SJonathan Peyton   }
2247cc577a4SJonathan Peyton 
2257cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_stack->ts_top != NULL);
2267cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_stack->ts_entries > 0);
2277cc577a4SJonathan Peyton 
228*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmp_pop_task_stack(enter): GTID: %d; THREAD: %p\n", gtid,
229*3041982dSJonathan Peyton                 thread));
2307cc577a4SJonathan Peyton 
2317cc577a4SJonathan Peyton   // fix up ts_top if we need to pop from previous block
232*3041982dSJonathan Peyton   if (task_stack->ts_entries & TASK_STACK_INDEX_MASK == 0) {
233*3041982dSJonathan Peyton     kmp_stack_block_t *stack_block = (kmp_stack_block_t *)(task_stack->ts_top);
2347cc577a4SJonathan Peyton 
2357cc577a4SJonathan Peyton     stack_block = stack_block->sb_prev;
2367cc577a4SJonathan Peyton     task_stack->ts_top = &stack_block->sb_block[TASK_STACK_BLOCK_SIZE];
2377cc577a4SJonathan Peyton   }
2387cc577a4SJonathan Peyton 
2397cc577a4SJonathan Peyton   // finish bookkeeping
2407cc577a4SJonathan Peyton   task_stack->ts_top--;
2417cc577a4SJonathan Peyton   task_stack->ts_entries--;
2427cc577a4SJonathan Peyton 
2437cc577a4SJonathan Peyton   tied_task = *(task_stack->ts_top);
2447cc577a4SJonathan Peyton 
2457cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(tied_task != NULL);
2467cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(tied_task->td_flags.tasktype == TASK_TIED);
2477cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(tied_task == ending_task); // If we built the stack correctly
2487cc577a4SJonathan Peyton 
249*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmp_pop_task_stack(exit): GTID: %d; TASK: %p\n", gtid,
250*3041982dSJonathan Peyton                 tied_task));
2517cc577a4SJonathan Peyton   return;
2527cc577a4SJonathan Peyton }
2537cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */
2547cc577a4SJonathan Peyton 
2557cc577a4SJonathan Peyton //  __kmp_push_task: Add a task to the thread's deque
256*3041982dSJonathan Peyton static kmp_int32 __kmp_push_task(kmp_int32 gtid, kmp_task_t *task) {
2577cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
2587cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
2597cc577a4SJonathan Peyton   kmp_task_team_t *task_team = thread->th.th_task_team;
2607cc577a4SJonathan Peyton   kmp_int32 tid = __kmp_tid_from_gtid(gtid);
2617cc577a4SJonathan Peyton   kmp_thread_data_t *thread_data;
2627cc577a4SJonathan Peyton 
263*3041982dSJonathan Peyton   KA_TRACE(20,
264*3041982dSJonathan Peyton            ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata));
2657cc577a4SJonathan Peyton 
2667cc577a4SJonathan Peyton   if (taskdata->td_flags.tiedness == TASK_UNTIED) {
267*3041982dSJonathan Peyton     // untied task needs to increment counter so that the task structure is not
268*3041982dSJonathan Peyton     // freed prematurely
2697cc577a4SJonathan Peyton     kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count);
270*3041982dSJonathan Peyton     KA_TRACE(
271*3041982dSJonathan Peyton         20,
272*3041982dSJonathan Peyton         ("__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n",
2737cc577a4SJonathan Peyton          gtid, counter, taskdata));
2747cc577a4SJonathan Peyton   }
2757cc577a4SJonathan Peyton 
2767cc577a4SJonathan Peyton   // The first check avoids building task_team thread data if serialized
2777cc577a4SJonathan Peyton   if (taskdata->td_flags.task_serial) {
278*3041982dSJonathan Peyton     KA_TRACE(20, ("__kmp_push_task: T#%d team serialized; returning "
279*3041982dSJonathan Peyton                   "TASK_NOT_PUSHED for task %p\n",
2807cc577a4SJonathan Peyton                   gtid, taskdata));
2817cc577a4SJonathan Peyton     return TASK_NOT_PUSHED;
2827cc577a4SJonathan Peyton   }
2837cc577a4SJonathan Peyton 
284*3041982dSJonathan Peyton   // Now that serialized tasks have returned, we can assume that we are not in
285*3041982dSJonathan Peyton   // immediate exec mode
2867cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
2877cc577a4SJonathan Peyton   if (!KMP_TASKING_ENABLED(task_team)) {
2887cc577a4SJonathan Peyton     __kmp_enable_tasking(task_team, thread);
2897cc577a4SJonathan Peyton   }
2907cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(TCR_4(task_team->tt.tt_found_tasks) == TRUE);
2917cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(TCR_PTR(task_team->tt.tt_threads_data) != NULL);
2927cc577a4SJonathan Peyton 
2937cc577a4SJonathan Peyton   // Find tasking deque specific to encountering thread
2947cc577a4SJonathan Peyton   thread_data = &task_team->tt.tt_threads_data[tid];
2957cc577a4SJonathan Peyton 
2967cc577a4SJonathan Peyton   // No lock needed since only owner can allocate
2977cc577a4SJonathan Peyton   if (thread_data->td.td_deque == NULL) {
2987cc577a4SJonathan Peyton     __kmp_alloc_task_deque(thread, thread_data);
2997cc577a4SJonathan Peyton   }
3007cc577a4SJonathan Peyton 
3017cc577a4SJonathan Peyton   // Check if deque is full
302*3041982dSJonathan Peyton   if (TCR_4(thread_data->td.td_deque_ntasks) >=
303*3041982dSJonathan Peyton       TASK_DEQUE_SIZE(thread_data->td)) {
304*3041982dSJonathan Peyton     KA_TRACE(20, ("__kmp_push_task: T#%d deque is full; returning "
305*3041982dSJonathan Peyton                   "TASK_NOT_PUSHED for task %p\n",
3067cc577a4SJonathan Peyton                   gtid, taskdata));
3077cc577a4SJonathan Peyton     return TASK_NOT_PUSHED;
3087cc577a4SJonathan Peyton   }
3097cc577a4SJonathan Peyton 
3107cc577a4SJonathan Peyton   // Lock the deque for the task push operation
3117cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
3127cc577a4SJonathan Peyton 
3137cc577a4SJonathan Peyton #if OMP_45_ENABLED
3147cc577a4SJonathan Peyton   // Need to recheck as we can get a proxy task from a thread outside of OpenMP
315*3041982dSJonathan Peyton   if (TCR_4(thread_data->td.td_deque_ntasks) >=
316*3041982dSJonathan Peyton       TASK_DEQUE_SIZE(thread_data->td)) {
3177cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
318*3041982dSJonathan Peyton     KA_TRACE(20, ("__kmp_push_task: T#%d deque is full on 2nd check; returning "
319*3041982dSJonathan Peyton                   "TASK_NOT_PUSHED for task %p\n",
3207cc577a4SJonathan Peyton                   gtid, taskdata));
3217cc577a4SJonathan Peyton     return TASK_NOT_PUSHED;
3227cc577a4SJonathan Peyton   }
3237cc577a4SJonathan Peyton #else
3247cc577a4SJonathan Peyton   // Must have room since no thread can add tasks but calling thread
325*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) <
326*3041982dSJonathan Peyton                    TASK_DEQUE_SIZE(thread_data->td));
3277cc577a4SJonathan Peyton #endif
3287cc577a4SJonathan Peyton 
329*3041982dSJonathan Peyton   thread_data->td.td_deque[thread_data->td.td_deque_tail] =
330*3041982dSJonathan Peyton       taskdata; // Push taskdata
3317cc577a4SJonathan Peyton   // Wrap index.
332*3041982dSJonathan Peyton   thread_data->td.td_deque_tail =
333*3041982dSJonathan Peyton       (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
334*3041982dSJonathan Peyton   TCW_4(thread_data->td.td_deque_ntasks,
335*3041982dSJonathan Peyton         TCR_4(thread_data->td.td_deque_ntasks) + 1); // Adjust task count
3367cc577a4SJonathan Peyton 
3377cc577a4SJonathan Peyton   KA_TRACE(20, ("__kmp_push_task: T#%d returning TASK_SUCCESSFULLY_PUSHED: "
3387cc577a4SJonathan Peyton                 "task=%p ntasks=%d head=%u tail=%u\n",
3397cc577a4SJonathan Peyton                 gtid, taskdata, thread_data->td.td_deque_ntasks,
3407cc577a4SJonathan Peyton                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
3417cc577a4SJonathan Peyton 
3427cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
3437cc577a4SJonathan Peyton 
3447cc577a4SJonathan Peyton   return TASK_SUCCESSFULLY_PUSHED;
3457cc577a4SJonathan Peyton }
3467cc577a4SJonathan Peyton 
347*3041982dSJonathan Peyton // __kmp_pop_current_task_from_thread: set up current task from called thread
348*3041982dSJonathan Peyton // when team ends
349*3041982dSJonathan Peyton //
3507cc577a4SJonathan Peyton // this_thr: thread structure to set current_task in.
351*3041982dSJonathan Peyton void __kmp_pop_current_task_from_thread(kmp_info_t *this_thr) {
352*3041982dSJonathan Peyton   KF_TRACE(10, ("__kmp_pop_current_task_from_thread(enter): T#%d "
353*3041982dSJonathan Peyton                 "this_thread=%p, curtask=%p, "
3547cc577a4SJonathan Peyton                 "curtask_parent=%p\n",
3557cc577a4SJonathan Peyton                 0, this_thr, this_thr->th.th_current_task,
3567cc577a4SJonathan Peyton                 this_thr->th.th_current_task->td_parent));
3577cc577a4SJonathan Peyton 
3587cc577a4SJonathan Peyton   this_thr->th.th_current_task = this_thr->th.th_current_task->td_parent;
3597cc577a4SJonathan Peyton 
360*3041982dSJonathan Peyton   KF_TRACE(10, ("__kmp_pop_current_task_from_thread(exit): T#%d "
361*3041982dSJonathan Peyton                 "this_thread=%p, curtask=%p, "
3627cc577a4SJonathan Peyton                 "curtask_parent=%p\n",
3637cc577a4SJonathan Peyton                 0, this_thr, this_thr->th.th_current_task,
3647cc577a4SJonathan Peyton                 this_thr->th.th_current_task->td_parent));
3657cc577a4SJonathan Peyton }
3667cc577a4SJonathan Peyton 
367*3041982dSJonathan Peyton // __kmp_push_current_task_to_thread: set up current task in called thread for a
368*3041982dSJonathan Peyton // new team
369*3041982dSJonathan Peyton //
3707cc577a4SJonathan Peyton // this_thr: thread structure to set up
3717cc577a4SJonathan Peyton // team: team for implicit task data
3727cc577a4SJonathan Peyton // tid: thread within team to set up
373*3041982dSJonathan Peyton void __kmp_push_current_task_to_thread(kmp_info_t *this_thr, kmp_team_t *team,
374*3041982dSJonathan Peyton                                        int tid) {
375*3041982dSJonathan Peyton   // current task of the thread is a parent of the new just created implicit
376*3041982dSJonathan Peyton   // tasks of new team
377*3041982dSJonathan Peyton   KF_TRACE(10, ("__kmp_push_current_task_to_thread(enter): T#%d this_thread=%p "
378*3041982dSJonathan Peyton                 "curtask=%p "
3797cc577a4SJonathan Peyton                 "parent_task=%p\n",
3807cc577a4SJonathan Peyton                 tid, this_thr, this_thr->th.th_current_task,
3817cc577a4SJonathan Peyton                 team->t.t_implicit_task_taskdata[tid].td_parent));
3827cc577a4SJonathan Peyton 
3837cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(this_thr != NULL);
3847cc577a4SJonathan Peyton 
3857cc577a4SJonathan Peyton   if (tid == 0) {
3867cc577a4SJonathan Peyton     if (this_thr->th.th_current_task != &team->t.t_implicit_task_taskdata[0]) {
387*3041982dSJonathan Peyton       team->t.t_implicit_task_taskdata[0].td_parent =
388*3041982dSJonathan Peyton           this_thr->th.th_current_task;
3897cc577a4SJonathan Peyton       this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[0];
3907cc577a4SJonathan Peyton     }
3917cc577a4SJonathan Peyton   } else {
392*3041982dSJonathan Peyton     team->t.t_implicit_task_taskdata[tid].td_parent =
393*3041982dSJonathan Peyton         team->t.t_implicit_task_taskdata[0].td_parent;
3947cc577a4SJonathan Peyton     this_thr->th.th_current_task = &team->t.t_implicit_task_taskdata[tid];
3957cc577a4SJonathan Peyton   }
3967cc577a4SJonathan Peyton 
397*3041982dSJonathan Peyton   KF_TRACE(10, ("__kmp_push_current_task_to_thread(exit): T#%d this_thread=%p "
398*3041982dSJonathan Peyton                 "curtask=%p "
3997cc577a4SJonathan Peyton                 "parent_task=%p\n",
4007cc577a4SJonathan Peyton                 tid, this_thr, this_thr->th.th_current_task,
4017cc577a4SJonathan Peyton                 team->t.t_implicit_task_taskdata[tid].td_parent));
4027cc577a4SJonathan Peyton }
4037cc577a4SJonathan Peyton 
4047cc577a4SJonathan Peyton // __kmp_task_start: bookkeeping for a task starting execution
405*3041982dSJonathan Peyton //
4067cc577a4SJonathan Peyton // GTID: global thread id of calling thread
4077cc577a4SJonathan Peyton // task: task starting execution
4087cc577a4SJonathan Peyton // current_task: task suspending
409*3041982dSJonathan Peyton static void __kmp_task_start(kmp_int32 gtid, kmp_task_t *task,
410*3041982dSJonathan Peyton                              kmp_taskdata_t *current_task) {
4117cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4127cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
4137cc577a4SJonathan Peyton 
414*3041982dSJonathan Peyton   KA_TRACE(10,
415*3041982dSJonathan Peyton            ("__kmp_task_start(enter): T#%d starting task %p: current_task=%p\n",
4167cc577a4SJonathan Peyton             gtid, taskdata, current_task));
4177cc577a4SJonathan Peyton 
4187cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
4197cc577a4SJonathan Peyton 
4207cc577a4SJonathan Peyton   // mark currently executing task as suspended
4217cc577a4SJonathan Peyton   // TODO: GEH - make sure root team implicit task is initialized properly.
4227cc577a4SJonathan Peyton   // KMP_DEBUG_ASSERT( current_task -> td_flags.executing == 1 );
4237cc577a4SJonathan Peyton   current_task->td_flags.executing = 0;
4247cc577a4SJonathan Peyton 
4257cc577a4SJonathan Peyton // Add task to stack if tied
4267cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
427*3041982dSJonathan Peyton   if (taskdata->td_flags.tiedness == TASK_TIED) {
4287cc577a4SJonathan Peyton     __kmp_push_task_stack(gtid, thread, taskdata);
4297cc577a4SJonathan Peyton   }
4307cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */
4317cc577a4SJonathan Peyton 
4327cc577a4SJonathan Peyton   // mark starting task as executing and as current task
4337cc577a4SJonathan Peyton   thread->th.th_current_task = taskdata;
4347cc577a4SJonathan Peyton 
435*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.started == 0 ||
436*3041982dSJonathan Peyton                    taskdata->td_flags.tiedness == TASK_UNTIED);
437*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0 ||
438*3041982dSJonathan Peyton                    taskdata->td_flags.tiedness == TASK_UNTIED);
4397cc577a4SJonathan Peyton   taskdata->td_flags.started = 1;
4407cc577a4SJonathan Peyton   taskdata->td_flags.executing = 1;
4417cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
4427cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
4437cc577a4SJonathan Peyton 
4447cc577a4SJonathan Peyton   // GEH TODO: shouldn't we pass some sort of location identifier here?
4457cc577a4SJonathan Peyton   // APT: yes, we will pass location here.
4467cc577a4SJonathan Peyton   // need to store current thread state (in a thread or taskdata structure)
4477cc577a4SJonathan Peyton   // before setting work_state, otherwise wrong state is set after end of task
4487cc577a4SJonathan Peyton 
449*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmp_task_start(exit): T#%d task=%p\n", gtid, taskdata));
4507cc577a4SJonathan Peyton 
4517cc577a4SJonathan Peyton #if OMPT_SUPPORT
452*3041982dSJonathan Peyton   if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_begin)) {
4537cc577a4SJonathan Peyton     kmp_taskdata_t *parent = taskdata->td_parent;
4547cc577a4SJonathan Peyton     ompt_callbacks.ompt_callback(ompt_event_task_begin)(
4557cc577a4SJonathan Peyton         parent ? parent->ompt_task_info.task_id : ompt_task_id_none,
4567cc577a4SJonathan Peyton         parent ? &(parent->ompt_task_info.frame) : NULL,
457*3041982dSJonathan Peyton         taskdata->ompt_task_info.task_id, taskdata->ompt_task_info.function);
4587cc577a4SJonathan Peyton   }
4597cc577a4SJonathan Peyton #endif
4607cc577a4SJonathan Peyton #if OMP_40_ENABLED && OMPT_SUPPORT && OMPT_TRACE
4617cc577a4SJonathan Peyton   /* OMPT emit all dependences if requested by the tool */
4627cc577a4SJonathan Peyton   if (ompt_enabled && taskdata->ompt_task_info.ndeps > 0 &&
463*3041982dSJonathan Peyton       ompt_callbacks.ompt_callback(ompt_event_task_dependences)) {
4647cc577a4SJonathan Peyton     ompt_callbacks.ompt_callback(ompt_event_task_dependences)(
465*3041982dSJonathan Peyton         taskdata->ompt_task_info.task_id, taskdata->ompt_task_info.deps,
466*3041982dSJonathan Peyton         taskdata->ompt_task_info.ndeps);
4677cc577a4SJonathan Peyton     /* We can now free the allocated memory for the dependencies */
4687cc577a4SJonathan Peyton     KMP_OMPT_DEPS_FREE(thread, taskdata->ompt_task_info.deps);
4697cc577a4SJonathan Peyton     taskdata->ompt_task_info.deps = NULL;
4707cc577a4SJonathan Peyton     taskdata->ompt_task_info.ndeps = 0;
4717cc577a4SJonathan Peyton   }
4727cc577a4SJonathan Peyton #endif /* OMP_40_ENABLED && OMPT_SUPPORT && OMPT_TRACE */
4737cc577a4SJonathan Peyton 
4747cc577a4SJonathan Peyton   return;
4757cc577a4SJonathan Peyton }
4767cc577a4SJonathan Peyton 
477*3041982dSJonathan Peyton // __kmpc_omp_task_begin_if0: report that a given serialized task has started
478*3041982dSJonathan Peyton // execution
479*3041982dSJonathan Peyton //
4807cc577a4SJonathan Peyton // loc_ref: source location information; points to beginning of task block.
4817cc577a4SJonathan Peyton // gtid: global thread number.
4827cc577a4SJonathan Peyton // task: task thunk for the started task.
483*3041982dSJonathan Peyton void __kmpc_omp_task_begin_if0(ident_t *loc_ref, kmp_int32 gtid,
484*3041982dSJonathan Peyton                                kmp_task_t *task) {
4857cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
4867cc577a4SJonathan Peyton   kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
4877cc577a4SJonathan Peyton 
488*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p "
489*3041982dSJonathan Peyton                 "current_task=%p\n",
4907cc577a4SJonathan Peyton                 gtid, loc_ref, taskdata, current_task));
4917cc577a4SJonathan Peyton 
4927cc577a4SJonathan Peyton   if (taskdata->td_flags.tiedness == TASK_UNTIED) {
493*3041982dSJonathan Peyton     // untied task needs to increment counter so that the task structure is not
494*3041982dSJonathan Peyton     // freed prematurely
4957cc577a4SJonathan Peyton     kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count);
496*3041982dSJonathan Peyton     KA_TRACE(20, ("__kmpc_omp_task_begin_if0: T#%d untied_count (%d) "
497*3041982dSJonathan Peyton                   "incremented for task %p\n",
4987cc577a4SJonathan Peyton                   gtid, counter, taskdata));
4997cc577a4SJonathan Peyton   }
5007cc577a4SJonathan Peyton 
501*3041982dSJonathan Peyton   taskdata->td_flags.task_serial =
502*3041982dSJonathan Peyton       1; // Execute this task immediately, not deferred.
5037cc577a4SJonathan Peyton   __kmp_task_start(gtid, task, current_task);
5047cc577a4SJonathan Peyton 
505*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_begin_if0(exit): T#%d loc=%p task=%p,\n", gtid,
506*3041982dSJonathan Peyton                 loc_ref, taskdata));
5077cc577a4SJonathan Peyton 
5087cc577a4SJonathan Peyton   return;
5097cc577a4SJonathan Peyton }
5107cc577a4SJonathan Peyton 
5117cc577a4SJonathan Peyton #ifdef TASK_UNUSED
5127cc577a4SJonathan Peyton // __kmpc_omp_task_begin: report that a given task has started execution
5137cc577a4SJonathan Peyton // NEVER GENERATED BY COMPILER, DEPRECATED!!!
514*3041982dSJonathan Peyton void __kmpc_omp_task_begin(ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task) {
5157cc577a4SJonathan Peyton   kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
5167cc577a4SJonathan Peyton 
517*3041982dSJonathan Peyton   KA_TRACE(
518*3041982dSJonathan Peyton       10,
519*3041982dSJonathan Peyton       ("__kmpc_omp_task_begin(enter): T#%d loc=%p task=%p current_task=%p\n",
5207cc577a4SJonathan Peyton        gtid, loc_ref, KMP_TASK_TO_TASKDATA(task), current_task));
5217cc577a4SJonathan Peyton 
5227cc577a4SJonathan Peyton   __kmp_task_start(gtid, task, current_task);
5237cc577a4SJonathan Peyton 
524*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_begin(exit): T#%d loc=%p task=%p,\n", gtid,
525*3041982dSJonathan Peyton                 loc_ref, KMP_TASK_TO_TASKDATA(task)));
5267cc577a4SJonathan Peyton   return;
5277cc577a4SJonathan Peyton }
5287cc577a4SJonathan Peyton #endif // TASK_UNUSED
5297cc577a4SJonathan Peyton 
5307cc577a4SJonathan Peyton // __kmp_free_task: free the current task space and the space for shareds
531*3041982dSJonathan Peyton //
5327cc577a4SJonathan Peyton // gtid: Global thread ID of calling thread
5337cc577a4SJonathan Peyton // taskdata: task to free
5347cc577a4SJonathan Peyton // thread: thread data structure of caller
535*3041982dSJonathan Peyton static void __kmp_free_task(kmp_int32 gtid, kmp_taskdata_t *taskdata,
536*3041982dSJonathan Peyton                             kmp_info_t *thread) {
537*3041982dSJonathan Peyton   KA_TRACE(30, ("__kmp_free_task: T#%d freeing data from task %p\n", gtid,
538*3041982dSJonathan Peyton                 taskdata));
5397cc577a4SJonathan Peyton 
5407cc577a4SJonathan Peyton   // Check to make sure all flags and counters have the correct values
5417cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
5427cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 0);
5437cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 1);
5447cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
545*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(TCR_4(taskdata->td_allocated_child_tasks) == 0 ||
546*3041982dSJonathan Peyton                    taskdata->td_flags.task_serial == 1);
5477cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(TCR_4(taskdata->td_incomplete_child_tasks) == 0);
5487cc577a4SJonathan Peyton 
5497cc577a4SJonathan Peyton   taskdata->td_flags.freed = 1;
5507cc577a4SJonathan Peyton   ANNOTATE_HAPPENS_BEFORE(taskdata);
5517cc577a4SJonathan Peyton // deallocate the taskdata and shared variable blocks associated with this task
5527cc577a4SJonathan Peyton #if USE_FAST_MEMORY
5537cc577a4SJonathan Peyton   __kmp_fast_free(thread, taskdata);
5547cc577a4SJonathan Peyton #else /* ! USE_FAST_MEMORY */
5557cc577a4SJonathan Peyton   __kmp_thread_free(thread, taskdata);
5567cc577a4SJonathan Peyton #endif
5577cc577a4SJonathan Peyton 
558*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n", gtid, taskdata));
5597cc577a4SJonathan Peyton }
5607cc577a4SJonathan Peyton 
561*3041982dSJonathan Peyton // __kmp_free_task_and_ancestors: free the current task and ancestors without
562*3041982dSJonathan Peyton // children
5637cc577a4SJonathan Peyton //
5647cc577a4SJonathan Peyton // gtid: Global thread ID of calling thread
5657cc577a4SJonathan Peyton // taskdata: task to free
5667cc577a4SJonathan Peyton // thread: thread data structure of caller
567*3041982dSJonathan Peyton static void __kmp_free_task_and_ancestors(kmp_int32 gtid,
568*3041982dSJonathan Peyton                                           kmp_taskdata_t *taskdata,
569*3041982dSJonathan Peyton                                           kmp_info_t *thread) {
5707cc577a4SJonathan Peyton #if OMP_45_ENABLED
5717cc577a4SJonathan Peyton   // Proxy tasks must always be allowed to free their parents
5727cc577a4SJonathan Peyton   // because they can be run in background even in serial mode.
573*3041982dSJonathan Peyton   kmp_int32 team_serial =
574*3041982dSJonathan Peyton       (taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) &&
575*3041982dSJonathan Peyton       !taskdata->td_flags.proxy;
5767cc577a4SJonathan Peyton #else
577*3041982dSJonathan Peyton   kmp_int32 team_serial =
578*3041982dSJonathan Peyton       taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser;
5797cc577a4SJonathan Peyton #endif
5807cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
5817cc577a4SJonathan Peyton 
582*3041982dSJonathan Peyton   kmp_int32 children =
583*3041982dSJonathan Peyton       KMP_TEST_THEN_DEC32((kmp_int32 *)(&taskdata->td_allocated_child_tasks)) -
584*3041982dSJonathan Peyton       1;
5857cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(children >= 0);
5867cc577a4SJonathan Peyton 
5877cc577a4SJonathan Peyton   // Now, go up the ancestor tree to see if any ancestors can now be freed.
588*3041982dSJonathan Peyton   while (children == 0) {
5897cc577a4SJonathan Peyton     kmp_taskdata_t *parent_taskdata = taskdata->td_parent;
5907cc577a4SJonathan Peyton 
5917cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_free_task_and_ancestors(enter): T#%d task %p complete "
592*3041982dSJonathan Peyton                   "and freeing itself\n",
593*3041982dSJonathan Peyton                   gtid, taskdata));
5947cc577a4SJonathan Peyton 
5957cc577a4SJonathan Peyton     // --- Deallocate my ancestor task ---
5967cc577a4SJonathan Peyton     __kmp_free_task(gtid, taskdata, thread);
5977cc577a4SJonathan Peyton 
5987cc577a4SJonathan Peyton     taskdata = parent_taskdata;
5997cc577a4SJonathan Peyton 
600*3041982dSJonathan Peyton     // Stop checking ancestors at implicit task instead of walking up ancestor
601*3041982dSJonathan Peyton     // tree to avoid premature deallocation of ancestors.
6027cc577a4SJonathan Peyton     if (team_serial || taskdata->td_flags.tasktype == TASK_IMPLICIT)
6037cc577a4SJonathan Peyton       return;
6047cc577a4SJonathan Peyton 
6057cc577a4SJonathan Peyton     // Predecrement simulated by "- 1" calculation
606*3041982dSJonathan Peyton     children = KMP_TEST_THEN_DEC32(
607*3041982dSJonathan Peyton                    (kmp_int32 *)(&taskdata->td_allocated_child_tasks)) -
608*3041982dSJonathan Peyton                1;
6097cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(children >= 0);
6107cc577a4SJonathan Peyton   }
6117cc577a4SJonathan Peyton 
612*3041982dSJonathan Peyton   KA_TRACE(
613*3041982dSJonathan Peyton       20, ("__kmp_free_task_and_ancestors(exit): T#%d task %p has %d children; "
614*3041982dSJonathan Peyton            "not freeing it yet\n",
615*3041982dSJonathan Peyton            gtid, taskdata, children));
6167cc577a4SJonathan Peyton }
6177cc577a4SJonathan Peyton 
6187cc577a4SJonathan Peyton // __kmp_task_finish: bookkeeping to do when a task finishes execution
619*3041982dSJonathan Peyton //
6207cc577a4SJonathan Peyton // gtid: global thread ID for calling thread
6217cc577a4SJonathan Peyton // task: task to be finished
6227cc577a4SJonathan Peyton // resumed_task: task to be resumed.  (may be NULL if task is serialized)
623*3041982dSJonathan Peyton static void __kmp_task_finish(kmp_int32 gtid, kmp_task_t *task,
624*3041982dSJonathan Peyton                               kmp_taskdata_t *resumed_task) {
6257cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
6267cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
627*3041982dSJonathan Peyton   kmp_task_team_t *task_team =
628*3041982dSJonathan Peyton       thread->th.th_task_team; // might be NULL for serial teams...
6297cc577a4SJonathan Peyton   kmp_int32 children = 0;
6307cc577a4SJonathan Peyton 
6317cc577a4SJonathan Peyton #if OMPT_SUPPORT
632*3041982dSJonathan Peyton   if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_end)) {
6337cc577a4SJonathan Peyton     kmp_taskdata_t *parent = taskdata->td_parent;
6347cc577a4SJonathan Peyton     ompt_callbacks.ompt_callback(ompt_event_task_end)(
6357cc577a4SJonathan Peyton         taskdata->ompt_task_info.task_id);
6367cc577a4SJonathan Peyton   }
6377cc577a4SJonathan Peyton #endif
6387cc577a4SJonathan Peyton 
639*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmp_task_finish(enter): T#%d finishing task %p and resuming "
640*3041982dSJonathan Peyton                 "task %p\n",
6417cc577a4SJonathan Peyton                 gtid, taskdata, resumed_task));
6427cc577a4SJonathan Peyton 
6437cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
6447cc577a4SJonathan Peyton 
6457cc577a4SJonathan Peyton // Pop task from stack if tied
6467cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
647*3041982dSJonathan Peyton   if (taskdata->td_flags.tiedness == TASK_TIED) {
6487cc577a4SJonathan Peyton     __kmp_pop_task_stack(gtid, thread, taskdata);
6497cc577a4SJonathan Peyton   }
6507cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */
6517cc577a4SJonathan Peyton 
6527cc577a4SJonathan Peyton   if (taskdata->td_flags.tiedness == TASK_UNTIED) {
653*3041982dSJonathan Peyton     // untied task needs to check the counter so that the task structure is not
654*3041982dSJonathan Peyton     // freed prematurely
6557cc577a4SJonathan Peyton     kmp_int32 counter = KMP_TEST_THEN_DEC32(&taskdata->td_untied_count) - 1;
656*3041982dSJonathan Peyton     KA_TRACE(
657*3041982dSJonathan Peyton         20,
658*3041982dSJonathan Peyton         ("__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n",
6597cc577a4SJonathan Peyton          gtid, counter, taskdata));
6607cc577a4SJonathan Peyton     if (counter > 0) {
661*3041982dSJonathan Peyton       // untied task is not done, to be continued possibly by other thread, do
662*3041982dSJonathan Peyton       // not free it now
6637cc577a4SJonathan Peyton       if (resumed_task == NULL) {
6647cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(taskdata->td_flags.task_serial);
665*3041982dSJonathan Peyton         resumed_task = taskdata->td_parent; // In a serialized task, the resumed
666*3041982dSJonathan Peyton         // task is the parent
6677cc577a4SJonathan Peyton       }
6687cc577a4SJonathan Peyton       thread->th.th_current_task = resumed_task; // restore current_task
6697cc577a4SJonathan Peyton       resumed_task->td_flags.executing = 1; // resume previous task
670*3041982dSJonathan Peyton       KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, "
671*3041982dSJonathan Peyton                     "resuming task %p\n",
6727cc577a4SJonathan Peyton                     gtid, taskdata, resumed_task));
6737cc577a4SJonathan Peyton       return;
6747cc577a4SJonathan Peyton     }
6757cc577a4SJonathan Peyton   }
6767cc577a4SJonathan Peyton 
6777cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
6787cc577a4SJonathan Peyton   taskdata->td_flags.complete = 1; // mark the task as completed
6797cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.started == 1);
6807cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
6817cc577a4SJonathan Peyton 
682*3041982dSJonathan Peyton   // Only need to keep track of count if team parallel and tasking not
683*3041982dSJonathan Peyton   // serialized
6847cc577a4SJonathan Peyton   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) {
6857cc577a4SJonathan Peyton     // Predecrement simulated by "- 1" calculation
686*3041982dSJonathan Peyton     children =
687*3041982dSJonathan Peyton         KMP_TEST_THEN_DEC32(
688*3041982dSJonathan Peyton             (kmp_int32 *)(&taskdata->td_parent->td_incomplete_child_tasks)) -
689*3041982dSJonathan Peyton         1;
6907cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(children >= 0);
6917cc577a4SJonathan Peyton #if OMP_40_ENABLED
6927cc577a4SJonathan Peyton     if (taskdata->td_taskgroup)
6937cc577a4SJonathan Peyton       KMP_TEST_THEN_DEC32((kmp_int32 *)(&taskdata->td_taskgroup->count));
6947cc577a4SJonathan Peyton #if OMP_45_ENABLED
6957cc577a4SJonathan Peyton   }
6967cc577a4SJonathan Peyton   // if we found proxy tasks there could exist a dependency chain
6977cc577a4SJonathan Peyton   // with the proxy task as origin
698*3041982dSJonathan Peyton   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser) ||
699*3041982dSJonathan Peyton       (task_team && task_team->tt.tt_found_proxy_tasks)) {
7007cc577a4SJonathan Peyton #endif
7017cc577a4SJonathan Peyton     __kmp_release_deps(gtid, taskdata);
7027cc577a4SJonathan Peyton #endif
7037cc577a4SJonathan Peyton   }
7047cc577a4SJonathan Peyton 
705*3041982dSJonathan Peyton   // td_flags.executing must be marked as 0 after __kmp_release_deps has been
706*3041982dSJonathan Peyton   // called. Othertwise, if a task is executed immediately from the release_deps
707*3041982dSJonathan Peyton   // code, the flag will be reset to 1 again by this same function
7087cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.executing == 1);
7097cc577a4SJonathan Peyton   taskdata->td_flags.executing = 0; // suspend the finishing task
7107cc577a4SJonathan Peyton 
711*3041982dSJonathan Peyton   KA_TRACE(
712*3041982dSJonathan Peyton       20, ("__kmp_task_finish: T#%d finished task %p, %d incomplete children\n",
7137cc577a4SJonathan Peyton            gtid, taskdata, children));
7147cc577a4SJonathan Peyton 
7157cc577a4SJonathan Peyton #if OMP_40_ENABLED
7167cc577a4SJonathan Peyton   /* If the tasks' destructor thunk flag has been set, we need to invoke the
717*3041982dSJonathan Peyton      destructor thunk that has been generated by the compiler. The code is
718*3041982dSJonathan Peyton      placed here, since at this point other tasks might have been released
7197cc577a4SJonathan Peyton      hence overlapping the destructor invokations with some other work in the
720*3041982dSJonathan Peyton      released tasks.  The OpenMP spec is not specific on when the destructors
721*3041982dSJonathan Peyton      are invoked, so we should be free to choose. */
7227cc577a4SJonathan Peyton   if (taskdata->td_flags.destructors_thunk) {
7237cc577a4SJonathan Peyton     kmp_routine_entry_t destr_thunk = task->data1.destructors;
7247cc577a4SJonathan Peyton     KMP_ASSERT(destr_thunk);
7257cc577a4SJonathan Peyton     destr_thunk(gtid, task);
7267cc577a4SJonathan Peyton   }
7277cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
7287cc577a4SJonathan Peyton 
7297cc577a4SJonathan Peyton   // bookkeeping for resuming task:
7307cc577a4SJonathan Peyton   // GEH - note tasking_ser => task_serial
731*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(
732*3041982dSJonathan Peyton       (taskdata->td_flags.tasking_ser || taskdata->td_flags.task_serial) ==
7337cc577a4SJonathan Peyton       taskdata->td_flags.task_serial);
734*3041982dSJonathan Peyton   if (taskdata->td_flags.task_serial) {
7357cc577a4SJonathan Peyton     if (resumed_task == NULL) {
736*3041982dSJonathan Peyton       resumed_task = taskdata->td_parent; // In a serialized task, the resumed
737*3041982dSJonathan Peyton       // task is the parent
738*3041982dSJonathan Peyton     } else
7397cc577a4SJonathan Peyton #if OMP_45_ENABLED
7407cc577a4SJonathan Peyton         if (!(task_team && task_team->tt.tt_found_proxy_tasks))
7417cc577a4SJonathan Peyton #endif
7427cc577a4SJonathan Peyton     {
7437cc577a4SJonathan Peyton       // verify resumed task passed in points to parent
7447cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(resumed_task == taskdata->td_parent);
7457cc577a4SJonathan Peyton     }
746*3041982dSJonathan Peyton   } else {
747*3041982dSJonathan Peyton     KMP_DEBUG_ASSERT(resumed_task !=
748*3041982dSJonathan Peyton                      NULL); // verify that resumed task is passed as arguemnt
7497cc577a4SJonathan Peyton   }
7507cc577a4SJonathan Peyton 
7517cc577a4SJonathan Peyton   // Free this task and then ancestor tasks if they have no children.
7527cc577a4SJonathan Peyton   // Restore th_current_task first as suggested by John:
7537cc577a4SJonathan Peyton   // johnmc: if an asynchronous inquiry peers into the runtime system
7547cc577a4SJonathan Peyton   // it doesn't see the freed task as the current task.
7557cc577a4SJonathan Peyton   thread->th.th_current_task = resumed_task;
7567cc577a4SJonathan Peyton   __kmp_free_task_and_ancestors(gtid, taskdata, thread);
7577cc577a4SJonathan Peyton 
7587cc577a4SJonathan Peyton   // TODO: GEH - make sure root team implicit task is initialized properly.
7597cc577a4SJonathan Peyton   // KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 );
7607cc577a4SJonathan Peyton   resumed_task->td_flags.executing = 1; // resume previous task
7617cc577a4SJonathan Peyton 
762*3041982dSJonathan Peyton   KA_TRACE(
763*3041982dSJonathan Peyton       10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n",
7647cc577a4SJonathan Peyton            gtid, taskdata, resumed_task));
7657cc577a4SJonathan Peyton 
7667cc577a4SJonathan Peyton   return;
7677cc577a4SJonathan Peyton }
7687cc577a4SJonathan Peyton 
7697cc577a4SJonathan Peyton // __kmpc_omp_task_complete_if0: report that a task has completed execution
770*3041982dSJonathan Peyton //
7717cc577a4SJonathan Peyton // loc_ref: source location information; points to end of task block.
7727cc577a4SJonathan Peyton // gtid: global thread number.
7737cc577a4SJonathan Peyton // task: task thunk for the completed task.
774*3041982dSJonathan Peyton void __kmpc_omp_task_complete_if0(ident_t *loc_ref, kmp_int32 gtid,
775*3041982dSJonathan Peyton                                   kmp_task_t *task) {
7767cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_complete_if0(enter): T#%d loc=%p task=%p\n",
7777cc577a4SJonathan Peyton                 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task)));
778*3041982dSJonathan Peyton   // this routine will provide task to resume
779*3041982dSJonathan Peyton   __kmp_task_finish(gtid, task, NULL);
7807cc577a4SJonathan Peyton 
7817cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_complete_if0(exit): T#%d loc=%p task=%p\n",
7827cc577a4SJonathan Peyton                 gtid, loc_ref, KMP_TASK_TO_TASKDATA(task)));
7837cc577a4SJonathan Peyton   return;
7847cc577a4SJonathan Peyton }
7857cc577a4SJonathan Peyton 
7867cc577a4SJonathan Peyton #ifdef TASK_UNUSED
7877cc577a4SJonathan Peyton // __kmpc_omp_task_complete: report that a task has completed execution
7887cc577a4SJonathan Peyton // NEVER GENERATED BY COMPILER, DEPRECATED!!!
789*3041982dSJonathan Peyton void __kmpc_omp_task_complete(ident_t *loc_ref, kmp_int32 gtid,
790*3041982dSJonathan Peyton                               kmp_task_t *task) {
791*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_complete(enter): T#%d loc=%p task=%p\n", gtid,
792*3041982dSJonathan Peyton                 loc_ref, KMP_TASK_TO_TASKDATA(task)));
7937cc577a4SJonathan Peyton 
7947cc577a4SJonathan Peyton   __kmp_task_finish(gtid, task, NULL); // Not sure how to find task to resume
7957cc577a4SJonathan Peyton 
796*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_complete(exit): T#%d loc=%p task=%p\n", gtid,
797*3041982dSJonathan Peyton                 loc_ref, KMP_TASK_TO_TASKDATA(task)));
7987cc577a4SJonathan Peyton   return;
7997cc577a4SJonathan Peyton }
8007cc577a4SJonathan Peyton #endif // TASK_UNUSED
8017cc577a4SJonathan Peyton 
8027cc577a4SJonathan Peyton #if OMPT_SUPPORT
803*3041982dSJonathan Peyton // __kmp_task_init_ompt: Initialize OMPT fields maintained by a task. This will
804*3041982dSJonathan Peyton //  only be called after ompt_tool, so we already know whether ompt is enabled
805*3041982dSJonathan Peyton // or not.
806*3041982dSJonathan Peyton static inline void __kmp_task_init_ompt(kmp_taskdata_t *task, int tid,
807*3041982dSJonathan Peyton                                         void *function) {
8087cc577a4SJonathan Peyton   if (ompt_enabled) {
8097cc577a4SJonathan Peyton     task->ompt_task_info.task_id = __ompt_task_id_new(tid);
8107cc577a4SJonathan Peyton     task->ompt_task_info.function = function;
8117cc577a4SJonathan Peyton     task->ompt_task_info.frame.exit_runtime_frame = NULL;
8127cc577a4SJonathan Peyton     task->ompt_task_info.frame.reenter_runtime_frame = NULL;
8137cc577a4SJonathan Peyton #if OMP_40_ENABLED
8147cc577a4SJonathan Peyton     task->ompt_task_info.ndeps = 0;
8157cc577a4SJonathan Peyton     task->ompt_task_info.deps = NULL;
8167cc577a4SJonathan Peyton #endif /* OMP_40_ENABLED */
8177cc577a4SJonathan Peyton   }
8187cc577a4SJonathan Peyton }
8197cc577a4SJonathan Peyton #endif
8207cc577a4SJonathan Peyton 
821*3041982dSJonathan Peyton // __kmp_init_implicit_task: Initialize the appropriate fields in the implicit
822*3041982dSJonathan Peyton // task for a given thread
8237cc577a4SJonathan Peyton //
8247cc577a4SJonathan Peyton // loc_ref:  reference to source location of parallel region
8257cc577a4SJonathan Peyton // this_thr:  thread data structure corresponding to implicit task
8267cc577a4SJonathan Peyton // team: team for this_thr
8277cc577a4SJonathan Peyton // tid: thread id of given thread within team
8287cc577a4SJonathan Peyton // set_curr_task: TRUE if need to push current task to thread
829*3041982dSJonathan Peyton // NOTE: Routine does not set up the implicit task ICVS.  This is assumed to
830*3041982dSJonathan Peyton // have already been done elsewhere.
8317cc577a4SJonathan Peyton // TODO: Get better loc_ref.  Value passed in may be NULL
832*3041982dSJonathan Peyton void __kmp_init_implicit_task(ident_t *loc_ref, kmp_info_t *this_thr,
833*3041982dSJonathan Peyton                               kmp_team_t *team, int tid, int set_curr_task) {
8347cc577a4SJonathan Peyton   kmp_taskdata_t *task = &team->t.t_implicit_task_taskdata[tid];
8357cc577a4SJonathan Peyton 
836*3041982dSJonathan Peyton   KF_TRACE(
837*3041982dSJonathan Peyton       10,
838*3041982dSJonathan Peyton       ("__kmp_init_implicit_task(enter): T#:%d team=%p task=%p, reinit=%s\n",
8397cc577a4SJonathan Peyton        tid, team, task, set_curr_task ? "TRUE" : "FALSE"));
8407cc577a4SJonathan Peyton 
8417cc577a4SJonathan Peyton   task->td_task_id = KMP_GEN_TASK_ID();
8427cc577a4SJonathan Peyton   task->td_team = team;
843*3041982dSJonathan Peyton   //    task->td_parent   = NULL;  // fix for CQ230101 (broken parent task info
844*3041982dSJonathan Peyton   //    in debugger)
8457cc577a4SJonathan Peyton   task->td_ident = loc_ref;
8467cc577a4SJonathan Peyton   task->td_taskwait_ident = NULL;
8477cc577a4SJonathan Peyton   task->td_taskwait_counter = 0;
8487cc577a4SJonathan Peyton   task->td_taskwait_thread = 0;
8497cc577a4SJonathan Peyton 
8507cc577a4SJonathan Peyton   task->td_flags.tiedness = TASK_TIED;
8517cc577a4SJonathan Peyton   task->td_flags.tasktype = TASK_IMPLICIT;
8527cc577a4SJonathan Peyton #if OMP_45_ENABLED
8537cc577a4SJonathan Peyton   task->td_flags.proxy = TASK_FULL;
8547cc577a4SJonathan Peyton #endif
8557cc577a4SJonathan Peyton 
8567cc577a4SJonathan Peyton   // All implicit tasks are executed immediately, not deferred
8577cc577a4SJonathan Peyton   task->td_flags.task_serial = 1;
8587cc577a4SJonathan Peyton   task->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec);
8597cc577a4SJonathan Peyton   task->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0;
8607cc577a4SJonathan Peyton 
8617cc577a4SJonathan Peyton   task->td_flags.started = 1;
8627cc577a4SJonathan Peyton   task->td_flags.executing = 1;
8637cc577a4SJonathan Peyton   task->td_flags.complete = 0;
8647cc577a4SJonathan Peyton   task->td_flags.freed = 0;
8657cc577a4SJonathan Peyton 
8667cc577a4SJonathan Peyton #if OMP_40_ENABLED
8677cc577a4SJonathan Peyton   task->td_depnode = NULL;
8687cc577a4SJonathan Peyton #endif
8697cc577a4SJonathan Peyton 
870*3041982dSJonathan Peyton   if (set_curr_task) { // only do this init first time thread is created
8717cc577a4SJonathan Peyton     task->td_incomplete_child_tasks = 0;
872*3041982dSJonathan Peyton     task->td_allocated_child_tasks = 0; // Not used: don't need to
873*3041982dSJonathan Peyton // deallocate implicit task
8747cc577a4SJonathan Peyton #if OMP_40_ENABLED
8757cc577a4SJonathan Peyton     task->td_taskgroup = NULL; // An implicit task does not have taskgroup
8767cc577a4SJonathan Peyton     task->td_dephash = NULL;
8777cc577a4SJonathan Peyton #endif
8787cc577a4SJonathan Peyton     __kmp_push_current_task_to_thread(this_thr, team, tid);
8797cc577a4SJonathan Peyton   } else {
8807cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(task->td_incomplete_child_tasks == 0);
8817cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(task->td_allocated_child_tasks == 0);
8827cc577a4SJonathan Peyton   }
8837cc577a4SJonathan Peyton 
8847cc577a4SJonathan Peyton #if OMPT_SUPPORT
8857cc577a4SJonathan Peyton   __kmp_task_init_ompt(task, tid, NULL);
8867cc577a4SJonathan Peyton #endif
8877cc577a4SJonathan Peyton 
888*3041982dSJonathan Peyton   KF_TRACE(10, ("__kmp_init_implicit_task(exit): T#:%d team=%p task=%p\n", tid,
889*3041982dSJonathan Peyton                 team, task));
8907cc577a4SJonathan Peyton }
8917cc577a4SJonathan Peyton 
892*3041982dSJonathan Peyton // __kmp_finish_implicit_task: Release resources associated to implicit tasks
893*3041982dSJonathan Peyton // at the end of parallel regions. Some resources are kept for reuse in the next
894*3041982dSJonathan Peyton // parallel region.
8957cc577a4SJonathan Peyton //
896*3041982dSJonathan Peyton // thread:  thread data structure corresponding to implicit task
897*3041982dSJonathan Peyton void __kmp_finish_implicit_task(kmp_info_t *thread) {
8987cc577a4SJonathan Peyton   kmp_taskdata_t *task = thread->th.th_current_task;
8997cc577a4SJonathan Peyton   if (task->td_dephash)
9007cc577a4SJonathan Peyton     __kmp_dephash_free_entries(thread, task->td_dephash);
9017cc577a4SJonathan Peyton }
9027cc577a4SJonathan Peyton 
903*3041982dSJonathan Peyton // __kmp_free_implicit_task: Release resources associated to implicit tasks
904*3041982dSJonathan Peyton // when these are destroyed regions
9057cc577a4SJonathan Peyton //
906*3041982dSJonathan Peyton // thread:  thread data structure corresponding to implicit task
907*3041982dSJonathan Peyton void __kmp_free_implicit_task(kmp_info_t *thread) {
9087cc577a4SJonathan Peyton   kmp_taskdata_t *task = thread->th.th_current_task;
9097cc577a4SJonathan Peyton   if (task->td_dephash)
9107cc577a4SJonathan Peyton     __kmp_dephash_free(thread, task->td_dephash);
9117cc577a4SJonathan Peyton   task->td_dephash = NULL;
9127cc577a4SJonathan Peyton }
9137cc577a4SJonathan Peyton 
914*3041982dSJonathan Peyton // Round up a size to a power of two specified by val: Used to insert padding
915*3041982dSJonathan Peyton // between structures co-allocated using a single malloc() call
916*3041982dSJonathan Peyton static size_t __kmp_round_up_to_val(size_t size, size_t val) {
9177cc577a4SJonathan Peyton   if (size & (val - 1)) {
9187cc577a4SJonathan Peyton     size &= ~(val - 1);
9197cc577a4SJonathan Peyton     if (size <= KMP_SIZE_T_MAX - val) {
9207cc577a4SJonathan Peyton       size += val; // Round up if there is no overflow.
9217cc577a4SJonathan Peyton     }; // if
9227cc577a4SJonathan Peyton   }; // if
9237cc577a4SJonathan Peyton   return size;
9247cc577a4SJonathan Peyton } // __kmp_round_up_to_va
9257cc577a4SJonathan Peyton 
9267cc577a4SJonathan Peyton // __kmp_task_alloc: Allocate the taskdata and task data structures for a task
9277cc577a4SJonathan Peyton //
9287cc577a4SJonathan Peyton // loc_ref: source location information
9297cc577a4SJonathan Peyton // gtid: global thread number.
930*3041982dSJonathan Peyton // flags: include tiedness & task type (explicit vs. implicit) of the ''new''
931*3041982dSJonathan Peyton // task encountered. Converted from kmp_int32 to kmp_tasking_flags_t in routine.
932*3041982dSJonathan Peyton // sizeof_kmp_task_t:  Size in bytes of kmp_task_t data structure including
933*3041982dSJonathan Peyton // private vars accessed in task.
934*3041982dSJonathan Peyton // sizeof_shareds:  Size in bytes of array of pointers to shared vars accessed
935*3041982dSJonathan Peyton // in task.
9367cc577a4SJonathan Peyton // task_entry: Pointer to task code entry point generated by compiler.
9377cc577a4SJonathan Peyton // returns: a pointer to the allocated kmp_task_t structure (task).
938*3041982dSJonathan Peyton kmp_task_t *__kmp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
939*3041982dSJonathan Peyton                              kmp_tasking_flags_t *flags,
9407cc577a4SJonathan Peyton                              size_t sizeof_kmp_task_t, size_t sizeof_shareds,
941*3041982dSJonathan Peyton                              kmp_routine_entry_t task_entry) {
9427cc577a4SJonathan Peyton   kmp_task_t *task;
9437cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata;
9447cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
9457cc577a4SJonathan Peyton   kmp_team_t *team = thread->th.th_team;
9467cc577a4SJonathan Peyton   kmp_taskdata_t *parent_task = thread->th.th_current_task;
9477cc577a4SJonathan Peyton   size_t shareds_offset;
9487cc577a4SJonathan Peyton 
9497cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmp_task_alloc(enter): T#%d loc=%p, flags=(0x%x) "
9507cc577a4SJonathan Peyton                 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
9517cc577a4SJonathan Peyton                 gtid, loc_ref, *((kmp_int32 *)flags), sizeof_kmp_task_t,
9527cc577a4SJonathan Peyton                 sizeof_shareds, task_entry));
9537cc577a4SJonathan Peyton 
9547cc577a4SJonathan Peyton   if (parent_task->td_flags.final) {
9557cc577a4SJonathan Peyton     if (flags->merged_if0) {
9567cc577a4SJonathan Peyton     }
9577cc577a4SJonathan Peyton     flags->final = 1;
9587cc577a4SJonathan Peyton   }
9597cc577a4SJonathan Peyton 
9607cc577a4SJonathan Peyton #if OMP_45_ENABLED
9617cc577a4SJonathan Peyton   if (flags->proxy == TASK_PROXY) {
9627cc577a4SJonathan Peyton     flags->tiedness = TASK_UNTIED;
9637cc577a4SJonathan Peyton     flags->merged_if0 = 1;
9647cc577a4SJonathan Peyton 
965*3041982dSJonathan Peyton     /* are we running in a sequential parallel or tskm_immediate_exec... we need
966*3041982dSJonathan Peyton        tasking support enabled */
9677cc577a4SJonathan Peyton     if ((thread->th.th_task_team) == NULL) {
9687cc577a4SJonathan Peyton       /* This should only happen if the team is serialized
969*3041982dSJonathan Peyton           setup a task team and propagate it to the thread */
9707cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(team->t.t_serialized);
971*3041982dSJonathan Peyton       KA_TRACE(30,
972*3041982dSJonathan Peyton                ("T#%d creating task team in __kmp_task_alloc for proxy task\n",
973*3041982dSJonathan Peyton                 gtid));
974*3041982dSJonathan Peyton       __kmp_task_team_setup(
975*3041982dSJonathan Peyton           thread, team,
976*3041982dSJonathan Peyton           1); // 1 indicates setup the current team regardless of nthreads
9777cc577a4SJonathan Peyton       thread->th.th_task_team = team->t.t_task_team[thread->th.th_task_state];
9787cc577a4SJonathan Peyton     }
9797cc577a4SJonathan Peyton     kmp_task_team_t *task_team = thread->th.th_task_team;
9807cc577a4SJonathan Peyton 
9817cc577a4SJonathan Peyton     /* tasking must be enabled now as the task might not be pushed */
9827cc577a4SJonathan Peyton     if (!KMP_TASKING_ENABLED(task_team)) {
983*3041982dSJonathan Peyton       KA_TRACE(
984*3041982dSJonathan Peyton           30,
985*3041982dSJonathan Peyton           ("T#%d enabling tasking in __kmp_task_alloc for proxy task\n", gtid));
9867cc577a4SJonathan Peyton       __kmp_enable_tasking(task_team, thread);
9877cc577a4SJonathan Peyton       kmp_int32 tid = thread->th.th_info.ds.ds_tid;
9887cc577a4SJonathan Peyton       kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid];
9897cc577a4SJonathan Peyton       // No lock needed since only owner can allocate
9907cc577a4SJonathan Peyton       if (thread_data->td.td_deque == NULL) {
9917cc577a4SJonathan Peyton         __kmp_alloc_task_deque(thread, thread_data);
9927cc577a4SJonathan Peyton       }
9937cc577a4SJonathan Peyton     }
9947cc577a4SJonathan Peyton 
9957cc577a4SJonathan Peyton     if (task_team->tt.tt_found_proxy_tasks == FALSE)
9967cc577a4SJonathan Peyton       TCW_4(task_team->tt.tt_found_proxy_tasks, TRUE);
9977cc577a4SJonathan Peyton   }
9987cc577a4SJonathan Peyton #endif
9997cc577a4SJonathan Peyton 
10007cc577a4SJonathan Peyton   // Calculate shared structure offset including padding after kmp_task_t struct
10017cc577a4SJonathan Peyton   // to align pointers in shared struct
10027cc577a4SJonathan Peyton   shareds_offset = sizeof(kmp_taskdata_t) + sizeof_kmp_task_t;
10037cc577a4SJonathan Peyton   shareds_offset = __kmp_round_up_to_val(shareds_offset, sizeof(void *));
10047cc577a4SJonathan Peyton 
10057cc577a4SJonathan Peyton   // Allocate a kmp_taskdata_t block and a kmp_task_t block.
1006*3041982dSJonathan Peyton   KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n", gtid,
1007*3041982dSJonathan Peyton                 shareds_offset));
1008*3041982dSJonathan Peyton   KA_TRACE(30, ("__kmp_task_alloc: T#%d Second malloc size: %ld\n", gtid,
1009*3041982dSJonathan Peyton                 sizeof_shareds));
10107cc577a4SJonathan Peyton 
10117cc577a4SJonathan Peyton // Avoid double allocation here by combining shareds with taskdata
10127cc577a4SJonathan Peyton #if USE_FAST_MEMORY
1013*3041982dSJonathan Peyton   taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, shareds_offset +
1014*3041982dSJonathan Peyton                                                                sizeof_shareds);
10157cc577a4SJonathan Peyton #else /* ! USE_FAST_MEMORY */
1016*3041982dSJonathan Peyton   taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, shareds_offset +
1017*3041982dSJonathan Peyton                                                                sizeof_shareds);
10187cc577a4SJonathan Peyton #endif /* USE_FAST_MEMORY */
10197cc577a4SJonathan Peyton   ANNOTATE_HAPPENS_AFTER(taskdata);
10207cc577a4SJonathan Peyton 
10217cc577a4SJonathan Peyton   task = KMP_TASKDATA_TO_TASK(taskdata);
10227cc577a4SJonathan Peyton 
10237cc577a4SJonathan Peyton // Make sure task & taskdata are aligned appropriately
10247cc577a4SJonathan Peyton #if KMP_ARCH_X86 || KMP_ARCH_PPC64 || !KMP_HAVE_QUAD
10257cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(double) - 1)) == 0);
10267cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(double) - 1)) == 0);
10277cc577a4SJonathan Peyton #else
10287cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((((kmp_uintptr_t)taskdata) & (sizeof(_Quad) - 1)) == 0);
10297cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((((kmp_uintptr_t)task) & (sizeof(_Quad) - 1)) == 0);
10307cc577a4SJonathan Peyton #endif
10317cc577a4SJonathan Peyton   if (sizeof_shareds > 0) {
10327cc577a4SJonathan Peyton     // Avoid double allocation here by combining shareds with taskdata
10337cc577a4SJonathan Peyton     task->shareds = &((char *)taskdata)[shareds_offset];
10347cc577a4SJonathan Peyton     // Make sure shareds struct is aligned to pointer size
1035*3041982dSJonathan Peyton     KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) ==
1036*3041982dSJonathan Peyton                      0);
10377cc577a4SJonathan Peyton   } else {
10387cc577a4SJonathan Peyton     task->shareds = NULL;
10397cc577a4SJonathan Peyton   }
10407cc577a4SJonathan Peyton   task->routine = task_entry;
10417cc577a4SJonathan Peyton   task->part_id = 0; // AC: Always start with 0 part id
10427cc577a4SJonathan Peyton 
10437cc577a4SJonathan Peyton   taskdata->td_task_id = KMP_GEN_TASK_ID();
10447cc577a4SJonathan Peyton   taskdata->td_team = team;
10457cc577a4SJonathan Peyton   taskdata->td_alloc_thread = thread;
10467cc577a4SJonathan Peyton   taskdata->td_parent = parent_task;
10477cc577a4SJonathan Peyton   taskdata->td_level = parent_task->td_level + 1; // increment nesting level
10487cc577a4SJonathan Peyton   taskdata->td_untied_count = 0;
10497cc577a4SJonathan Peyton   taskdata->td_ident = loc_ref;
10507cc577a4SJonathan Peyton   taskdata->td_taskwait_ident = NULL;
10517cc577a4SJonathan Peyton   taskdata->td_taskwait_counter = 0;
10527cc577a4SJonathan Peyton   taskdata->td_taskwait_thread = 0;
10537cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_parent != NULL);
10547cc577a4SJonathan Peyton #if OMP_45_ENABLED
10557cc577a4SJonathan Peyton   // avoid copying icvs for proxy tasks
10567cc577a4SJonathan Peyton   if (flags->proxy == TASK_FULL)
10577cc577a4SJonathan Peyton #endif
10587cc577a4SJonathan Peyton     copy_icvs(&taskdata->td_icvs, &taskdata->td_parent->td_icvs);
10597cc577a4SJonathan Peyton 
10607cc577a4SJonathan Peyton   taskdata->td_flags.tiedness = flags->tiedness;
10617cc577a4SJonathan Peyton   taskdata->td_flags.final = flags->final;
10627cc577a4SJonathan Peyton   taskdata->td_flags.merged_if0 = flags->merged_if0;
10637cc577a4SJonathan Peyton #if OMP_40_ENABLED
10647cc577a4SJonathan Peyton   taskdata->td_flags.destructors_thunk = flags->destructors_thunk;
10657cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
10667cc577a4SJonathan Peyton #if OMP_45_ENABLED
10677cc577a4SJonathan Peyton   taskdata->td_flags.proxy = flags->proxy;
10687cc577a4SJonathan Peyton   taskdata->td_task_team = thread->th.th_task_team;
10697cc577a4SJonathan Peyton   taskdata->td_size_alloc = shareds_offset + sizeof_shareds;
10707cc577a4SJonathan Peyton #endif
10717cc577a4SJonathan Peyton   taskdata->td_flags.tasktype = TASK_EXPLICIT;
10727cc577a4SJonathan Peyton 
10737cc577a4SJonathan Peyton   // GEH - TODO: fix this to copy parent task's value of tasking_ser flag
10747cc577a4SJonathan Peyton   taskdata->td_flags.tasking_ser = (__kmp_tasking_mode == tskm_immediate_exec);
10757cc577a4SJonathan Peyton 
10767cc577a4SJonathan Peyton   // GEH - TODO: fix this to copy parent task's value of team_serial flag
10777cc577a4SJonathan Peyton   taskdata->td_flags.team_serial = (team->t.t_serialized) ? 1 : 0;
10787cc577a4SJonathan Peyton 
1079*3041982dSJonathan Peyton   // GEH - Note we serialize the task if the team is serialized to make sure
1080*3041982dSJonathan Peyton   // implicit parallel region tasks are not left until program termination to
1081*3041982dSJonathan Peyton   // execute. Also, it helps locality to execute immediately.
1082*3041982dSJonathan Peyton 
1083*3041982dSJonathan Peyton   taskdata->td_flags.task_serial =
1084*3041982dSJonathan Peyton       (parent_task->td_flags.final || taskdata->td_flags.team_serial ||
1085*3041982dSJonathan Peyton        taskdata->td_flags.tasking_ser);
10867cc577a4SJonathan Peyton 
10877cc577a4SJonathan Peyton   taskdata->td_flags.started = 0;
10887cc577a4SJonathan Peyton   taskdata->td_flags.executing = 0;
10897cc577a4SJonathan Peyton   taskdata->td_flags.complete = 0;
10907cc577a4SJonathan Peyton   taskdata->td_flags.freed = 0;
10917cc577a4SJonathan Peyton 
10927cc577a4SJonathan Peyton   taskdata->td_flags.native = flags->native;
10937cc577a4SJonathan Peyton 
10947cc577a4SJonathan Peyton   taskdata->td_incomplete_child_tasks = 0;
1095*3041982dSJonathan Peyton   taskdata->td_allocated_child_tasks = 1; // start at one because counts current
1096*3041982dSJonathan Peyton // task and children
10977cc577a4SJonathan Peyton #if OMP_40_ENABLED
1098*3041982dSJonathan Peyton   taskdata->td_taskgroup =
1099*3041982dSJonathan Peyton       parent_task->td_taskgroup; // task inherits taskgroup from the parent task
11007cc577a4SJonathan Peyton   taskdata->td_dephash = NULL;
11017cc577a4SJonathan Peyton   taskdata->td_depnode = NULL;
11027cc577a4SJonathan Peyton #endif
11037cc577a4SJonathan Peyton 
1104*3041982dSJonathan Peyton // Only need to keep track of child task counts if team parallel and tasking not
1105*3041982dSJonathan Peyton // serialized or if it is a proxy task
11067cc577a4SJonathan Peyton #if OMP_45_ENABLED
1107*3041982dSJonathan Peyton   if (flags->proxy == TASK_PROXY ||
1108*3041982dSJonathan Peyton       !(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser))
11097cc577a4SJonathan Peyton #else
11107cc577a4SJonathan Peyton   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser))
11117cc577a4SJonathan Peyton #endif
11127cc577a4SJonathan Peyton   {
11137cc577a4SJonathan Peyton     KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_incomplete_child_tasks));
11147cc577a4SJonathan Peyton #if OMP_40_ENABLED
11157cc577a4SJonathan Peyton     if (parent_task->td_taskgroup)
11167cc577a4SJonathan Peyton       KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_taskgroup->count));
11177cc577a4SJonathan Peyton #endif
1118*3041982dSJonathan Peyton     // Only need to keep track of allocated child tasks for explicit tasks since
1119*3041982dSJonathan Peyton     // implicit not deallocated
11207cc577a4SJonathan Peyton     if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT) {
1121*3041982dSJonathan Peyton       KMP_TEST_THEN_INC32(
1122*3041982dSJonathan Peyton           (kmp_int32 *)(&taskdata->td_parent->td_allocated_child_tasks));
11237cc577a4SJonathan Peyton     }
11247cc577a4SJonathan Peyton   }
11257cc577a4SJonathan Peyton 
11267cc577a4SJonathan Peyton   KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n",
11277cc577a4SJonathan Peyton                 gtid, taskdata, taskdata->td_parent));
11287cc577a4SJonathan Peyton   ANNOTATE_HAPPENS_BEFORE(task);
11297cc577a4SJonathan Peyton 
11307cc577a4SJonathan Peyton #if OMPT_SUPPORT
11317cc577a4SJonathan Peyton   __kmp_task_init_ompt(taskdata, gtid, (void *)task_entry);
11327cc577a4SJonathan Peyton #endif
11337cc577a4SJonathan Peyton 
11347cc577a4SJonathan Peyton   return task;
11357cc577a4SJonathan Peyton }
11367cc577a4SJonathan Peyton 
1137*3041982dSJonathan Peyton kmp_task_t *__kmpc_omp_task_alloc(ident_t *loc_ref, kmp_int32 gtid,
1138*3041982dSJonathan Peyton                                   kmp_int32 flags, size_t sizeof_kmp_task_t,
1139*3041982dSJonathan Peyton                                   size_t sizeof_shareds,
1140*3041982dSJonathan Peyton                                   kmp_routine_entry_t task_entry) {
11417cc577a4SJonathan Peyton   kmp_task_t *retval;
11427cc577a4SJonathan Peyton   kmp_tasking_flags_t *input_flags = (kmp_tasking_flags_t *)&flags;
11437cc577a4SJonathan Peyton 
11447cc577a4SJonathan Peyton   input_flags->native = FALSE;
11457cc577a4SJonathan Peyton // __kmp_task_alloc() sets up all other runtime flags
11467cc577a4SJonathan Peyton 
11477cc577a4SJonathan Peyton #if OMP_45_ENABLED
11487cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s %s) "
11497cc577a4SJonathan Peyton                 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
11507cc577a4SJonathan Peyton                 gtid, loc_ref, input_flags->tiedness ? "tied  " : "untied",
1151*3041982dSJonathan Peyton                 input_flags->proxy ? "proxy" : "", sizeof_kmp_task_t,
1152*3041982dSJonathan Peyton                 sizeof_shareds, task_entry));
11537cc577a4SJonathan Peyton #else
11547cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s) "
11557cc577a4SJonathan Peyton                 "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
11567cc577a4SJonathan Peyton                 gtid, loc_ref, input_flags->tiedness ? "tied  " : "untied",
11577cc577a4SJonathan Peyton                 sizeof_kmp_task_t, sizeof_shareds, task_entry));
11587cc577a4SJonathan Peyton #endif
11597cc577a4SJonathan Peyton 
11607cc577a4SJonathan Peyton   retval = __kmp_task_alloc(loc_ref, gtid, input_flags, sizeof_kmp_task_t,
11617cc577a4SJonathan Peyton                             sizeof_shareds, task_entry);
11627cc577a4SJonathan Peyton 
11637cc577a4SJonathan Peyton   KA_TRACE(20, ("__kmpc_omp_task_alloc(exit): T#%d retval %p\n", gtid, retval));
11647cc577a4SJonathan Peyton 
11657cc577a4SJonathan Peyton   return retval;
11667cc577a4SJonathan Peyton }
11677cc577a4SJonathan Peyton 
11687cc577a4SJonathan Peyton //  __kmp_invoke_task: invoke the specified task
11697cc577a4SJonathan Peyton //
11707cc577a4SJonathan Peyton // gtid: global thread ID of caller
11717cc577a4SJonathan Peyton // task: the task to invoke
11727cc577a4SJonathan Peyton // current_task: the task to resume after task invokation
1173*3041982dSJonathan Peyton static void __kmp_invoke_task(kmp_int32 gtid, kmp_task_t *task,
1174*3041982dSJonathan Peyton                               kmp_taskdata_t *current_task) {
11757cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
11767cc577a4SJonathan Peyton   kmp_uint64 cur_time;
11777cc577a4SJonathan Peyton #if OMP_40_ENABLED
11787cc577a4SJonathan Peyton   int discard = 0 /* false */;
11797cc577a4SJonathan Peyton #endif
1180*3041982dSJonathan Peyton   KA_TRACE(
1181*3041982dSJonathan Peyton       30, ("__kmp_invoke_task(enter): T#%d invoking task %p, current_task=%p\n",
11827cc577a4SJonathan Peyton            gtid, taskdata, current_task));
11837cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task);
11847cc577a4SJonathan Peyton #if OMP_45_ENABLED
11857cc577a4SJonathan Peyton   if (taskdata->td_flags.proxy == TASK_PROXY &&
1186*3041982dSJonathan Peyton       taskdata->td_flags.complete == 1) {
11877cc577a4SJonathan Peyton     // This is a proxy task that was already completed but it needs to run
11887cc577a4SJonathan Peyton     // its bottom-half finish
1189*3041982dSJonathan Peyton     KA_TRACE(
1190*3041982dSJonathan Peyton         30,
1191*3041982dSJonathan Peyton         ("__kmp_invoke_task: T#%d running bottom finish for proxy task %p\n",
11927cc577a4SJonathan Peyton          gtid, taskdata));
11937cc577a4SJonathan Peyton 
11947cc577a4SJonathan Peyton     __kmp_bottom_half_finish_proxy(gtid, task);
11957cc577a4SJonathan Peyton 
1196*3041982dSJonathan Peyton     KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed bottom finish for "
1197*3041982dSJonathan Peyton                   "proxy task %p, resuming task %p\n",
1198*3041982dSJonathan Peyton                   gtid, taskdata, current_task));
11997cc577a4SJonathan Peyton 
12007cc577a4SJonathan Peyton     return;
12017cc577a4SJonathan Peyton   }
12027cc577a4SJonathan Peyton #endif
12037cc577a4SJonathan Peyton 
12047cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY
12057cc577a4SJonathan Peyton   if (__kmp_forkjoin_frames_mode == 3) {
1206*3041982dSJonathan Peyton     // Get the current time stamp to measure task execution time to correct
1207*3041982dSJonathan Peyton     // barrier imbalance time
12087cc577a4SJonathan Peyton     cur_time = __itt_get_timestamp();
12097cc577a4SJonathan Peyton   }
12107cc577a4SJonathan Peyton #endif
12117cc577a4SJonathan Peyton 
12127cc577a4SJonathan Peyton #if OMP_45_ENABLED
12137cc577a4SJonathan Peyton   // Proxy tasks are not handled by the runtime
12147cc577a4SJonathan Peyton   if (taskdata->td_flags.proxy != TASK_PROXY) {
12157cc577a4SJonathan Peyton #endif
12167cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_AFTER(task);
12177cc577a4SJonathan Peyton     __kmp_task_start(gtid, task, current_task);
12187cc577a4SJonathan Peyton #if OMP_45_ENABLED
12197cc577a4SJonathan Peyton   }
12207cc577a4SJonathan Peyton #endif
12217cc577a4SJonathan Peyton 
12227cc577a4SJonathan Peyton #if OMPT_SUPPORT
12237cc577a4SJonathan Peyton   ompt_thread_info_t oldInfo;
12247cc577a4SJonathan Peyton   kmp_info_t *thread;
12257cc577a4SJonathan Peyton   if (ompt_enabled) {
12267cc577a4SJonathan Peyton     // Store the threads states and restore them after the task
12277cc577a4SJonathan Peyton     thread = __kmp_threads[gtid];
12287cc577a4SJonathan Peyton     oldInfo = thread->th.ompt_thread_info;
12297cc577a4SJonathan Peyton     thread->th.ompt_thread_info.wait_id = 0;
12307cc577a4SJonathan Peyton     thread->th.ompt_thread_info.state = ompt_state_work_parallel;
1231*3041982dSJonathan Peyton     taskdata->ompt_task_info.frame.exit_runtime_frame =
1232*3041982dSJonathan Peyton         __builtin_frame_address(0);
12337cc577a4SJonathan Peyton   }
12347cc577a4SJonathan Peyton #endif
12357cc577a4SJonathan Peyton 
12367cc577a4SJonathan Peyton #if OMP_40_ENABLED
12377cc577a4SJonathan Peyton   // TODO: cancel tasks if the parallel region has also been cancelled
12387cc577a4SJonathan Peyton   // TODO: check if this sequence can be hoisted above __kmp_task_start
12397cc577a4SJonathan Peyton   // if cancellation has been enabled for this run ...
12407cc577a4SJonathan Peyton   if (__kmp_omp_cancellation) {
12417cc577a4SJonathan Peyton     kmp_info_t *this_thr = __kmp_threads[gtid];
12427cc577a4SJonathan Peyton     kmp_team_t *this_team = this_thr->th.th_team;
12437cc577a4SJonathan Peyton     kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup;
1244*3041982dSJonathan Peyton     if ((taskgroup && taskgroup->cancel_request) ||
1245*3041982dSJonathan Peyton         (this_team->t.t_cancel_request == cancel_parallel)) {
12467cc577a4SJonathan Peyton       KMP_COUNT_BLOCK(TASK_cancelled);
12477cc577a4SJonathan Peyton       // this task belongs to a task group and we need to cancel it
12487cc577a4SJonathan Peyton       discard = 1 /* true */;
12497cc577a4SJonathan Peyton     }
12507cc577a4SJonathan Peyton   }
12517cc577a4SJonathan Peyton 
12527cc577a4SJonathan Peyton   // Invoke the task routine and pass in relevant data.
12537cc577a4SJonathan Peyton   // Thunks generated by gcc take a different argument list.
12547cc577a4SJonathan Peyton   if (!discard) {
12557cc577a4SJonathan Peyton #if KMP_STATS_ENABLED
12567cc577a4SJonathan Peyton     KMP_COUNT_BLOCK(TASK_executed);
12577cc577a4SJonathan Peyton     switch (KMP_GET_THREAD_STATE()) {
1258*3041982dSJonathan Peyton     case FORK_JOIN_BARRIER:
1259*3041982dSJonathan Peyton       KMP_PUSH_PARTITIONED_TIMER(OMP_task_join_bar);
1260*3041982dSJonathan Peyton       break;
1261*3041982dSJonathan Peyton     case PLAIN_BARRIER:
1262*3041982dSJonathan Peyton       KMP_PUSH_PARTITIONED_TIMER(OMP_task_plain_bar);
1263*3041982dSJonathan Peyton       break;
1264*3041982dSJonathan Peyton     case TASKYIELD:
1265*3041982dSJonathan Peyton       KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskyield);
1266*3041982dSJonathan Peyton       break;
1267*3041982dSJonathan Peyton     case TASKWAIT:
1268*3041982dSJonathan Peyton       KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskwait);
1269*3041982dSJonathan Peyton       break;
1270*3041982dSJonathan Peyton     case TASKGROUP:
1271*3041982dSJonathan Peyton       KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskgroup);
1272*3041982dSJonathan Peyton       break;
1273*3041982dSJonathan Peyton     default:
1274*3041982dSJonathan Peyton       KMP_PUSH_PARTITIONED_TIMER(OMP_task_immediate);
1275*3041982dSJonathan Peyton       break;
12767cc577a4SJonathan Peyton     }
12777cc577a4SJonathan Peyton #endif // KMP_STATS_ENABLED
12787cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
12797cc577a4SJonathan Peyton 
12807cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
12817cc577a4SJonathan Peyton     /* let OMPT know that we're about to run this task */
1282*3041982dSJonathan Peyton     if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_switch)) {
12837cc577a4SJonathan Peyton       ompt_callbacks.ompt_callback(ompt_event_task_switch)(
12847cc577a4SJonathan Peyton           current_task->ompt_task_info.task_id,
12857cc577a4SJonathan Peyton           taskdata->ompt_task_info.task_id);
12867cc577a4SJonathan Peyton     }
12877cc577a4SJonathan Peyton #endif
12887cc577a4SJonathan Peyton 
12897cc577a4SJonathan Peyton #ifdef KMP_GOMP_COMPAT
12907cc577a4SJonathan Peyton     if (taskdata->td_flags.native) {
12917cc577a4SJonathan Peyton       ((void (*)(void *))(*(task->routine)))(task->shareds);
1292*3041982dSJonathan Peyton     } else
12937cc577a4SJonathan Peyton #endif /* KMP_GOMP_COMPAT */
12947cc577a4SJonathan Peyton     {
12957cc577a4SJonathan Peyton       (*(task->routine))(gtid, task);
12967cc577a4SJonathan Peyton     }
12977cc577a4SJonathan Peyton     KMP_POP_PARTITIONED_TIMER();
12987cc577a4SJonathan Peyton 
12997cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
13007cc577a4SJonathan Peyton     /* let OMPT know that we're returning to the callee task */
1301*3041982dSJonathan Peyton     if (ompt_enabled && ompt_callbacks.ompt_callback(ompt_event_task_switch)) {
13027cc577a4SJonathan Peyton       ompt_callbacks.ompt_callback(ompt_event_task_switch)(
13037cc577a4SJonathan Peyton           taskdata->ompt_task_info.task_id,
13047cc577a4SJonathan Peyton           current_task->ompt_task_info.task_id);
13057cc577a4SJonathan Peyton     }
13067cc577a4SJonathan Peyton #endif
13077cc577a4SJonathan Peyton 
13087cc577a4SJonathan Peyton #if OMP_40_ENABLED
13097cc577a4SJonathan Peyton   }
13107cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
13117cc577a4SJonathan Peyton 
13127cc577a4SJonathan Peyton #if OMPT_SUPPORT
13137cc577a4SJonathan Peyton   if (ompt_enabled) {
13147cc577a4SJonathan Peyton     thread->th.ompt_thread_info = oldInfo;
13157cc577a4SJonathan Peyton     taskdata->ompt_task_info.frame.exit_runtime_frame = NULL;
13167cc577a4SJonathan Peyton   }
13177cc577a4SJonathan Peyton #endif
13187cc577a4SJonathan Peyton 
13197cc577a4SJonathan Peyton #if OMP_45_ENABLED
13207cc577a4SJonathan Peyton   // Proxy tasks are not handled by the runtime
13217cc577a4SJonathan Peyton   if (taskdata->td_flags.proxy != TASK_PROXY) {
13227cc577a4SJonathan Peyton #endif
13237cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_BEFORE(taskdata->td_parent);
13247cc577a4SJonathan Peyton     __kmp_task_finish(gtid, task, current_task);
13257cc577a4SJonathan Peyton #if OMP_45_ENABLED
13267cc577a4SJonathan Peyton   }
13277cc577a4SJonathan Peyton #endif
13287cc577a4SJonathan Peyton 
13297cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY
13307cc577a4SJonathan Peyton   // Barrier imbalance - correct arrive time after the task finished
13317cc577a4SJonathan Peyton   if (__kmp_forkjoin_frames_mode == 3) {
13327cc577a4SJonathan Peyton     kmp_info_t *this_thr = __kmp_threads[gtid];
13337cc577a4SJonathan Peyton     if (this_thr->th.th_bar_arrive_time) {
13347cc577a4SJonathan Peyton       this_thr->th.th_bar_arrive_time += (__itt_get_timestamp() - cur_time);
13357cc577a4SJonathan Peyton     }
13367cc577a4SJonathan Peyton   }
13377cc577a4SJonathan Peyton #endif
1338*3041982dSJonathan Peyton   KA_TRACE(
1339*3041982dSJonathan Peyton       30,
1340*3041982dSJonathan Peyton       ("__kmp_invoke_task(exit): T#%d completed task %p, resuming task %p\n",
13417cc577a4SJonathan Peyton        gtid, taskdata, current_task));
13427cc577a4SJonathan Peyton   return;
13437cc577a4SJonathan Peyton }
13447cc577a4SJonathan Peyton 
13457cc577a4SJonathan Peyton // __kmpc_omp_task_parts: Schedule a thread-switchable task for execution
13467cc577a4SJonathan Peyton //
13477cc577a4SJonathan Peyton // loc_ref: location of original task pragma (ignored)
13487cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread
13497cc577a4SJonathan Peyton // new_task: task thunk allocated by __kmp_omp_task_alloc() for the ''new task''
13507cc577a4SJonathan Peyton // Returns:
1351*3041982dSJonathan Peyton //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1352*3041982dSJonathan Peyton //    be resumed later.
1353*3041982dSJonathan Peyton //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1354*3041982dSJonathan Peyton //    resumed later.
1355*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_task_parts(ident_t *loc_ref, kmp_int32 gtid,
1356*3041982dSJonathan Peyton                                 kmp_task_t *new_task) {
13577cc577a4SJonathan Peyton   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
13587cc577a4SJonathan Peyton 
1359*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task_parts(enter): T#%d loc=%p task=%p\n", gtid,
1360*3041982dSJonathan Peyton                 loc_ref, new_taskdata));
13617cc577a4SJonathan Peyton 
1362*3041982dSJonathan Peyton   /* Should we execute the new task or queue it? For now, let's just always try
1363*3041982dSJonathan Peyton      to queue it.  If the queue fills up, then we'll execute it.  */
13647cc577a4SJonathan Peyton 
13657cc577a4SJonathan Peyton   if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
13667cc577a4SJonathan Peyton   { // Execute this task immediately
13677cc577a4SJonathan Peyton     kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
13687cc577a4SJonathan Peyton     new_taskdata->td_flags.task_serial = 1;
13697cc577a4SJonathan Peyton     __kmp_invoke_task(gtid, new_task, current_task);
13707cc577a4SJonathan Peyton   }
13717cc577a4SJonathan Peyton 
1372*3041982dSJonathan Peyton   KA_TRACE(
1373*3041982dSJonathan Peyton       10,
1374*3041982dSJonathan Peyton       ("__kmpc_omp_task_parts(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: "
1375*3041982dSJonathan Peyton        "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n",
1376*3041982dSJonathan Peyton        gtid, loc_ref, new_taskdata));
13777cc577a4SJonathan Peyton 
13787cc577a4SJonathan Peyton   ANNOTATE_HAPPENS_BEFORE(new_task);
13797cc577a4SJonathan Peyton   return TASK_CURRENT_NOT_QUEUED;
13807cc577a4SJonathan Peyton }
13817cc577a4SJonathan Peyton 
13827cc577a4SJonathan Peyton // __kmp_omp_task: Schedule a non-thread-switchable task for execution
1383*3041982dSJonathan Peyton //
13847cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread
13857cc577a4SJonathan Peyton // new_task:non-thread-switchable task thunk allocated by __kmp_omp_task_alloc()
1386*3041982dSJonathan Peyton // serialize_immediate: if TRUE then if the task is executed immediately its
1387*3041982dSJonathan Peyton // execution will be serialized
1388*3041982dSJonathan Peyton // Returns:
1389*3041982dSJonathan Peyton //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1390*3041982dSJonathan Peyton //    be resumed later.
1391*3041982dSJonathan Peyton //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1392*3041982dSJonathan Peyton //    resumed later.
1393*3041982dSJonathan Peyton kmp_int32 __kmp_omp_task(kmp_int32 gtid, kmp_task_t *new_task,
1394*3041982dSJonathan Peyton                          bool serialize_immediate) {
13957cc577a4SJonathan Peyton   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
13967cc577a4SJonathan Peyton 
13977cc577a4SJonathan Peyton #if OMPT_SUPPORT
13987cc577a4SJonathan Peyton   if (ompt_enabled) {
13997cc577a4SJonathan Peyton     new_taskdata->ompt_task_info.frame.reenter_runtime_frame =
14007cc577a4SJonathan Peyton         __builtin_frame_address(1);
14017cc577a4SJonathan Peyton   }
14027cc577a4SJonathan Peyton #endif
14037cc577a4SJonathan Peyton 
14047cc577a4SJonathan Peyton /* Should we execute the new task or queue it? For now, let's just always try to
14057cc577a4SJonathan Peyton    queue it.  If the queue fills up, then we'll execute it.  */
14067cc577a4SJonathan Peyton #if OMP_45_ENABLED
1407*3041982dSJonathan Peyton   if (new_taskdata->td_flags.proxy == TASK_PROXY ||
1408*3041982dSJonathan Peyton       __kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
14097cc577a4SJonathan Peyton #else
14107cc577a4SJonathan Peyton   if (__kmp_push_task(gtid, new_task) == TASK_NOT_PUSHED) // if cannot defer
14117cc577a4SJonathan Peyton #endif
14127cc577a4SJonathan Peyton   { // Execute this task immediately
14137cc577a4SJonathan Peyton     kmp_taskdata_t *current_task = __kmp_threads[gtid]->th.th_current_task;
14147cc577a4SJonathan Peyton     if (serialize_immediate)
14157cc577a4SJonathan Peyton       new_taskdata->td_flags.task_serial = 1;
14167cc577a4SJonathan Peyton     __kmp_invoke_task(gtid, new_task, current_task);
14177cc577a4SJonathan Peyton   }
14187cc577a4SJonathan Peyton 
14197cc577a4SJonathan Peyton #if OMPT_SUPPORT
14207cc577a4SJonathan Peyton   if (ompt_enabled) {
14217cc577a4SJonathan Peyton     new_taskdata->ompt_task_info.frame.reenter_runtime_frame = NULL;
14227cc577a4SJonathan Peyton   }
14237cc577a4SJonathan Peyton #endif
14247cc577a4SJonathan Peyton 
14257cc577a4SJonathan Peyton   ANNOTATE_HAPPENS_BEFORE(new_task);
14267cc577a4SJonathan Peyton   return TASK_CURRENT_NOT_QUEUED;
14277cc577a4SJonathan Peyton }
14287cc577a4SJonathan Peyton 
1429*3041982dSJonathan Peyton // __kmpc_omp_task: Wrapper around __kmp_omp_task to schedule a
1430*3041982dSJonathan Peyton // non-thread-switchable task from the parent thread only!
1431*3041982dSJonathan Peyton //
14327cc577a4SJonathan Peyton // loc_ref: location of original task pragma (ignored)
14337cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread
1434*3041982dSJonathan Peyton // new_task: non-thread-switchable task thunk allocated by
1435*3041982dSJonathan Peyton // __kmp_omp_task_alloc()
1436*3041982dSJonathan Peyton // Returns:
1437*3041982dSJonathan Peyton //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to
1438*3041982dSJonathan Peyton //    be resumed later.
1439*3041982dSJonathan Peyton //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be
1440*3041982dSJonathan Peyton //    resumed later.
1441*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_task(ident_t *loc_ref, kmp_int32 gtid,
1442*3041982dSJonathan Peyton                           kmp_task_t *new_task) {
14437cc577a4SJonathan Peyton   kmp_int32 res;
14447cc577a4SJonathan Peyton   KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK);
14457cc577a4SJonathan Peyton 
14467cc577a4SJonathan Peyton #if KMP_DEBUG
14477cc577a4SJonathan Peyton   kmp_taskdata_t *new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
14487cc577a4SJonathan Peyton #endif
1449*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n", gtid, loc_ref,
1450*3041982dSJonathan Peyton                 new_taskdata));
14517cc577a4SJonathan Peyton 
14527cc577a4SJonathan Peyton   res = __kmp_omp_task(gtid, new_task, true);
14537cc577a4SJonathan Peyton 
1454*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning "
1455*3041982dSJonathan Peyton                 "TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n",
14567cc577a4SJonathan Peyton                 gtid, loc_ref, new_taskdata));
14577cc577a4SJonathan Peyton   return res;
14587cc577a4SJonathan Peyton }
14597cc577a4SJonathan Peyton 
1460*3041982dSJonathan Peyton // __kmpc_omp_taskwait: Wait until all tasks generated by the current task are
1461*3041982dSJonathan Peyton // complete
1462*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_taskwait(ident_t *loc_ref, kmp_int32 gtid) {
14637cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata;
14647cc577a4SJonathan Peyton   kmp_info_t *thread;
14657cc577a4SJonathan Peyton   int thread_finished = FALSE;
14667cc577a4SJonathan Peyton   KMP_SET_THREAD_STATE_BLOCK(TASKWAIT);
14677cc577a4SJonathan Peyton 
14687cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_taskwait(enter): T#%d loc=%p\n", gtid, loc_ref));
14697cc577a4SJonathan Peyton 
14707cc577a4SJonathan Peyton   if (__kmp_tasking_mode != tskm_immediate_exec) {
1471*3041982dSJonathan Peyton     // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark
1472*3041982dSJonathan Peyton     // begin wait?
14737cc577a4SJonathan Peyton 
14747cc577a4SJonathan Peyton     thread = __kmp_threads[gtid];
14757cc577a4SJonathan Peyton     taskdata = thread->th.th_current_task;
14767cc577a4SJonathan Peyton 
14777cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
14787cc577a4SJonathan Peyton     ompt_task_id_t my_task_id;
14797cc577a4SJonathan Peyton     ompt_parallel_id_t my_parallel_id;
14807cc577a4SJonathan Peyton 
14817cc577a4SJonathan Peyton     if (ompt_enabled) {
14827cc577a4SJonathan Peyton       kmp_team_t *team = thread->th.th_team;
14837cc577a4SJonathan Peyton       my_task_id = taskdata->ompt_task_info.task_id;
14847cc577a4SJonathan Peyton       my_parallel_id = team->t.ompt_team_info.parallel_id;
14857cc577a4SJonathan Peyton 
1486*3041982dSJonathan Peyton       taskdata->ompt_task_info.frame.reenter_runtime_frame =
1487*3041982dSJonathan Peyton           __builtin_frame_address(1);
14887cc577a4SJonathan Peyton       if (ompt_callbacks.ompt_callback(ompt_event_taskwait_begin)) {
1489*3041982dSJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_taskwait_begin)(my_parallel_id,
1490*3041982dSJonathan Peyton                                                                 my_task_id);
14917cc577a4SJonathan Peyton       }
14927cc577a4SJonathan Peyton     }
14937cc577a4SJonathan Peyton #endif
14947cc577a4SJonathan Peyton 
1495*3041982dSJonathan Peyton // Debugger: The taskwait is active. Store location and thread encountered the
1496*3041982dSJonathan Peyton // taskwait.
14977cc577a4SJonathan Peyton #if USE_ITT_BUILD
14987cc577a4SJonathan Peyton // Note: These values are used by ITT events as well.
14997cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
15007cc577a4SJonathan Peyton     taskdata->td_taskwait_counter += 1;
15017cc577a4SJonathan Peyton     taskdata->td_taskwait_ident = loc_ref;
15027cc577a4SJonathan Peyton     taskdata->td_taskwait_thread = gtid + 1;
15037cc577a4SJonathan Peyton 
15047cc577a4SJonathan Peyton #if USE_ITT_BUILD
15057cc577a4SJonathan Peyton     void *itt_sync_obj = __kmp_itt_taskwait_object(gtid);
15067cc577a4SJonathan Peyton     if (itt_sync_obj != NULL)
15077cc577a4SJonathan Peyton       __kmp_itt_taskwait_starting(gtid, itt_sync_obj);
15087cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
15097cc577a4SJonathan Peyton 
1510*3041982dSJonathan Peyton     bool must_wait =
1511*3041982dSJonathan Peyton         !taskdata->td_flags.team_serial && !taskdata->td_flags.final;
15127cc577a4SJonathan Peyton 
15137cc577a4SJonathan Peyton #if OMP_45_ENABLED
1514*3041982dSJonathan Peyton     must_wait = must_wait || (thread->th.th_task_team != NULL &&
1515*3041982dSJonathan Peyton                               thread->th.th_task_team->tt.tt_found_proxy_tasks);
15167cc577a4SJonathan Peyton #endif
1517*3041982dSJonathan Peyton     if (must_wait) {
15187cc577a4SJonathan Peyton       kmp_flag_32 flag(&(taskdata->td_incomplete_child_tasks), 0U);
15197cc577a4SJonathan Peyton       while (TCR_4(taskdata->td_incomplete_child_tasks) != 0) {
1520*3041982dSJonathan Peyton         flag.execute_tasks(thread, gtid, FALSE,
1521*3041982dSJonathan Peyton                            &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
1522*3041982dSJonathan Peyton                            __kmp_task_stealing_constraint);
15237cc577a4SJonathan Peyton       }
15247cc577a4SJonathan Peyton     }
15257cc577a4SJonathan Peyton #if USE_ITT_BUILD
15267cc577a4SJonathan Peyton     if (itt_sync_obj != NULL)
15277cc577a4SJonathan Peyton       __kmp_itt_taskwait_finished(gtid, itt_sync_obj);
15287cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
15297cc577a4SJonathan Peyton 
1530*3041982dSJonathan Peyton     // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark
1531*3041982dSJonathan Peyton     // end of wait?
1532*3041982dSJonathan Peyton     // Debugger:  The taskwait is completed. Location remains, but thread is
1533*3041982dSJonathan Peyton     // negated.
15347cc577a4SJonathan Peyton     taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread;
15357cc577a4SJonathan Peyton 
15367cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
15377cc577a4SJonathan Peyton     if (ompt_enabled) {
15387cc577a4SJonathan Peyton       if (ompt_callbacks.ompt_callback(ompt_event_taskwait_end)) {
1539*3041982dSJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_taskwait_end)(my_parallel_id,
1540*3041982dSJonathan Peyton                                                               my_task_id);
15417cc577a4SJonathan Peyton       }
15427cc577a4SJonathan Peyton       taskdata->ompt_task_info.frame.reenter_runtime_frame = NULL;
15437cc577a4SJonathan Peyton     }
15447cc577a4SJonathan Peyton #endif
15457cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_AFTER(taskdata);
15467cc577a4SJonathan Peyton   }
15477cc577a4SJonathan Peyton 
15487cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_taskwait(exit): T#%d task %p finished waiting, "
1549*3041982dSJonathan Peyton                 "returning TASK_CURRENT_NOT_QUEUED\n",
1550*3041982dSJonathan Peyton                 gtid, taskdata));
15517cc577a4SJonathan Peyton 
15527cc577a4SJonathan Peyton   return TASK_CURRENT_NOT_QUEUED;
15537cc577a4SJonathan Peyton }
15547cc577a4SJonathan Peyton 
15557cc577a4SJonathan Peyton // __kmpc_omp_taskyield: switch to a different task
1556*3041982dSJonathan Peyton kmp_int32 __kmpc_omp_taskyield(ident_t *loc_ref, kmp_int32 gtid, int end_part) {
15577cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata;
15587cc577a4SJonathan Peyton   kmp_info_t *thread;
15597cc577a4SJonathan Peyton   int thread_finished = FALSE;
15607cc577a4SJonathan Peyton 
15617cc577a4SJonathan Peyton   KMP_COUNT_BLOCK(OMP_TASKYIELD);
15627cc577a4SJonathan Peyton   KMP_SET_THREAD_STATE_BLOCK(TASKYIELD);
15637cc577a4SJonathan Peyton 
15647cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_taskyield(enter): T#%d loc=%p end_part = %d\n",
15657cc577a4SJonathan Peyton                 gtid, loc_ref, end_part));
15667cc577a4SJonathan Peyton 
15677cc577a4SJonathan Peyton   if (__kmp_tasking_mode != tskm_immediate_exec && __kmp_init_parallel) {
1568*3041982dSJonathan Peyton     // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark
1569*3041982dSJonathan Peyton     // begin wait?
15707cc577a4SJonathan Peyton 
15717cc577a4SJonathan Peyton     thread = __kmp_threads[gtid];
15727cc577a4SJonathan Peyton     taskdata = thread->th.th_current_task;
15737cc577a4SJonathan Peyton // Should we model this as a task wait or not?
1574*3041982dSJonathan Peyton // Debugger: The taskwait is active. Store location and thread encountered the
1575*3041982dSJonathan Peyton // taskwait.
15767cc577a4SJonathan Peyton #if USE_ITT_BUILD
15777cc577a4SJonathan Peyton // Note: These values are used by ITT events as well.
15787cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
15797cc577a4SJonathan Peyton     taskdata->td_taskwait_counter += 1;
15807cc577a4SJonathan Peyton     taskdata->td_taskwait_ident = loc_ref;
15817cc577a4SJonathan Peyton     taskdata->td_taskwait_thread = gtid + 1;
15827cc577a4SJonathan Peyton 
15837cc577a4SJonathan Peyton #if USE_ITT_BUILD
15847cc577a4SJonathan Peyton     void *itt_sync_obj = __kmp_itt_taskwait_object(gtid);
15857cc577a4SJonathan Peyton     if (itt_sync_obj != NULL)
15867cc577a4SJonathan Peyton       __kmp_itt_taskwait_starting(gtid, itt_sync_obj);
15877cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
15887cc577a4SJonathan Peyton     if (!taskdata->td_flags.team_serial) {
15897cc577a4SJonathan Peyton       kmp_task_team_t *task_team = thread->th.th_task_team;
15907cc577a4SJonathan Peyton       if (task_team != NULL) {
15917cc577a4SJonathan Peyton         if (KMP_TASKING_ENABLED(task_team)) {
1592*3041982dSJonathan Peyton           __kmp_execute_tasks_32(
1593*3041982dSJonathan Peyton               thread, gtid, NULL, FALSE,
1594*3041982dSJonathan Peyton               &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
1595*3041982dSJonathan Peyton               __kmp_task_stealing_constraint);
15967cc577a4SJonathan Peyton         }
15977cc577a4SJonathan Peyton       }
15987cc577a4SJonathan Peyton     }
15997cc577a4SJonathan Peyton #if USE_ITT_BUILD
16007cc577a4SJonathan Peyton     if (itt_sync_obj != NULL)
16017cc577a4SJonathan Peyton       __kmp_itt_taskwait_finished(gtid, itt_sync_obj);
16027cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
16037cc577a4SJonathan Peyton 
1604*3041982dSJonathan Peyton     // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark
1605*3041982dSJonathan Peyton     // end of wait?
1606*3041982dSJonathan Peyton     // Debugger:  The taskwait is completed. Location remains, but thread is
1607*3041982dSJonathan Peyton     // negated.
16087cc577a4SJonathan Peyton     taskdata->td_taskwait_thread = -taskdata->td_taskwait_thread;
16097cc577a4SJonathan Peyton   }
16107cc577a4SJonathan Peyton 
16117cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_omp_taskyield(exit): T#%d task %p resuming, "
1612*3041982dSJonathan Peyton                 "returning TASK_CURRENT_NOT_QUEUED\n",
1613*3041982dSJonathan Peyton                 gtid, taskdata));
16147cc577a4SJonathan Peyton 
16157cc577a4SJonathan Peyton   return TASK_CURRENT_NOT_QUEUED;
16167cc577a4SJonathan Peyton }
16177cc577a4SJonathan Peyton 
161872ba2109SAndrey Churbanov // TODO: change to OMP_50_ENABLED, need to change build tools for this to work
161972ba2109SAndrey Churbanov #if OMP_45_ENABLED
162072ba2109SAndrey Churbanov // Task Reduction implementation
162172ba2109SAndrey Churbanov 
162272ba2109SAndrey Churbanov typedef struct kmp_task_red_flags {
162372ba2109SAndrey Churbanov   unsigned lazy_priv : 1; // hint: (1) use lazy allocation (big objects)
162472ba2109SAndrey Churbanov   unsigned reserved31 : 31;
162572ba2109SAndrey Churbanov } kmp_task_red_flags_t;
162672ba2109SAndrey Churbanov 
162772ba2109SAndrey Churbanov // internal structure for reduction data item related info
162872ba2109SAndrey Churbanov typedef struct kmp_task_red_data {
162972ba2109SAndrey Churbanov   void *reduce_shar; // shared reduction item
163072ba2109SAndrey Churbanov   size_t reduce_size; // size of data item
163172ba2109SAndrey Churbanov   void *reduce_priv; // thread specific data
163272ba2109SAndrey Churbanov   void *reduce_pend; // end of private data for comparison op
163372ba2109SAndrey Churbanov   void *reduce_init; // data initialization routine
163472ba2109SAndrey Churbanov   void *reduce_fini; // data finalization routine
163572ba2109SAndrey Churbanov   void *reduce_comb; // data combiner routine
163672ba2109SAndrey Churbanov   kmp_task_red_flags_t flags; // flags for additional info from compiler
163772ba2109SAndrey Churbanov } kmp_task_red_data_t;
163872ba2109SAndrey Churbanov 
163972ba2109SAndrey Churbanov // structure sent us by compiler - one per reduction item
164072ba2109SAndrey Churbanov typedef struct kmp_task_red_input {
164172ba2109SAndrey Churbanov   void *reduce_shar; // shared reduction item
164272ba2109SAndrey Churbanov   size_t reduce_size; // size of data item
164372ba2109SAndrey Churbanov   void *reduce_init; // data initialization routine
164472ba2109SAndrey Churbanov   void *reduce_fini; // data finalization routine
164572ba2109SAndrey Churbanov   void *reduce_comb; // data combiner routine
164672ba2109SAndrey Churbanov   kmp_task_red_flags_t flags; // flags for additional info from compiler
164772ba2109SAndrey Churbanov } kmp_task_red_input_t;
164872ba2109SAndrey Churbanov 
164972ba2109SAndrey Churbanov /*!
165072ba2109SAndrey Churbanov @ingroup TASKING
165172ba2109SAndrey Churbanov @param gtid      Global thread ID
165272ba2109SAndrey Churbanov @param num       Number of data items to reduce
165372ba2109SAndrey Churbanov @param data      Array of data for reduction
165472ba2109SAndrey Churbanov @return The taskgroup identifier
165572ba2109SAndrey Churbanov 
165672ba2109SAndrey Churbanov Initialize task reduction for the taskgroup.
165772ba2109SAndrey Churbanov */
1658*3041982dSJonathan Peyton void *__kmpc_task_reduction_init(int gtid, int num, void *data) {
165972ba2109SAndrey Churbanov   kmp_info_t *thread = __kmp_threads[gtid];
166072ba2109SAndrey Churbanov   kmp_taskgroup_t *tg = thread->th.th_current_task->td_taskgroup;
166172ba2109SAndrey Churbanov   kmp_int32 nth = thread->th.th_team_nproc;
166272ba2109SAndrey Churbanov   kmp_task_red_input_t *input = (kmp_task_red_input_t *)data;
166372ba2109SAndrey Churbanov   kmp_task_red_data_t *arr;
166472ba2109SAndrey Churbanov 
166572ba2109SAndrey Churbanov   // check input data just in case
166672ba2109SAndrey Churbanov   KMP_ASSERT(tg != NULL);
166772ba2109SAndrey Churbanov   KMP_ASSERT(data != NULL);
166872ba2109SAndrey Churbanov   KMP_ASSERT(num > 0);
166972ba2109SAndrey Churbanov   if (nth == 1) {
167072ba2109SAndrey Churbanov     KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, tg %p, exiting nth=1\n",
167172ba2109SAndrey Churbanov                   gtid, tg));
167272ba2109SAndrey Churbanov     return (void *)tg;
167372ba2109SAndrey Churbanov   }
167472ba2109SAndrey Churbanov   KA_TRACE(10, ("__kmpc_task_reduction_init: T#%d, taskgroup %p, #items %d\n",
167572ba2109SAndrey Churbanov                 gtid, tg, num));
1676*3041982dSJonathan Peyton   arr = (kmp_task_red_data_t *)__kmp_thread_malloc(
1677*3041982dSJonathan Peyton       thread, num * sizeof(kmp_task_red_data_t));
167872ba2109SAndrey Churbanov   for (int i = 0; i < num; ++i) {
167972ba2109SAndrey Churbanov     void (*f_init)(void *) = (void (*)(void *))(input[i].reduce_init);
168072ba2109SAndrey Churbanov     size_t size = input[i].reduce_size - 1;
168172ba2109SAndrey Churbanov     // round the size up to cache line per thread-specific item
168272ba2109SAndrey Churbanov     size += CACHE_LINE - size % CACHE_LINE;
168372ba2109SAndrey Churbanov     KMP_ASSERT(input[i].reduce_comb != NULL); // combiner is mandatory
168472ba2109SAndrey Churbanov     arr[i].reduce_shar = input[i].reduce_shar;
168572ba2109SAndrey Churbanov     arr[i].reduce_size = size;
168672ba2109SAndrey Churbanov     arr[i].reduce_init = input[i].reduce_init;
168772ba2109SAndrey Churbanov     arr[i].reduce_fini = input[i].reduce_fini;
168872ba2109SAndrey Churbanov     arr[i].reduce_comb = input[i].reduce_comb;
168972ba2109SAndrey Churbanov     arr[i].flags = input[i].flags;
169072ba2109SAndrey Churbanov     if (!input[i].flags.lazy_priv) {
169172ba2109SAndrey Churbanov       // allocate cache-line aligned block and fill it with zeros
169272ba2109SAndrey Churbanov       arr[i].reduce_priv = __kmp_allocate(nth * size);
169372ba2109SAndrey Churbanov       arr[i].reduce_pend = (char *)(arr[i].reduce_priv) + nth * size;
169472ba2109SAndrey Churbanov       if (f_init != NULL) {
169572ba2109SAndrey Churbanov         // initialize thread-specific items
169672ba2109SAndrey Churbanov         for (int j = 0; j < nth; ++j) {
169772ba2109SAndrey Churbanov           f_init((char *)(arr[i].reduce_priv) + j * size);
169872ba2109SAndrey Churbanov         }
169972ba2109SAndrey Churbanov       }
170072ba2109SAndrey Churbanov     } else {
170172ba2109SAndrey Churbanov       // only allocate space for pointers now,
170272ba2109SAndrey Churbanov       // objects will be lazily allocated/initialized once requested
170372ba2109SAndrey Churbanov       arr[i].reduce_priv = __kmp_allocate(nth * sizeof(void *));
170472ba2109SAndrey Churbanov     }
170572ba2109SAndrey Churbanov   }
170672ba2109SAndrey Churbanov   tg->reduce_data = (void *)arr;
170772ba2109SAndrey Churbanov   tg->reduce_num_data = num;
170872ba2109SAndrey Churbanov   return (void *)tg;
170972ba2109SAndrey Churbanov }
171072ba2109SAndrey Churbanov 
171172ba2109SAndrey Churbanov /*!
171272ba2109SAndrey Churbanov @ingroup TASKING
171372ba2109SAndrey Churbanov @param gtid    Global thread ID
171472ba2109SAndrey Churbanov @param tskgrp  The taskgroup ID (optional)
171572ba2109SAndrey Churbanov @param data    Shared location of the item
171672ba2109SAndrey Churbanov @return The pointer to per-thread data
171772ba2109SAndrey Churbanov 
171872ba2109SAndrey Churbanov Get thread-specific location of data item
171972ba2109SAndrey Churbanov */
1720*3041982dSJonathan Peyton void *__kmpc_task_reduction_get_th_data(int gtid, void *tskgrp, void *data) {
172172ba2109SAndrey Churbanov   kmp_info_t *thread = __kmp_threads[gtid];
172272ba2109SAndrey Churbanov   kmp_int32 nth = thread->th.th_team_nproc;
172372ba2109SAndrey Churbanov   if (nth == 1)
172472ba2109SAndrey Churbanov     return data; // nothing to do
172572ba2109SAndrey Churbanov 
172672ba2109SAndrey Churbanov   kmp_taskgroup_t *tg = (kmp_taskgroup_t *)tskgrp;
172772ba2109SAndrey Churbanov   if (tg == NULL)
172872ba2109SAndrey Churbanov     tg = thread->th.th_current_task->td_taskgroup;
172972ba2109SAndrey Churbanov   KMP_ASSERT(tg != NULL);
173072ba2109SAndrey Churbanov   kmp_task_red_data_t *arr = (kmp_task_red_data_t *)(tg->reduce_data);
173172ba2109SAndrey Churbanov   kmp_int32 num = tg->reduce_num_data;
173272ba2109SAndrey Churbanov   kmp_int32 tid = thread->th.th_info.ds.ds_tid;
173372ba2109SAndrey Churbanov 
173472ba2109SAndrey Churbanov   KMP_ASSERT(data != NULL);
173572ba2109SAndrey Churbanov   while (tg != NULL) {
173672ba2109SAndrey Churbanov     for (int i = 0; i < num; ++i) {
173772ba2109SAndrey Churbanov       if (!arr[i].flags.lazy_priv) {
173872ba2109SAndrey Churbanov         if (data == arr[i].reduce_shar ||
173972ba2109SAndrey Churbanov             (data >= arr[i].reduce_priv && data < arr[i].reduce_pend))
174072ba2109SAndrey Churbanov           return (char *)(arr[i].reduce_priv) + tid * arr[i].reduce_size;
174172ba2109SAndrey Churbanov       } else {
174272ba2109SAndrey Churbanov         // check shared location first
174372ba2109SAndrey Churbanov         void **p_priv = (void **)(arr[i].reduce_priv);
174472ba2109SAndrey Churbanov         if (data == arr[i].reduce_shar)
174572ba2109SAndrey Churbanov           goto found;
174672ba2109SAndrey Churbanov         // check if we get some thread specific location as parameter
174772ba2109SAndrey Churbanov         for (int j = 0; j < nth; ++j)
174872ba2109SAndrey Churbanov           if (data == p_priv[j])
174972ba2109SAndrey Churbanov             goto found;
175072ba2109SAndrey Churbanov         continue; // not found, continue search
175172ba2109SAndrey Churbanov       found:
175272ba2109SAndrey Churbanov         if (p_priv[tid] == NULL) {
175372ba2109SAndrey Churbanov           // allocate thread specific object lazily
175472ba2109SAndrey Churbanov           void (*f_init)(void *) = (void (*)(void *))(arr[i].reduce_init);
175572ba2109SAndrey Churbanov           p_priv[tid] = __kmp_allocate(arr[i].reduce_size);
175672ba2109SAndrey Churbanov           if (f_init != NULL) {
175772ba2109SAndrey Churbanov             f_init(p_priv[tid]);
175872ba2109SAndrey Churbanov           }
175972ba2109SAndrey Churbanov         }
176072ba2109SAndrey Churbanov         return p_priv[tid];
176172ba2109SAndrey Churbanov       }
176272ba2109SAndrey Churbanov     }
176372ba2109SAndrey Churbanov     tg = tg->parent;
176472ba2109SAndrey Churbanov     arr = (kmp_task_red_data_t *)(tg->reduce_data);
176572ba2109SAndrey Churbanov     num = tg->reduce_num_data;
176672ba2109SAndrey Churbanov   }
176772ba2109SAndrey Churbanov   KMP_ASSERT2(0, "Unknown task reduction item");
176872ba2109SAndrey Churbanov   return NULL; // ERROR, this line never executed
176972ba2109SAndrey Churbanov }
177072ba2109SAndrey Churbanov 
177172ba2109SAndrey Churbanov // Finalize task reduction.
177272ba2109SAndrey Churbanov // Called from __kmpc_end_taskgroup()
1773*3041982dSJonathan Peyton static void __kmp_task_reduction_fini(kmp_info_t *th, kmp_taskgroup_t *tg) {
177472ba2109SAndrey Churbanov   kmp_int32 nth = th->th.th_team_nproc;
177572ba2109SAndrey Churbanov   KMP_DEBUG_ASSERT(nth > 1); // should not be called if nth == 1
177672ba2109SAndrey Churbanov   kmp_task_red_data_t *arr = (kmp_task_red_data_t *)tg->reduce_data;
177772ba2109SAndrey Churbanov   kmp_int32 num = tg->reduce_num_data;
177872ba2109SAndrey Churbanov   for (int i = 0; i < num; ++i) {
177972ba2109SAndrey Churbanov     void *sh_data = arr[i].reduce_shar;
178072ba2109SAndrey Churbanov     void (*f_fini)(void *) = (void (*)(void *))(arr[i].reduce_fini);
1781*3041982dSJonathan Peyton     void (*f_comb)(void *, void *) =
1782*3041982dSJonathan Peyton         (void (*)(void *, void *))(arr[i].reduce_comb);
178372ba2109SAndrey Churbanov     if (!arr[i].flags.lazy_priv) {
178472ba2109SAndrey Churbanov       void *pr_data = arr[i].reduce_priv;
178572ba2109SAndrey Churbanov       size_t size = arr[i].reduce_size;
178672ba2109SAndrey Churbanov       for (int j = 0; j < nth; ++j) {
178772ba2109SAndrey Churbanov         void *priv_data = (char *)pr_data + j * size;
178872ba2109SAndrey Churbanov         f_comb(sh_data, priv_data); // combine results
178972ba2109SAndrey Churbanov         if (f_fini)
179072ba2109SAndrey Churbanov           f_fini(priv_data); // finalize if needed
179172ba2109SAndrey Churbanov       }
179272ba2109SAndrey Churbanov     } else {
179372ba2109SAndrey Churbanov       void **pr_data = (void **)(arr[i].reduce_priv);
179472ba2109SAndrey Churbanov       for (int j = 0; j < nth; ++j) {
179572ba2109SAndrey Churbanov         if (pr_data[j] != NULL) {
179672ba2109SAndrey Churbanov           f_comb(sh_data, pr_data[j]); // combine results
179772ba2109SAndrey Churbanov           if (f_fini)
179872ba2109SAndrey Churbanov             f_fini(pr_data[j]); // finalize if needed
179972ba2109SAndrey Churbanov           __kmp_free(pr_data[j]);
180072ba2109SAndrey Churbanov         }
180172ba2109SAndrey Churbanov       }
180272ba2109SAndrey Churbanov     }
180372ba2109SAndrey Churbanov     __kmp_free(arr[i].reduce_priv);
180472ba2109SAndrey Churbanov   }
180572ba2109SAndrey Churbanov   __kmp_thread_free(th, arr);
180672ba2109SAndrey Churbanov   tg->reduce_data = NULL;
180772ba2109SAndrey Churbanov   tg->reduce_num_data = 0;
180872ba2109SAndrey Churbanov }
180972ba2109SAndrey Churbanov #endif
18107cc577a4SJonathan Peyton 
18117cc577a4SJonathan Peyton #if OMP_40_ENABLED
18127cc577a4SJonathan Peyton // __kmpc_taskgroup: Start a new taskgroup
1813*3041982dSJonathan Peyton void __kmpc_taskgroup(ident_t *loc, int gtid) {
18147cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
18157cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = thread->th.th_current_task;
18167cc577a4SJonathan Peyton   kmp_taskgroup_t *tg_new =
18177cc577a4SJonathan Peyton       (kmp_taskgroup_t *)__kmp_thread_malloc(thread, sizeof(kmp_taskgroup_t));
18187cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_taskgroup: T#%d loc=%p group=%p\n", gtid, loc, tg_new));
18197cc577a4SJonathan Peyton   tg_new->count = 0;
18207cc577a4SJonathan Peyton   tg_new->cancel_request = cancel_noreq;
18217cc577a4SJonathan Peyton   tg_new->parent = taskdata->td_taskgroup;
182272ba2109SAndrey Churbanov // TODO: change to OMP_50_ENABLED, need to change build tools for this to work
182372ba2109SAndrey Churbanov #if OMP_45_ENABLED
182472ba2109SAndrey Churbanov   tg_new->reduce_data = NULL;
182572ba2109SAndrey Churbanov   tg_new->reduce_num_data = 0;
182672ba2109SAndrey Churbanov #endif
18277cc577a4SJonathan Peyton   taskdata->td_taskgroup = tg_new;
18287cc577a4SJonathan Peyton }
18297cc577a4SJonathan Peyton 
18307cc577a4SJonathan Peyton // __kmpc_end_taskgroup: Wait until all tasks generated by the current task
18317cc577a4SJonathan Peyton //                       and its descendants are complete
1832*3041982dSJonathan Peyton void __kmpc_end_taskgroup(ident_t *loc, int gtid) {
18337cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
18347cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = thread->th.th_current_task;
18357cc577a4SJonathan Peyton   kmp_taskgroup_t *taskgroup = taskdata->td_taskgroup;
18367cc577a4SJonathan Peyton   int thread_finished = FALSE;
18377cc577a4SJonathan Peyton 
18387cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_end_taskgroup(enter): T#%d loc=%p\n", gtid, loc));
18397cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskgroup != NULL);
18407cc577a4SJonathan Peyton   KMP_SET_THREAD_STATE_BLOCK(TASKGROUP);
18417cc577a4SJonathan Peyton 
18427cc577a4SJonathan Peyton   if (__kmp_tasking_mode != tskm_immediate_exec) {
18437cc577a4SJonathan Peyton #if USE_ITT_BUILD
1844*3041982dSJonathan Peyton     // For ITT the taskgroup wait is similar to taskwait until we need to
1845*3041982dSJonathan Peyton     // distinguish them
18467cc577a4SJonathan Peyton     void *itt_sync_obj = __kmp_itt_taskwait_object(gtid);
18477cc577a4SJonathan Peyton     if (itt_sync_obj != NULL)
18487cc577a4SJonathan Peyton       __kmp_itt_taskwait_starting(gtid, itt_sync_obj);
18497cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
18507cc577a4SJonathan Peyton 
18517cc577a4SJonathan Peyton #if OMP_45_ENABLED
1852*3041982dSJonathan Peyton     if (!taskdata->td_flags.team_serial ||
1853*3041982dSJonathan Peyton         (thread->th.th_task_team != NULL &&
1854*3041982dSJonathan Peyton          thread->th.th_task_team->tt.tt_found_proxy_tasks))
18557cc577a4SJonathan Peyton #else
18567cc577a4SJonathan Peyton     if (!taskdata->td_flags.team_serial)
18577cc577a4SJonathan Peyton #endif
18587cc577a4SJonathan Peyton     {
18597cc577a4SJonathan Peyton       kmp_flag_32 flag(&(taskgroup->count), 0U);
18607cc577a4SJonathan Peyton       while (TCR_4(taskgroup->count) != 0) {
1861*3041982dSJonathan Peyton         flag.execute_tasks(thread, gtid, FALSE,
1862*3041982dSJonathan Peyton                            &thread_finished USE_ITT_BUILD_ARG(itt_sync_obj),
1863*3041982dSJonathan Peyton                            __kmp_task_stealing_constraint);
18647cc577a4SJonathan Peyton       }
18657cc577a4SJonathan Peyton     }
18667cc577a4SJonathan Peyton 
18677cc577a4SJonathan Peyton #if USE_ITT_BUILD
18687cc577a4SJonathan Peyton     if (itt_sync_obj != NULL)
18697cc577a4SJonathan Peyton       __kmp_itt_taskwait_finished(gtid, itt_sync_obj);
18707cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
18717cc577a4SJonathan Peyton   }
18727cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskgroup->count == 0);
18737cc577a4SJonathan Peyton 
187472ba2109SAndrey Churbanov // TODO: change to OMP_50_ENABLED, need to change build tools for this to work
187572ba2109SAndrey Churbanov #if OMP_45_ENABLED
187672ba2109SAndrey Churbanov   if (taskgroup->reduce_data != NULL) // need to reduce?
187772ba2109SAndrey Churbanov     __kmp_task_reduction_fini(thread, taskgroup);
187872ba2109SAndrey Churbanov #endif
18797cc577a4SJonathan Peyton   // Restore parent taskgroup for the current task
18807cc577a4SJonathan Peyton   taskdata->td_taskgroup = taskgroup->parent;
18817cc577a4SJonathan Peyton   __kmp_thread_free(thread, taskgroup);
18827cc577a4SJonathan Peyton 
1883*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_end_taskgroup(exit): T#%d task %p finished waiting\n",
1884*3041982dSJonathan Peyton                 gtid, taskdata));
18857cc577a4SJonathan Peyton   ANNOTATE_HAPPENS_AFTER(taskdata);
18867cc577a4SJonathan Peyton }
18877cc577a4SJonathan Peyton #endif
18887cc577a4SJonathan Peyton 
18897cc577a4SJonathan Peyton // __kmp_remove_my_task: remove a task from my own deque
1890*3041982dSJonathan Peyton static kmp_task_t *__kmp_remove_my_task(kmp_info_t *thread, kmp_int32 gtid,
1891*3041982dSJonathan Peyton                                         kmp_task_team_t *task_team,
1892*3041982dSJonathan Peyton                                         kmp_int32 is_constrained) {
18937cc577a4SJonathan Peyton   kmp_task_t *task;
18947cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata;
18957cc577a4SJonathan Peyton   kmp_thread_data_t *thread_data;
18967cc577a4SJonathan Peyton   kmp_uint32 tail;
18977cc577a4SJonathan Peyton 
18987cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
1899*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(task_team->tt.tt_threads_data !=
1900*3041982dSJonathan Peyton                    NULL); // Caller should check this condition
19017cc577a4SJonathan Peyton 
19027cc577a4SJonathan Peyton   thread_data = &task_team->tt.tt_threads_data[__kmp_tid_from_gtid(gtid)];
19037cc577a4SJonathan Peyton 
19047cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmp_remove_my_task(enter): T#%d ntasks=%d head=%u tail=%u\n",
1905*3041982dSJonathan Peyton                 gtid, thread_data->td.td_deque_ntasks,
1906*3041982dSJonathan Peyton                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
19077cc577a4SJonathan Peyton 
19087cc577a4SJonathan Peyton   if (TCR_4(thread_data->td.td_deque_ntasks) == 0) {
1909*3041982dSJonathan Peyton     KA_TRACE(10,
1910*3041982dSJonathan Peyton              ("__kmp_remove_my_task(exit #1): T#%d No tasks to remove: "
1911*3041982dSJonathan Peyton               "ntasks=%d head=%u tail=%u\n",
1912*3041982dSJonathan Peyton               gtid, thread_data->td.td_deque_ntasks,
1913*3041982dSJonathan Peyton               thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
19147cc577a4SJonathan Peyton     return NULL;
19157cc577a4SJonathan Peyton   }
19167cc577a4SJonathan Peyton 
19177cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
19187cc577a4SJonathan Peyton 
19197cc577a4SJonathan Peyton   if (TCR_4(thread_data->td.td_deque_ntasks) == 0) {
19207cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
1921*3041982dSJonathan Peyton     KA_TRACE(10,
1922*3041982dSJonathan Peyton              ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: "
1923*3041982dSJonathan Peyton               "ntasks=%d head=%u tail=%u\n",
1924*3041982dSJonathan Peyton               gtid, thread_data->td.td_deque_ntasks,
1925*3041982dSJonathan Peyton               thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
19267cc577a4SJonathan Peyton     return NULL;
19277cc577a4SJonathan Peyton   }
19287cc577a4SJonathan Peyton 
1929*3041982dSJonathan Peyton   tail = (thread_data->td.td_deque_tail - 1) &
1930*3041982dSJonathan Peyton          TASK_DEQUE_MASK(thread_data->td); // Wrap index.
19317cc577a4SJonathan Peyton   taskdata = thread_data->td.td_deque[tail];
19327cc577a4SJonathan Peyton 
19337cc577a4SJonathan Peyton   if (is_constrained && (taskdata->td_flags.tiedness == TASK_TIED)) {
19347cc577a4SJonathan Peyton     // we need to check if the candidate obeys task scheduling constraint:
19357cc577a4SJonathan Peyton     // only child of current task can be scheduled
19367cc577a4SJonathan Peyton     kmp_taskdata_t *current = thread->th.th_current_task;
19377cc577a4SJonathan Peyton     kmp_int32 level = current->td_level;
19387cc577a4SJonathan Peyton     kmp_taskdata_t *parent = taskdata->td_parent;
19397cc577a4SJonathan Peyton     while (parent != current && parent->td_level > level) {
1940*3041982dSJonathan Peyton       parent = parent->td_parent; // check generation up to the level of the
1941*3041982dSJonathan Peyton       // current task
19427cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(parent != NULL);
19437cc577a4SJonathan Peyton     }
19447cc577a4SJonathan Peyton     if (parent != current) {
1945*3041982dSJonathan Peyton       // If the tail task is not a child, then no other child can appear in the
1946*3041982dSJonathan Peyton       // deque.
19477cc577a4SJonathan Peyton       __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
1948*3041982dSJonathan Peyton       KA_TRACE(10,
1949*3041982dSJonathan Peyton                ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: "
1950*3041982dSJonathan Peyton                 "ntasks=%d head=%u tail=%u\n",
1951*3041982dSJonathan Peyton                 gtid, thread_data->td.td_deque_ntasks,
1952*3041982dSJonathan Peyton                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
19537cc577a4SJonathan Peyton       return NULL;
19547cc577a4SJonathan Peyton     }
19557cc577a4SJonathan Peyton   }
19567cc577a4SJonathan Peyton 
19577cc577a4SJonathan Peyton   thread_data->td.td_deque_tail = tail;
19587cc577a4SJonathan Peyton   TCW_4(thread_data->td.td_deque_ntasks, thread_data->td.td_deque_ntasks - 1);
19597cc577a4SJonathan Peyton 
19607cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
19617cc577a4SJonathan Peyton 
1962*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmp_remove_my_task(exit #2): T#%d task %p removed: "
1963*3041982dSJonathan Peyton                 "ntasks=%d head=%u tail=%u\n",
1964*3041982dSJonathan Peyton                 gtid, taskdata, thread_data->td.td_deque_ntasks,
1965*3041982dSJonathan Peyton                 thread_data->td.td_deque_head, thread_data->td.td_deque_tail));
19667cc577a4SJonathan Peyton 
19677cc577a4SJonathan Peyton   task = KMP_TASKDATA_TO_TASK(taskdata);
19687cc577a4SJonathan Peyton   return task;
19697cc577a4SJonathan Peyton }
19707cc577a4SJonathan Peyton 
19717cc577a4SJonathan Peyton // __kmp_steal_task: remove a task from another thread's deque
19727cc577a4SJonathan Peyton // Assume that calling thread has already checked existence of
19737cc577a4SJonathan Peyton // task_team thread_data before calling this routine.
19747cc577a4SJonathan Peyton static kmp_task_t *
19757cc577a4SJonathan Peyton __kmp_steal_task(kmp_info_t *victim, kmp_int32 gtid, kmp_task_team_t *task_team,
19767cc577a4SJonathan Peyton                  volatile kmp_uint32 *unfinished_threads, int *thread_finished,
19777cc577a4SJonathan Peyton                  kmp_int32 is_constrained)
19787cc577a4SJonathan Peyton {
19797cc577a4SJonathan Peyton   kmp_task_t *task;
19807cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata;
19817cc577a4SJonathan Peyton   kmp_thread_data_t *victim_td, *threads_data;
19827cc577a4SJonathan Peyton   kmp_int32 victim_tid;
19837cc577a4SJonathan Peyton 
19847cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
19857cc577a4SJonathan Peyton 
19867cc577a4SJonathan Peyton   threads_data = task_team->tt.tt_threads_data;
19877cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(threads_data != NULL); // Caller should check this condition
19887cc577a4SJonathan Peyton 
19897cc577a4SJonathan Peyton   victim_tid = victim->th.th_info.ds.ds_tid;
19907cc577a4SJonathan Peyton   victim_td = &threads_data[victim_tid];
19917cc577a4SJonathan Peyton 
1992*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmp_steal_task(enter): T#%d try to steal from T#%d: "
1993*3041982dSJonathan Peyton                 "task_team=%p ntasks=%d "
19947cc577a4SJonathan Peyton                 "head=%u tail=%u\n",
1995*3041982dSJonathan Peyton                 gtid, __kmp_gtid_from_thread(victim), task_team,
1996*3041982dSJonathan Peyton                 victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
1997*3041982dSJonathan Peyton                 victim_td->td.td_deque_tail));
19987cc577a4SJonathan Peyton 
1999*3041982dSJonathan Peyton   if ((TCR_4(victim_td->td.td_deque_ntasks) ==
2000*3041982dSJonathan Peyton        0) || // Caller should not check this condition
2001*3041982dSJonathan Peyton       (TCR_PTR(victim->th.th_task_team) !=
2002*3041982dSJonathan Peyton        task_team)) // GEH: why would this happen?
20037cc577a4SJonathan Peyton   {
2004*3041982dSJonathan Peyton     KA_TRACE(10, ("__kmp_steal_task(exit #1): T#%d could not steal from T#%d: "
2005*3041982dSJonathan Peyton                   "task_team=%p "
20067cc577a4SJonathan Peyton                   "ntasks=%d head=%u tail=%u\n",
2007*3041982dSJonathan Peyton                   gtid, __kmp_gtid_from_thread(victim), task_team,
2008*3041982dSJonathan Peyton                   victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
2009*3041982dSJonathan Peyton                   victim_td->td.td_deque_tail));
20107cc577a4SJonathan Peyton     return NULL;
20117cc577a4SJonathan Peyton   }
20127cc577a4SJonathan Peyton 
20137cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&victim_td->td.td_deque_lock);
20147cc577a4SJonathan Peyton 
20157cc577a4SJonathan Peyton   // Check again after we acquire the lock
20167cc577a4SJonathan Peyton   if ((TCR_4(victim_td->td.td_deque_ntasks) == 0) ||
2017*3041982dSJonathan Peyton       (TCR_PTR(victim->th.th_task_team) !=
2018*3041982dSJonathan Peyton        task_team)) // GEH: why would this happen?
20197cc577a4SJonathan Peyton   {
20207cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2021*3041982dSJonathan Peyton     KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: "
2022*3041982dSJonathan Peyton                   "task_team=%p "
20237cc577a4SJonathan Peyton                   "ntasks=%d head=%u tail=%u\n",
2024*3041982dSJonathan Peyton                   gtid, __kmp_gtid_from_thread(victim), task_team,
2025*3041982dSJonathan Peyton                   victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
2026*3041982dSJonathan Peyton                   victim_td->td.td_deque_tail));
20277cc577a4SJonathan Peyton     return NULL;
20287cc577a4SJonathan Peyton   }
20297cc577a4SJonathan Peyton 
20307cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(victim_td->td.td_deque != NULL);
20317cc577a4SJonathan Peyton 
20327cc577a4SJonathan Peyton   taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head];
20337cc577a4SJonathan Peyton   if (is_constrained) {
20347cc577a4SJonathan Peyton     // we need to check if the candidate obeys task scheduling constraint:
20357cc577a4SJonathan Peyton     // only descendant of current task can be scheduled
20367cc577a4SJonathan Peyton     kmp_taskdata_t *current = __kmp_threads[gtid]->th.th_current_task;
20377cc577a4SJonathan Peyton     kmp_int32 level = current->td_level;
20387cc577a4SJonathan Peyton     kmp_taskdata_t *parent = taskdata->td_parent;
20397cc577a4SJonathan Peyton     while (parent != current && parent->td_level > level) {
2040*3041982dSJonathan Peyton       parent = parent->td_parent; // check generation up to the level of the
2041*3041982dSJonathan Peyton       // current task
20427cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(parent != NULL);
20437cc577a4SJonathan Peyton     }
20447cc577a4SJonathan Peyton     if (parent != current) {
20457cc577a4SJonathan Peyton       // If the head task is not a descendant of the current task then do not
20467cc577a4SJonathan Peyton       // steal it. No other task in victim's deque can be a descendant of the
20477cc577a4SJonathan Peyton       // current task.
20487cc577a4SJonathan Peyton       __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
2049*3041982dSJonathan Peyton       KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from "
2050*3041982dSJonathan Peyton                     "T#%d: task_team=%p "
20517cc577a4SJonathan Peyton                     "ntasks=%d head=%u tail=%u\n",
2052*3041982dSJonathan Peyton                     gtid,
2053*3041982dSJonathan Peyton                     __kmp_gtid_from_thread(threads_data[victim_tid].td.td_thr),
20547cc577a4SJonathan Peyton                     task_team, victim_td->td.td_deque_ntasks,
20557cc577a4SJonathan Peyton                     victim_td->td.td_deque_head, victim_td->td.td_deque_tail));
20567cc577a4SJonathan Peyton       return NULL;
20577cc577a4SJonathan Peyton     }
20587cc577a4SJonathan Peyton   }
20597cc577a4SJonathan Peyton   // Bump head pointer and Wrap.
2060*3041982dSJonathan Peyton   victim_td->td.td_deque_head =
2061*3041982dSJonathan Peyton       (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td);
20627cc577a4SJonathan Peyton   if (*thread_finished) {
2063*3041982dSJonathan Peyton     // We need to un-mark this victim as a finished victim.  This must be done
2064*3041982dSJonathan Peyton     // before releasing the lock, or else other threads (starting with the
2065*3041982dSJonathan Peyton     // master victim) might be prematurely released from the barrier!!!
20667cc577a4SJonathan Peyton     kmp_uint32 count;
20677cc577a4SJonathan Peyton 
20687cc577a4SJonathan Peyton     count = KMP_TEST_THEN_INC32((kmp_int32 *)unfinished_threads);
20697cc577a4SJonathan Peyton 
2070*3041982dSJonathan Peyton     KA_TRACE(
2071*3041982dSJonathan Peyton         20,
2072*3041982dSJonathan Peyton         ("__kmp_steal_task: T#%d inc unfinished_threads to %d: task_team=%p\n",
20737cc577a4SJonathan Peyton          gtid, count + 1, task_team));
20747cc577a4SJonathan Peyton 
20757cc577a4SJonathan Peyton     *thread_finished = FALSE;
20767cc577a4SJonathan Peyton   }
2077*3041982dSJonathan Peyton   TCW_4(victim_td->td.td_deque_ntasks,
2078*3041982dSJonathan Peyton         TCR_4(victim_td->td.td_deque_ntasks) - 1);
2079*3041982dSJonathan Peyton 
20807cc577a4SJonathan Peyton 
20817cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&victim_td->td.td_deque_lock);
20827cc577a4SJonathan Peyton 
20837cc577a4SJonathan Peyton   KMP_COUNT_BLOCK(TASK_stolen);
2084*3041982dSJonathan Peyton   KA_TRACE(
2085*3041982dSJonathan Peyton       10,
2086*3041982dSJonathan Peyton       ("__kmp_steal_task(exit #3): T#%d stole task %p from T#%d: task_team=%p "
20877cc577a4SJonathan Peyton        "ntasks=%d head=%u tail=%u\n",
20887cc577a4SJonathan Peyton        gtid, taskdata, __kmp_gtid_from_thread(victim), task_team,
20897cc577a4SJonathan Peyton        victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
20907cc577a4SJonathan Peyton        victim_td->td.td_deque_tail));
20917cc577a4SJonathan Peyton 
20927cc577a4SJonathan Peyton   task = KMP_TASKDATA_TO_TASK(taskdata);
20937cc577a4SJonathan Peyton   return task;
20947cc577a4SJonathan Peyton }
20957cc577a4SJonathan Peyton 
20967cc577a4SJonathan Peyton 
2097*3041982dSJonathan Peyton // __kmp_execute_tasks_template: Choose and execute tasks until either the
2098*3041982dSJonathan Peyton // condition is statisfied (return true) or there are none left (return false).
2099*3041982dSJonathan Peyton //
21007cc577a4SJonathan Peyton // final_spin is TRUE if this is the spin at the release barrier.
21017cc577a4SJonathan Peyton // thread_finished indicates whether the thread is finished executing all
21027cc577a4SJonathan Peyton // the tasks it has on its deque, and is at the release barrier.
21037cc577a4SJonathan Peyton // spinner is the location on which to spin.
21047cc577a4SJonathan Peyton // spinner == NULL means only execute a single task and return.
21057cc577a4SJonathan Peyton // checker is the value to check to terminate the spin.
21067cc577a4SJonathan Peyton template <class C>
2107*3041982dSJonathan Peyton static inline int __kmp_execute_tasks_template(
2108*3041982dSJonathan Peyton     kmp_info_t *thread, kmp_int32 gtid, C *flag, int final_spin,
2109*3041982dSJonathan Peyton     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2110*3041982dSJonathan Peyton     kmp_int32 is_constrained) {
21117cc577a4SJonathan Peyton   kmp_task_team_t *task_team = thread->th.th_task_team;
21127cc577a4SJonathan Peyton   kmp_thread_data_t *threads_data;
21137cc577a4SJonathan Peyton   kmp_task_t *task;
21147cc577a4SJonathan Peyton   kmp_info_t *other_thread;
21157cc577a4SJonathan Peyton   kmp_taskdata_t *current_task = thread->th.th_current_task;
21167cc577a4SJonathan Peyton   volatile kmp_uint32 *unfinished_threads;
2117*3041982dSJonathan Peyton   kmp_int32 nthreads, victim = -2, use_own_tasks = 1, new_victim = 0,
2118*3041982dSJonathan Peyton                       tid = thread->th.th_info.ds.ds_tid;
21197cc577a4SJonathan Peyton 
21207cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
21217cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(thread == __kmp_threads[gtid]);
21227cc577a4SJonathan Peyton 
2123*3041982dSJonathan Peyton   if (task_team == NULL)
2124*3041982dSJonathan Peyton     return FALSE;
21257cc577a4SJonathan Peyton 
2126*3041982dSJonathan Peyton   KA_TRACE(15, ("__kmp_execute_tasks_template(enter): T#%d final_spin=%d "
2127*3041982dSJonathan Peyton                 "*thread_finished=%d\n",
21287cc577a4SJonathan Peyton                 gtid, final_spin, *thread_finished));
21297cc577a4SJonathan Peyton 
2130581490e7SAndrey Churbanov   thread->th.th_reap_state = KMP_NOT_SAFE_TO_REAP;
21317cc577a4SJonathan Peyton   threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
21327cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(threads_data != NULL);
21337cc577a4SJonathan Peyton 
21347cc577a4SJonathan Peyton   nthreads = task_team->tt.tt_nproc;
21357cc577a4SJonathan Peyton   unfinished_threads = &(task_team->tt.tt_unfinished_threads);
21367cc577a4SJonathan Peyton #if OMP_45_ENABLED
21377cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(nthreads > 1 || task_team->tt.tt_found_proxy_tasks);
21387cc577a4SJonathan Peyton #else
21397cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(nthreads > 1);
21407cc577a4SJonathan Peyton #endif
21417cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT((int)(TCR_4(*unfinished_threads)) >= 0);
21427cc577a4SJonathan Peyton 
2143*3041982dSJonathan Peyton   while (1) { // Outer loop keeps trying to find tasks in case of single thread
2144*3041982dSJonathan Peyton     // getting tasks from target constructs
21457cc577a4SJonathan Peyton     while (1) { // Inner loop to find a task and execute it
21467cc577a4SJonathan Peyton       task = NULL;
21477cc577a4SJonathan Peyton       if (use_own_tasks) { // check on own queue first
21487cc577a4SJonathan Peyton         task = __kmp_remove_my_task(thread, gtid, task_team, is_constrained);
21497cc577a4SJonathan Peyton       }
21507cc577a4SJonathan Peyton       if ((task == NULL) && (nthreads > 1)) { // Steal a task
21517cc577a4SJonathan Peyton         int asleep = 1;
21527cc577a4SJonathan Peyton         use_own_tasks = 0;
21537cc577a4SJonathan Peyton         // Try to steal from the last place I stole from successfully.
21547cc577a4SJonathan Peyton         if (victim == -2) { // haven't stolen anything yet
21557cc577a4SJonathan Peyton           victim = threads_data[tid].td.td_deque_last_stolen;
2156*3041982dSJonathan Peyton           if (victim !=
2157*3041982dSJonathan Peyton               -1) // if we have a last stolen from victim, get the thread
21587cc577a4SJonathan Peyton             other_thread = threads_data[victim].td.td_thr;
21597cc577a4SJonathan Peyton         }
21607cc577a4SJonathan Peyton         if (victim != -1) { // found last victim
21617cc577a4SJonathan Peyton           asleep = 0;
2162*3041982dSJonathan Peyton         } else if (!new_victim) { // no recent steals and we haven't already
2163*3041982dSJonathan Peyton           // used a new victim; select a random thread
21647cc577a4SJonathan Peyton           do { // Find a different thread to steal work from.
2165*3041982dSJonathan Peyton             // Pick a random thread. Initial plan was to cycle through all the
2166*3041982dSJonathan Peyton             // threads, and only return if we tried to steal from every thread,
2167*3041982dSJonathan Peyton             // and failed.  Arch says that's not such a great idea.
21687cc577a4SJonathan Peyton             victim = __kmp_get_random(thread) % (nthreads - 1);
21697cc577a4SJonathan Peyton             if (victim >= tid) {
21707cc577a4SJonathan Peyton               ++victim; // Adjusts random distribution to exclude self
21717cc577a4SJonathan Peyton             }
21727cc577a4SJonathan Peyton             // Found a potential victim
21737cc577a4SJonathan Peyton             other_thread = threads_data[victim].td.td_thr;
2174*3041982dSJonathan Peyton             // There is a slight chance that __kmp_enable_tasking() did not wake
2175*3041982dSJonathan Peyton             // up all threads waiting at the barrier.  If victim is sleeping,
2176*3041982dSJonathan Peyton             // then wake it up. Since we were going to pay the cache miss
2177*3041982dSJonathan Peyton             // penalty for referencing another thread's kmp_info_t struct
2178*3041982dSJonathan Peyton             // anyway,
2179*3041982dSJonathan Peyton             // the check shouldn't cost too much performance at this point. In
2180*3041982dSJonathan Peyton             // extra barrier mode, tasks do not sleep at the separate tasking
2181*3041982dSJonathan Peyton             // barrier, so this isn't a problem.
21827cc577a4SJonathan Peyton             asleep = 0;
21837cc577a4SJonathan Peyton             if ((__kmp_tasking_mode == tskm_task_teams) &&
21847cc577a4SJonathan Peyton                 (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) &&
21857cc577a4SJonathan Peyton                 (TCR_PTR(other_thread->th.th_sleep_loc) != NULL)) {
21867cc577a4SJonathan Peyton               asleep = 1;
2187*3041982dSJonathan Peyton               __kmp_null_resume_wrapper(__kmp_gtid_from_thread(other_thread),
2188*3041982dSJonathan Peyton                                         other_thread->th.th_sleep_loc);
2189*3041982dSJonathan Peyton               // A sleeping thread should not have any tasks on it's queue.
2190*3041982dSJonathan Peyton               // There is a slight possibility that it resumes, steals a task
2191*3041982dSJonathan Peyton               // from another thread, which spawns more tasks, all in the time
2192*3041982dSJonathan Peyton               // that it takes this thread to check => don't write an assertion
2193*3041982dSJonathan Peyton               // that the victim's queue is empty.  Try stealing from a
2194*3041982dSJonathan Peyton               // different thread.
21957cc577a4SJonathan Peyton             }
21967cc577a4SJonathan Peyton           } while (asleep);
21977cc577a4SJonathan Peyton         }
21987cc577a4SJonathan Peyton 
21997cc577a4SJonathan Peyton         if (!asleep) {
22007cc577a4SJonathan Peyton           // We have a victim to try to steal from
2201*3041982dSJonathan Peyton           task = __kmp_steal_task(other_thread, gtid, task_team,
2202*3041982dSJonathan Peyton                                   unfinished_threads, thread_finished,
2203*3041982dSJonathan Peyton                                   is_constrained);
22047cc577a4SJonathan Peyton         }
22057cc577a4SJonathan Peyton         if (task != NULL) { // set last stolen to victim
22067cc577a4SJonathan Peyton           if (threads_data[tid].td.td_deque_last_stolen != victim) {
22077cc577a4SJonathan Peyton             threads_data[tid].td.td_deque_last_stolen = victim;
2208*3041982dSJonathan Peyton             // The pre-refactored code did not try more than 1 successful new
2209*3041982dSJonathan Peyton             // vicitm, unless the last one generated more local tasks;
2210*3041982dSJonathan Peyton             // new_victim keeps track of this
22117cc577a4SJonathan Peyton             new_victim = 1;
22127cc577a4SJonathan Peyton           }
2213*3041982dSJonathan Peyton         } else { // No tasks found; unset last_stolen
22147cc577a4SJonathan Peyton           KMP_CHECK_UPDATE(threads_data[tid].td.td_deque_last_stolen, -1);
22157cc577a4SJonathan Peyton           victim = -2; // no successful victim found
22167cc577a4SJonathan Peyton         }
22177cc577a4SJonathan Peyton       }
22187cc577a4SJonathan Peyton 
22197cc577a4SJonathan Peyton       if (task == NULL) // break out of tasking loop
22207cc577a4SJonathan Peyton         break;
22217cc577a4SJonathan Peyton 
22227cc577a4SJonathan Peyton // Found a task; execute it
22237cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY
22247cc577a4SJonathan Peyton       if (__itt_sync_create_ptr || KMP_ITT_DEBUG) {
2225*3041982dSJonathan Peyton         if (itt_sync_obj == NULL) { // we are at fork barrier where we could not
2226*3041982dSJonathan Peyton           // get the object reliably
22277cc577a4SJonathan Peyton           itt_sync_obj = __kmp_itt_barrier_object(gtid, bs_forkjoin_barrier);
22287cc577a4SJonathan Peyton         }
22297cc577a4SJonathan Peyton         __kmp_itt_task_starting(itt_sync_obj);
22307cc577a4SJonathan Peyton       }
22317cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
22327cc577a4SJonathan Peyton       __kmp_invoke_task(gtid, task, current_task);
22337cc577a4SJonathan Peyton #if USE_ITT_BUILD
2234*3041982dSJonathan Peyton       if (itt_sync_obj != NULL)
2235*3041982dSJonathan Peyton         __kmp_itt_task_finished(itt_sync_obj);
22367cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
2237*3041982dSJonathan Peyton       // If this thread is only partway through the barrier and the condition is
2238*3041982dSJonathan Peyton       // met, then return now, so that the barrier gather/release pattern can
2239*3041982dSJonathan Peyton       // proceed. If this thread is in the last spin loop in the barrier,
2240*3041982dSJonathan Peyton       // waiting to be released, we know that the termination condition will not
2241*3041982dSJonathan Peyton       // be satisified, so don't waste any cycles checking it.
22427cc577a4SJonathan Peyton       if (flag == NULL || (!final_spin && flag->done_check())) {
2243*3041982dSJonathan Peyton         KA_TRACE(
2244*3041982dSJonathan Peyton             15,
2245*3041982dSJonathan Peyton             ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
2246*3041982dSJonathan Peyton              gtid));
22477cc577a4SJonathan Peyton         return TRUE;
22487cc577a4SJonathan Peyton       }
22497cc577a4SJonathan Peyton       if (thread->th.th_task_team == NULL) {
22507cc577a4SJonathan Peyton         break;
22517cc577a4SJonathan Peyton       }
2252*3041982dSJonathan Peyton       // Yield before executing next task
2253*3041982dSJonathan Peyton       KMP_YIELD(__kmp_library == library_throughput);
2254*3041982dSJonathan Peyton       // If execution of a stolen task results in more tasks being placed on our
2255*3041982dSJonathan Peyton       // run queue, reset use_own_tasks
22567cc577a4SJonathan Peyton       if (!use_own_tasks && TCR_4(threads_data[tid].td.td_deque_ntasks) != 0) {
2257*3041982dSJonathan Peyton         KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d stolen task spawned "
2258*3041982dSJonathan Peyton                       "other tasks, restart\n",
2259*3041982dSJonathan Peyton                       gtid));
22607cc577a4SJonathan Peyton         use_own_tasks = 1;
22617cc577a4SJonathan Peyton         new_victim = 0;
22627cc577a4SJonathan Peyton       }
22637cc577a4SJonathan Peyton     }
22647cc577a4SJonathan Peyton 
2265*3041982dSJonathan Peyton // The task source has been exhausted. If in final spin loop of barrier, check
2266*3041982dSJonathan Peyton // if termination condition is satisfied.
22677cc577a4SJonathan Peyton #if OMP_45_ENABLED
2268*3041982dSJonathan Peyton     // The work queue may be empty but there might be proxy tasks still
2269*3041982dSJonathan Peyton     // executing
22707cc577a4SJonathan Peyton     if (final_spin && TCR_4(current_task->td_incomplete_child_tasks) == 0)
22717cc577a4SJonathan Peyton #else
22727cc577a4SJonathan Peyton     if (final_spin)
22737cc577a4SJonathan Peyton #endif
22747cc577a4SJonathan Peyton     {
2275*3041982dSJonathan Peyton       // First, decrement the #unfinished threads, if that has not already been
2276*3041982dSJonathan Peyton       // done.  This decrement might be to the spin location, and result in the
2277*3041982dSJonathan Peyton       // termination condition being satisfied.
22787cc577a4SJonathan Peyton       if (!*thread_finished) {
22797cc577a4SJonathan Peyton         kmp_uint32 count;
22807cc577a4SJonathan Peyton 
22817cc577a4SJonathan Peyton         count = KMP_TEST_THEN_DEC32((kmp_int32 *)unfinished_threads) - 1;
2282*3041982dSJonathan Peyton         KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d dec "
2283*3041982dSJonathan Peyton                       "unfinished_threads to %d task_team=%p\n",
22847cc577a4SJonathan Peyton                       gtid, count, task_team));
22857cc577a4SJonathan Peyton         *thread_finished = TRUE;
22867cc577a4SJonathan Peyton       }
22877cc577a4SJonathan Peyton 
22887cc577a4SJonathan Peyton       // It is now unsafe to reference thread->th.th_team !!!
2289*3041982dSJonathan Peyton       // Decrementing task_team->tt.tt_unfinished_threads can allow the master
2290*3041982dSJonathan Peyton       // thread to pass through the barrier, where it might reset each thread's
2291*3041982dSJonathan Peyton       // th.th_team field for the next parallel region. If we can steal more
2292*3041982dSJonathan Peyton       // work, we know that this has not happened yet.
22937cc577a4SJonathan Peyton       if (flag != NULL && flag->done_check()) {
2294*3041982dSJonathan Peyton         KA_TRACE(
2295*3041982dSJonathan Peyton             15,
2296*3041982dSJonathan Peyton             ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n",
2297*3041982dSJonathan Peyton              gtid));
22987cc577a4SJonathan Peyton         return TRUE;
22997cc577a4SJonathan Peyton       }
23007cc577a4SJonathan Peyton     }
23017cc577a4SJonathan Peyton 
2302*3041982dSJonathan Peyton     // If this thread's task team is NULL, master has recognized that there are
2303*3041982dSJonathan Peyton     // no more tasks; bail out
23047cc577a4SJonathan Peyton     if (thread->th.th_task_team == NULL) {
2305*3041982dSJonathan Peyton       KA_TRACE(15,
2306*3041982dSJonathan Peyton                ("__kmp_execute_tasks_template: T#%d no more tasks\n", gtid));
23077cc577a4SJonathan Peyton       return FALSE;
23087cc577a4SJonathan Peyton     }
23097cc577a4SJonathan Peyton 
23107cc577a4SJonathan Peyton #if OMP_45_ENABLED
2311*3041982dSJonathan Peyton     // We could be getting tasks from target constructs; if this is the only
2312*3041982dSJonathan Peyton     // thread, keep trying to execute tasks from own queue
23137cc577a4SJonathan Peyton     if (nthreads == 1)
23147cc577a4SJonathan Peyton       use_own_tasks = 1;
23157cc577a4SJonathan Peyton     else
23167cc577a4SJonathan Peyton #endif
23177cc577a4SJonathan Peyton     {
2318*3041982dSJonathan Peyton       KA_TRACE(15,
2319*3041982dSJonathan Peyton                ("__kmp_execute_tasks_template: T#%d can't find work\n", gtid));
23207cc577a4SJonathan Peyton       return FALSE;
23217cc577a4SJonathan Peyton     }
23227cc577a4SJonathan Peyton   }
23237cc577a4SJonathan Peyton }
23247cc577a4SJonathan Peyton 
2325*3041982dSJonathan Peyton int __kmp_execute_tasks_32(
2326*3041982dSJonathan Peyton     kmp_info_t *thread, kmp_int32 gtid, kmp_flag_32 *flag, int final_spin,
2327*3041982dSJonathan Peyton     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2328*3041982dSJonathan Peyton     kmp_int32 is_constrained) {
2329*3041982dSJonathan Peyton   return __kmp_execute_tasks_template(
2330*3041982dSJonathan Peyton       thread, gtid, flag, final_spin,
2331*3041982dSJonathan Peyton       thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
23327cc577a4SJonathan Peyton }
23337cc577a4SJonathan Peyton 
2334*3041982dSJonathan Peyton int __kmp_execute_tasks_64(
2335*3041982dSJonathan Peyton     kmp_info_t *thread, kmp_int32 gtid, kmp_flag_64 *flag, int final_spin,
2336*3041982dSJonathan Peyton     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2337*3041982dSJonathan Peyton     kmp_int32 is_constrained) {
2338*3041982dSJonathan Peyton   return __kmp_execute_tasks_template(
2339*3041982dSJonathan Peyton       thread, gtid, flag, final_spin,
2340*3041982dSJonathan Peyton       thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
23417cc577a4SJonathan Peyton }
23427cc577a4SJonathan Peyton 
2343*3041982dSJonathan Peyton int __kmp_execute_tasks_oncore(
2344*3041982dSJonathan Peyton     kmp_info_t *thread, kmp_int32 gtid, kmp_flag_oncore *flag, int final_spin,
2345*3041982dSJonathan Peyton     int *thread_finished USE_ITT_BUILD_ARG(void *itt_sync_obj),
2346*3041982dSJonathan Peyton     kmp_int32 is_constrained) {
2347*3041982dSJonathan Peyton   return __kmp_execute_tasks_template(
2348*3041982dSJonathan Peyton       thread, gtid, flag, final_spin,
2349*3041982dSJonathan Peyton       thread_finished USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
23507cc577a4SJonathan Peyton }
23517cc577a4SJonathan Peyton 
23527cc577a4SJonathan Peyton // __kmp_enable_tasking: Allocate task team and resume threads sleeping at the
23537cc577a4SJonathan Peyton // next barrier so they can assist in executing enqueued tasks.
23547cc577a4SJonathan Peyton // First thread in allocates the task team atomically.
2355*3041982dSJonathan Peyton static void __kmp_enable_tasking(kmp_task_team_t *task_team,
2356*3041982dSJonathan Peyton                                  kmp_info_t *this_thr) {
23577cc577a4SJonathan Peyton   kmp_thread_data_t *threads_data;
23587cc577a4SJonathan Peyton   int nthreads, i, is_init_thread;
23597cc577a4SJonathan Peyton 
23607cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmp_enable_tasking(enter): T#%d\n",
23617cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr)));
23627cc577a4SJonathan Peyton 
23637cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_team != NULL);
23647cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(this_thr->th.th_team != NULL);
23657cc577a4SJonathan Peyton 
23667cc577a4SJonathan Peyton   nthreads = task_team->tt.tt_nproc;
23677cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(nthreads > 0);
23687cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(nthreads == this_thr->th.th_team->t.t_nproc);
23697cc577a4SJonathan Peyton 
23707cc577a4SJonathan Peyton   // Allocate or increase the size of threads_data if necessary
23717cc577a4SJonathan Peyton   is_init_thread = __kmp_realloc_task_threads_data(this_thr, task_team);
23727cc577a4SJonathan Peyton 
23737cc577a4SJonathan Peyton   if (!is_init_thread) {
23747cc577a4SJonathan Peyton     // Some other thread already set up the array.
2375*3041982dSJonathan Peyton     KA_TRACE(
2376*3041982dSJonathan Peyton         20,
2377*3041982dSJonathan Peyton         ("__kmp_enable_tasking(exit): T#%d: threads array already set up.\n",
23787cc577a4SJonathan Peyton          __kmp_gtid_from_thread(this_thr)));
23797cc577a4SJonathan Peyton     return;
23807cc577a4SJonathan Peyton   }
23817cc577a4SJonathan Peyton   threads_data = (kmp_thread_data_t *)TCR_PTR(task_team->tt.tt_threads_data);
23827cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(threads_data != NULL);
23837cc577a4SJonathan Peyton 
23847cc577a4SJonathan Peyton   if ((__kmp_tasking_mode == tskm_task_teams) &&
2385*3041982dSJonathan Peyton       (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME)) {
23867cc577a4SJonathan Peyton     // Release any threads sleeping at the barrier, so that they can steal
23877cc577a4SJonathan Peyton     // tasks and execute them.  In extra barrier mode, tasks do not sleep
23887cc577a4SJonathan Peyton     // at the separate tasking barrier, so this isn't a problem.
23897cc577a4SJonathan Peyton     for (i = 0; i < nthreads; i++) {
23907cc577a4SJonathan Peyton       volatile void *sleep_loc;
23917cc577a4SJonathan Peyton       kmp_info_t *thread = threads_data[i].td.td_thr;
23927cc577a4SJonathan Peyton 
23937cc577a4SJonathan Peyton       if (i == this_thr->th.th_info.ds.ds_tid) {
23947cc577a4SJonathan Peyton         continue;
23957cc577a4SJonathan Peyton       }
23967cc577a4SJonathan Peyton       // Since we haven't locked the thread's suspend mutex lock at this
23977cc577a4SJonathan Peyton       // point, there is a small window where a thread might be putting
23987cc577a4SJonathan Peyton       // itself to sleep, but hasn't set the th_sleep_loc field yet.
23997cc577a4SJonathan Peyton       // To work around this, __kmp_execute_tasks_template() periodically checks
2400*3041982dSJonathan Peyton       // see if other threads are sleeping (using the same random mechanism that
2401*3041982dSJonathan Peyton       // is used for task stealing) and awakens them if they are.
2402*3041982dSJonathan Peyton       if ((sleep_loc = TCR_PTR(thread->th.th_sleep_loc)) != NULL) {
24037cc577a4SJonathan Peyton         KF_TRACE(50, ("__kmp_enable_tasking: T#%d waking up thread T#%d\n",
24047cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(this_thr),
24057cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(thread)));
24067cc577a4SJonathan Peyton         __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc);
2407*3041982dSJonathan Peyton       } else {
24087cc577a4SJonathan Peyton         KF_TRACE(50, ("__kmp_enable_tasking: T#%d don't wake up thread T#%d\n",
24097cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(this_thr),
24107cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(thread)));
24117cc577a4SJonathan Peyton       }
24127cc577a4SJonathan Peyton     }
24137cc577a4SJonathan Peyton   }
24147cc577a4SJonathan Peyton 
24157cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmp_enable_tasking(exit): T#%d\n",
24167cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(this_thr)));
24177cc577a4SJonathan Peyton }
24187cc577a4SJonathan Peyton 
24197cc577a4SJonathan Peyton /* // TODO: Check the comment consistency
24207cc577a4SJonathan Peyton  * Utility routines for "task teams".  A task team (kmp_task_t) is kind of
24217cc577a4SJonathan Peyton  * like a shadow of the kmp_team_t data struct, with a different lifetime.
24227cc577a4SJonathan Peyton  * After a child * thread checks into a barrier and calls __kmp_release() from
24237cc577a4SJonathan Peyton  * the particular variant of __kmp_<barrier_kind>_barrier_gather(), it can no
24247cc577a4SJonathan Peyton  * longer assume that the kmp_team_t structure is intact (at any moment, the
24257cc577a4SJonathan Peyton  * master thread may exit the barrier code and free the team data structure,
24267cc577a4SJonathan Peyton  * and return the threads to the thread pool).
24277cc577a4SJonathan Peyton  *
24287cc577a4SJonathan Peyton  * This does not work with the the tasking code, as the thread is still
24297cc577a4SJonathan Peyton  * expected to participate in the execution of any tasks that may have been
24307cc577a4SJonathan Peyton  * spawned my a member of the team, and the thread still needs access to all
24317cc577a4SJonathan Peyton  * to each thread in the team, so that it can steal work from it.
24327cc577a4SJonathan Peyton  *
24337cc577a4SJonathan Peyton  * Enter the existence of the kmp_task_team_t struct.  It employs a reference
24347cc577a4SJonathan Peyton  * counting mechanims, and is allocated by the master thread before calling
24357cc577a4SJonathan Peyton  * __kmp_<barrier_kind>_release, and then is release by the last thread to
24367cc577a4SJonathan Peyton  * exit __kmp_<barrier_kind>_release at the next barrier.  I.e. the lifetimes
24377cc577a4SJonathan Peyton  * of the kmp_task_team_t structs for consecutive barriers can overlap
24387cc577a4SJonathan Peyton  * (and will, unless the master thread is the last thread to exit the barrier
24397cc577a4SJonathan Peyton  * release phase, which is not typical).
24407cc577a4SJonathan Peyton  *
24417cc577a4SJonathan Peyton  * The existence of such a struct is useful outside the context of tasking,
24427cc577a4SJonathan Peyton  * but for now, I'm trying to keep it specific to the OMP_30_ENABLED macro,
24437cc577a4SJonathan Peyton  * so that any performance differences show up when comparing the 2.5 vs. 3.0
24447cc577a4SJonathan Peyton  * libraries.
24457cc577a4SJonathan Peyton  *
24467cc577a4SJonathan Peyton  * We currently use the existence of the threads array as an indicator that
24477cc577a4SJonathan Peyton  * tasks were spawned since the last barrier.  If the structure is to be
24487cc577a4SJonathan Peyton  * useful outside the context of tasking, then this will have to change, but
24497cc577a4SJonathan Peyton  * not settting the field minimizes the performance impact of tasking on
24507cc577a4SJonathan Peyton  * barriers, when no explicit tasks were spawned (pushed, actually).
24517cc577a4SJonathan Peyton  */
24527cc577a4SJonathan Peyton 
2453*3041982dSJonathan Peyton static kmp_task_team_t *__kmp_free_task_teams =
2454*3041982dSJonathan Peyton     NULL; // Free list for task_team data structures
24557cc577a4SJonathan Peyton // Lock for task team data structures
2456*3041982dSJonathan Peyton static kmp_bootstrap_lock_t __kmp_task_team_lock =
2457*3041982dSJonathan Peyton     KMP_BOOTSTRAP_LOCK_INITIALIZER(__kmp_task_team_lock);
24587cc577a4SJonathan Peyton 
24597cc577a4SJonathan Peyton // __kmp_alloc_task_deque:
24607cc577a4SJonathan Peyton // Allocates a task deque for a particular thread, and initialize the necessary
24617cc577a4SJonathan Peyton // data structures relating to the deque.  This only happens once per thread
2462*3041982dSJonathan Peyton // per task team since task teams are recycled. No lock is needed during
2463*3041982dSJonathan Peyton // allocation since each thread allocates its own deque.
2464*3041982dSJonathan Peyton static void __kmp_alloc_task_deque(kmp_info_t *thread,
2465*3041982dSJonathan Peyton                                    kmp_thread_data_t *thread_data) {
24667cc577a4SJonathan Peyton   __kmp_init_bootstrap_lock(&thread_data->td.td_deque_lock);
24677cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(thread_data->td.td_deque == NULL);
24687cc577a4SJonathan Peyton 
24697cc577a4SJonathan Peyton   // Initialize last stolen task field to "none"
24707cc577a4SJonathan Peyton   thread_data->td.td_deque_last_stolen = -1;
24717cc577a4SJonathan Peyton 
24727cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(TCR_4(thread_data->td.td_deque_ntasks) == 0);
24737cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(thread_data->td.td_deque_head == 0);
24747cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(thread_data->td.td_deque_tail == 0);
24757cc577a4SJonathan Peyton 
2476*3041982dSJonathan Peyton   KE_TRACE(
2477*3041982dSJonathan Peyton       10,
2478*3041982dSJonathan Peyton       ("__kmp_alloc_task_deque: T#%d allocating deque[%d] for thread_data %p\n",
24797cc577a4SJonathan Peyton        __kmp_gtid_from_thread(thread), INITIAL_TASK_DEQUE_SIZE, thread_data));
24807cc577a4SJonathan Peyton   // Allocate space for task deque, and zero the deque
24817cc577a4SJonathan Peyton   // Cannot use __kmp_thread_calloc() because threads not around for
24827cc577a4SJonathan Peyton   // kmp_reap_task_team( ).
2483*3041982dSJonathan Peyton   thread_data->td.td_deque = (kmp_taskdata_t **)__kmp_allocate(
2484*3041982dSJonathan Peyton       INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *));
24857cc577a4SJonathan Peyton   thread_data->td.td_deque_size = INITIAL_TASK_DEQUE_SIZE;
24867cc577a4SJonathan Peyton }
24877cc577a4SJonathan Peyton 
24887cc577a4SJonathan Peyton // __kmp_realloc_task_deque:
2489*3041982dSJonathan Peyton // Re-allocates a task deque for a particular thread, copies the content from
2490*3041982dSJonathan Peyton // the old deque and adjusts the necessary data structures relating to the
2491*3041982dSJonathan Peyton // deque. This operation must be done with a the deque_lock being held
2492*3041982dSJonathan Peyton static void __kmp_realloc_task_deque(kmp_info_t *thread,
2493*3041982dSJonathan Peyton                                      kmp_thread_data_t *thread_data) {
24947cc577a4SJonathan Peyton   kmp_int32 size = TASK_DEQUE_SIZE(thread_data->td);
24957cc577a4SJonathan Peyton   kmp_int32 new_size = 2 * size;
24967cc577a4SJonathan Peyton 
2497*3041982dSJonathan Peyton   KE_TRACE(10, ("__kmp_realloc_task_deque: T#%d reallocating deque[from %d to "
2498*3041982dSJonathan Peyton                 "%d] for thread_data %p\n",
24997cc577a4SJonathan Peyton                 __kmp_gtid_from_thread(thread), size, new_size, thread_data));
25007cc577a4SJonathan Peyton 
2501*3041982dSJonathan Peyton   kmp_taskdata_t **new_deque =
2502*3041982dSJonathan Peyton       (kmp_taskdata_t **)__kmp_allocate(new_size * sizeof(kmp_taskdata_t *));
25037cc577a4SJonathan Peyton 
25047cc577a4SJonathan Peyton   int i, j;
2505*3041982dSJonathan Peyton   for (i = thread_data->td.td_deque_head, j = 0; j < size;
2506*3041982dSJonathan Peyton        i = (i + 1) & TASK_DEQUE_MASK(thread_data->td), j++)
25077cc577a4SJonathan Peyton     new_deque[j] = thread_data->td.td_deque[i];
25087cc577a4SJonathan Peyton 
25097cc577a4SJonathan Peyton   __kmp_free(thread_data->td.td_deque);
25107cc577a4SJonathan Peyton 
25117cc577a4SJonathan Peyton   thread_data->td.td_deque_head = 0;
25127cc577a4SJonathan Peyton   thread_data->td.td_deque_tail = size;
25137cc577a4SJonathan Peyton   thread_data->td.td_deque = new_deque;
25147cc577a4SJonathan Peyton   thread_data->td.td_deque_size = new_size;
25157cc577a4SJonathan Peyton }
25167cc577a4SJonathan Peyton 
25177cc577a4SJonathan Peyton // __kmp_free_task_deque:
2518*3041982dSJonathan Peyton // Deallocates a task deque for a particular thread. Happens at library
2519*3041982dSJonathan Peyton // deallocation so don't need to reset all thread data fields.
2520*3041982dSJonathan Peyton static void __kmp_free_task_deque(kmp_thread_data_t *thread_data) {
25217cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
25227cc577a4SJonathan Peyton 
25237cc577a4SJonathan Peyton   if (thread_data->td.td_deque != NULL) {
25247cc577a4SJonathan Peyton     TCW_4(thread_data->td.td_deque_ntasks, 0);
25257cc577a4SJonathan Peyton     __kmp_free(thread_data->td.td_deque);
25267cc577a4SJonathan Peyton     thread_data->td.td_deque = NULL;
25277cc577a4SJonathan Peyton   }
25287cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
25297cc577a4SJonathan Peyton 
25307cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
25317cc577a4SJonathan Peyton   // GEH: Figure out what to do here for td_susp_tied_tasks
25327cc577a4SJonathan Peyton   if (thread_data->td.td_susp_tied_tasks.ts_entries != TASK_STACK_EMPTY) {
25337cc577a4SJonathan Peyton     __kmp_free_task_stack(__kmp_thread_from_gtid(gtid), thread_data);
25347cc577a4SJonathan Peyton   }
25357cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK
25367cc577a4SJonathan Peyton }
25377cc577a4SJonathan Peyton 
25387cc577a4SJonathan Peyton // __kmp_realloc_task_threads_data:
2539*3041982dSJonathan Peyton // Allocates a threads_data array for a task team, either by allocating an
2540*3041982dSJonathan Peyton // initial array or enlarging an existing array.  Only the first thread to get
2541*3041982dSJonathan Peyton // the lock allocs or enlarges the array and re-initializes the array eleemnts.
25427cc577a4SJonathan Peyton // That thread returns "TRUE", the rest return "FALSE".
25437cc577a4SJonathan Peyton // Assumes that the new array size is given by task_team -> tt.tt_nproc.
25447cc577a4SJonathan Peyton // The current size is given by task_team -> tt.tt_max_threads.
2545*3041982dSJonathan Peyton static int __kmp_realloc_task_threads_data(kmp_info_t *thread,
2546*3041982dSJonathan Peyton                                            kmp_task_team_t *task_team) {
25477cc577a4SJonathan Peyton   kmp_thread_data_t **threads_data_p;
25487cc577a4SJonathan Peyton   kmp_int32 nthreads, maxthreads;
25497cc577a4SJonathan Peyton   int is_init_thread = FALSE;
25507cc577a4SJonathan Peyton 
25517cc577a4SJonathan Peyton   if (TCR_4(task_team->tt.tt_found_tasks)) {
25527cc577a4SJonathan Peyton     // Already reallocated and initialized.
25537cc577a4SJonathan Peyton     return FALSE;
25547cc577a4SJonathan Peyton   }
25557cc577a4SJonathan Peyton 
25567cc577a4SJonathan Peyton   threads_data_p = &task_team->tt.tt_threads_data;
25577cc577a4SJonathan Peyton   nthreads = task_team->tt.tt_nproc;
25587cc577a4SJonathan Peyton   maxthreads = task_team->tt.tt_max_threads;
25597cc577a4SJonathan Peyton 
2560*3041982dSJonathan Peyton   // All threads must lock when they encounter the first task of the implicit
2561*3041982dSJonathan Peyton   // task region to make sure threads_data fields are (re)initialized before
2562*3041982dSJonathan Peyton   // used.
25637cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock);
25647cc577a4SJonathan Peyton 
25657cc577a4SJonathan Peyton   if (!TCR_4(task_team->tt.tt_found_tasks)) {
25667cc577a4SJonathan Peyton     // first thread to enable tasking
25677cc577a4SJonathan Peyton     kmp_team_t *team = thread->th.th_team;
25687cc577a4SJonathan Peyton     int i;
25697cc577a4SJonathan Peyton 
25707cc577a4SJonathan Peyton     is_init_thread = TRUE;
25717cc577a4SJonathan Peyton     if (maxthreads < nthreads) {
25727cc577a4SJonathan Peyton 
25737cc577a4SJonathan Peyton       if (*threads_data_p != NULL) {
25747cc577a4SJonathan Peyton         kmp_thread_data_t *old_data = *threads_data_p;
25757cc577a4SJonathan Peyton         kmp_thread_data_t *new_data = NULL;
25767cc577a4SJonathan Peyton 
2577*3041982dSJonathan Peyton         KE_TRACE(
2578*3041982dSJonathan Peyton             10,
2579*3041982dSJonathan Peyton             ("__kmp_realloc_task_threads_data: T#%d reallocating "
25807cc577a4SJonathan Peyton              "threads data for task_team %p, new_size = %d, old_size = %d\n",
2581*3041982dSJonathan Peyton              __kmp_gtid_from_thread(thread), task_team, nthreads, maxthreads));
25827cc577a4SJonathan Peyton         // Reallocate threads_data to have more elements than current array
25837cc577a4SJonathan Peyton         // Cannot use __kmp_thread_realloc() because threads not around for
25847cc577a4SJonathan Peyton         // kmp_reap_task_team( ).  Note all new array entries are initialized
25857cc577a4SJonathan Peyton         // to zero by __kmp_allocate().
2586*3041982dSJonathan Peyton         new_data = (kmp_thread_data_t *)__kmp_allocate(
2587*3041982dSJonathan Peyton             nthreads * sizeof(kmp_thread_data_t));
25887cc577a4SJonathan Peyton         // copy old data to new data
25897cc577a4SJonathan Peyton         KMP_MEMCPY_S((void *)new_data, nthreads * sizeof(kmp_thread_data_t),
2590*3041982dSJonathan Peyton                      (void *)old_data, maxthreads * sizeof(kmp_taskdata_t *));
25917cc577a4SJonathan Peyton 
25927cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
25937cc577a4SJonathan Peyton         // GEH: Figure out if this is the right thing to do
25947cc577a4SJonathan Peyton         for (i = maxthreads; i < nthreads; i++) {
25957cc577a4SJonathan Peyton           kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
25967cc577a4SJonathan Peyton           __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data);
25977cc577a4SJonathan Peyton         }
25987cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK
25997cc577a4SJonathan Peyton         // Install the new data and free the old data
26007cc577a4SJonathan Peyton         (*threads_data_p) = new_data;
26017cc577a4SJonathan Peyton         __kmp_free(old_data);
2602*3041982dSJonathan Peyton       } else {
26037cc577a4SJonathan Peyton         KE_TRACE(10, ("__kmp_realloc_task_threads_data: T#%d allocating "
26047cc577a4SJonathan Peyton                       "threads data for task_team %p, size = %d\n",
26057cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(thread), task_team, nthreads));
26067cc577a4SJonathan Peyton         // Make the initial allocate for threads_data array, and zero entries
26077cc577a4SJonathan Peyton         // Cannot use __kmp_thread_calloc() because threads not around for
26087cc577a4SJonathan Peyton         // kmp_reap_task_team( ).
26097cc577a4SJonathan Peyton         ANNOTATE_IGNORE_WRITES_BEGIN();
2610*3041982dSJonathan Peyton         *threads_data_p = (kmp_thread_data_t *)__kmp_allocate(
2611*3041982dSJonathan Peyton             nthreads * sizeof(kmp_thread_data_t));
26127cc577a4SJonathan Peyton         ANNOTATE_IGNORE_WRITES_END();
26137cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
26147cc577a4SJonathan Peyton         // GEH: Figure out if this is the right thing to do
26157cc577a4SJonathan Peyton         for (i = 0; i < nthreads; i++) {
26167cc577a4SJonathan Peyton           kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
26177cc577a4SJonathan Peyton           __kmp_init_task_stack(__kmp_gtid_from_thread(thread), thread_data);
26187cc577a4SJonathan Peyton         }
26197cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK
26207cc577a4SJonathan Peyton       }
26217cc577a4SJonathan Peyton       task_team->tt.tt_max_threads = nthreads;
2622*3041982dSJonathan Peyton     } else {
26237cc577a4SJonathan Peyton       // If array has (more than) enough elements, go ahead and use it
26247cc577a4SJonathan Peyton       KMP_DEBUG_ASSERT(*threads_data_p != NULL);
26257cc577a4SJonathan Peyton     }
26267cc577a4SJonathan Peyton 
26277cc577a4SJonathan Peyton     // initialize threads_data pointers back to thread_info structures
26287cc577a4SJonathan Peyton     for (i = 0; i < nthreads; i++) {
26297cc577a4SJonathan Peyton       kmp_thread_data_t *thread_data = &(*threads_data_p)[i];
26307cc577a4SJonathan Peyton       thread_data->td.td_thr = team->t.t_threads[i];
26317cc577a4SJonathan Peyton 
26327cc577a4SJonathan Peyton       if (thread_data->td.td_deque_last_stolen >= nthreads) {
26337cc577a4SJonathan Peyton         // The last stolen field survives across teams / barrier, and the number
26347cc577a4SJonathan Peyton         // of threads may have changed.  It's possible (likely?) that a new
2635*3041982dSJonathan Peyton         // parallel region will exhibit the same behavior as previous region.
26367cc577a4SJonathan Peyton         thread_data->td.td_deque_last_stolen = -1;
26377cc577a4SJonathan Peyton       }
26387cc577a4SJonathan Peyton     }
26397cc577a4SJonathan Peyton 
26407cc577a4SJonathan Peyton     KMP_MB();
26417cc577a4SJonathan Peyton     TCW_SYNC_4(task_team->tt.tt_found_tasks, TRUE);
26427cc577a4SJonathan Peyton   }
26437cc577a4SJonathan Peyton 
26447cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock);
26457cc577a4SJonathan Peyton   return is_init_thread;
26467cc577a4SJonathan Peyton }
26477cc577a4SJonathan Peyton 
26487cc577a4SJonathan Peyton // __kmp_free_task_threads_data:
26497cc577a4SJonathan Peyton // Deallocates a threads_data array for a task team, including any attached
26507cc577a4SJonathan Peyton // tasking deques.  Only occurs at library shutdown.
2651*3041982dSJonathan Peyton static void __kmp_free_task_threads_data(kmp_task_team_t *task_team) {
26527cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&task_team->tt.tt_threads_lock);
26537cc577a4SJonathan Peyton   if (task_team->tt.tt_threads_data != NULL) {
26547cc577a4SJonathan Peyton     int i;
26557cc577a4SJonathan Peyton     for (i = 0; i < task_team->tt.tt_max_threads; i++) {
26567cc577a4SJonathan Peyton       __kmp_free_task_deque(&task_team->tt.tt_threads_data[i]);
26577cc577a4SJonathan Peyton     }
26587cc577a4SJonathan Peyton     __kmp_free(task_team->tt.tt_threads_data);
26597cc577a4SJonathan Peyton     task_team->tt.tt_threads_data = NULL;
26607cc577a4SJonathan Peyton   }
26617cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&task_team->tt.tt_threads_lock);
26627cc577a4SJonathan Peyton }
26637cc577a4SJonathan Peyton 
26647cc577a4SJonathan Peyton // __kmp_allocate_task_team:
26657cc577a4SJonathan Peyton // Allocates a task team associated with a specific team, taking it from
2666*3041982dSJonathan Peyton // the global task team free list if possible.  Also initializes data
2667*3041982dSJonathan Peyton // structures.
2668*3041982dSJonathan Peyton static kmp_task_team_t *__kmp_allocate_task_team(kmp_info_t *thread,
2669*3041982dSJonathan Peyton                                                  kmp_team_t *team) {
26707cc577a4SJonathan Peyton   kmp_task_team_t *task_team = NULL;
26717cc577a4SJonathan Peyton   int nthreads;
26727cc577a4SJonathan Peyton 
26737cc577a4SJonathan Peyton   KA_TRACE(20, ("__kmp_allocate_task_team: T#%d entering; team = %p\n",
26747cc577a4SJonathan Peyton                 (thread ? __kmp_gtid_from_thread(thread) : -1), team));
26757cc577a4SJonathan Peyton 
26767cc577a4SJonathan Peyton   if (TCR_PTR(__kmp_free_task_teams) != NULL) {
26777cc577a4SJonathan Peyton     // Take a task team from the task team pool
26787cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
26797cc577a4SJonathan Peyton     if (__kmp_free_task_teams != NULL) {
26807cc577a4SJonathan Peyton       task_team = __kmp_free_task_teams;
26817cc577a4SJonathan Peyton       TCW_PTR(__kmp_free_task_teams, task_team->tt.tt_next);
26827cc577a4SJonathan Peyton       task_team->tt.tt_next = NULL;
26837cc577a4SJonathan Peyton     }
26847cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
26857cc577a4SJonathan Peyton   }
26867cc577a4SJonathan Peyton 
26877cc577a4SJonathan Peyton   if (task_team == NULL) {
26887cc577a4SJonathan Peyton     KE_TRACE(10, ("__kmp_allocate_task_team: T#%d allocating "
26897cc577a4SJonathan Peyton                   "task team for team %p\n",
26907cc577a4SJonathan Peyton                   __kmp_gtid_from_thread(thread), team));
26917cc577a4SJonathan Peyton     // Allocate a new task team if one is not available.
26927cc577a4SJonathan Peyton     // Cannot use __kmp_thread_malloc() because threads not around for
26937cc577a4SJonathan Peyton     // kmp_reap_task_team( ).
26947cc577a4SJonathan Peyton     task_team = (kmp_task_team_t *)__kmp_allocate(sizeof(kmp_task_team_t));
26957cc577a4SJonathan Peyton     __kmp_init_bootstrap_lock(&task_team->tt.tt_threads_lock);
2696*3041982dSJonathan Peyton     // AC: __kmp_allocate zeroes returned memory
2697*3041982dSJonathan Peyton     // task_team -> tt.tt_threads_data = NULL;
26987cc577a4SJonathan Peyton     // task_team -> tt.tt_max_threads = 0;
26997cc577a4SJonathan Peyton     // task_team -> tt.tt_next = NULL;
27007cc577a4SJonathan Peyton   }
27017cc577a4SJonathan Peyton 
27027cc577a4SJonathan Peyton   TCW_4(task_team->tt.tt_found_tasks, FALSE);
27037cc577a4SJonathan Peyton #if OMP_45_ENABLED
27047cc577a4SJonathan Peyton   TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE);
27057cc577a4SJonathan Peyton #endif
27067cc577a4SJonathan Peyton   task_team->tt.tt_nproc = nthreads = team->t.t_nproc;
27077cc577a4SJonathan Peyton 
27087cc577a4SJonathan Peyton   TCW_4(task_team->tt.tt_unfinished_threads, nthreads);
27097cc577a4SJonathan Peyton   TCW_4(task_team->tt.tt_active, TRUE);
27107cc577a4SJonathan Peyton 
2711*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmp_allocate_task_team: T#%d exiting; task_team = %p "
2712*3041982dSJonathan Peyton                 "unfinished_threads init'd to %d\n",
2713*3041982dSJonathan Peyton                 (thread ? __kmp_gtid_from_thread(thread) : -1), task_team,
2714*3041982dSJonathan Peyton                 task_team->tt.tt_unfinished_threads));
27157cc577a4SJonathan Peyton   return task_team;
27167cc577a4SJonathan Peyton }
27177cc577a4SJonathan Peyton 
27187cc577a4SJonathan Peyton // __kmp_free_task_team:
27197cc577a4SJonathan Peyton // Frees the task team associated with a specific thread, and adds it
27207cc577a4SJonathan Peyton // to the global task team free list.
2721*3041982dSJonathan Peyton void __kmp_free_task_team(kmp_info_t *thread, kmp_task_team_t *task_team) {
27227cc577a4SJonathan Peyton   KA_TRACE(20, ("__kmp_free_task_team: T#%d task_team = %p\n",
27237cc577a4SJonathan Peyton                 thread ? __kmp_gtid_from_thread(thread) : -1, task_team));
27247cc577a4SJonathan Peyton 
27257cc577a4SJonathan Peyton   // Put task team back on free list
27267cc577a4SJonathan Peyton   __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
27277cc577a4SJonathan Peyton 
27287cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_team->tt.tt_next == NULL);
27297cc577a4SJonathan Peyton   task_team->tt.tt_next = __kmp_free_task_teams;
27307cc577a4SJonathan Peyton   TCW_PTR(__kmp_free_task_teams, task_team);
27317cc577a4SJonathan Peyton 
27327cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
27337cc577a4SJonathan Peyton }
27347cc577a4SJonathan Peyton 
27357cc577a4SJonathan Peyton // __kmp_reap_task_teams:
27367cc577a4SJonathan Peyton // Free all the task teams on the task team free list.
27377cc577a4SJonathan Peyton // Should only be done during library shutdown.
2738*3041982dSJonathan Peyton // Cannot do anything that needs a thread structure or gtid since they are
2739*3041982dSJonathan Peyton // already gone.
2740*3041982dSJonathan Peyton void __kmp_reap_task_teams(void) {
27417cc577a4SJonathan Peyton   kmp_task_team_t *task_team;
27427cc577a4SJonathan Peyton 
27437cc577a4SJonathan Peyton   if (TCR_PTR(__kmp_free_task_teams) != NULL) {
27447cc577a4SJonathan Peyton     // Free all task_teams on the free list
27457cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock(&__kmp_task_team_lock);
27467cc577a4SJonathan Peyton     while ((task_team = __kmp_free_task_teams) != NULL) {
27477cc577a4SJonathan Peyton       __kmp_free_task_teams = task_team->tt.tt_next;
27487cc577a4SJonathan Peyton       task_team->tt.tt_next = NULL;
27497cc577a4SJonathan Peyton 
27507cc577a4SJonathan Peyton       // Free threads_data if necessary
27517cc577a4SJonathan Peyton       if (task_team->tt.tt_threads_data != NULL) {
27527cc577a4SJonathan Peyton         __kmp_free_task_threads_data(task_team);
27537cc577a4SJonathan Peyton       }
27547cc577a4SJonathan Peyton       __kmp_free(task_team);
27557cc577a4SJonathan Peyton     }
27567cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock(&__kmp_task_team_lock);
27577cc577a4SJonathan Peyton   }
27587cc577a4SJonathan Peyton }
27597cc577a4SJonathan Peyton 
27607cc577a4SJonathan Peyton // __kmp_wait_to_unref_task_teams:
27617cc577a4SJonathan Peyton // Some threads could still be in the fork barrier release code, possibly
27627cc577a4SJonathan Peyton // trying to steal tasks.  Wait for each thread to unreference its task team.
2763*3041982dSJonathan Peyton void __kmp_wait_to_unref_task_teams(void) {
27647cc577a4SJonathan Peyton   kmp_info_t *thread;
27657cc577a4SJonathan Peyton   kmp_uint32 spins;
27667cc577a4SJonathan Peyton   int done;
27677cc577a4SJonathan Peyton 
27687cc577a4SJonathan Peyton   KMP_INIT_YIELD(spins);
27697cc577a4SJonathan Peyton 
27707cc577a4SJonathan Peyton   for (;;) {
27717cc577a4SJonathan Peyton     done = TRUE;
27727cc577a4SJonathan Peyton 
27737cc577a4SJonathan Peyton     // TODO: GEH - this may be is wrong because some sync would be necessary
2774*3041982dSJonathan Peyton     // in case threads are added to the pool during the traversal. Need to
2775*3041982dSJonathan Peyton     // verify that lock for thread pool is held when calling this routine.
2776*3041982dSJonathan Peyton     for (thread = (kmp_info_t *)__kmp_thread_pool; thread != NULL;
2777*3041982dSJonathan Peyton          thread = thread->th.th_next_pool) {
27787cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
27797cc577a4SJonathan Peyton       DWORD exit_val;
27807cc577a4SJonathan Peyton #endif
27817cc577a4SJonathan Peyton       if (TCR_PTR(thread->th.th_task_team) == NULL) {
27827cc577a4SJonathan Peyton         KA_TRACE(10, ("__kmp_wait_to_unref_task_team: T#%d task_team == NULL\n",
27837cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(thread)));
27847cc577a4SJonathan Peyton         continue;
27857cc577a4SJonathan Peyton       }
27867cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
27877cc577a4SJonathan Peyton       // TODO: GEH - add this check for Linux* OS / OS X* as well?
27887cc577a4SJonathan Peyton       if (!__kmp_is_thread_alive(thread, &exit_val)) {
27897cc577a4SJonathan Peyton         thread->th.th_task_team = NULL;
27907cc577a4SJonathan Peyton         continue;
27917cc577a4SJonathan Peyton       }
27927cc577a4SJonathan Peyton #endif
27937cc577a4SJonathan Peyton 
27947cc577a4SJonathan Peyton       done = FALSE; // Because th_task_team pointer is not NULL for this thread
27957cc577a4SJonathan Peyton 
2796*3041982dSJonathan Peyton       KA_TRACE(10, ("__kmp_wait_to_unref_task_team: Waiting for T#%d to "
2797*3041982dSJonathan Peyton                     "unreference task_team\n",
27987cc577a4SJonathan Peyton                     __kmp_gtid_from_thread(thread)));
27997cc577a4SJonathan Peyton 
28007cc577a4SJonathan Peyton       if (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) {
28017cc577a4SJonathan Peyton         volatile void *sleep_loc;
28027cc577a4SJonathan Peyton         // If the thread is sleeping, awaken it.
28037cc577a4SJonathan Peyton         if ((sleep_loc = TCR_PTR(thread->th.th_sleep_loc)) != NULL) {
2804*3041982dSJonathan Peyton           KA_TRACE(
2805*3041982dSJonathan Peyton               10,
2806*3041982dSJonathan Peyton               ("__kmp_wait_to_unref_task_team: T#%d waking up thread T#%d\n",
28077cc577a4SJonathan Peyton                __kmp_gtid_from_thread(thread), __kmp_gtid_from_thread(thread)));
28087cc577a4SJonathan Peyton           __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc);
28097cc577a4SJonathan Peyton         }
28107cc577a4SJonathan Peyton       }
28117cc577a4SJonathan Peyton     }
28127cc577a4SJonathan Peyton     if (done) {
28137cc577a4SJonathan Peyton       break;
28147cc577a4SJonathan Peyton     }
28157cc577a4SJonathan Peyton 
2816*3041982dSJonathan Peyton     // If we are oversubscribed, or have waited a bit (and library mode is
2817*3041982dSJonathan Peyton     // throughput), yield. Pause is in the following code.
28187cc577a4SJonathan Peyton     KMP_YIELD(TCR_4(__kmp_nth) > __kmp_avail_proc);
28197cc577a4SJonathan Peyton     KMP_YIELD_SPIN(spins); // Yields only if KMP_LIBRARY=throughput
28207cc577a4SJonathan Peyton   }
28217cc577a4SJonathan Peyton }
28227cc577a4SJonathan Peyton 
28237cc577a4SJonathan Peyton // __kmp_task_team_setup:  Create a task_team for the current team, but use
28247cc577a4SJonathan Peyton // an already created, unused one if it already exists.
2825*3041982dSJonathan Peyton void __kmp_task_team_setup(kmp_info_t *this_thr, kmp_team_t *team, int always) {
28267cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
28277cc577a4SJonathan Peyton 
2828*3041982dSJonathan Peyton   // If this task_team hasn't been created yet, allocate it. It will be used in
2829*3041982dSJonathan Peyton   // the region after the next.
2830*3041982dSJonathan Peyton   // If it exists, it is the current task team and shouldn't be touched yet as
2831*3041982dSJonathan Peyton   // it may still be in use.
2832*3041982dSJonathan Peyton   if (team->t.t_task_team[this_thr->th.th_task_state] == NULL &&
2833*3041982dSJonathan Peyton       (always || team->t.t_nproc > 1)) {
2834*3041982dSJonathan Peyton     team->t.t_task_team[this_thr->th.th_task_state] =
2835*3041982dSJonathan Peyton         __kmp_allocate_task_team(this_thr, team);
2836*3041982dSJonathan Peyton     KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created new task_team %p "
2837*3041982dSJonathan Peyton                   "for team %d at parity=%d\n",
2838*3041982dSJonathan Peyton                   __kmp_gtid_from_thread(this_thr),
2839*3041982dSJonathan Peyton                   team->t.t_task_team[this_thr->th.th_task_state],
2840*3041982dSJonathan Peyton                   ((team != NULL) ? team->t.t_id : -1),
2841*3041982dSJonathan Peyton                   this_thr->th.th_task_state));
28427cc577a4SJonathan Peyton   }
28437cc577a4SJonathan Peyton 
2844*3041982dSJonathan Peyton   // After threads exit the release, they will call sync, and then point to this
2845*3041982dSJonathan Peyton   // other task_team; make sure it is allocated and properly initialized. As
2846*3041982dSJonathan Peyton   // threads spin in the barrier release phase, they will continue to use the
2847*3041982dSJonathan Peyton   // previous task_team struct(above), until they receive the signal to stop
2848*3041982dSJonathan Peyton   // checking for tasks (they can't safely reference the kmp_team_t struct,
2849*3041982dSJonathan Peyton   // which could be reallocated by the master thread). No task teams are formed
2850*3041982dSJonathan Peyton   // for serialized teams.
28517cc577a4SJonathan Peyton   if (team->t.t_nproc > 1) {
28527cc577a4SJonathan Peyton     int other_team = 1 - this_thr->th.th_task_state;
28537cc577a4SJonathan Peyton     if (team->t.t_task_team[other_team] == NULL) { // setup other team as well
2854*3041982dSJonathan Peyton       team->t.t_task_team[other_team] =
2855*3041982dSJonathan Peyton           __kmp_allocate_task_team(this_thr, team);
2856*3041982dSJonathan Peyton       KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created second new "
2857*3041982dSJonathan Peyton                     "task_team %p for team %d at parity=%d\n",
2858*3041982dSJonathan Peyton                     __kmp_gtid_from_thread(this_thr),
2859*3041982dSJonathan Peyton                     team->t.t_task_team[other_team],
28607cc577a4SJonathan Peyton                     ((team != NULL) ? team->t.t_id : -1), other_team));
2861*3041982dSJonathan Peyton     } else { // Leave the old task team struct in place for the upcoming region;
2862*3041982dSJonathan Peyton       // adjust as needed
28637cc577a4SJonathan Peyton       kmp_task_team_t *task_team = team->t.t_task_team[other_team];
2864*3041982dSJonathan Peyton       if (!task_team->tt.tt_active ||
2865*3041982dSJonathan Peyton           team->t.t_nproc != task_team->tt.tt_nproc) {
28667cc577a4SJonathan Peyton         TCW_4(task_team->tt.tt_nproc, team->t.t_nproc);
28677cc577a4SJonathan Peyton         TCW_4(task_team->tt.tt_found_tasks, FALSE);
28687cc577a4SJonathan Peyton #if OMP_45_ENABLED
28697cc577a4SJonathan Peyton         TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE);
28707cc577a4SJonathan Peyton #endif
28717cc577a4SJonathan Peyton         TCW_4(task_team->tt.tt_unfinished_threads, team->t.t_nproc);
28727cc577a4SJonathan Peyton         TCW_4(task_team->tt.tt_active, TRUE);
28737cc577a4SJonathan Peyton       }
2874*3041982dSJonathan Peyton       // if team size has changed, the first thread to enable tasking will
2875*3041982dSJonathan Peyton       // realloc threads_data if necessary
2876*3041982dSJonathan Peyton       KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d reset next task_team "
2877*3041982dSJonathan Peyton                     "%p for team %d at parity=%d\n",
2878*3041982dSJonathan Peyton                     __kmp_gtid_from_thread(this_thr),
2879*3041982dSJonathan Peyton                     team->t.t_task_team[other_team],
28807cc577a4SJonathan Peyton                     ((team != NULL) ? team->t.t_id : -1), other_team));
28817cc577a4SJonathan Peyton     }
28827cc577a4SJonathan Peyton   }
28837cc577a4SJonathan Peyton }
28847cc577a4SJonathan Peyton 
28857cc577a4SJonathan Peyton // __kmp_task_team_sync: Propagation of task team data from team to threads
28867cc577a4SJonathan Peyton // which happens just after the release phase of a team barrier.  This may be
28877cc577a4SJonathan Peyton // called by any thread, but only for teams with # threads > 1.
2888*3041982dSJonathan Peyton void __kmp_task_team_sync(kmp_info_t *this_thr, kmp_team_t *team) {
28897cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
28907cc577a4SJonathan Peyton 
2891*3041982dSJonathan Peyton   // Toggle the th_task_state field, to switch which task_team this thread
2892*3041982dSJonathan Peyton   // refers to
28937cc577a4SJonathan Peyton   this_thr->th.th_task_state = 1 - this_thr->th.th_task_state;
2894*3041982dSJonathan Peyton   // It is now safe to propagate the task team pointer from the team struct to
2895*3041982dSJonathan Peyton   // the current thread.
2896*3041982dSJonathan Peyton   TCW_PTR(this_thr->th.th_task_team,
2897*3041982dSJonathan Peyton           team->t.t_task_team[this_thr->th.th_task_state]);
2898*3041982dSJonathan Peyton   KA_TRACE(20,
2899*3041982dSJonathan Peyton            ("__kmp_task_team_sync: Thread T#%d task team switched to task_team "
2900*3041982dSJonathan Peyton             "%p from Team #%d (parity=%d)\n",
29017cc577a4SJonathan Peyton             __kmp_gtid_from_thread(this_thr), this_thr->th.th_task_team,
29027cc577a4SJonathan Peyton             ((team != NULL) ? team->t.t_id : -1), this_thr->th.th_task_state));
29037cc577a4SJonathan Peyton }
29047cc577a4SJonathan Peyton 
2905*3041982dSJonathan Peyton // __kmp_task_team_wait: Master thread waits for outstanding tasks after the
2906*3041982dSJonathan Peyton // barrier gather phase. Only called by master thread if #threads in team > 1 or
2907*3041982dSJonathan Peyton // if proxy tasks were created.
2908*3041982dSJonathan Peyton //
2909*3041982dSJonathan Peyton // wait is a flag that defaults to 1 (see kmp.h), but waiting can be turned off
2910*3041982dSJonathan Peyton // by passing in 0 optionally as the last argument. When wait is zero, master
2911*3041982dSJonathan Peyton // thread does not wait for unfinished_threads to reach 0.
2912*3041982dSJonathan Peyton void __kmp_task_team_wait(
2913*3041982dSJonathan Peyton     kmp_info_t *this_thr,
2914*3041982dSJonathan Peyton     kmp_team_t *team USE_ITT_BUILD_ARG(void *itt_sync_obj), int wait) {
29157cc577a4SJonathan Peyton   kmp_task_team_t *task_team = team->t.t_task_team[this_thr->th.th_task_state];
29167cc577a4SJonathan Peyton 
29177cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode != tskm_immediate_exec);
29187cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_team == this_thr->th.th_task_team);
29197cc577a4SJonathan Peyton 
29207cc577a4SJonathan Peyton   if ((task_team != NULL) && KMP_TASKING_ENABLED(task_team)) {
29217cc577a4SJonathan Peyton     if (wait) {
2922*3041982dSJonathan Peyton       KA_TRACE(20, ("__kmp_task_team_wait: Master T#%d waiting for all tasks "
2923*3041982dSJonathan Peyton                     "(for unfinished_threads to reach 0) on task_team = %p\n",
29247cc577a4SJonathan Peyton                     __kmp_gtid_from_thread(this_thr), task_team));
2925*3041982dSJonathan Peyton       // Worker threads may have dropped through to release phase, but could
2926*3041982dSJonathan Peyton       // still be executing tasks. Wait here for tasks to complete. To avoid
2927*3041982dSJonathan Peyton       // memory contention, only master thread checks termination condition.
29287cc577a4SJonathan Peyton       kmp_flag_32 flag(&task_team->tt.tt_unfinished_threads, 0U);
2929*3041982dSJonathan Peyton       flag.wait(this_thr, TRUE USE_ITT_BUILD_ARG(itt_sync_obj));
29307cc577a4SJonathan Peyton     }
2931*3041982dSJonathan Peyton     // Deactivate the old task team, so that the worker threads will stop
2932*3041982dSJonathan Peyton     // referencing it while spinning.
2933*3041982dSJonathan Peyton     KA_TRACE(
2934*3041982dSJonathan Peyton         20,
2935*3041982dSJonathan Peyton         ("__kmp_task_team_wait: Master T#%d deactivating task_team %p: "
29367cc577a4SJonathan Peyton          "setting active to false, setting local and team's pointer to NULL\n",
29377cc577a4SJonathan Peyton          __kmp_gtid_from_thread(this_thr), task_team));
29387cc577a4SJonathan Peyton #if OMP_45_ENABLED
2939*3041982dSJonathan Peyton     KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1 ||
2940*3041982dSJonathan Peyton                      task_team->tt.tt_found_proxy_tasks == TRUE);
29417cc577a4SJonathan Peyton     TCW_SYNC_4(task_team->tt.tt_found_proxy_tasks, FALSE);
29427cc577a4SJonathan Peyton #else
29437cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(task_team->tt.tt_nproc > 1);
29447cc577a4SJonathan Peyton #endif
29457cc577a4SJonathan Peyton     TCW_SYNC_4(task_team->tt.tt_active, FALSE);
29467cc577a4SJonathan Peyton     KMP_MB();
29477cc577a4SJonathan Peyton 
29487cc577a4SJonathan Peyton     TCW_PTR(this_thr->th.th_task_team, NULL);
29497cc577a4SJonathan Peyton   }
29507cc577a4SJonathan Peyton }
29517cc577a4SJonathan Peyton 
29527cc577a4SJonathan Peyton // __kmp_tasking_barrier:
29537cc577a4SJonathan Peyton // This routine may only called when __kmp_tasking_mode == tskm_extra_barrier.
2954*3041982dSJonathan Peyton // Internal function to execute all tasks prior to a regular barrier or a join
2955*3041982dSJonathan Peyton // barrier. It is a full barrier itself, which unfortunately turns regular
2956*3041982dSJonathan Peyton // barriers into double barriers and join barriers into 1 1/2 barriers.
2957*3041982dSJonathan Peyton void __kmp_tasking_barrier(kmp_team_t *team, kmp_info_t *thread, int gtid) {
2958*3041982dSJonathan Peyton   volatile kmp_uint32 *spin =
2959*3041982dSJonathan Peyton       &team->t.t_task_team[thread->th.th_task_state]->tt.tt_unfinished_threads;
29607cc577a4SJonathan Peyton   int flag = FALSE;
29617cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(__kmp_tasking_mode == tskm_extra_barrier);
29627cc577a4SJonathan Peyton 
29637cc577a4SJonathan Peyton #if USE_ITT_BUILD
29647cc577a4SJonathan Peyton   KMP_FSYNC_SPIN_INIT(spin, (kmp_uint32 *)NULL);
29657cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
29667cc577a4SJonathan Peyton   kmp_flag_32 spin_flag(spin, 0U);
2967*3041982dSJonathan Peyton   while (!spin_flag.execute_tasks(thread, gtid, TRUE,
2968*3041982dSJonathan Peyton                                   &flag USE_ITT_BUILD_ARG(NULL), 0)) {
29697cc577a4SJonathan Peyton #if USE_ITT_BUILD
29707cc577a4SJonathan Peyton     // TODO: What about itt_sync_obj??
29717cc577a4SJonathan Peyton     KMP_FSYNC_SPIN_PREPARE(spin);
29727cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
29737cc577a4SJonathan Peyton 
29747cc577a4SJonathan Peyton     if (TCR_4(__kmp_global.g.g_done)) {
29757cc577a4SJonathan Peyton       if (__kmp_global.g.g_abort)
29767cc577a4SJonathan Peyton         __kmp_abort_thread();
29777cc577a4SJonathan Peyton       break;
29787cc577a4SJonathan Peyton     }
29797cc577a4SJonathan Peyton     KMP_YIELD(TRUE); // GH: We always yield here
29807cc577a4SJonathan Peyton   }
29817cc577a4SJonathan Peyton #if USE_ITT_BUILD
29827cc577a4SJonathan Peyton   KMP_FSYNC_SPIN_ACQUIRED((void *)spin);
29837cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
29847cc577a4SJonathan Peyton }
29857cc577a4SJonathan Peyton 
29867cc577a4SJonathan Peyton #if OMP_45_ENABLED
29877cc577a4SJonathan Peyton 
2988*3041982dSJonathan Peyton // __kmp_give_task puts a task into a given thread queue if:
2989*3041982dSJonathan Peyton //  - the queue for that thread was created
2990*3041982dSJonathan Peyton //  - there's space in that queue
2991*3041982dSJonathan Peyton // Because of this, __kmp_push_task needs to check if there's space after
2992*3041982dSJonathan Peyton // getting the lock
2993*3041982dSJonathan Peyton static bool __kmp_give_task(kmp_info_t *thread, kmp_int32 tid, kmp_task_t *task,
2994*3041982dSJonathan Peyton                             kmp_int32 pass) {
29957cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
29967cc577a4SJonathan Peyton   kmp_task_team_t *task_team = taskdata->td_task_team;
29977cc577a4SJonathan Peyton 
2998*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmp_give_task: trying to give task %p to thread %d.\n",
2999*3041982dSJonathan Peyton                 taskdata, tid));
30007cc577a4SJonathan Peyton 
30017cc577a4SJonathan Peyton   // If task_team is NULL something went really bad...
30027cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task_team != NULL);
30037cc577a4SJonathan Peyton 
30047cc577a4SJonathan Peyton   bool result = false;
30057cc577a4SJonathan Peyton   kmp_thread_data_t *thread_data = &task_team->tt.tt_threads_data[tid];
30067cc577a4SJonathan Peyton 
30077cc577a4SJonathan Peyton   if (thread_data->td.td_deque == NULL) {
30087cc577a4SJonathan Peyton     // There's no queue in this thread, go find another one
30097cc577a4SJonathan Peyton     // We're guaranteed that at least one thread has a queue
3010*3041982dSJonathan Peyton     KA_TRACE(30,
3011*3041982dSJonathan Peyton              ("__kmp_give_task: thread %d has no queue while giving task %p.\n",
3012*3041982dSJonathan Peyton               tid, taskdata));
30137cc577a4SJonathan Peyton     return result;
30147cc577a4SJonathan Peyton   }
30157cc577a4SJonathan Peyton 
3016*3041982dSJonathan Peyton   if (TCR_4(thread_data->td.td_deque_ntasks) >=
3017*3041982dSJonathan Peyton       TASK_DEQUE_SIZE(thread_data->td)) {
3018*3041982dSJonathan Peyton     KA_TRACE(
3019*3041982dSJonathan Peyton         30,
3020*3041982dSJonathan Peyton         ("__kmp_give_task: queue is full while giving task %p to thread %d.\n",
3021*3041982dSJonathan Peyton          taskdata, tid));
30227cc577a4SJonathan Peyton 
3023*3041982dSJonathan Peyton     // if this deque is bigger than the pass ratio give a chance to another
3024*3041982dSJonathan Peyton     // thread
3025*3041982dSJonathan Peyton     if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass)
3026*3041982dSJonathan Peyton       return result;
30277cc577a4SJonathan Peyton 
30287cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
30297cc577a4SJonathan Peyton     __kmp_realloc_task_deque(thread, thread_data);
30307cc577a4SJonathan Peyton 
30317cc577a4SJonathan Peyton   } else {
30327cc577a4SJonathan Peyton 
30337cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock(&thread_data->td.td_deque_lock);
30347cc577a4SJonathan Peyton 
3035*3041982dSJonathan Peyton     if (TCR_4(thread_data->td.td_deque_ntasks) >=
3036*3041982dSJonathan Peyton         TASK_DEQUE_SIZE(thread_data->td)) {
3037*3041982dSJonathan Peyton       KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to "
3038*3041982dSJonathan Peyton                     "thread %d.\n",
3039*3041982dSJonathan Peyton                     taskdata, tid));
30407cc577a4SJonathan Peyton 
3041*3041982dSJonathan Peyton       // if this deque is bigger than the pass ratio give a chance to another
3042*3041982dSJonathan Peyton       // thread
30437cc577a4SJonathan Peyton       if (TASK_DEQUE_SIZE(thread_data->td) / INITIAL_TASK_DEQUE_SIZE >= pass)
30447cc577a4SJonathan Peyton         goto release_and_exit;
30457cc577a4SJonathan Peyton 
30467cc577a4SJonathan Peyton       __kmp_realloc_task_deque(thread, thread_data);
30477cc577a4SJonathan Peyton     }
30487cc577a4SJonathan Peyton   }
30497cc577a4SJonathan Peyton 
30507cc577a4SJonathan Peyton   // lock is held here, and there is space in the deque
30517cc577a4SJonathan Peyton 
30527cc577a4SJonathan Peyton   thread_data->td.td_deque[thread_data->td.td_deque_tail] = taskdata;
30537cc577a4SJonathan Peyton   // Wrap index.
3054*3041982dSJonathan Peyton   thread_data->td.td_deque_tail =
3055*3041982dSJonathan Peyton       (thread_data->td.td_deque_tail + 1) & TASK_DEQUE_MASK(thread_data->td);
3056*3041982dSJonathan Peyton   TCW_4(thread_data->td.td_deque_ntasks,
3057*3041982dSJonathan Peyton         TCR_4(thread_data->td.td_deque_ntasks) + 1);
30587cc577a4SJonathan Peyton 
30597cc577a4SJonathan Peyton   result = true;
3060*3041982dSJonathan Peyton   KA_TRACE(30, ("__kmp_give_task: successfully gave task %p to thread %d.\n",
3061*3041982dSJonathan Peyton                 taskdata, tid));
30627cc577a4SJonathan Peyton 
30637cc577a4SJonathan Peyton release_and_exit:
30647cc577a4SJonathan Peyton   __kmp_release_bootstrap_lock(&thread_data->td.td_deque_lock);
30657cc577a4SJonathan Peyton 
30667cc577a4SJonathan Peyton   return result;
30677cc577a4SJonathan Peyton }
30687cc577a4SJonathan Peyton 
3069*3041982dSJonathan Peyton /* The finish of the proxy tasks is divided in two pieces:
30707cc577a4SJonathan Peyton     - the top half is the one that can be done from a thread outside the team
30717cc577a4SJonathan Peyton     - the bottom half must be run from a them within the team
30727cc577a4SJonathan Peyton 
3073*3041982dSJonathan Peyton    In order to run the bottom half the task gets queued back into one of the
3074*3041982dSJonathan Peyton    threads of the team. Once the td_incomplete_child_task counter of the parent
3075*3041982dSJonathan Peyton    is decremented the threads can leave the barriers. So, the bottom half needs
3076*3041982dSJonathan Peyton    to be queued before the counter is decremented. The top half is therefore
3077*3041982dSJonathan Peyton    divided in two parts:
30787cc577a4SJonathan Peyton     - things that can be run before queuing the bottom half
30797cc577a4SJonathan Peyton     - things that must be run after queuing the bottom half
30807cc577a4SJonathan Peyton 
3081*3041982dSJonathan Peyton    This creates a second race as the bottom half can free the task before the
3082*3041982dSJonathan Peyton    second top half is executed. To avoid this we use the
3083*3041982dSJonathan Peyton    td_incomplete_child_task of the proxy task to synchronize the top and bottom
3084*3041982dSJonathan Peyton    half. */
3085*3041982dSJonathan Peyton static void __kmp_first_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
30867cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.tasktype == TASK_EXPLICIT);
30877cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
30887cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.complete == 0);
30897cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.freed == 0);
30907cc577a4SJonathan Peyton 
30917cc577a4SJonathan Peyton   taskdata->td_flags.complete = 1; // mark the task as completed
30927cc577a4SJonathan Peyton 
30937cc577a4SJonathan Peyton   if (taskdata->td_taskgroup)
30947cc577a4SJonathan Peyton     KMP_TEST_THEN_DEC32((kmp_int32 *)(&taskdata->td_taskgroup->count));
30957cc577a4SJonathan Peyton 
3096*3041982dSJonathan Peyton   // Create an imaginary children for this task so the bottom half cannot
3097*3041982dSJonathan Peyton   // release the task before we have completed the second top half
30987cc577a4SJonathan Peyton   TCI_4(taskdata->td_incomplete_child_tasks);
30997cc577a4SJonathan Peyton }
31007cc577a4SJonathan Peyton 
3101*3041982dSJonathan Peyton static void __kmp_second_top_half_finish_proxy(kmp_taskdata_t *taskdata) {
31027cc577a4SJonathan Peyton   kmp_int32 children = 0;
31037cc577a4SJonathan Peyton 
31047cc577a4SJonathan Peyton   // Predecrement simulated by "- 1" calculation
3105*3041982dSJonathan Peyton   children =
3106*3041982dSJonathan Peyton       KMP_TEST_THEN_DEC32(
3107*3041982dSJonathan Peyton           (kmp_int32 *)(&taskdata->td_parent->td_incomplete_child_tasks)) -
3108*3041982dSJonathan Peyton       1;
31097cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(children >= 0);
31107cc577a4SJonathan Peyton 
31117cc577a4SJonathan Peyton   // Remove the imaginary children
31127cc577a4SJonathan Peyton   TCD_4(taskdata->td_incomplete_child_tasks);
31137cc577a4SJonathan Peyton }
31147cc577a4SJonathan Peyton 
3115*3041982dSJonathan Peyton static void __kmp_bottom_half_finish_proxy(kmp_int32 gtid, kmp_task_t *ptask) {
31167cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
31177cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
31187cc577a4SJonathan Peyton 
31197cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
3120*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.complete ==
3121*3041982dSJonathan Peyton                    1); // top half must run before bottom half
31227cc577a4SJonathan Peyton 
31237cc577a4SJonathan Peyton   // We need to wait to make sure the top half is finished
31247cc577a4SJonathan Peyton   // Spinning here should be ok as this should happen quickly
3125*3041982dSJonathan Peyton   while (TCR_4(taskdata->td_incomplete_child_tasks) > 0)
3126*3041982dSJonathan Peyton     ;
31277cc577a4SJonathan Peyton 
31287cc577a4SJonathan Peyton   __kmp_release_deps(gtid, taskdata);
31297cc577a4SJonathan Peyton   __kmp_free_task_and_ancestors(gtid, taskdata, thread);
31307cc577a4SJonathan Peyton }
31317cc577a4SJonathan Peyton 
31327cc577a4SJonathan Peyton /*!
31337cc577a4SJonathan Peyton @ingroup TASKING
31347cc577a4SJonathan Peyton @param gtid Global Thread ID of encountering thread
31357cc577a4SJonathan Peyton @param ptask Task which execution is completed
31367cc577a4SJonathan Peyton 
3137*3041982dSJonathan Peyton Execute the completation of a proxy task from a thread of that is part of the
3138*3041982dSJonathan Peyton team. Run first and bottom halves directly.
31397cc577a4SJonathan Peyton */
3140*3041982dSJonathan Peyton void __kmpc_proxy_task_completed(kmp_int32 gtid, kmp_task_t *ptask) {
31417cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(ptask != NULL);
31427cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
3143*3041982dSJonathan Peyton   KA_TRACE(
3144*3041982dSJonathan Peyton       10, ("__kmp_proxy_task_completed(enter): T#%d proxy task %p completing\n",
3145*3041982dSJonathan Peyton            gtid, taskdata));
31467cc577a4SJonathan Peyton 
31477cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
31487cc577a4SJonathan Peyton 
31497cc577a4SJonathan Peyton   __kmp_first_top_half_finish_proxy(taskdata);
31507cc577a4SJonathan Peyton   __kmp_second_top_half_finish_proxy(taskdata);
31517cc577a4SJonathan Peyton   __kmp_bottom_half_finish_proxy(gtid, ptask);
31527cc577a4SJonathan Peyton 
3153*3041982dSJonathan Peyton   KA_TRACE(10,
3154*3041982dSJonathan Peyton            ("__kmp_proxy_task_completed(exit): T#%d proxy task %p completing\n",
3155*3041982dSJonathan Peyton             gtid, taskdata));
31567cc577a4SJonathan Peyton }
31577cc577a4SJonathan Peyton 
31587cc577a4SJonathan Peyton /*!
31597cc577a4SJonathan Peyton @ingroup TASKING
31607cc577a4SJonathan Peyton @param ptask Task which execution is completed
31617cc577a4SJonathan Peyton 
3162*3041982dSJonathan Peyton Execute the completation of a proxy task from a thread that could not belong to
3163*3041982dSJonathan Peyton the team.
31647cc577a4SJonathan Peyton */
3165*3041982dSJonathan Peyton void __kmpc_proxy_task_completed_ooo(kmp_task_t *ptask) {
31667cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(ptask != NULL);
31677cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(ptask);
31687cc577a4SJonathan Peyton 
3169*3041982dSJonathan Peyton   KA_TRACE(
3170*3041982dSJonathan Peyton       10,
3171*3041982dSJonathan Peyton       ("__kmp_proxy_task_completed_ooo(enter): proxy task completing ooo %p\n",
3172*3041982dSJonathan Peyton        taskdata));
31737cc577a4SJonathan Peyton 
31747cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata->td_flags.proxy == TASK_PROXY);
31757cc577a4SJonathan Peyton 
31767cc577a4SJonathan Peyton   __kmp_first_top_half_finish_proxy(taskdata);
31777cc577a4SJonathan Peyton 
3178*3041982dSJonathan Peyton   // Enqueue task to complete bottom half completion from a thread within the
3179*3041982dSJonathan Peyton   // corresponding team
31807cc577a4SJonathan Peyton   kmp_team_t *team = taskdata->td_team;
31817cc577a4SJonathan Peyton   kmp_int32 nthreads = team->t.t_nproc;
31827cc577a4SJonathan Peyton   kmp_info_t *thread;
31837cc577a4SJonathan Peyton 
3184*3041982dSJonathan Peyton   // This should be similar to start_k = __kmp_get_random( thread ) % nthreads
3185*3041982dSJonathan Peyton   // but we cannot use __kmp_get_random here
31867cc577a4SJonathan Peyton   kmp_int32 start_k = 0;
31877cc577a4SJonathan Peyton   kmp_int32 pass = 1;
31887cc577a4SJonathan Peyton   kmp_int32 k = start_k;
31897cc577a4SJonathan Peyton 
31907cc577a4SJonathan Peyton   do {
31917cc577a4SJonathan Peyton     // For now we're just linearly trying to find a thread
31927cc577a4SJonathan Peyton     thread = team->t.t_threads[k];
31937cc577a4SJonathan Peyton     k = (k + 1) % nthreads;
31947cc577a4SJonathan Peyton 
31957cc577a4SJonathan Peyton     // we did a full pass through all the threads
3196*3041982dSJonathan Peyton     if (k == start_k)
3197*3041982dSJonathan Peyton       pass = pass << 1;
31987cc577a4SJonathan Peyton 
31997cc577a4SJonathan Peyton   } while (!__kmp_give_task(thread, k, ptask, pass));
32007cc577a4SJonathan Peyton 
32017cc577a4SJonathan Peyton   __kmp_second_top_half_finish_proxy(taskdata);
32027cc577a4SJonathan Peyton 
3203*3041982dSJonathan Peyton   KA_TRACE(
3204*3041982dSJonathan Peyton       10,
3205*3041982dSJonathan Peyton       ("__kmp_proxy_task_completed_ooo(exit): proxy task completing ooo %p\n",
3206*3041982dSJonathan Peyton        taskdata));
32077cc577a4SJonathan Peyton }
32087cc577a4SJonathan Peyton 
3209*3041982dSJonathan Peyton // __kmp_task_dup_alloc: Allocate the taskdata and make a copy of source task
3210*3041982dSJonathan Peyton // for taskloop
32117cc577a4SJonathan Peyton //
32127cc577a4SJonathan Peyton // thread:   allocating thread
32137cc577a4SJonathan Peyton // task_src: pointer to source task to be duplicated
32147cc577a4SJonathan Peyton // returns:  a pointer to the allocated kmp_task_t structure (task).
3215*3041982dSJonathan Peyton kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) {
32167cc577a4SJonathan Peyton   kmp_task_t *task;
32177cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata;
32187cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata_src;
32197cc577a4SJonathan Peyton   kmp_taskdata_t *parent_task = thread->th.th_current_task;
32207cc577a4SJonathan Peyton   size_t shareds_offset;
32217cc577a4SJonathan Peyton   size_t task_size;
32227cc577a4SJonathan Peyton 
3223*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmp_task_dup_alloc(enter): Th %p, source task %p\n", thread,
3224*3041982dSJonathan Peyton                 task_src));
32257cc577a4SJonathan Peyton   taskdata_src = KMP_TASK_TO_TASKDATA(task_src);
3226*3041982dSJonathan Peyton   KMP_DEBUG_ASSERT(taskdata_src->td_flags.proxy ==
3227*3041982dSJonathan Peyton                    TASK_FULL); // it should not be proxy task
32287cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(taskdata_src->td_flags.tasktype == TASK_EXPLICIT);
32297cc577a4SJonathan Peyton   task_size = taskdata_src->td_size_alloc;
32307cc577a4SJonathan Peyton 
32317cc577a4SJonathan Peyton   // Allocate a kmp_taskdata_t block and a kmp_task_t block.
3232*3041982dSJonathan Peyton   KA_TRACE(30, ("__kmp_task_dup_alloc: Th %p, malloc size %ld\n", thread,
3233*3041982dSJonathan Peyton                 task_size));
32347cc577a4SJonathan Peyton #if USE_FAST_MEMORY
32357cc577a4SJonathan Peyton   taskdata = (kmp_taskdata_t *)__kmp_fast_allocate(thread, task_size);
32367cc577a4SJonathan Peyton #else
32377cc577a4SJonathan Peyton   taskdata = (kmp_taskdata_t *)__kmp_thread_malloc(thread, task_size);
32387cc577a4SJonathan Peyton #endif /* USE_FAST_MEMORY */
32397cc577a4SJonathan Peyton   KMP_MEMCPY(taskdata, taskdata_src, task_size);
32407cc577a4SJonathan Peyton 
32417cc577a4SJonathan Peyton   task = KMP_TASKDATA_TO_TASK(taskdata);
32427cc577a4SJonathan Peyton 
32437cc577a4SJonathan Peyton   // Initialize new task (only specific fields not affected by memcpy)
32447cc577a4SJonathan Peyton   taskdata->td_task_id = KMP_GEN_TASK_ID();
32457cc577a4SJonathan Peyton   if (task->shareds != NULL) { // need setup shareds pointer
32467cc577a4SJonathan Peyton     shareds_offset = (char *)task_src->shareds - (char *)taskdata_src;
32477cc577a4SJonathan Peyton     task->shareds = &((char *)taskdata)[shareds_offset];
3248*3041982dSJonathan Peyton     KMP_DEBUG_ASSERT((((kmp_uintptr_t)task->shareds) & (sizeof(void *) - 1)) ==
3249*3041982dSJonathan Peyton                      0);
32507cc577a4SJonathan Peyton   }
32517cc577a4SJonathan Peyton   taskdata->td_alloc_thread = thread;
3252*3041982dSJonathan Peyton   taskdata->td_taskgroup =
3253*3041982dSJonathan Peyton       parent_task
3254*3041982dSJonathan Peyton           ->td_taskgroup; // task inherits the taskgroup from the parent task
32557cc577a4SJonathan Peyton 
3256*3041982dSJonathan Peyton   // Only need to keep track of child task counts if team parallel and tasking
3257*3041982dSJonathan Peyton   // not serialized
32587cc577a4SJonathan Peyton   if (!(taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser)) {
32597cc577a4SJonathan Peyton     KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_incomplete_child_tasks));
32607cc577a4SJonathan Peyton     if (parent_task->td_taskgroup)
32617cc577a4SJonathan Peyton       KMP_TEST_THEN_INC32((kmp_int32 *)(&parent_task->td_taskgroup->count));
3262*3041982dSJonathan Peyton     // Only need to keep track of allocated child tasks for explicit tasks since
3263*3041982dSJonathan Peyton     // implicit not deallocated
32647cc577a4SJonathan Peyton     if (taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT)
3265*3041982dSJonathan Peyton       KMP_TEST_THEN_INC32(
3266*3041982dSJonathan Peyton           (kmp_int32 *)(&taskdata->td_parent->td_allocated_child_tasks));
32677cc577a4SJonathan Peyton   }
32687cc577a4SJonathan Peyton 
3269*3041982dSJonathan Peyton   KA_TRACE(20,
3270*3041982dSJonathan Peyton            ("__kmp_task_dup_alloc(exit): Th %p, created task %p, parent=%p\n",
32717cc577a4SJonathan Peyton             thread, taskdata, taskdata->td_parent));
32727cc577a4SJonathan Peyton #if OMPT_SUPPORT
3273*3041982dSJonathan Peyton   __kmp_task_init_ompt(taskdata, thread->th.th_info.ds.ds_gtid,
3274*3041982dSJonathan Peyton                        (void *)task->routine);
32757cc577a4SJonathan Peyton #endif
32767cc577a4SJonathan Peyton   return task;
32777cc577a4SJonathan Peyton }
32787cc577a4SJonathan Peyton 
32797cc577a4SJonathan Peyton // Routine optionally generated by th ecompiler for setting the lastprivate flag
32807cc577a4SJonathan Peyton // and calling needed constructors for private/firstprivate objects
32817cc577a4SJonathan Peyton // (used to form taskloop tasks from pattern task)
32827cc577a4SJonathan Peyton typedef void (*p_task_dup_t)(kmp_task_t *, kmp_task_t *, kmp_int32);
32837cc577a4SJonathan Peyton 
32847cc577a4SJonathan Peyton // __kmp_taskloop_linear: Start tasks of the taskloop linearly
32857cc577a4SJonathan Peyton //
32867cc577a4SJonathan Peyton // loc       Source location information
32877cc577a4SJonathan Peyton // gtid      Global thread ID
32887cc577a4SJonathan Peyton // task      Task with whole loop iteration range
32897cc577a4SJonathan Peyton // lb        Pointer to loop lower bound
32907cc577a4SJonathan Peyton // ub        Pointer to loop upper bound
32917cc577a4SJonathan Peyton // st        Loop stride
32927cc577a4SJonathan Peyton // sched     Schedule specified 0/1/2 for none/grainsize/num_tasks
32937cc577a4SJonathan Peyton // grainsize Schedule value if specified
32947cc577a4SJonathan Peyton // task_dup  Tasks duplication routine
3295*3041982dSJonathan Peyton void __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task,
32967cc577a4SJonathan Peyton                            kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
3297*3041982dSJonathan Peyton                            int sched, kmp_uint64 grainsize, void *task_dup) {
32987cc577a4SJonathan Peyton   KMP_COUNT_BLOCK(OMP_TASKLOOP);
32997cc577a4SJonathan Peyton   KMP_TIME_PARTITIONED_BLOCK(OMP_taskloop_scheduling);
33007cc577a4SJonathan Peyton   p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
33017cc577a4SJonathan Peyton   kmp_uint64 tc;
33027cc577a4SJonathan Peyton   kmp_uint64 lower = *lb; // compiler provides global bounds here
33037cc577a4SJonathan Peyton   kmp_uint64 upper = *ub;
33047cc577a4SJonathan Peyton   kmp_uint64 i, num_tasks = 0, extras = 0;
33057cc577a4SJonathan Peyton   kmp_info_t *thread = __kmp_threads[gtid];
33067cc577a4SJonathan Peyton   kmp_taskdata_t *current_task = thread->th.th_current_task;
33077cc577a4SJonathan Peyton   kmp_task_t *next_task;
33087cc577a4SJonathan Peyton   kmp_int32 lastpriv = 0;
3309*3041982dSJonathan Peyton   size_t lower_offset =
3310*3041982dSJonathan Peyton       (char *)lb - (char *)task; // remember offset of lb in the task structure
3311*3041982dSJonathan Peyton   size_t upper_offset =
3312*3041982dSJonathan Peyton       (char *)ub - (char *)task; // remember offset of ub in the task structure
33137cc577a4SJonathan Peyton 
33147cc577a4SJonathan Peyton   // compute trip count
33157cc577a4SJonathan Peyton   if (st == 1) { // most common case
33167cc577a4SJonathan Peyton     tc = upper - lower + 1;
33177cc577a4SJonathan Peyton   } else if (st < 0) {
33187cc577a4SJonathan Peyton     tc = (lower - upper) / (-st) + 1;
33197cc577a4SJonathan Peyton   } else { // st > 0
33207cc577a4SJonathan Peyton     tc = (upper - lower) / st + 1;
33217cc577a4SJonathan Peyton   }
33227cc577a4SJonathan Peyton   if (tc == 0) {
33237cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d zero-trip loop\n", gtid));
33247cc577a4SJonathan Peyton     // free the pattern task and exit
33257cc577a4SJonathan Peyton     __kmp_task_start(gtid, task, current_task);
33267cc577a4SJonathan Peyton     // do not execute anything for zero-trip loop
33277cc577a4SJonathan Peyton     __kmp_task_finish(gtid, task, current_task);
33287cc577a4SJonathan Peyton     return;
33297cc577a4SJonathan Peyton   }
33307cc577a4SJonathan Peyton 
33317cc577a4SJonathan Peyton   // compute num_tasks/grainsize based on the input provided
33327cc577a4SJonathan Peyton   switch (sched) {
33337cc577a4SJonathan Peyton   case 0: // no schedule clause specified, we can choose the default
33347cc577a4SJonathan Peyton     // let's try to schedule (team_size*10) tasks
33357cc577a4SJonathan Peyton     grainsize = thread->th.th_team_nproc * 10;
33367cc577a4SJonathan Peyton   case 2: // num_tasks provided
33377cc577a4SJonathan Peyton     if (grainsize > tc) {
33387cc577a4SJonathan Peyton       num_tasks = tc; // too big num_tasks requested, adjust values
33397cc577a4SJonathan Peyton       grainsize = 1;
33407cc577a4SJonathan Peyton       extras = 0;
33417cc577a4SJonathan Peyton     } else {
33427cc577a4SJonathan Peyton       num_tasks = grainsize;
33437cc577a4SJonathan Peyton       grainsize = tc / num_tasks;
33447cc577a4SJonathan Peyton       extras = tc % num_tasks;
33457cc577a4SJonathan Peyton     }
33467cc577a4SJonathan Peyton     break;
33477cc577a4SJonathan Peyton   case 1: // grainsize provided
33487cc577a4SJonathan Peyton     if (grainsize > tc) {
33497cc577a4SJonathan Peyton       num_tasks = 1; // too big grainsize requested, adjust values
33507cc577a4SJonathan Peyton       grainsize = tc;
33517cc577a4SJonathan Peyton       extras = 0;
33527cc577a4SJonathan Peyton     } else {
33537cc577a4SJonathan Peyton       num_tasks = tc / grainsize;
3354*3041982dSJonathan Peyton       grainsize =
3355*3041982dSJonathan Peyton           tc /
3356*3041982dSJonathan Peyton           num_tasks; // adjust grainsize for balanced distribution of iterations
33577cc577a4SJonathan Peyton       extras = tc % num_tasks;
33587cc577a4SJonathan Peyton     }
33597cc577a4SJonathan Peyton     break;
33607cc577a4SJonathan Peyton   default:
33617cc577a4SJonathan Peyton     KMP_ASSERT2(0, "unknown scheduling of taskloop");
33627cc577a4SJonathan Peyton   }
33637cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras);
33647cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(num_tasks > extras);
33657cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(num_tasks > 0);
3366*3041982dSJonathan Peyton   KA_TRACE(20, ("__kmpc_taskloop: T#%d will launch: num_tasks %lld, grainsize "
3367*3041982dSJonathan Peyton                 "%lld, extras %lld\n",
33687cc577a4SJonathan Peyton                 gtid, num_tasks, grainsize, extras));
33697cc577a4SJonathan Peyton 
33707cc577a4SJonathan Peyton   // Main loop, launch num_tasks tasks, assign grainsize iterations each task
33717cc577a4SJonathan Peyton   for (i = 0; i < num_tasks; ++i) {
33727cc577a4SJonathan Peyton     kmp_uint64 chunk_minus_1;
33737cc577a4SJonathan Peyton     if (extras == 0) {
33747cc577a4SJonathan Peyton       chunk_minus_1 = grainsize - 1;
33757cc577a4SJonathan Peyton     } else {
33767cc577a4SJonathan Peyton       chunk_minus_1 = grainsize;
33777cc577a4SJonathan Peyton       --extras; // first extras iterations get bigger chunk (grainsize+1)
33787cc577a4SJonathan Peyton     }
33797cc577a4SJonathan Peyton     upper = lower + st * chunk_minus_1;
33807cc577a4SJonathan Peyton     if (i == num_tasks - 1) {
33817cc577a4SJonathan Peyton       // schedule the last task, set lastprivate flag
33827cc577a4SJonathan Peyton       lastpriv = 1;
33837cc577a4SJonathan Peyton #if KMP_DEBUG
33847cc577a4SJonathan Peyton       if (st == 1)
33857cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(upper == *ub);
33867cc577a4SJonathan Peyton       else if (st > 0)
33877cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(upper + st > *ub);
33887cc577a4SJonathan Peyton       else
33897cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(upper + st < *ub);
33907cc577a4SJonathan Peyton #endif
33917cc577a4SJonathan Peyton     }
33927cc577a4SJonathan Peyton     next_task = __kmp_task_dup_alloc(thread, task); // allocate new task
3393*3041982dSJonathan Peyton     *(kmp_uint64 *)((char *)next_task + lower_offset) =
3394*3041982dSJonathan Peyton         lower; // adjust task-specific bounds
33957cc577a4SJonathan Peyton     *(kmp_uint64 *)((char *)next_task + upper_offset) = upper;
33967cc577a4SJonathan Peyton     if (ptask_dup != NULL)
3397*3041982dSJonathan Peyton       ptask_dup(next_task, task,
3398*3041982dSJonathan Peyton                 lastpriv); // set lastprivate flag, construct fistprivates, etc.
3399*3041982dSJonathan Peyton     KA_TRACE(20, ("__kmpc_taskloop: T#%d schedule task %p: lower %lld, upper "
3400*3041982dSJonathan Peyton                   "%lld (offsets %p %p)\n",
34017cc577a4SJonathan Peyton                   gtid, next_task, lower, upper, lower_offset, upper_offset));
34027cc577a4SJonathan Peyton     __kmp_omp_task(gtid, next_task, true); // schedule new task
34037cc577a4SJonathan Peyton     lower = upper + st; // adjust lower bound for the next iteration
34047cc577a4SJonathan Peyton   }
34057cc577a4SJonathan Peyton   // free the pattern task and exit
34067cc577a4SJonathan Peyton   __kmp_task_start(gtid, task, current_task);
34077cc577a4SJonathan Peyton   // do not execute the pattern task, just do bookkeeping
34087cc577a4SJonathan Peyton   __kmp_task_finish(gtid, task, current_task);
34097cc577a4SJonathan Peyton }
34107cc577a4SJonathan Peyton 
34117cc577a4SJonathan Peyton /*!
34127cc577a4SJonathan Peyton @ingroup TASKING
34137cc577a4SJonathan Peyton @param loc       Source location information
34147cc577a4SJonathan Peyton @param gtid      Global thread ID
34157cc577a4SJonathan Peyton @param task      Task structure
34167cc577a4SJonathan Peyton @param if_val    Value of the if clause
34177cc577a4SJonathan Peyton @param lb        Pointer to loop lower bound
34187cc577a4SJonathan Peyton @param ub        Pointer to loop upper bound
34197cc577a4SJonathan Peyton @param st        Loop stride
34207cc577a4SJonathan Peyton @param nogroup   Flag, 1 if nogroup clause specified, 0 otherwise
34217cc577a4SJonathan Peyton @param sched     Schedule specified 0/1/2 for none/grainsize/num_tasks
34227cc577a4SJonathan Peyton @param grainsize Schedule value if specified
34237cc577a4SJonathan Peyton @param task_dup  Tasks duplication routine
34247cc577a4SJonathan Peyton 
34257cc577a4SJonathan Peyton Execute the taskloop construct.
34267cc577a4SJonathan Peyton */
3427*3041982dSJonathan Peyton void __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
3428*3041982dSJonathan Peyton                      kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, int nogroup,
3429*3041982dSJonathan Peyton                      int sched, kmp_uint64 grainsize, void *task_dup) {
34307cc577a4SJonathan Peyton   kmp_taskdata_t *taskdata = KMP_TASK_TO_TASKDATA(task);
34317cc577a4SJonathan Peyton   KMP_DEBUG_ASSERT(task != NULL);
34327cc577a4SJonathan Peyton 
3433*3041982dSJonathan Peyton   KA_TRACE(10, ("__kmpc_taskloop(enter): T#%d, pattern task %p, lb %lld ub "
3434*3041982dSJonathan Peyton                 "%lld st %lld, grain %llu(%d)\n",
34357cc577a4SJonathan Peyton                 gtid, taskdata, *lb, *ub, st, grainsize, sched));
34367cc577a4SJonathan Peyton 
34377cc577a4SJonathan Peyton   // check if clause value first
34387cc577a4SJonathan Peyton   if (if_val == 0) { // if(0) specified, mark task as serial
34397cc577a4SJonathan Peyton     taskdata->td_flags.task_serial = 1;
34407cc577a4SJonathan Peyton     taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied
34417cc577a4SJonathan Peyton   }
34427cc577a4SJonathan Peyton   if (nogroup == 0) {
34437cc577a4SJonathan Peyton     __kmpc_taskgroup(loc, gtid);
34447cc577a4SJonathan Peyton   }
34457cc577a4SJonathan Peyton 
34467cc577a4SJonathan Peyton   if (1 /* AC: use some heuristic here to choose task scheduling method */) {
3447*3041982dSJonathan Peyton     __kmp_taskloop_linear(loc, gtid, task, lb, ub, st, sched, grainsize,
3448*3041982dSJonathan Peyton                           task_dup);
34497cc577a4SJonathan Peyton   }
34507cc577a4SJonathan Peyton 
34517cc577a4SJonathan Peyton   if (nogroup == 0) {
34527cc577a4SJonathan Peyton     __kmpc_end_taskgroup(loc, gtid);
34537cc577a4SJonathan Peyton   }
34547cc577a4SJonathan Peyton   KA_TRACE(10, ("__kmpc_taskloop(exit): T#%d\n", gtid));
34557cc577a4SJonathan Peyton }
34567cc577a4SJonathan Peyton 
34577cc577a4SJonathan Peyton #endif
3458