1*7cc577a4SJonathan Peyton /*
2*7cc577a4SJonathan Peyton  * kmp_tasking.c -- OpenMP 3.0 tasking support.
3*7cc577a4SJonathan Peyton  */
4*7cc577a4SJonathan Peyton 
5*7cc577a4SJonathan Peyton 
6*7cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
7*7cc577a4SJonathan Peyton //
8*7cc577a4SJonathan Peyton //                     The LLVM Compiler Infrastructure
9*7cc577a4SJonathan Peyton //
10*7cc577a4SJonathan Peyton // This file is dual licensed under the MIT and the University of Illinois Open
11*7cc577a4SJonathan Peyton // Source Licenses. See LICENSE.txt for details.
12*7cc577a4SJonathan Peyton //
13*7cc577a4SJonathan Peyton //===----------------------------------------------------------------------===//
14*7cc577a4SJonathan Peyton 
15*7cc577a4SJonathan Peyton 
16*7cc577a4SJonathan Peyton #include "kmp.h"
17*7cc577a4SJonathan Peyton #include "kmp_i18n.h"
18*7cc577a4SJonathan Peyton #include "kmp_itt.h"
19*7cc577a4SJonathan Peyton #include "kmp_wait_release.h"
20*7cc577a4SJonathan Peyton #include "kmp_stats.h"
21*7cc577a4SJonathan Peyton 
22*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
23*7cc577a4SJonathan Peyton #include "ompt-specific.h"
24*7cc577a4SJonathan Peyton #endif
25*7cc577a4SJonathan Peyton 
26*7cc577a4SJonathan Peyton #include "tsan_annotations.h"
27*7cc577a4SJonathan Peyton 
28*7cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
29*7cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
30*7cc577a4SJonathan Peyton 
31*7cc577a4SJonathan Peyton 
32*7cc577a4SJonathan Peyton /* forward declaration */
33*7cc577a4SJonathan Peyton static void __kmp_enable_tasking( kmp_task_team_t *task_team, kmp_info_t *this_thr );
34*7cc577a4SJonathan Peyton static void __kmp_alloc_task_deque( kmp_info_t *thread, kmp_thread_data_t *thread_data );
35*7cc577a4SJonathan Peyton static int  __kmp_realloc_task_threads_data( kmp_info_t *thread, kmp_task_team_t *task_team );
36*7cc577a4SJonathan Peyton 
37*7cc577a4SJonathan Peyton #ifdef OMP_45_ENABLED
38*7cc577a4SJonathan Peyton static void __kmp_bottom_half_finish_proxy( kmp_int32 gtid, kmp_task_t * ptask );
39*7cc577a4SJonathan Peyton #endif
40*7cc577a4SJonathan Peyton 
41*7cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
42*7cc577a4SJonathan Peyton 
43*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------
44*7cc577a4SJonathan Peyton //  __kmp_trace_task_stack: print the tied tasks from the task stack in order
45*7cc577a4SJonathan Peyton //     from top do bottom
46*7cc577a4SJonathan Peyton //
47*7cc577a4SJonathan Peyton //  gtid: global thread identifier for thread containing stack
48*7cc577a4SJonathan Peyton //  thread_data: thread data for task team thread containing stack
49*7cc577a4SJonathan Peyton //  threshold: value above which the trace statement triggers
50*7cc577a4SJonathan Peyton //  location: string identifying call site of this function (for trace)
51*7cc577a4SJonathan Peyton 
52*7cc577a4SJonathan Peyton static void
53*7cc577a4SJonathan Peyton __kmp_trace_task_stack( kmp_int32 gtid, kmp_thread_data_t *thread_data, int threshold, char *location )
54*7cc577a4SJonathan Peyton {
55*7cc577a4SJonathan Peyton     kmp_task_stack_t *task_stack = & thread_data->td.td_susp_tied_tasks;
56*7cc577a4SJonathan Peyton     kmp_taskdata_t **stack_top = task_stack -> ts_top;
57*7cc577a4SJonathan Peyton     kmp_int32 entries = task_stack -> ts_entries;
58*7cc577a4SJonathan Peyton     kmp_taskdata_t *tied_task;
59*7cc577a4SJonathan Peyton 
60*7cc577a4SJonathan Peyton     KA_TRACE(threshold, ("__kmp_trace_task_stack(start): location = %s, gtid = %d, entries = %d, "
61*7cc577a4SJonathan Peyton                          "first_block = %p, stack_top = %p \n",
62*7cc577a4SJonathan Peyton                          location, gtid, entries, task_stack->ts_first_block, stack_top ) );
63*7cc577a4SJonathan Peyton 
64*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( stack_top != NULL );
65*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( entries > 0 );
66*7cc577a4SJonathan Peyton 
67*7cc577a4SJonathan Peyton     while ( entries != 0 )
68*7cc577a4SJonathan Peyton     {
69*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( stack_top != & task_stack->ts_first_block.sb_block[0] );
70*7cc577a4SJonathan Peyton         // fix up ts_top if we need to pop from previous block
71*7cc577a4SJonathan Peyton         if ( entries & TASK_STACK_INDEX_MASK == 0 )
72*7cc577a4SJonathan Peyton         {
73*7cc577a4SJonathan Peyton             kmp_stack_block_t *stack_block = (kmp_stack_block_t *) (stack_top) ;
74*7cc577a4SJonathan Peyton 
75*7cc577a4SJonathan Peyton             stack_block = stack_block -> sb_prev;
76*7cc577a4SJonathan Peyton             stack_top = & stack_block -> sb_block[TASK_STACK_BLOCK_SIZE];
77*7cc577a4SJonathan Peyton         }
78*7cc577a4SJonathan Peyton 
79*7cc577a4SJonathan Peyton         // finish bookkeeping
80*7cc577a4SJonathan Peyton         stack_top--;
81*7cc577a4SJonathan Peyton         entries--;
82*7cc577a4SJonathan Peyton 
83*7cc577a4SJonathan Peyton         tied_task = * stack_top;
84*7cc577a4SJonathan Peyton 
85*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( tied_task != NULL );
86*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( tied_task -> td_flags.tasktype == TASK_TIED );
87*7cc577a4SJonathan Peyton 
88*7cc577a4SJonathan Peyton         KA_TRACE(threshold, ("__kmp_trace_task_stack(%s):             gtid=%d, entry=%d, "
89*7cc577a4SJonathan Peyton                              "stack_top=%p, tied_task=%p\n",
90*7cc577a4SJonathan Peyton                              location, gtid, entries, stack_top, tied_task ) );
91*7cc577a4SJonathan Peyton     }
92*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( stack_top == & task_stack->ts_first_block.sb_block[0] );
93*7cc577a4SJonathan Peyton 
94*7cc577a4SJonathan Peyton     KA_TRACE(threshold, ("__kmp_trace_task_stack(exit): location = %s, gtid = %d\n",
95*7cc577a4SJonathan Peyton                          location, gtid ) );
96*7cc577a4SJonathan Peyton }
97*7cc577a4SJonathan Peyton 
98*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------
99*7cc577a4SJonathan Peyton //  __kmp_init_task_stack: initialize the task stack for the first time
100*7cc577a4SJonathan Peyton //    after a thread_data structure is created.
101*7cc577a4SJonathan Peyton //    It should not be necessary to do this again (assuming the stack works).
102*7cc577a4SJonathan Peyton //
103*7cc577a4SJonathan Peyton //  gtid: global thread identifier of calling thread
104*7cc577a4SJonathan Peyton //  thread_data: thread data for task team thread containing stack
105*7cc577a4SJonathan Peyton 
106*7cc577a4SJonathan Peyton static void
107*7cc577a4SJonathan Peyton __kmp_init_task_stack( kmp_int32 gtid, kmp_thread_data_t *thread_data )
108*7cc577a4SJonathan Peyton {
109*7cc577a4SJonathan Peyton     kmp_task_stack_t *task_stack = & thread_data->td.td_susp_tied_tasks;
110*7cc577a4SJonathan Peyton     kmp_stack_block_t *first_block;
111*7cc577a4SJonathan Peyton 
112*7cc577a4SJonathan Peyton     // set up the first block of the stack
113*7cc577a4SJonathan Peyton     first_block = & task_stack -> ts_first_block;
114*7cc577a4SJonathan Peyton     task_stack -> ts_top = (kmp_taskdata_t **) first_block;
115*7cc577a4SJonathan Peyton     memset( (void *) first_block, '\0', TASK_STACK_BLOCK_SIZE * sizeof(kmp_taskdata_t *));
116*7cc577a4SJonathan Peyton 
117*7cc577a4SJonathan Peyton     // initialize the stack to be empty
118*7cc577a4SJonathan Peyton     task_stack  -> ts_entries = TASK_STACK_EMPTY;
119*7cc577a4SJonathan Peyton     first_block -> sb_next = NULL;
120*7cc577a4SJonathan Peyton     first_block -> sb_prev = NULL;
121*7cc577a4SJonathan Peyton }
122*7cc577a4SJonathan Peyton 
123*7cc577a4SJonathan Peyton 
124*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------
125*7cc577a4SJonathan Peyton //  __kmp_free_task_stack: free the task stack when thread_data is destroyed.
126*7cc577a4SJonathan Peyton //
127*7cc577a4SJonathan Peyton //  gtid: global thread identifier for calling thread
128*7cc577a4SJonathan Peyton //  thread_data: thread info for thread containing stack
129*7cc577a4SJonathan Peyton 
130*7cc577a4SJonathan Peyton static void
131*7cc577a4SJonathan Peyton __kmp_free_task_stack( kmp_int32 gtid, kmp_thread_data_t *thread_data )
132*7cc577a4SJonathan Peyton {
133*7cc577a4SJonathan Peyton     kmp_task_stack_t *task_stack = & thread_data->td.td_susp_tied_tasks;
134*7cc577a4SJonathan Peyton     kmp_stack_block_t *stack_block = & task_stack -> ts_first_block;
135*7cc577a4SJonathan Peyton 
136*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_stack -> ts_entries == TASK_STACK_EMPTY );
137*7cc577a4SJonathan Peyton     // free from the second block of the stack
138*7cc577a4SJonathan Peyton     while ( stack_block != NULL ) {
139*7cc577a4SJonathan Peyton         kmp_stack_block_t *next_block = (stack_block) ? stack_block -> sb_next : NULL;
140*7cc577a4SJonathan Peyton 
141*7cc577a4SJonathan Peyton         stack_block -> sb_next = NULL;
142*7cc577a4SJonathan Peyton         stack_block -> sb_prev = NULL;
143*7cc577a4SJonathan Peyton         if (stack_block != & task_stack -> ts_first_block) {
144*7cc577a4SJonathan Peyton             __kmp_thread_free( thread, stack_block );  // free the block, if not the first
145*7cc577a4SJonathan Peyton         }
146*7cc577a4SJonathan Peyton         stack_block = next_block;
147*7cc577a4SJonathan Peyton     }
148*7cc577a4SJonathan Peyton     // initialize the stack to be empty
149*7cc577a4SJonathan Peyton     task_stack -> ts_entries = 0;
150*7cc577a4SJonathan Peyton     task_stack -> ts_top = NULL;
151*7cc577a4SJonathan Peyton }
152*7cc577a4SJonathan Peyton 
153*7cc577a4SJonathan Peyton 
154*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------
155*7cc577a4SJonathan Peyton //  __kmp_push_task_stack: Push the tied task onto the task stack.
156*7cc577a4SJonathan Peyton //     Grow the stack if necessary by allocating another block.
157*7cc577a4SJonathan Peyton //
158*7cc577a4SJonathan Peyton //  gtid: global thread identifier for calling thread
159*7cc577a4SJonathan Peyton //  thread: thread info for thread containing stack
160*7cc577a4SJonathan Peyton //  tied_task: the task to push on the stack
161*7cc577a4SJonathan Peyton 
162*7cc577a4SJonathan Peyton static void
163*7cc577a4SJonathan Peyton __kmp_push_task_stack( kmp_int32 gtid, kmp_info_t *thread, kmp_taskdata_t * tied_task )
164*7cc577a4SJonathan Peyton {
165*7cc577a4SJonathan Peyton     // GEH - need to consider what to do if tt_threads_data not allocated yet
166*7cc577a4SJonathan Peyton     kmp_thread_data_t *thread_data = & thread -> th.th_task_team ->
167*7cc577a4SJonathan Peyton                                         tt.tt_threads_data[ __kmp_tid_from_gtid( gtid ) ];
168*7cc577a4SJonathan Peyton     kmp_task_stack_t *task_stack = & thread_data->td.td_susp_tied_tasks ;
169*7cc577a4SJonathan Peyton 
170*7cc577a4SJonathan Peyton     if ( tied_task->td_flags.team_serial || tied_task->td_flags.tasking_ser ) {
171*7cc577a4SJonathan Peyton         return;  // Don't push anything on stack if team or team tasks are serialized
172*7cc577a4SJonathan Peyton     }
173*7cc577a4SJonathan Peyton 
174*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( tied_task -> td_flags.tasktype == TASK_TIED );
175*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_stack -> ts_top != NULL );
176*7cc577a4SJonathan Peyton 
177*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_push_task_stack(enter): GTID: %d; THREAD: %p; TASK: %p\n",
178*7cc577a4SJonathan Peyton                   gtid, thread, tied_task ) );
179*7cc577a4SJonathan Peyton     // Store entry
180*7cc577a4SJonathan Peyton     * (task_stack -> ts_top) = tied_task;
181*7cc577a4SJonathan Peyton 
182*7cc577a4SJonathan Peyton     // Do bookkeeping for next push
183*7cc577a4SJonathan Peyton     task_stack -> ts_top++;
184*7cc577a4SJonathan Peyton     task_stack -> ts_entries++;
185*7cc577a4SJonathan Peyton 
186*7cc577a4SJonathan Peyton     if ( task_stack -> ts_entries & TASK_STACK_INDEX_MASK == 0 )
187*7cc577a4SJonathan Peyton     {
188*7cc577a4SJonathan Peyton         // Find beginning of this task block
189*7cc577a4SJonathan Peyton         kmp_stack_block_t *stack_block =
190*7cc577a4SJonathan Peyton              (kmp_stack_block_t *) (task_stack -> ts_top - TASK_STACK_BLOCK_SIZE);
191*7cc577a4SJonathan Peyton 
192*7cc577a4SJonathan Peyton         // Check if we already have a block
193*7cc577a4SJonathan Peyton         if ( stack_block -> sb_next != NULL )
194*7cc577a4SJonathan Peyton         {    // reset ts_top to beginning of next block
195*7cc577a4SJonathan Peyton             task_stack -> ts_top = & stack_block -> sb_next -> sb_block[0];
196*7cc577a4SJonathan Peyton         }
197*7cc577a4SJonathan Peyton         else
198*7cc577a4SJonathan Peyton         {   // Alloc new block and link it up
199*7cc577a4SJonathan Peyton             kmp_stack_block_t *new_block = (kmp_stack_block_t *)
200*7cc577a4SJonathan Peyton               __kmp_thread_calloc(thread, sizeof(kmp_stack_block_t));
201*7cc577a4SJonathan Peyton 
202*7cc577a4SJonathan Peyton             task_stack -> ts_top  = & new_block -> sb_block[0];
203*7cc577a4SJonathan Peyton             stack_block -> sb_next = new_block;
204*7cc577a4SJonathan Peyton             new_block  -> sb_prev = stack_block;
205*7cc577a4SJonathan Peyton             new_block  -> sb_next = NULL;
206*7cc577a4SJonathan Peyton 
207*7cc577a4SJonathan Peyton             KA_TRACE(30, ("__kmp_push_task_stack(): GTID: %d; TASK: %p; Alloc new block: %p\n",
208*7cc577a4SJonathan Peyton                           gtid, tied_task, new_block ) );
209*7cc577a4SJonathan Peyton         }
210*7cc577a4SJonathan Peyton     }
211*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_push_task_stack(exit): GTID: %d; TASK: %p\n", gtid, tied_task ) );
212*7cc577a4SJonathan Peyton }
213*7cc577a4SJonathan Peyton 
214*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------
215*7cc577a4SJonathan Peyton //  __kmp_pop_task_stack: Pop the tied task from the task stack.  Don't return
216*7cc577a4SJonathan Peyton //     the task, just check to make sure it matches the ending task passed in.
217*7cc577a4SJonathan Peyton //
218*7cc577a4SJonathan Peyton //  gtid: global thread identifier for the calling thread
219*7cc577a4SJonathan Peyton //  thread: thread info structure containing stack
220*7cc577a4SJonathan Peyton //  tied_task: the task popped off the stack
221*7cc577a4SJonathan Peyton //  ending_task: the task that is ending (should match popped task)
222*7cc577a4SJonathan Peyton 
223*7cc577a4SJonathan Peyton static void
224*7cc577a4SJonathan Peyton __kmp_pop_task_stack( kmp_int32 gtid, kmp_info_t *thread, kmp_taskdata_t *ending_task )
225*7cc577a4SJonathan Peyton {
226*7cc577a4SJonathan Peyton     // GEH - need to consider what to do if tt_threads_data not allocated yet
227*7cc577a4SJonathan Peyton     kmp_thread_data_t *thread_data = & thread -> th.th_task_team -> tt_threads_data[ __kmp_tid_from_gtid( gtid ) ];
228*7cc577a4SJonathan Peyton     kmp_task_stack_t *task_stack = & thread_data->td.td_susp_tied_tasks ;
229*7cc577a4SJonathan Peyton     kmp_taskdata_t *tied_task;
230*7cc577a4SJonathan Peyton 
231*7cc577a4SJonathan Peyton     if ( ending_task->td_flags.team_serial || ending_task->td_flags.tasking_ser ) {
232*7cc577a4SJonathan Peyton         return;  // Don't pop anything from stack if team or team tasks are serialized
233*7cc577a4SJonathan Peyton     }
234*7cc577a4SJonathan Peyton 
235*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_stack -> ts_top != NULL );
236*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_stack -> ts_entries > 0 );
237*7cc577a4SJonathan Peyton 
238*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_pop_task_stack(enter): GTID: %d; THREAD: %p\n", gtid, thread ) );
239*7cc577a4SJonathan Peyton 
240*7cc577a4SJonathan Peyton     // fix up ts_top if we need to pop from previous block
241*7cc577a4SJonathan Peyton     if ( task_stack -> ts_entries & TASK_STACK_INDEX_MASK == 0 )
242*7cc577a4SJonathan Peyton     {
243*7cc577a4SJonathan Peyton         kmp_stack_block_t *stack_block =
244*7cc577a4SJonathan Peyton            (kmp_stack_block_t *) (task_stack -> ts_top) ;
245*7cc577a4SJonathan Peyton 
246*7cc577a4SJonathan Peyton         stack_block = stack_block -> sb_prev;
247*7cc577a4SJonathan Peyton         task_stack -> ts_top = & stack_block -> sb_block[TASK_STACK_BLOCK_SIZE];
248*7cc577a4SJonathan Peyton     }
249*7cc577a4SJonathan Peyton 
250*7cc577a4SJonathan Peyton     // finish bookkeeping
251*7cc577a4SJonathan Peyton     task_stack -> ts_top--;
252*7cc577a4SJonathan Peyton     task_stack -> ts_entries--;
253*7cc577a4SJonathan Peyton 
254*7cc577a4SJonathan Peyton     tied_task = * (task_stack -> ts_top );
255*7cc577a4SJonathan Peyton 
256*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( tied_task != NULL );
257*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( tied_task -> td_flags.tasktype == TASK_TIED );
258*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( tied_task == ending_task );  // If we built the stack correctly
259*7cc577a4SJonathan Peyton 
260*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_pop_task_stack(exit): GTID: %d; TASK: %p\n", gtid, tied_task ) );
261*7cc577a4SJonathan Peyton     return;
262*7cc577a4SJonathan Peyton }
263*7cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */
264*7cc577a4SJonathan Peyton 
265*7cc577a4SJonathan Peyton //---------------------------------------------------
266*7cc577a4SJonathan Peyton //  __kmp_push_task: Add a task to the thread's deque
267*7cc577a4SJonathan Peyton 
268*7cc577a4SJonathan Peyton static kmp_int32
269*7cc577a4SJonathan Peyton __kmp_push_task(kmp_int32 gtid, kmp_task_t * task )
270*7cc577a4SJonathan Peyton {
271*7cc577a4SJonathan Peyton     kmp_info_t *        thread = __kmp_threads[ gtid ];
272*7cc577a4SJonathan Peyton     kmp_taskdata_t *    taskdata = KMP_TASK_TO_TASKDATA(task);
273*7cc577a4SJonathan Peyton     kmp_task_team_t *   task_team = thread->th.th_task_team;
274*7cc577a4SJonathan Peyton     kmp_int32           tid = __kmp_tid_from_gtid( gtid );
275*7cc577a4SJonathan Peyton     kmp_thread_data_t * thread_data;
276*7cc577a4SJonathan Peyton 
277*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata ) );
278*7cc577a4SJonathan Peyton 
279*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.tiedness == TASK_UNTIED ) {
280*7cc577a4SJonathan Peyton         // untied task needs to increment counter so that the task structure is not freed prematurely
281*7cc577a4SJonathan Peyton         kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count);
282*7cc577a4SJonathan Peyton         KA_TRACE(20, ( "__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n",
283*7cc577a4SJonathan Peyton                        gtid, counter, taskdata ) );
284*7cc577a4SJonathan Peyton     }
285*7cc577a4SJonathan Peyton 
286*7cc577a4SJonathan Peyton     // The first check avoids building task_team thread data if serialized
287*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.task_serial ) {
288*7cc577a4SJonathan Peyton         KA_TRACE(20, ( "__kmp_push_task: T#%d team serialized; returning TASK_NOT_PUSHED for task %p\n",
289*7cc577a4SJonathan Peyton                        gtid, taskdata ) );
290*7cc577a4SJonathan Peyton         return TASK_NOT_PUSHED;
291*7cc577a4SJonathan Peyton     }
292*7cc577a4SJonathan Peyton 
293*7cc577a4SJonathan Peyton     // Now that serialized tasks have returned, we can assume that we are not in immediate exec mode
294*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
295*7cc577a4SJonathan Peyton     if ( ! KMP_TASKING_ENABLED(task_team) ) {
296*7cc577a4SJonathan Peyton          __kmp_enable_tasking( task_team, thread );
297*7cc577a4SJonathan Peyton     }
298*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( TCR_4(task_team -> tt.tt_found_tasks) == TRUE );
299*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( TCR_PTR(task_team -> tt.tt_threads_data) != NULL );
300*7cc577a4SJonathan Peyton 
301*7cc577a4SJonathan Peyton     // Find tasking deque specific to encountering thread
302*7cc577a4SJonathan Peyton     thread_data = & task_team -> tt.tt_threads_data[ tid ];
303*7cc577a4SJonathan Peyton 
304*7cc577a4SJonathan Peyton     // No lock needed since only owner can allocate
305*7cc577a4SJonathan Peyton     if (thread_data -> td.td_deque == NULL ) {
306*7cc577a4SJonathan Peyton         __kmp_alloc_task_deque( thread, thread_data );
307*7cc577a4SJonathan Peyton     }
308*7cc577a4SJonathan Peyton 
309*7cc577a4SJonathan Peyton     // Check if deque is full
310*7cc577a4SJonathan Peyton     if ( TCR_4(thread_data -> td.td_deque_ntasks) >= TASK_DEQUE_SIZE(thread_data->td) )
311*7cc577a4SJonathan Peyton     {
312*7cc577a4SJonathan Peyton         KA_TRACE(20, ( "__kmp_push_task: T#%d deque is full; returning TASK_NOT_PUSHED for task %p\n",
313*7cc577a4SJonathan Peyton                        gtid, taskdata ) );
314*7cc577a4SJonathan Peyton         return TASK_NOT_PUSHED;
315*7cc577a4SJonathan Peyton     }
316*7cc577a4SJonathan Peyton 
317*7cc577a4SJonathan Peyton     // Lock the deque for the task push operation
318*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & thread_data -> td.td_deque_lock );
319*7cc577a4SJonathan Peyton 
320*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
321*7cc577a4SJonathan Peyton     // Need to recheck as we can get a proxy task from a thread outside of OpenMP
322*7cc577a4SJonathan Peyton     if ( TCR_4(thread_data -> td.td_deque_ntasks) >= TASK_DEQUE_SIZE(thread_data->td) )
323*7cc577a4SJonathan Peyton     {
324*7cc577a4SJonathan Peyton         __kmp_release_bootstrap_lock( & thread_data -> td.td_deque_lock );
325*7cc577a4SJonathan Peyton         KA_TRACE(20, ( "__kmp_push_task: T#%d deque is full on 2nd check; returning TASK_NOT_PUSHED for task %p\n",
326*7cc577a4SJonathan Peyton                        gtid, taskdata ) );
327*7cc577a4SJonathan Peyton         return TASK_NOT_PUSHED;
328*7cc577a4SJonathan Peyton     }
329*7cc577a4SJonathan Peyton #else
330*7cc577a4SJonathan Peyton     // Must have room since no thread can add tasks but calling thread
331*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( TCR_4(thread_data -> td.td_deque_ntasks) < TASK_DEQUE_SIZE(thread_data->td) );
332*7cc577a4SJonathan Peyton #endif
333*7cc577a4SJonathan Peyton 
334*7cc577a4SJonathan Peyton     thread_data -> td.td_deque[ thread_data -> td.td_deque_tail ] = taskdata;  // Push taskdata
335*7cc577a4SJonathan Peyton     // Wrap index.
336*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_tail = ( thread_data -> td.td_deque_tail + 1 ) & TASK_DEQUE_MASK(thread_data->td);
337*7cc577a4SJonathan Peyton     TCW_4(thread_data -> td.td_deque_ntasks, TCR_4(thread_data -> td.td_deque_ntasks) + 1);             // Adjust task count
338*7cc577a4SJonathan Peyton 
339*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_push_task: T#%d returning TASK_SUCCESSFULLY_PUSHED: "
340*7cc577a4SJonathan Peyton           "task=%p ntasks=%d head=%u tail=%u\n",
341*7cc577a4SJonathan Peyton           gtid, taskdata, thread_data->td.td_deque_ntasks,
342*7cc577a4SJonathan Peyton           thread_data->td.td_deque_head, thread_data->td.td_deque_tail) );
343*7cc577a4SJonathan Peyton 
344*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & thread_data->td.td_deque_lock );
345*7cc577a4SJonathan Peyton 
346*7cc577a4SJonathan Peyton     return TASK_SUCCESSFULLY_PUSHED;
347*7cc577a4SJonathan Peyton }
348*7cc577a4SJonathan Peyton 
349*7cc577a4SJonathan Peyton 
350*7cc577a4SJonathan Peyton //-----------------------------------------------------------------------------------------
351*7cc577a4SJonathan Peyton // __kmp_pop_current_task_from_thread: set up current task from called thread when team ends
352*7cc577a4SJonathan Peyton // this_thr: thread structure to set current_task in.
353*7cc577a4SJonathan Peyton 
354*7cc577a4SJonathan Peyton void
355*7cc577a4SJonathan Peyton __kmp_pop_current_task_from_thread( kmp_info_t *this_thr )
356*7cc577a4SJonathan Peyton {
357*7cc577a4SJonathan Peyton     KF_TRACE( 10, ("__kmp_pop_current_task_from_thread(enter): T#%d this_thread=%p, curtask=%p, "
358*7cc577a4SJonathan Peyton                    "curtask_parent=%p\n",
359*7cc577a4SJonathan Peyton                    0, this_thr, this_thr -> th.th_current_task,
360*7cc577a4SJonathan Peyton                    this_thr -> th.th_current_task -> td_parent ) );
361*7cc577a4SJonathan Peyton 
362*7cc577a4SJonathan Peyton     this_thr -> th.th_current_task = this_thr -> th.th_current_task -> td_parent;
363*7cc577a4SJonathan Peyton 
364*7cc577a4SJonathan Peyton     KF_TRACE( 10, ("__kmp_pop_current_task_from_thread(exit): T#%d this_thread=%p, curtask=%p, "
365*7cc577a4SJonathan Peyton                    "curtask_parent=%p\n",
366*7cc577a4SJonathan Peyton                    0, this_thr, this_thr -> th.th_current_task,
367*7cc577a4SJonathan Peyton                    this_thr -> th.th_current_task -> td_parent ) );
368*7cc577a4SJonathan Peyton }
369*7cc577a4SJonathan Peyton 
370*7cc577a4SJonathan Peyton 
371*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------------------
372*7cc577a4SJonathan Peyton // __kmp_push_current_task_to_thread: set up current task in called thread for a new team
373*7cc577a4SJonathan Peyton // this_thr: thread structure to set up
374*7cc577a4SJonathan Peyton // team: team for implicit task data
375*7cc577a4SJonathan Peyton // tid: thread within team to set up
376*7cc577a4SJonathan Peyton 
377*7cc577a4SJonathan Peyton void
378*7cc577a4SJonathan Peyton __kmp_push_current_task_to_thread( kmp_info_t *this_thr, kmp_team_t *team, int tid )
379*7cc577a4SJonathan Peyton {
380*7cc577a4SJonathan Peyton     // current task of the thread is a parent of the new just created implicit tasks of new team
381*7cc577a4SJonathan Peyton     KF_TRACE( 10, ( "__kmp_push_current_task_to_thread(enter): T#%d this_thread=%p curtask=%p "
382*7cc577a4SJonathan Peyton                     "parent_task=%p\n",
383*7cc577a4SJonathan Peyton                     tid, this_thr, this_thr->th.th_current_task,
384*7cc577a4SJonathan Peyton                     team->t.t_implicit_task_taskdata[tid].td_parent ) );
385*7cc577a4SJonathan Peyton 
386*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT (this_thr != NULL);
387*7cc577a4SJonathan Peyton 
388*7cc577a4SJonathan Peyton     if( tid == 0 ) {
389*7cc577a4SJonathan Peyton         if( this_thr->th.th_current_task != & team -> t.t_implicit_task_taskdata[ 0 ] ) {
390*7cc577a4SJonathan Peyton             team -> t.t_implicit_task_taskdata[ 0 ].td_parent = this_thr->th.th_current_task;
391*7cc577a4SJonathan Peyton             this_thr->th.th_current_task = & team -> t.t_implicit_task_taskdata[ 0 ];
392*7cc577a4SJonathan Peyton         }
393*7cc577a4SJonathan Peyton     } else {
394*7cc577a4SJonathan Peyton         team -> t.t_implicit_task_taskdata[ tid ].td_parent = team -> t.t_implicit_task_taskdata[ 0 ].td_parent;
395*7cc577a4SJonathan Peyton         this_thr->th.th_current_task = & team -> t.t_implicit_task_taskdata[ tid ];
396*7cc577a4SJonathan Peyton     }
397*7cc577a4SJonathan Peyton 
398*7cc577a4SJonathan Peyton     KF_TRACE( 10, ( "__kmp_push_current_task_to_thread(exit): T#%d this_thread=%p curtask=%p "
399*7cc577a4SJonathan Peyton                     "parent_task=%p\n",
400*7cc577a4SJonathan Peyton                     tid, this_thr, this_thr->th.th_current_task,
401*7cc577a4SJonathan Peyton                     team->t.t_implicit_task_taskdata[tid].td_parent ) );
402*7cc577a4SJonathan Peyton }
403*7cc577a4SJonathan Peyton 
404*7cc577a4SJonathan Peyton 
405*7cc577a4SJonathan Peyton //----------------------------------------------------------------------
406*7cc577a4SJonathan Peyton // __kmp_task_start: bookkeeping for a task starting execution
407*7cc577a4SJonathan Peyton // GTID: global thread id of calling thread
408*7cc577a4SJonathan Peyton // task: task starting execution
409*7cc577a4SJonathan Peyton // current_task: task suspending
410*7cc577a4SJonathan Peyton 
411*7cc577a4SJonathan Peyton static void
412*7cc577a4SJonathan Peyton __kmp_task_start( kmp_int32 gtid, kmp_task_t * task, kmp_taskdata_t * current_task )
413*7cc577a4SJonathan Peyton {
414*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(task);
415*7cc577a4SJonathan Peyton     kmp_info_t * thread = __kmp_threads[ gtid ];
416*7cc577a4SJonathan Peyton 
417*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_task_start(enter): T#%d starting task %p: current_task=%p\n",
418*7cc577a4SJonathan Peyton                   gtid, taskdata, current_task) );
419*7cc577a4SJonathan Peyton 
420*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.tasktype == TASK_EXPLICIT );
421*7cc577a4SJonathan Peyton 
422*7cc577a4SJonathan Peyton     // mark currently executing task as suspended
423*7cc577a4SJonathan Peyton     // TODO: GEH - make sure root team implicit task is initialized properly.
424*7cc577a4SJonathan Peyton     // KMP_DEBUG_ASSERT( current_task -> td_flags.executing == 1 );
425*7cc577a4SJonathan Peyton     current_task -> td_flags.executing = 0;
426*7cc577a4SJonathan Peyton 
427*7cc577a4SJonathan Peyton     // Add task to stack if tied
428*7cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
429*7cc577a4SJonathan Peyton     if ( taskdata -> td_flags.tiedness == TASK_TIED )
430*7cc577a4SJonathan Peyton     {
431*7cc577a4SJonathan Peyton         __kmp_push_task_stack( gtid, thread, taskdata );
432*7cc577a4SJonathan Peyton     }
433*7cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */
434*7cc577a4SJonathan Peyton 
435*7cc577a4SJonathan Peyton     // mark starting task as executing and as current task
436*7cc577a4SJonathan Peyton     thread -> th.th_current_task = taskdata;
437*7cc577a4SJonathan Peyton 
438*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.started == 0 || taskdata->td_flags.tiedness == TASK_UNTIED );
439*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.executing == 0 || taskdata->td_flags.tiedness == TASK_UNTIED );
440*7cc577a4SJonathan Peyton     taskdata -> td_flags.started = 1;
441*7cc577a4SJonathan Peyton     taskdata -> td_flags.executing = 1;
442*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.complete == 0 );
443*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.freed == 0 );
444*7cc577a4SJonathan Peyton 
445*7cc577a4SJonathan Peyton     // GEH TODO: shouldn't we pass some sort of location identifier here?
446*7cc577a4SJonathan Peyton     // APT: yes, we will pass location here.
447*7cc577a4SJonathan Peyton     // need to store current thread state (in a thread or taskdata structure)
448*7cc577a4SJonathan Peyton     // before setting work_state, otherwise wrong state is set after end of task
449*7cc577a4SJonathan Peyton 
450*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_task_start(exit): T#%d task=%p\n",
451*7cc577a4SJonathan Peyton                   gtid, taskdata ) );
452*7cc577a4SJonathan Peyton 
453*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
454*7cc577a4SJonathan Peyton     if (ompt_enabled &&
455*7cc577a4SJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_task_begin)) {
456*7cc577a4SJonathan Peyton         kmp_taskdata_t *parent = taskdata->td_parent;
457*7cc577a4SJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_task_begin)(
458*7cc577a4SJonathan Peyton             parent ? parent->ompt_task_info.task_id : ompt_task_id_none,
459*7cc577a4SJonathan Peyton             parent ? &(parent->ompt_task_info.frame) : NULL,
460*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.task_id,
461*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.function);
462*7cc577a4SJonathan Peyton     }
463*7cc577a4SJonathan Peyton #endif
464*7cc577a4SJonathan Peyton #if OMP_40_ENABLED && OMPT_SUPPORT && OMPT_TRACE
465*7cc577a4SJonathan Peyton     /* OMPT emit all dependences if requested by the tool */
466*7cc577a4SJonathan Peyton     if (ompt_enabled && taskdata->ompt_task_info.ndeps > 0 &&
467*7cc577a4SJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_task_dependences))
468*7cc577a4SJonathan Peyton 	{
469*7cc577a4SJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_task_dependences)(
470*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.task_id,
471*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.deps,
472*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.ndeps
473*7cc577a4SJonathan Peyton         );
474*7cc577a4SJonathan Peyton 		/* We can now free the allocated memory for the dependencies */
475*7cc577a4SJonathan Peyton 		KMP_OMPT_DEPS_FREE (thread, taskdata->ompt_task_info.deps);
476*7cc577a4SJonathan Peyton         taskdata->ompt_task_info.deps = NULL;
477*7cc577a4SJonathan Peyton         taskdata->ompt_task_info.ndeps = 0;
478*7cc577a4SJonathan Peyton     }
479*7cc577a4SJonathan Peyton #endif /* OMP_40_ENABLED && OMPT_SUPPORT && OMPT_TRACE */
480*7cc577a4SJonathan Peyton 
481*7cc577a4SJonathan Peyton     return;
482*7cc577a4SJonathan Peyton }
483*7cc577a4SJonathan Peyton 
484*7cc577a4SJonathan Peyton 
485*7cc577a4SJonathan Peyton //----------------------------------------------------------------------
486*7cc577a4SJonathan Peyton // __kmpc_omp_task_begin_if0: report that a given serialized task has started execution
487*7cc577a4SJonathan Peyton // loc_ref: source location information; points to beginning of task block.
488*7cc577a4SJonathan Peyton // gtid: global thread number.
489*7cc577a4SJonathan Peyton // task: task thunk for the started task.
490*7cc577a4SJonathan Peyton 
491*7cc577a4SJonathan Peyton void
492*7cc577a4SJonathan Peyton __kmpc_omp_task_begin_if0( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * task )
493*7cc577a4SJonathan Peyton {
494*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(task);
495*7cc577a4SJonathan Peyton     kmp_taskdata_t * current_task = __kmp_threads[ gtid ] -> th.th_current_task;
496*7cc577a4SJonathan Peyton 
497*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p current_task=%p\n",
498*7cc577a4SJonathan Peyton                   gtid, loc_ref, taskdata, current_task ) );
499*7cc577a4SJonathan Peyton 
500*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.tiedness == TASK_UNTIED ) {
501*7cc577a4SJonathan Peyton         // untied task needs to increment counter so that the task structure is not freed prematurely
502*7cc577a4SJonathan Peyton         kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count);
503*7cc577a4SJonathan Peyton         KA_TRACE(20, ( "__kmpc_omp_task_begin_if0: T#%d untied_count (%d) incremented for task %p\n",
504*7cc577a4SJonathan Peyton                        gtid, counter, taskdata ) );
505*7cc577a4SJonathan Peyton     }
506*7cc577a4SJonathan Peyton 
507*7cc577a4SJonathan Peyton     taskdata -> td_flags.task_serial = 1;  // Execute this task immediately, not deferred.
508*7cc577a4SJonathan Peyton     __kmp_task_start( gtid, task, current_task );
509*7cc577a4SJonathan Peyton 
510*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_begin_if0(exit): T#%d loc=%p task=%p,\n",
511*7cc577a4SJonathan Peyton                   gtid, loc_ref, taskdata ) );
512*7cc577a4SJonathan Peyton 
513*7cc577a4SJonathan Peyton     return;
514*7cc577a4SJonathan Peyton }
515*7cc577a4SJonathan Peyton 
516*7cc577a4SJonathan Peyton #ifdef TASK_UNUSED
517*7cc577a4SJonathan Peyton //----------------------------------------------------------------------
518*7cc577a4SJonathan Peyton // __kmpc_omp_task_begin: report that a given task has started execution
519*7cc577a4SJonathan Peyton // NEVER GENERATED BY COMPILER, DEPRECATED!!!
520*7cc577a4SJonathan Peyton 
521*7cc577a4SJonathan Peyton void
522*7cc577a4SJonathan Peyton __kmpc_omp_task_begin( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * task )
523*7cc577a4SJonathan Peyton {
524*7cc577a4SJonathan Peyton     kmp_taskdata_t * current_task = __kmp_threads[ gtid ] -> th.th_current_task;
525*7cc577a4SJonathan Peyton 
526*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_begin(enter): T#%d loc=%p task=%p current_task=%p\n",
527*7cc577a4SJonathan Peyton                   gtid, loc_ref, KMP_TASK_TO_TASKDATA(task), current_task ) );
528*7cc577a4SJonathan Peyton 
529*7cc577a4SJonathan Peyton     __kmp_task_start( gtid, task, current_task );
530*7cc577a4SJonathan Peyton 
531*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_begin(exit): T#%d loc=%p task=%p,\n",
532*7cc577a4SJonathan Peyton                   gtid, loc_ref, KMP_TASK_TO_TASKDATA(task) ) );
533*7cc577a4SJonathan Peyton 
534*7cc577a4SJonathan Peyton     return;
535*7cc577a4SJonathan Peyton }
536*7cc577a4SJonathan Peyton #endif // TASK_UNUSED
537*7cc577a4SJonathan Peyton 
538*7cc577a4SJonathan Peyton 
539*7cc577a4SJonathan Peyton //-------------------------------------------------------------------------------------
540*7cc577a4SJonathan Peyton // __kmp_free_task: free the current task space and the space for shareds
541*7cc577a4SJonathan Peyton // gtid: Global thread ID of calling thread
542*7cc577a4SJonathan Peyton // taskdata: task to free
543*7cc577a4SJonathan Peyton // thread: thread data structure of caller
544*7cc577a4SJonathan Peyton 
545*7cc577a4SJonathan Peyton static void
546*7cc577a4SJonathan Peyton __kmp_free_task( kmp_int32 gtid, kmp_taskdata_t * taskdata, kmp_info_t * thread )
547*7cc577a4SJonathan Peyton {
548*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_free_task: T#%d freeing data from task %p\n",
549*7cc577a4SJonathan Peyton                   gtid, taskdata) );
550*7cc577a4SJonathan Peyton 
551*7cc577a4SJonathan Peyton     // Check to make sure all flags and counters have the correct values
552*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.tasktype == TASK_EXPLICIT );
553*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.executing == 0 );
554*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.complete == 1 );
555*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.freed == 0 );
556*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( TCR_4(taskdata->td_allocated_child_tasks) == 0  || taskdata->td_flags.task_serial == 1);
557*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( TCR_4(taskdata->td_incomplete_child_tasks) == 0 );
558*7cc577a4SJonathan Peyton 
559*7cc577a4SJonathan Peyton     taskdata->td_flags.freed = 1;
560*7cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_BEFORE(taskdata);
561*7cc577a4SJonathan Peyton     // deallocate the taskdata and shared variable blocks associated with this task
562*7cc577a4SJonathan Peyton     #if USE_FAST_MEMORY
563*7cc577a4SJonathan Peyton         __kmp_fast_free( thread, taskdata );
564*7cc577a4SJonathan Peyton     #else /* ! USE_FAST_MEMORY */
565*7cc577a4SJonathan Peyton         __kmp_thread_free( thread, taskdata );
566*7cc577a4SJonathan Peyton     #endif
567*7cc577a4SJonathan Peyton 
568*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_free_task: T#%d freed task %p\n",
569*7cc577a4SJonathan Peyton                   gtid, taskdata) );
570*7cc577a4SJonathan Peyton }
571*7cc577a4SJonathan Peyton 
572*7cc577a4SJonathan Peyton //-------------------------------------------------------------------------------------
573*7cc577a4SJonathan Peyton // __kmp_free_task_and_ancestors: free the current task and ancestors without children
574*7cc577a4SJonathan Peyton //
575*7cc577a4SJonathan Peyton // gtid: Global thread ID of calling thread
576*7cc577a4SJonathan Peyton // taskdata: task to free
577*7cc577a4SJonathan Peyton // thread: thread data structure of caller
578*7cc577a4SJonathan Peyton 
579*7cc577a4SJonathan Peyton static void
580*7cc577a4SJonathan Peyton __kmp_free_task_and_ancestors( kmp_int32 gtid, kmp_taskdata_t * taskdata, kmp_info_t * thread )
581*7cc577a4SJonathan Peyton {
582*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
583*7cc577a4SJonathan Peyton     // Proxy tasks must always be allowed to free their parents
584*7cc577a4SJonathan Peyton     // because they can be run in background even in serial mode.
585*7cc577a4SJonathan Peyton     kmp_int32 team_serial = ( taskdata->td_flags.team_serial ||
586*7cc577a4SJonathan Peyton         taskdata->td_flags.tasking_ser ) && !taskdata->td_flags.proxy;
587*7cc577a4SJonathan Peyton #else
588*7cc577a4SJonathan Peyton     kmp_int32 team_serial = taskdata->td_flags.team_serial ||
589*7cc577a4SJonathan Peyton         taskdata->td_flags.tasking_ser;
590*7cc577a4SJonathan Peyton #endif
591*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.tasktype == TASK_EXPLICIT );
592*7cc577a4SJonathan Peyton 
593*7cc577a4SJonathan Peyton     kmp_int32 children = KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata -> td_allocated_child_tasks) ) - 1;
594*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( children >= 0 );
595*7cc577a4SJonathan Peyton 
596*7cc577a4SJonathan Peyton     // Now, go up the ancestor tree to see if any ancestors can now be freed.
597*7cc577a4SJonathan Peyton     while ( children == 0 )
598*7cc577a4SJonathan Peyton     {
599*7cc577a4SJonathan Peyton         kmp_taskdata_t * parent_taskdata = taskdata -> td_parent;
600*7cc577a4SJonathan Peyton 
601*7cc577a4SJonathan Peyton         KA_TRACE(20, ("__kmp_free_task_and_ancestors(enter): T#%d task %p complete "
602*7cc577a4SJonathan Peyton                       "and freeing itself\n", gtid, taskdata) );
603*7cc577a4SJonathan Peyton 
604*7cc577a4SJonathan Peyton         // --- Deallocate my ancestor task ---
605*7cc577a4SJonathan Peyton         __kmp_free_task( gtid, taskdata, thread );
606*7cc577a4SJonathan Peyton 
607*7cc577a4SJonathan Peyton         taskdata = parent_taskdata;
608*7cc577a4SJonathan Peyton 
609*7cc577a4SJonathan Peyton         // Stop checking ancestors at implicit task
610*7cc577a4SJonathan Peyton         // instead of walking up ancestor tree to avoid premature deallocation of ancestors.
611*7cc577a4SJonathan Peyton         if ( team_serial || taskdata -> td_flags.tasktype == TASK_IMPLICIT )
612*7cc577a4SJonathan Peyton             return;
613*7cc577a4SJonathan Peyton 
614*7cc577a4SJonathan Peyton         // Predecrement simulated by "- 1" calculation
615*7cc577a4SJonathan Peyton         children = KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata -> td_allocated_child_tasks) ) - 1;
616*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( children >= 0 );
617*7cc577a4SJonathan Peyton     }
618*7cc577a4SJonathan Peyton 
619*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_free_task_and_ancestors(exit): T#%d task %p has %d children; "
620*7cc577a4SJonathan Peyton                   "not freeing it yet\n", gtid, taskdata, children) );
621*7cc577a4SJonathan Peyton }
622*7cc577a4SJonathan Peyton 
623*7cc577a4SJonathan Peyton //---------------------------------------------------------------------
624*7cc577a4SJonathan Peyton // __kmp_task_finish: bookkeeping to do when a task finishes execution
625*7cc577a4SJonathan Peyton // gtid: global thread ID for calling thread
626*7cc577a4SJonathan Peyton // task: task to be finished
627*7cc577a4SJonathan Peyton // resumed_task: task to be resumed.  (may be NULL if task is serialized)
628*7cc577a4SJonathan Peyton 
629*7cc577a4SJonathan Peyton static void
630*7cc577a4SJonathan Peyton __kmp_task_finish( kmp_int32 gtid, kmp_task_t *task, kmp_taskdata_t *resumed_task )
631*7cc577a4SJonathan Peyton {
632*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(task);
633*7cc577a4SJonathan Peyton     kmp_info_t * thread = __kmp_threads[ gtid ];
634*7cc577a4SJonathan Peyton     kmp_task_team_t * task_team = thread->th.th_task_team; // might be NULL for serial teams...
635*7cc577a4SJonathan Peyton     kmp_int32 children = 0;
636*7cc577a4SJonathan Peyton 
637*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
638*7cc577a4SJonathan Peyton     if (ompt_enabled &&
639*7cc577a4SJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_task_end)) {
640*7cc577a4SJonathan Peyton         kmp_taskdata_t *parent = taskdata->td_parent;
641*7cc577a4SJonathan Peyton         ompt_callbacks.ompt_callback(ompt_event_task_end)(
642*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.task_id);
643*7cc577a4SJonathan Peyton     }
644*7cc577a4SJonathan Peyton #endif
645*7cc577a4SJonathan Peyton 
646*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_task_finish(enter): T#%d finishing task %p and resuming task %p\n",
647*7cc577a4SJonathan Peyton                   gtid, taskdata, resumed_task) );
648*7cc577a4SJonathan Peyton 
649*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.tasktype == TASK_EXPLICIT );
650*7cc577a4SJonathan Peyton 
651*7cc577a4SJonathan Peyton     // Pop task from stack if tied
652*7cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
653*7cc577a4SJonathan Peyton     if ( taskdata -> td_flags.tiedness == TASK_TIED )
654*7cc577a4SJonathan Peyton     {
655*7cc577a4SJonathan Peyton         __kmp_pop_task_stack( gtid, thread, taskdata );
656*7cc577a4SJonathan Peyton     }
657*7cc577a4SJonathan Peyton #endif /* BUILD_TIED_TASK_STACK */
658*7cc577a4SJonathan Peyton 
659*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.tiedness == TASK_UNTIED ) {
660*7cc577a4SJonathan Peyton         // untied task needs to check the counter so that the task structure is not freed prematurely
661*7cc577a4SJonathan Peyton         kmp_int32 counter = KMP_TEST_THEN_DEC32(&taskdata->td_untied_count) - 1;
662*7cc577a4SJonathan Peyton         KA_TRACE(20, ( "__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n",
663*7cc577a4SJonathan Peyton                        gtid, counter, taskdata ) );
664*7cc577a4SJonathan Peyton         if ( counter > 0 ) {
665*7cc577a4SJonathan Peyton             // untied task is not done, to be continued possibly by other thread, do not free it now
666*7cc577a4SJonathan Peyton             if (resumed_task == NULL) {
667*7cc577a4SJonathan Peyton                 KMP_DEBUG_ASSERT( taskdata->td_flags.task_serial );
668*7cc577a4SJonathan Peyton                 resumed_task = taskdata->td_parent;  // In a serialized task, the resumed task is the parent
669*7cc577a4SJonathan Peyton             }
670*7cc577a4SJonathan Peyton             thread->th.th_current_task = resumed_task; // restore current_task
671*7cc577a4SJonathan Peyton             resumed_task->td_flags.executing = 1;  // resume previous task
672*7cc577a4SJonathan Peyton             KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, resuming task %p\n",
673*7cc577a4SJonathan Peyton                           gtid, taskdata, resumed_task) );
674*7cc577a4SJonathan Peyton             return;
675*7cc577a4SJonathan Peyton         }
676*7cc577a4SJonathan Peyton     }
677*7cc577a4SJonathan Peyton 
678*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.complete == 0 );
679*7cc577a4SJonathan Peyton     taskdata -> td_flags.complete = 1;   // mark the task as completed
680*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.started == 1 );
681*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.freed == 0 );
682*7cc577a4SJonathan Peyton 
683*7cc577a4SJonathan Peyton     // Only need to keep track of count if team parallel and tasking not serialized
684*7cc577a4SJonathan Peyton     if ( !( taskdata -> td_flags.team_serial || taskdata -> td_flags.tasking_ser ) ) {
685*7cc577a4SJonathan Peyton         // Predecrement simulated by "- 1" calculation
686*7cc577a4SJonathan Peyton         children = KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata -> td_parent -> td_incomplete_child_tasks) ) - 1;
687*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( children >= 0 );
688*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
689*7cc577a4SJonathan Peyton         if ( taskdata->td_taskgroup )
690*7cc577a4SJonathan Peyton             KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata->td_taskgroup->count) );
691*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
692*7cc577a4SJonathan Peyton     }
693*7cc577a4SJonathan Peyton     // if we found proxy tasks there could exist a dependency chain
694*7cc577a4SJonathan Peyton     // with the proxy task as origin
695*7cc577a4SJonathan Peyton     if ( !( taskdata -> td_flags.team_serial || taskdata -> td_flags.tasking_ser ) || (task_team && task_team->tt.tt_found_proxy_tasks) ) {
696*7cc577a4SJonathan Peyton #endif
697*7cc577a4SJonathan Peyton         __kmp_release_deps(gtid,taskdata);
698*7cc577a4SJonathan Peyton #endif
699*7cc577a4SJonathan Peyton     }
700*7cc577a4SJonathan Peyton 
701*7cc577a4SJonathan Peyton     // td_flags.executing  must be marked as 0 after __kmp_release_deps has been called
702*7cc577a4SJonathan Peyton     // Othertwise, if a task is executed immediately from the release_deps code
703*7cc577a4SJonathan Peyton     // the flag will be reset to 1 again by this same function
704*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.executing == 1 );
705*7cc577a4SJonathan Peyton     taskdata -> td_flags.executing = 0;  // suspend the finishing task
706*7cc577a4SJonathan Peyton 
707*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_task_finish: T#%d finished task %p, %d incomplete children\n",
708*7cc577a4SJonathan Peyton                   gtid, taskdata, children) );
709*7cc577a4SJonathan Peyton 
710*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
711*7cc577a4SJonathan Peyton     /* If the tasks' destructor thunk flag has been set, we need to invoke the
712*7cc577a4SJonathan Peyton        destructor thunk that has been generated by the compiler.
713*7cc577a4SJonathan Peyton        The code is placed here, since at this point other tasks might have been released
714*7cc577a4SJonathan Peyton        hence overlapping the destructor invokations with some other work in the
715*7cc577a4SJonathan Peyton        released tasks.  The OpenMP spec is not specific on when the destructors are
716*7cc577a4SJonathan Peyton        invoked, so we should be free to choose.
717*7cc577a4SJonathan Peyton     */
718*7cc577a4SJonathan Peyton     if (taskdata->td_flags.destructors_thunk) {
719*7cc577a4SJonathan Peyton         kmp_routine_entry_t destr_thunk = task->data1.destructors;
720*7cc577a4SJonathan Peyton         KMP_ASSERT(destr_thunk);
721*7cc577a4SJonathan Peyton         destr_thunk(gtid, task);
722*7cc577a4SJonathan Peyton     }
723*7cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
724*7cc577a4SJonathan Peyton 
725*7cc577a4SJonathan Peyton     // bookkeeping for resuming task:
726*7cc577a4SJonathan Peyton     // GEH - note tasking_ser => task_serial
727*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( (taskdata->td_flags.tasking_ser || taskdata->td_flags.task_serial) ==
728*7cc577a4SJonathan Peyton                        taskdata->td_flags.task_serial);
729*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.task_serial )
730*7cc577a4SJonathan Peyton     {
731*7cc577a4SJonathan Peyton         if (resumed_task == NULL) {
732*7cc577a4SJonathan Peyton             resumed_task = taskdata->td_parent;  // In a serialized task, the resumed task is the parent
733*7cc577a4SJonathan Peyton         }
734*7cc577a4SJonathan Peyton         else
735*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
736*7cc577a4SJonathan Peyton              if ( !(task_team && task_team->tt.tt_found_proxy_tasks) )
737*7cc577a4SJonathan Peyton #endif
738*7cc577a4SJonathan Peyton         {
739*7cc577a4SJonathan Peyton             // verify resumed task passed in points to parent
740*7cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT( resumed_task == taskdata->td_parent );
741*7cc577a4SJonathan Peyton         }
742*7cc577a4SJonathan Peyton     }
743*7cc577a4SJonathan Peyton     else {
744*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( resumed_task != NULL );        // verify that resumed task is passed as arguemnt
745*7cc577a4SJonathan Peyton     }
746*7cc577a4SJonathan Peyton 
747*7cc577a4SJonathan Peyton     // Free this task and then ancestor tasks if they have no children.
748*7cc577a4SJonathan Peyton     // Restore th_current_task first as suggested by John:
749*7cc577a4SJonathan Peyton     // johnmc: if an asynchronous inquiry peers into the runtime system
750*7cc577a4SJonathan Peyton     // it doesn't see the freed task as the current task.
751*7cc577a4SJonathan Peyton     thread->th.th_current_task = resumed_task;
752*7cc577a4SJonathan Peyton     __kmp_free_task_and_ancestors(gtid, taskdata, thread);
753*7cc577a4SJonathan Peyton 
754*7cc577a4SJonathan Peyton     // TODO: GEH - make sure root team implicit task is initialized properly.
755*7cc577a4SJonathan Peyton     // KMP_DEBUG_ASSERT( resumed_task->td_flags.executing == 0 );
756*7cc577a4SJonathan Peyton     resumed_task->td_flags.executing = 1;  // resume previous task
757*7cc577a4SJonathan Peyton 
758*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_task_finish(exit): T#%d finished task %p, resuming task %p\n",
759*7cc577a4SJonathan Peyton                   gtid, taskdata, resumed_task) );
760*7cc577a4SJonathan Peyton 
761*7cc577a4SJonathan Peyton     return;
762*7cc577a4SJonathan Peyton }
763*7cc577a4SJonathan Peyton 
764*7cc577a4SJonathan Peyton //---------------------------------------------------------------------
765*7cc577a4SJonathan Peyton // __kmpc_omp_task_complete_if0: report that a task has completed execution
766*7cc577a4SJonathan Peyton // loc_ref: source location information; points to end of task block.
767*7cc577a4SJonathan Peyton // gtid: global thread number.
768*7cc577a4SJonathan Peyton // task: task thunk for the completed task.
769*7cc577a4SJonathan Peyton 
770*7cc577a4SJonathan Peyton void
771*7cc577a4SJonathan Peyton __kmpc_omp_task_complete_if0( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task )
772*7cc577a4SJonathan Peyton {
773*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_complete_if0(enter): T#%d loc=%p task=%p\n",
774*7cc577a4SJonathan Peyton                   gtid, loc_ref, KMP_TASK_TO_TASKDATA(task) ) );
775*7cc577a4SJonathan Peyton 
776*7cc577a4SJonathan Peyton     __kmp_task_finish( gtid, task, NULL );  // this routine will provide task to resume
777*7cc577a4SJonathan Peyton 
778*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_complete_if0(exit): T#%d loc=%p task=%p\n",
779*7cc577a4SJonathan Peyton                   gtid, loc_ref, KMP_TASK_TO_TASKDATA(task) ) );
780*7cc577a4SJonathan Peyton 
781*7cc577a4SJonathan Peyton     return;
782*7cc577a4SJonathan Peyton }
783*7cc577a4SJonathan Peyton 
784*7cc577a4SJonathan Peyton #ifdef TASK_UNUSED
785*7cc577a4SJonathan Peyton //---------------------------------------------------------------------
786*7cc577a4SJonathan Peyton // __kmpc_omp_task_complete: report that a task has completed execution
787*7cc577a4SJonathan Peyton // NEVER GENERATED BY COMPILER, DEPRECATED!!!
788*7cc577a4SJonathan Peyton 
789*7cc577a4SJonathan Peyton void
790*7cc577a4SJonathan Peyton __kmpc_omp_task_complete( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t *task )
791*7cc577a4SJonathan Peyton {
792*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_complete(enter): T#%d loc=%p task=%p\n",
793*7cc577a4SJonathan Peyton                   gtid, loc_ref, KMP_TASK_TO_TASKDATA(task) ) );
794*7cc577a4SJonathan Peyton 
795*7cc577a4SJonathan Peyton     __kmp_task_finish( gtid, task, NULL );  // Not sure how to find task to resume
796*7cc577a4SJonathan Peyton 
797*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_complete(exit): T#%d loc=%p task=%p\n",
798*7cc577a4SJonathan Peyton                   gtid, loc_ref, KMP_TASK_TO_TASKDATA(task) ) );
799*7cc577a4SJonathan Peyton     return;
800*7cc577a4SJonathan Peyton }
801*7cc577a4SJonathan Peyton #endif // TASK_UNUSED
802*7cc577a4SJonathan Peyton 
803*7cc577a4SJonathan Peyton 
804*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
805*7cc577a4SJonathan Peyton //----------------------------------------------------------------------------------------------------
806*7cc577a4SJonathan Peyton // __kmp_task_init_ompt:
807*7cc577a4SJonathan Peyton //   Initialize OMPT fields maintained by a task. This will only be called after
808*7cc577a4SJonathan Peyton //   ompt_tool, so we already know whether ompt is enabled or not.
809*7cc577a4SJonathan Peyton 
810*7cc577a4SJonathan Peyton static inline void
811*7cc577a4SJonathan Peyton __kmp_task_init_ompt( kmp_taskdata_t * task, int tid, void * function )
812*7cc577a4SJonathan Peyton {
813*7cc577a4SJonathan Peyton     if (ompt_enabled) {
814*7cc577a4SJonathan Peyton         task->ompt_task_info.task_id = __ompt_task_id_new(tid);
815*7cc577a4SJonathan Peyton         task->ompt_task_info.function = function;
816*7cc577a4SJonathan Peyton         task->ompt_task_info.frame.exit_runtime_frame = NULL;
817*7cc577a4SJonathan Peyton         task->ompt_task_info.frame.reenter_runtime_frame = NULL;
818*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
819*7cc577a4SJonathan Peyton         task->ompt_task_info.ndeps = 0;
820*7cc577a4SJonathan Peyton         task->ompt_task_info.deps = NULL;
821*7cc577a4SJonathan Peyton #endif /* OMP_40_ENABLED */
822*7cc577a4SJonathan Peyton     }
823*7cc577a4SJonathan Peyton }
824*7cc577a4SJonathan Peyton #endif
825*7cc577a4SJonathan Peyton 
826*7cc577a4SJonathan Peyton 
827*7cc577a4SJonathan Peyton //----------------------------------------------------------------------------------------------------
828*7cc577a4SJonathan Peyton // __kmp_init_implicit_task: Initialize the appropriate fields in the implicit task for a given thread
829*7cc577a4SJonathan Peyton //
830*7cc577a4SJonathan Peyton // loc_ref:  reference to source location of parallel region
831*7cc577a4SJonathan Peyton // this_thr:  thread data structure corresponding to implicit task
832*7cc577a4SJonathan Peyton // team: team for this_thr
833*7cc577a4SJonathan Peyton // tid: thread id of given thread within team
834*7cc577a4SJonathan Peyton // set_curr_task: TRUE if need to push current task to thread
835*7cc577a4SJonathan Peyton // NOTE: Routine does not set up the implicit task ICVS.  This is assumed to have already been done elsewhere.
836*7cc577a4SJonathan Peyton // TODO: Get better loc_ref.  Value passed in may be NULL
837*7cc577a4SJonathan Peyton 
838*7cc577a4SJonathan Peyton void
839*7cc577a4SJonathan Peyton __kmp_init_implicit_task( ident_t *loc_ref, kmp_info_t *this_thr, kmp_team_t *team, int tid, int set_curr_task )
840*7cc577a4SJonathan Peyton {
841*7cc577a4SJonathan Peyton     kmp_taskdata_t * task   = & team->t.t_implicit_task_taskdata[ tid ];
842*7cc577a4SJonathan Peyton 
843*7cc577a4SJonathan Peyton     KF_TRACE(10, ("__kmp_init_implicit_task(enter): T#:%d team=%p task=%p, reinit=%s\n",
844*7cc577a4SJonathan Peyton                   tid, team, task, set_curr_task ? "TRUE" : "FALSE" ) );
845*7cc577a4SJonathan Peyton 
846*7cc577a4SJonathan Peyton     task->td_task_id  = KMP_GEN_TASK_ID();
847*7cc577a4SJonathan Peyton     task->td_team     = team;
848*7cc577a4SJonathan Peyton //    task->td_parent   = NULL;  // fix for CQ230101 (broken parent task info in debugger)
849*7cc577a4SJonathan Peyton     task->td_ident    = loc_ref;
850*7cc577a4SJonathan Peyton     task->td_taskwait_ident   = NULL;
851*7cc577a4SJonathan Peyton     task->td_taskwait_counter = 0;
852*7cc577a4SJonathan Peyton     task->td_taskwait_thread  = 0;
853*7cc577a4SJonathan Peyton 
854*7cc577a4SJonathan Peyton     task->td_flags.tiedness    = TASK_TIED;
855*7cc577a4SJonathan Peyton     task->td_flags.tasktype    = TASK_IMPLICIT;
856*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
857*7cc577a4SJonathan Peyton     task->td_flags.proxy       = TASK_FULL;
858*7cc577a4SJonathan Peyton #endif
859*7cc577a4SJonathan Peyton 
860*7cc577a4SJonathan Peyton     // All implicit tasks are executed immediately, not deferred
861*7cc577a4SJonathan Peyton     task->td_flags.task_serial = 1;
862*7cc577a4SJonathan Peyton     task->td_flags.tasking_ser = ( __kmp_tasking_mode == tskm_immediate_exec );
863*7cc577a4SJonathan Peyton     task->td_flags.team_serial = ( team->t.t_serialized ) ? 1 : 0;
864*7cc577a4SJonathan Peyton 
865*7cc577a4SJonathan Peyton     task->td_flags.started     = 1;
866*7cc577a4SJonathan Peyton     task->td_flags.executing   = 1;
867*7cc577a4SJonathan Peyton     task->td_flags.complete    = 0;
868*7cc577a4SJonathan Peyton     task->td_flags.freed       = 0;
869*7cc577a4SJonathan Peyton 
870*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
871*7cc577a4SJonathan Peyton     task->td_depnode = NULL;
872*7cc577a4SJonathan Peyton #endif
873*7cc577a4SJonathan Peyton 
874*7cc577a4SJonathan Peyton     if (set_curr_task) {  // only do this initialization the first time a thread is created
875*7cc577a4SJonathan Peyton         task->td_incomplete_child_tasks = 0;
876*7cc577a4SJonathan Peyton         task->td_allocated_child_tasks  = 0; // Not used because do not need to deallocate implicit task
877*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
878*7cc577a4SJonathan Peyton         task->td_taskgroup = NULL;           // An implicit task does not have taskgroup
879*7cc577a4SJonathan Peyton         task->td_dephash = NULL;
880*7cc577a4SJonathan Peyton #endif
881*7cc577a4SJonathan Peyton         __kmp_push_current_task_to_thread( this_thr, team, tid );
882*7cc577a4SJonathan Peyton     } else {
883*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(task->td_incomplete_child_tasks == 0);
884*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT(task->td_allocated_child_tasks  == 0);
885*7cc577a4SJonathan Peyton     }
886*7cc577a4SJonathan Peyton 
887*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
888*7cc577a4SJonathan Peyton     __kmp_task_init_ompt(task, tid, NULL);
889*7cc577a4SJonathan Peyton #endif
890*7cc577a4SJonathan Peyton 
891*7cc577a4SJonathan Peyton     KF_TRACE(10, ("__kmp_init_implicit_task(exit): T#:%d team=%p task=%p\n",
892*7cc577a4SJonathan Peyton                   tid, team, task ) );
893*7cc577a4SJonathan Peyton }
894*7cc577a4SJonathan Peyton 
895*7cc577a4SJonathan Peyton 
896*7cc577a4SJonathan Peyton //-----------------------------------------------------------------------------
897*7cc577a4SJonathan Peyton //// __kmp_finish_implicit_task: Release resources associated to implicit tasks
898*7cc577a4SJonathan Peyton //// at the end of parallel regions. Some resources are kept for reuse in the
899*7cc577a4SJonathan Peyton //// next parallel region.
900*7cc577a4SJonathan Peyton ////
901*7cc577a4SJonathan Peyton //// thread:  thread data structure corresponding to implicit task
902*7cc577a4SJonathan Peyton //
903*7cc577a4SJonathan Peyton void
904*7cc577a4SJonathan Peyton __kmp_finish_implicit_task(kmp_info_t *thread)
905*7cc577a4SJonathan Peyton {
906*7cc577a4SJonathan Peyton     kmp_taskdata_t *task = thread->th.th_current_task;
907*7cc577a4SJonathan Peyton     if (task->td_dephash)
908*7cc577a4SJonathan Peyton         __kmp_dephash_free_entries(thread, task->td_dephash);
909*7cc577a4SJonathan Peyton }
910*7cc577a4SJonathan Peyton 
911*7cc577a4SJonathan Peyton 
912*7cc577a4SJonathan Peyton //-----------------------------------------------------------------------------
913*7cc577a4SJonathan Peyton //// __kmp_free_implicit_task: Release resources associated to implicit tasks
914*7cc577a4SJonathan Peyton //// when these are destroyed regions
915*7cc577a4SJonathan Peyton ////
916*7cc577a4SJonathan Peyton //// thread:  thread data structure corresponding to implicit task
917*7cc577a4SJonathan Peyton //
918*7cc577a4SJonathan Peyton void
919*7cc577a4SJonathan Peyton __kmp_free_implicit_task(kmp_info_t *thread)
920*7cc577a4SJonathan Peyton {
921*7cc577a4SJonathan Peyton     kmp_taskdata_t *task = thread->th.th_current_task;
922*7cc577a4SJonathan Peyton     if (task->td_dephash)
923*7cc577a4SJonathan Peyton         __kmp_dephash_free(thread, task->td_dephash);
924*7cc577a4SJonathan Peyton     task->td_dephash = NULL;
925*7cc577a4SJonathan Peyton }
926*7cc577a4SJonathan Peyton 
927*7cc577a4SJonathan Peyton 
928*7cc577a4SJonathan Peyton // Round up a size to a power of two specified by val
929*7cc577a4SJonathan Peyton // Used to insert padding between structures co-allocated using a single malloc() call
930*7cc577a4SJonathan Peyton static size_t
931*7cc577a4SJonathan Peyton __kmp_round_up_to_val( size_t size, size_t val ) {
932*7cc577a4SJonathan Peyton     if ( size & ( val - 1 ) ) {
933*7cc577a4SJonathan Peyton         size &= ~ ( val - 1 );
934*7cc577a4SJonathan Peyton         if ( size <= KMP_SIZE_T_MAX - val ) {
935*7cc577a4SJonathan Peyton             size += val;    // Round up if there is no overflow.
936*7cc577a4SJonathan Peyton         }; // if
937*7cc577a4SJonathan Peyton     }; // if
938*7cc577a4SJonathan Peyton     return size;
939*7cc577a4SJonathan Peyton } // __kmp_round_up_to_va
940*7cc577a4SJonathan Peyton 
941*7cc577a4SJonathan Peyton 
942*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------------
943*7cc577a4SJonathan Peyton // __kmp_task_alloc: Allocate the taskdata and task data structures for a task
944*7cc577a4SJonathan Peyton //
945*7cc577a4SJonathan Peyton // loc_ref: source location information
946*7cc577a4SJonathan Peyton // gtid: global thread number.
947*7cc577a4SJonathan Peyton // flags: include tiedness & task type (explicit vs. implicit) of the ''new'' task encountered.
948*7cc577a4SJonathan Peyton //        Converted from kmp_int32 to kmp_tasking_flags_t in routine.
949*7cc577a4SJonathan Peyton // sizeof_kmp_task_t:  Size in bytes of kmp_task_t data structure including private vars accessed in task.
950*7cc577a4SJonathan Peyton // sizeof_shareds:  Size in bytes of array of pointers to shared vars accessed in task.
951*7cc577a4SJonathan Peyton // task_entry: Pointer to task code entry point generated by compiler.
952*7cc577a4SJonathan Peyton // returns: a pointer to the allocated kmp_task_t structure (task).
953*7cc577a4SJonathan Peyton 
954*7cc577a4SJonathan Peyton kmp_task_t *
955*7cc577a4SJonathan Peyton __kmp_task_alloc( ident_t *loc_ref, kmp_int32 gtid, kmp_tasking_flags_t *flags,
956*7cc577a4SJonathan Peyton                   size_t sizeof_kmp_task_t, size_t sizeof_shareds,
957*7cc577a4SJonathan Peyton                   kmp_routine_entry_t task_entry )
958*7cc577a4SJonathan Peyton {
959*7cc577a4SJonathan Peyton     kmp_task_t *task;
960*7cc577a4SJonathan Peyton     kmp_taskdata_t *taskdata;
961*7cc577a4SJonathan Peyton     kmp_info_t *thread = __kmp_threads[ gtid ];
962*7cc577a4SJonathan Peyton     kmp_team_t *team = thread->th.th_team;
963*7cc577a4SJonathan Peyton     kmp_taskdata_t *parent_task = thread->th.th_current_task;
964*7cc577a4SJonathan Peyton     size_t shareds_offset;
965*7cc577a4SJonathan Peyton 
966*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_task_alloc(enter): T#%d loc=%p, flags=(0x%x) "
967*7cc577a4SJonathan Peyton                   "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
968*7cc577a4SJonathan Peyton                   gtid, loc_ref, *((kmp_int32 *)flags), sizeof_kmp_task_t,
969*7cc577a4SJonathan Peyton                   sizeof_shareds, task_entry) );
970*7cc577a4SJonathan Peyton 
971*7cc577a4SJonathan Peyton     if ( parent_task->td_flags.final ) {
972*7cc577a4SJonathan Peyton         if (flags->merged_if0) {
973*7cc577a4SJonathan Peyton         }
974*7cc577a4SJonathan Peyton         flags->final = 1;
975*7cc577a4SJonathan Peyton     }
976*7cc577a4SJonathan Peyton 
977*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
978*7cc577a4SJonathan Peyton     if ( flags->proxy == TASK_PROXY ) {
979*7cc577a4SJonathan Peyton         flags->tiedness = TASK_UNTIED;
980*7cc577a4SJonathan Peyton         flags->merged_if0 = 1;
981*7cc577a4SJonathan Peyton 
982*7cc577a4SJonathan Peyton         /* are we running in a sequential parallel or tskm_immediate_exec... we need tasking support enabled */
983*7cc577a4SJonathan Peyton         if ( (thread->th.th_task_team) == NULL ) {
984*7cc577a4SJonathan Peyton             /* This should only happen if the team is serialized
985*7cc577a4SJonathan Peyton                 setup a task team and propagate it to the thread
986*7cc577a4SJonathan Peyton             */
987*7cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(team->t.t_serialized);
988*7cc577a4SJonathan Peyton             KA_TRACE(30,("T#%d creating task team in __kmp_task_alloc for proxy task\n", gtid));
989*7cc577a4SJonathan Peyton             __kmp_task_team_setup(thread,team,1); // 1 indicates setup the current team regardless of nthreads
990*7cc577a4SJonathan Peyton             thread->th.th_task_team = team->t.t_task_team[thread->th.th_task_state];
991*7cc577a4SJonathan Peyton         }
992*7cc577a4SJonathan Peyton         kmp_task_team_t * task_team = thread->th.th_task_team;
993*7cc577a4SJonathan Peyton 
994*7cc577a4SJonathan Peyton         /* tasking must be enabled now as the task might not be pushed */
995*7cc577a4SJonathan Peyton         if ( !KMP_TASKING_ENABLED( task_team ) ) {
996*7cc577a4SJonathan Peyton             KA_TRACE(30,("T#%d enabling tasking in __kmp_task_alloc for proxy task\n", gtid));
997*7cc577a4SJonathan Peyton             __kmp_enable_tasking( task_team, thread );
998*7cc577a4SJonathan Peyton             kmp_int32 tid = thread->th.th_info.ds.ds_tid;
999*7cc577a4SJonathan Peyton             kmp_thread_data_t * thread_data = & task_team -> tt.tt_threads_data[ tid ];
1000*7cc577a4SJonathan Peyton             // No lock needed since only owner can allocate
1001*7cc577a4SJonathan Peyton             if (thread_data -> td.td_deque == NULL ) {
1002*7cc577a4SJonathan Peyton                 __kmp_alloc_task_deque( thread, thread_data );
1003*7cc577a4SJonathan Peyton             }
1004*7cc577a4SJonathan Peyton         }
1005*7cc577a4SJonathan Peyton 
1006*7cc577a4SJonathan Peyton         if ( task_team->tt.tt_found_proxy_tasks == FALSE )
1007*7cc577a4SJonathan Peyton           TCW_4(task_team -> tt.tt_found_proxy_tasks, TRUE);
1008*7cc577a4SJonathan Peyton     }
1009*7cc577a4SJonathan Peyton #endif
1010*7cc577a4SJonathan Peyton 
1011*7cc577a4SJonathan Peyton     // Calculate shared structure offset including padding after kmp_task_t struct
1012*7cc577a4SJonathan Peyton     // to align pointers in shared struct
1013*7cc577a4SJonathan Peyton     shareds_offset = sizeof( kmp_taskdata_t ) + sizeof_kmp_task_t;
1014*7cc577a4SJonathan Peyton     shareds_offset = __kmp_round_up_to_val( shareds_offset, sizeof( void * ));
1015*7cc577a4SJonathan Peyton 
1016*7cc577a4SJonathan Peyton     // Allocate a kmp_taskdata_t block and a kmp_task_t block.
1017*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_task_alloc: T#%d First malloc size: %ld\n",
1018*7cc577a4SJonathan Peyton                   gtid, shareds_offset) );
1019*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_task_alloc: T#%d Second malloc size: %ld\n",
1020*7cc577a4SJonathan Peyton                   gtid, sizeof_shareds) );
1021*7cc577a4SJonathan Peyton 
1022*7cc577a4SJonathan Peyton     // Avoid double allocation here by combining shareds with taskdata
1023*7cc577a4SJonathan Peyton     #if USE_FAST_MEMORY
1024*7cc577a4SJonathan Peyton     taskdata = (kmp_taskdata_t *) __kmp_fast_allocate( thread, shareds_offset + sizeof_shareds );
1025*7cc577a4SJonathan Peyton     #else /* ! USE_FAST_MEMORY */
1026*7cc577a4SJonathan Peyton     taskdata = (kmp_taskdata_t *) __kmp_thread_malloc( thread, shareds_offset + sizeof_shareds );
1027*7cc577a4SJonathan Peyton     #endif /* USE_FAST_MEMORY */
1028*7cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_AFTER(taskdata);
1029*7cc577a4SJonathan Peyton 
1030*7cc577a4SJonathan Peyton     task                      = KMP_TASKDATA_TO_TASK(taskdata);
1031*7cc577a4SJonathan Peyton 
1032*7cc577a4SJonathan Peyton     // Make sure task & taskdata are aligned appropriately
1033*7cc577a4SJonathan Peyton #if KMP_ARCH_X86 || KMP_ARCH_PPC64 || !KMP_HAVE_QUAD
1034*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( ( ((kmp_uintptr_t)taskdata) & (sizeof(double)-1) ) == 0 );
1035*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( ( ((kmp_uintptr_t)task) & (sizeof(double)-1) ) == 0 );
1036*7cc577a4SJonathan Peyton #else
1037*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( ( ((kmp_uintptr_t)taskdata) & (sizeof(_Quad)-1) ) == 0 );
1038*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( ( ((kmp_uintptr_t)task) & (sizeof(_Quad)-1) ) == 0 );
1039*7cc577a4SJonathan Peyton #endif
1040*7cc577a4SJonathan Peyton     if (sizeof_shareds > 0) {
1041*7cc577a4SJonathan Peyton         // Avoid double allocation here by combining shareds with taskdata
1042*7cc577a4SJonathan Peyton         task->shareds         = & ((char *) taskdata)[ shareds_offset ];
1043*7cc577a4SJonathan Peyton         // Make sure shareds struct is aligned to pointer size
1044*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( ( ((kmp_uintptr_t)task->shareds) & (sizeof(void *)-1) ) == 0 );
1045*7cc577a4SJonathan Peyton     } else {
1046*7cc577a4SJonathan Peyton         task->shareds         = NULL;
1047*7cc577a4SJonathan Peyton     }
1048*7cc577a4SJonathan Peyton     task->routine             = task_entry;
1049*7cc577a4SJonathan Peyton     task->part_id             = 0;      // AC: Always start with 0 part id
1050*7cc577a4SJonathan Peyton 
1051*7cc577a4SJonathan Peyton     taskdata->td_task_id      = KMP_GEN_TASK_ID();
1052*7cc577a4SJonathan Peyton     taskdata->td_team         = team;
1053*7cc577a4SJonathan Peyton     taskdata->td_alloc_thread = thread;
1054*7cc577a4SJonathan Peyton     taskdata->td_parent       = parent_task;
1055*7cc577a4SJonathan Peyton     taskdata->td_level        = parent_task->td_level + 1; // increment nesting level
1056*7cc577a4SJonathan Peyton     taskdata->td_untied_count = 0;
1057*7cc577a4SJonathan Peyton     taskdata->td_ident        = loc_ref;
1058*7cc577a4SJonathan Peyton     taskdata->td_taskwait_ident   = NULL;
1059*7cc577a4SJonathan Peyton     taskdata->td_taskwait_counter = 0;
1060*7cc577a4SJonathan Peyton     taskdata->td_taskwait_thread  = 0;
1061*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_parent != NULL );
1062*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1063*7cc577a4SJonathan Peyton     // avoid copying icvs for proxy tasks
1064*7cc577a4SJonathan Peyton     if ( flags->proxy == TASK_FULL )
1065*7cc577a4SJonathan Peyton #endif
1066*7cc577a4SJonathan Peyton        copy_icvs( &taskdata->td_icvs, &taskdata->td_parent->td_icvs );
1067*7cc577a4SJonathan Peyton 
1068*7cc577a4SJonathan Peyton     taskdata->td_flags.tiedness    = flags->tiedness;
1069*7cc577a4SJonathan Peyton     taskdata->td_flags.final       = flags->final;
1070*7cc577a4SJonathan Peyton     taskdata->td_flags.merged_if0  = flags->merged_if0;
1071*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1072*7cc577a4SJonathan Peyton     taskdata->td_flags.destructors_thunk = flags->destructors_thunk;
1073*7cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
1074*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1075*7cc577a4SJonathan Peyton     taskdata->td_flags.proxy           = flags->proxy;
1076*7cc577a4SJonathan Peyton     taskdata->td_task_team         = thread->th.th_task_team;
1077*7cc577a4SJonathan Peyton     taskdata->td_size_alloc        = shareds_offset + sizeof_shareds;
1078*7cc577a4SJonathan Peyton #endif
1079*7cc577a4SJonathan Peyton     taskdata->td_flags.tasktype    = TASK_EXPLICIT;
1080*7cc577a4SJonathan Peyton 
1081*7cc577a4SJonathan Peyton     // GEH - TODO: fix this to copy parent task's value of tasking_ser flag
1082*7cc577a4SJonathan Peyton     taskdata->td_flags.tasking_ser = ( __kmp_tasking_mode == tskm_immediate_exec );
1083*7cc577a4SJonathan Peyton 
1084*7cc577a4SJonathan Peyton     // GEH - TODO: fix this to copy parent task's value of team_serial flag
1085*7cc577a4SJonathan Peyton     taskdata->td_flags.team_serial = ( team->t.t_serialized ) ? 1 : 0;
1086*7cc577a4SJonathan Peyton 
1087*7cc577a4SJonathan Peyton     // GEH - Note we serialize the task if the team is serialized to make sure implicit parallel region
1088*7cc577a4SJonathan Peyton     //       tasks are not left until program termination to execute.  Also, it helps locality to execute
1089*7cc577a4SJonathan Peyton     //       immediately.
1090*7cc577a4SJonathan Peyton     taskdata->td_flags.task_serial = ( parent_task->td_flags.final
1091*7cc577a4SJonathan Peyton       || taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser );
1092*7cc577a4SJonathan Peyton 
1093*7cc577a4SJonathan Peyton     taskdata->td_flags.started     = 0;
1094*7cc577a4SJonathan Peyton     taskdata->td_flags.executing   = 0;
1095*7cc577a4SJonathan Peyton     taskdata->td_flags.complete    = 0;
1096*7cc577a4SJonathan Peyton     taskdata->td_flags.freed       = 0;
1097*7cc577a4SJonathan Peyton 
1098*7cc577a4SJonathan Peyton     taskdata->td_flags.native      = flags->native;
1099*7cc577a4SJonathan Peyton 
1100*7cc577a4SJonathan Peyton     taskdata->td_incomplete_child_tasks = 0;
1101*7cc577a4SJonathan Peyton     taskdata->td_allocated_child_tasks  = 1; // start at one because counts current task and children
1102*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1103*7cc577a4SJonathan Peyton     taskdata->td_taskgroup = parent_task->td_taskgroup; // task inherits the taskgroup from the parent task
1104*7cc577a4SJonathan Peyton     taskdata->td_dephash = NULL;
1105*7cc577a4SJonathan Peyton     taskdata->td_depnode = NULL;
1106*7cc577a4SJonathan Peyton #endif
1107*7cc577a4SJonathan Peyton 
1108*7cc577a4SJonathan Peyton     // Only need to keep track of child task counts if team parallel and tasking not serialized or if it is a proxy task
1109*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1110*7cc577a4SJonathan Peyton     if ( flags->proxy == TASK_PROXY || !( taskdata -> td_flags.team_serial || taskdata -> td_flags.tasking_ser ) )
1111*7cc577a4SJonathan Peyton #else
1112*7cc577a4SJonathan Peyton     if ( !( taskdata -> td_flags.team_serial || taskdata -> td_flags.tasking_ser ) )
1113*7cc577a4SJonathan Peyton #endif
1114*7cc577a4SJonathan Peyton     {
1115*7cc577a4SJonathan Peyton         KMP_TEST_THEN_INC32( (kmp_int32 *)(& parent_task->td_incomplete_child_tasks) );
1116*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1117*7cc577a4SJonathan Peyton         if ( parent_task->td_taskgroup )
1118*7cc577a4SJonathan Peyton             KMP_TEST_THEN_INC32( (kmp_int32 *)(& parent_task->td_taskgroup->count) );
1119*7cc577a4SJonathan Peyton #endif
1120*7cc577a4SJonathan Peyton         // Only need to keep track of allocated child tasks for explicit tasks since implicit not deallocated
1121*7cc577a4SJonathan Peyton         if ( taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT ) {
1122*7cc577a4SJonathan Peyton             KMP_TEST_THEN_INC32( (kmp_int32 *)(& taskdata->td_parent->td_allocated_child_tasks) );
1123*7cc577a4SJonathan Peyton         }
1124*7cc577a4SJonathan Peyton     }
1125*7cc577a4SJonathan Peyton 
1126*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_task_alloc(exit): T#%d created task %p parent=%p\n",
1127*7cc577a4SJonathan Peyton                   gtid, taskdata, taskdata->td_parent) );
1128*7cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_BEFORE(task);
1129*7cc577a4SJonathan Peyton 
1130*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
1131*7cc577a4SJonathan Peyton     __kmp_task_init_ompt(taskdata, gtid, (void*) task_entry);
1132*7cc577a4SJonathan Peyton #endif
1133*7cc577a4SJonathan Peyton 
1134*7cc577a4SJonathan Peyton     return task;
1135*7cc577a4SJonathan Peyton }
1136*7cc577a4SJonathan Peyton 
1137*7cc577a4SJonathan Peyton 
1138*7cc577a4SJonathan Peyton kmp_task_t *
1139*7cc577a4SJonathan Peyton __kmpc_omp_task_alloc( ident_t *loc_ref, kmp_int32 gtid, kmp_int32 flags,
1140*7cc577a4SJonathan Peyton                        size_t sizeof_kmp_task_t, size_t sizeof_shareds,
1141*7cc577a4SJonathan Peyton                        kmp_routine_entry_t task_entry )
1142*7cc577a4SJonathan Peyton {
1143*7cc577a4SJonathan Peyton     kmp_task_t *retval;
1144*7cc577a4SJonathan Peyton     kmp_tasking_flags_t *input_flags = (kmp_tasking_flags_t *) & flags;
1145*7cc577a4SJonathan Peyton 
1146*7cc577a4SJonathan Peyton     input_flags->native = FALSE;
1147*7cc577a4SJonathan Peyton     // __kmp_task_alloc() sets up all other runtime flags
1148*7cc577a4SJonathan Peyton 
1149*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1150*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s %s) "
1151*7cc577a4SJonathan Peyton                   "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1152*7cc577a4SJonathan Peyton                   gtid, loc_ref, input_flags->tiedness ? "tied  " : "untied",
1153*7cc577a4SJonathan Peyton                   input_flags->proxy ? "proxy" : "",
1154*7cc577a4SJonathan Peyton                   sizeof_kmp_task_t, sizeof_shareds, task_entry) );
1155*7cc577a4SJonathan Peyton #else
1156*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_alloc(enter): T#%d loc=%p, flags=(%s) "
1157*7cc577a4SJonathan Peyton                   "sizeof_task=%ld sizeof_shared=%ld entry=%p\n",
1158*7cc577a4SJonathan Peyton                   gtid, loc_ref, input_flags->tiedness ? "tied  " : "untied",
1159*7cc577a4SJonathan Peyton                   sizeof_kmp_task_t, sizeof_shareds, task_entry) );
1160*7cc577a4SJonathan Peyton #endif
1161*7cc577a4SJonathan Peyton 
1162*7cc577a4SJonathan Peyton     retval = __kmp_task_alloc( loc_ref, gtid, input_flags, sizeof_kmp_task_t,
1163*7cc577a4SJonathan Peyton                                sizeof_shareds, task_entry );
1164*7cc577a4SJonathan Peyton 
1165*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmpc_omp_task_alloc(exit): T#%d retval %p\n", gtid, retval) );
1166*7cc577a4SJonathan Peyton 
1167*7cc577a4SJonathan Peyton     return retval;
1168*7cc577a4SJonathan Peyton }
1169*7cc577a4SJonathan Peyton 
1170*7cc577a4SJonathan Peyton //-----------------------------------------------------------
1171*7cc577a4SJonathan Peyton //  __kmp_invoke_task: invoke the specified task
1172*7cc577a4SJonathan Peyton //
1173*7cc577a4SJonathan Peyton // gtid: global thread ID of caller
1174*7cc577a4SJonathan Peyton // task: the task to invoke
1175*7cc577a4SJonathan Peyton // current_task: the task to resume after task invokation
1176*7cc577a4SJonathan Peyton 
1177*7cc577a4SJonathan Peyton static void
1178*7cc577a4SJonathan Peyton __kmp_invoke_task( kmp_int32 gtid, kmp_task_t *task, kmp_taskdata_t * current_task )
1179*7cc577a4SJonathan Peyton {
1180*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(task);
1181*7cc577a4SJonathan Peyton     kmp_uint64 cur_time;
1182*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1183*7cc577a4SJonathan Peyton     int discard = 0 /* false */;
1184*7cc577a4SJonathan Peyton #endif
1185*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_invoke_task(enter): T#%d invoking task %p, current_task=%p\n",
1186*7cc577a4SJonathan Peyton                   gtid, taskdata, current_task) );
1187*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(task);
1188*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1189*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.proxy == TASK_PROXY &&
1190*7cc577a4SJonathan Peyton          taskdata->td_flags.complete == 1)
1191*7cc577a4SJonathan Peyton          {
1192*7cc577a4SJonathan Peyton             // This is a proxy task that was already completed but it needs to run
1193*7cc577a4SJonathan Peyton             // its bottom-half finish
1194*7cc577a4SJonathan Peyton             KA_TRACE(30, ("__kmp_invoke_task: T#%d running bottom finish for proxy task %p\n",
1195*7cc577a4SJonathan Peyton                   gtid, taskdata) );
1196*7cc577a4SJonathan Peyton 
1197*7cc577a4SJonathan Peyton             __kmp_bottom_half_finish_proxy(gtid,task);
1198*7cc577a4SJonathan Peyton 
1199*7cc577a4SJonathan Peyton             KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed bottom finish for proxy task %p, resuming task %p\n", gtid, taskdata, current_task) );
1200*7cc577a4SJonathan Peyton 
1201*7cc577a4SJonathan Peyton             return;
1202*7cc577a4SJonathan Peyton          }
1203*7cc577a4SJonathan Peyton #endif
1204*7cc577a4SJonathan Peyton 
1205*7cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY
1206*7cc577a4SJonathan Peyton     if(__kmp_forkjoin_frames_mode == 3) {
1207*7cc577a4SJonathan Peyton         // Get the current time stamp to measure task execution time to correct barrier imbalance time
1208*7cc577a4SJonathan Peyton         cur_time = __itt_get_timestamp();
1209*7cc577a4SJonathan Peyton     }
1210*7cc577a4SJonathan Peyton #endif
1211*7cc577a4SJonathan Peyton 
1212*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1213*7cc577a4SJonathan Peyton     // Proxy tasks are not handled by the runtime
1214*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.proxy != TASK_PROXY ) {
1215*7cc577a4SJonathan Peyton #endif
1216*7cc577a4SJonathan Peyton       ANNOTATE_HAPPENS_AFTER(task);
1217*7cc577a4SJonathan Peyton       __kmp_task_start( gtid, task, current_task );
1218*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1219*7cc577a4SJonathan Peyton     }
1220*7cc577a4SJonathan Peyton #endif
1221*7cc577a4SJonathan Peyton 
1222*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
1223*7cc577a4SJonathan Peyton     ompt_thread_info_t oldInfo;
1224*7cc577a4SJonathan Peyton     kmp_info_t * thread;
1225*7cc577a4SJonathan Peyton     if (ompt_enabled) {
1226*7cc577a4SJonathan Peyton         // Store the threads states and restore them after the task
1227*7cc577a4SJonathan Peyton         thread = __kmp_threads[ gtid ];
1228*7cc577a4SJonathan Peyton         oldInfo = thread->th.ompt_thread_info;
1229*7cc577a4SJonathan Peyton         thread->th.ompt_thread_info.wait_id = 0;
1230*7cc577a4SJonathan Peyton         thread->th.ompt_thread_info.state = ompt_state_work_parallel;
1231*7cc577a4SJonathan Peyton         taskdata->ompt_task_info.frame.exit_runtime_frame = __builtin_frame_address(0);
1232*7cc577a4SJonathan Peyton     }
1233*7cc577a4SJonathan Peyton #endif
1234*7cc577a4SJonathan Peyton 
1235*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1236*7cc577a4SJonathan Peyton     // TODO: cancel tasks if the parallel region has also been cancelled
1237*7cc577a4SJonathan Peyton     // TODO: check if this sequence can be hoisted above __kmp_task_start
1238*7cc577a4SJonathan Peyton     // if cancellation has been enabled for this run ...
1239*7cc577a4SJonathan Peyton     if (__kmp_omp_cancellation) {
1240*7cc577a4SJonathan Peyton         kmp_info_t *this_thr = __kmp_threads [ gtid ];
1241*7cc577a4SJonathan Peyton         kmp_team_t * this_team = this_thr->th.th_team;
1242*7cc577a4SJonathan Peyton         kmp_taskgroup_t * taskgroup = taskdata->td_taskgroup;
1243*7cc577a4SJonathan Peyton         if ((taskgroup && taskgroup->cancel_request) || (this_team->t.t_cancel_request == cancel_parallel)) {
1244*7cc577a4SJonathan Peyton             KMP_COUNT_BLOCK(TASK_cancelled);
1245*7cc577a4SJonathan Peyton             // this task belongs to a task group and we need to cancel it
1246*7cc577a4SJonathan Peyton             discard = 1 /* true */;
1247*7cc577a4SJonathan Peyton         }
1248*7cc577a4SJonathan Peyton     }
1249*7cc577a4SJonathan Peyton 
1250*7cc577a4SJonathan Peyton     //
1251*7cc577a4SJonathan Peyton     // Invoke the task routine and pass in relevant data.
1252*7cc577a4SJonathan Peyton     // Thunks generated by gcc take a different argument list.
1253*7cc577a4SJonathan Peyton     //
1254*7cc577a4SJonathan Peyton     if (!discard) {
1255*7cc577a4SJonathan Peyton #if KMP_STATS_ENABLED
1256*7cc577a4SJonathan Peyton         KMP_COUNT_BLOCK(TASK_executed);
1257*7cc577a4SJonathan Peyton         switch(KMP_GET_THREAD_STATE()) {
1258*7cc577a4SJonathan Peyton          case FORK_JOIN_BARRIER: KMP_PUSH_PARTITIONED_TIMER(OMP_task_join_bar); break;
1259*7cc577a4SJonathan Peyton          case PLAIN_BARRIER: KMP_PUSH_PARTITIONED_TIMER(OMP_task_plain_bar); break;
1260*7cc577a4SJonathan Peyton          case TASKYIELD: KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskyield); break;
1261*7cc577a4SJonathan Peyton          case TASKWAIT: KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskwait); break;
1262*7cc577a4SJonathan Peyton          case TASKGROUP: KMP_PUSH_PARTITIONED_TIMER(OMP_task_taskgroup); break;
1263*7cc577a4SJonathan Peyton          default: KMP_PUSH_PARTITIONED_TIMER(OMP_task_immediate); break;
1264*7cc577a4SJonathan Peyton         }
1265*7cc577a4SJonathan Peyton #endif // KMP_STATS_ENABLED
1266*7cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
1267*7cc577a4SJonathan Peyton 
1268*7cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
1269*7cc577a4SJonathan Peyton         /* let OMPT know that we're about to run this task */
1270*7cc577a4SJonathan Peyton         if (ompt_enabled &&
1271*7cc577a4SJonathan Peyton              ompt_callbacks.ompt_callback(ompt_event_task_switch))
1272*7cc577a4SJonathan Peyton         {
1273*7cc577a4SJonathan Peyton           ompt_callbacks.ompt_callback(ompt_event_task_switch)(
1274*7cc577a4SJonathan Peyton             current_task->ompt_task_info.task_id,
1275*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.task_id);
1276*7cc577a4SJonathan Peyton         }
1277*7cc577a4SJonathan Peyton #endif
1278*7cc577a4SJonathan Peyton 
1279*7cc577a4SJonathan Peyton #ifdef KMP_GOMP_COMPAT
1280*7cc577a4SJonathan Peyton         if (taskdata->td_flags.native) {
1281*7cc577a4SJonathan Peyton             ((void (*)(void *))(*(task->routine)))(task->shareds);
1282*7cc577a4SJonathan Peyton         }
1283*7cc577a4SJonathan Peyton         else
1284*7cc577a4SJonathan Peyton #endif /* KMP_GOMP_COMPAT */
1285*7cc577a4SJonathan Peyton         {
1286*7cc577a4SJonathan Peyton             (*(task->routine))(gtid, task);
1287*7cc577a4SJonathan Peyton         }
1288*7cc577a4SJonathan Peyton         KMP_POP_PARTITIONED_TIMER();
1289*7cc577a4SJonathan Peyton 
1290*7cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
1291*7cc577a4SJonathan Peyton         /* let OMPT know that we're returning to the callee task */
1292*7cc577a4SJonathan Peyton         if (ompt_enabled &&
1293*7cc577a4SJonathan Peyton              ompt_callbacks.ompt_callback(ompt_event_task_switch))
1294*7cc577a4SJonathan Peyton         {
1295*7cc577a4SJonathan Peyton           ompt_callbacks.ompt_callback(ompt_event_task_switch)(
1296*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.task_id,
1297*7cc577a4SJonathan Peyton             current_task->ompt_task_info.task_id);
1298*7cc577a4SJonathan Peyton         }
1299*7cc577a4SJonathan Peyton #endif
1300*7cc577a4SJonathan Peyton 
1301*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1302*7cc577a4SJonathan Peyton     }
1303*7cc577a4SJonathan Peyton #endif // OMP_40_ENABLED
1304*7cc577a4SJonathan Peyton 
1305*7cc577a4SJonathan Peyton 
1306*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
1307*7cc577a4SJonathan Peyton     if (ompt_enabled) {
1308*7cc577a4SJonathan Peyton         thread->th.ompt_thread_info = oldInfo;
1309*7cc577a4SJonathan Peyton         taskdata->ompt_task_info.frame.exit_runtime_frame = NULL;
1310*7cc577a4SJonathan Peyton     }
1311*7cc577a4SJonathan Peyton #endif
1312*7cc577a4SJonathan Peyton 
1313*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1314*7cc577a4SJonathan Peyton     // Proxy tasks are not handled by the runtime
1315*7cc577a4SJonathan Peyton     if ( taskdata->td_flags.proxy != TASK_PROXY ) {
1316*7cc577a4SJonathan Peyton #endif
1317*7cc577a4SJonathan Peyton       ANNOTATE_HAPPENS_BEFORE(taskdata->td_parent);
1318*7cc577a4SJonathan Peyton       __kmp_task_finish( gtid, task, current_task );
1319*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1320*7cc577a4SJonathan Peyton     }
1321*7cc577a4SJonathan Peyton #endif
1322*7cc577a4SJonathan Peyton 
1323*7cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY
1324*7cc577a4SJonathan Peyton     // Barrier imbalance - correct arrive time after the task finished
1325*7cc577a4SJonathan Peyton     if(__kmp_forkjoin_frames_mode == 3) {
1326*7cc577a4SJonathan Peyton         kmp_info_t *this_thr = __kmp_threads [ gtid ];
1327*7cc577a4SJonathan Peyton         if(this_thr->th.th_bar_arrive_time) {
1328*7cc577a4SJonathan Peyton             this_thr->th.th_bar_arrive_time += (__itt_get_timestamp() - cur_time);
1329*7cc577a4SJonathan Peyton         }
1330*7cc577a4SJonathan Peyton     }
1331*7cc577a4SJonathan Peyton #endif
1332*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_invoke_task(exit): T#%d completed task %p, resuming task %p\n",
1333*7cc577a4SJonathan Peyton                   gtid, taskdata, current_task) );
1334*7cc577a4SJonathan Peyton     return;
1335*7cc577a4SJonathan Peyton }
1336*7cc577a4SJonathan Peyton 
1337*7cc577a4SJonathan Peyton //-----------------------------------------------------------------------
1338*7cc577a4SJonathan Peyton // __kmpc_omp_task_parts: Schedule a thread-switchable task for execution
1339*7cc577a4SJonathan Peyton //
1340*7cc577a4SJonathan Peyton // loc_ref: location of original task pragma (ignored)
1341*7cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread
1342*7cc577a4SJonathan Peyton // new_task: task thunk allocated by __kmp_omp_task_alloc() for the ''new task''
1343*7cc577a4SJonathan Peyton // Returns:
1344*7cc577a4SJonathan Peyton //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to be resumed later.
1345*7cc577a4SJonathan Peyton //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be resumed later.
1346*7cc577a4SJonathan Peyton 
1347*7cc577a4SJonathan Peyton kmp_int32
1348*7cc577a4SJonathan Peyton __kmpc_omp_task_parts( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task)
1349*7cc577a4SJonathan Peyton {
1350*7cc577a4SJonathan Peyton     kmp_taskdata_t * new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1351*7cc577a4SJonathan Peyton 
1352*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_parts(enter): T#%d loc=%p task=%p\n",
1353*7cc577a4SJonathan Peyton                   gtid, loc_ref, new_taskdata ) );
1354*7cc577a4SJonathan Peyton 
1355*7cc577a4SJonathan Peyton     /* Should we execute the new task or queue it?   For now, let's just always try to
1356*7cc577a4SJonathan Peyton        queue it.  If the queue fills up, then we'll execute it.  */
1357*7cc577a4SJonathan Peyton 
1358*7cc577a4SJonathan Peyton     if ( __kmp_push_task( gtid, new_task ) == TASK_NOT_PUSHED ) // if cannot defer
1359*7cc577a4SJonathan Peyton     {                                                           // Execute this task immediately
1360*7cc577a4SJonathan Peyton         kmp_taskdata_t * current_task = __kmp_threads[ gtid ] -> th.th_current_task;
1361*7cc577a4SJonathan Peyton         new_taskdata->td_flags.task_serial = 1;
1362*7cc577a4SJonathan Peyton         __kmp_invoke_task( gtid, new_task, current_task );
1363*7cc577a4SJonathan Peyton     }
1364*7cc577a4SJonathan Peyton 
1365*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task_parts(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: "
1366*7cc577a4SJonathan Peyton                   "loc=%p task=%p, return: TASK_CURRENT_NOT_QUEUED\n", gtid, loc_ref,
1367*7cc577a4SJonathan Peyton                   new_taskdata ) );
1368*7cc577a4SJonathan Peyton 
1369*7cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_BEFORE(new_task);
1370*7cc577a4SJonathan Peyton     return TASK_CURRENT_NOT_QUEUED;
1371*7cc577a4SJonathan Peyton }
1372*7cc577a4SJonathan Peyton 
1373*7cc577a4SJonathan Peyton //---------------------------------------------------------------------
1374*7cc577a4SJonathan Peyton // __kmp_omp_task: Schedule a non-thread-switchable task for execution
1375*7cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread
1376*7cc577a4SJonathan Peyton // new_task: non-thread-switchable task thunk allocated by __kmp_omp_task_alloc()
1377*7cc577a4SJonathan Peyton // serialize_immediate: if TRUE then if the task is executed immediately its execution will be serialized
1378*7cc577a4SJonathan Peyton // returns:
1379*7cc577a4SJonathan Peyton //
1380*7cc577a4SJonathan Peyton //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to be resumed later.
1381*7cc577a4SJonathan Peyton //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be resumed later.
1382*7cc577a4SJonathan Peyton kmp_int32
1383*7cc577a4SJonathan Peyton __kmp_omp_task( kmp_int32 gtid, kmp_task_t * new_task, bool serialize_immediate )
1384*7cc577a4SJonathan Peyton {
1385*7cc577a4SJonathan Peyton     kmp_taskdata_t * new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1386*7cc577a4SJonathan Peyton 
1387*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
1388*7cc577a4SJonathan Peyton     if (ompt_enabled) {
1389*7cc577a4SJonathan Peyton         new_taskdata->ompt_task_info.frame.reenter_runtime_frame =
1390*7cc577a4SJonathan Peyton             __builtin_frame_address(1);
1391*7cc577a4SJonathan Peyton     }
1392*7cc577a4SJonathan Peyton #endif
1393*7cc577a4SJonathan Peyton 
1394*7cc577a4SJonathan Peyton     /* Should we execute the new task or queue it?   For now, let's just always try to
1395*7cc577a4SJonathan Peyton        queue it.  If the queue fills up, then we'll execute it.  */
1396*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1397*7cc577a4SJonathan Peyton     if ( new_taskdata->td_flags.proxy == TASK_PROXY || __kmp_push_task( gtid, new_task ) == TASK_NOT_PUSHED ) // if cannot defer
1398*7cc577a4SJonathan Peyton #else
1399*7cc577a4SJonathan Peyton     if ( __kmp_push_task( gtid, new_task ) == TASK_NOT_PUSHED ) // if cannot defer
1400*7cc577a4SJonathan Peyton #endif
1401*7cc577a4SJonathan Peyton     {                                                           // Execute this task immediately
1402*7cc577a4SJonathan Peyton         kmp_taskdata_t * current_task = __kmp_threads[ gtid ] -> th.th_current_task;
1403*7cc577a4SJonathan Peyton         if ( serialize_immediate )
1404*7cc577a4SJonathan Peyton           new_taskdata -> td_flags.task_serial = 1;
1405*7cc577a4SJonathan Peyton         __kmp_invoke_task( gtid, new_task, current_task );
1406*7cc577a4SJonathan Peyton     }
1407*7cc577a4SJonathan Peyton 
1408*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
1409*7cc577a4SJonathan Peyton     if (ompt_enabled) {
1410*7cc577a4SJonathan Peyton         new_taskdata->ompt_task_info.frame.reenter_runtime_frame = NULL;
1411*7cc577a4SJonathan Peyton     }
1412*7cc577a4SJonathan Peyton #endif
1413*7cc577a4SJonathan Peyton 
1414*7cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_BEFORE(new_task);
1415*7cc577a4SJonathan Peyton     return TASK_CURRENT_NOT_QUEUED;
1416*7cc577a4SJonathan Peyton }
1417*7cc577a4SJonathan Peyton 
1418*7cc577a4SJonathan Peyton //---------------------------------------------------------------------
1419*7cc577a4SJonathan Peyton // __kmpc_omp_task: Wrapper around __kmp_omp_task to schedule a non-thread-switchable task from
1420*7cc577a4SJonathan Peyton // the parent thread only!
1421*7cc577a4SJonathan Peyton // loc_ref: location of original task pragma (ignored)
1422*7cc577a4SJonathan Peyton // gtid: Global Thread ID of encountering thread
1423*7cc577a4SJonathan Peyton // new_task: non-thread-switchable task thunk allocated by __kmp_omp_task_alloc()
1424*7cc577a4SJonathan Peyton // returns:
1425*7cc577a4SJonathan Peyton //
1426*7cc577a4SJonathan Peyton //    TASK_CURRENT_NOT_QUEUED (0) if did not suspend and queue current task to be resumed later.
1427*7cc577a4SJonathan Peyton //    TASK_CURRENT_QUEUED (1) if suspended and queued the current task to be resumed later.
1428*7cc577a4SJonathan Peyton 
1429*7cc577a4SJonathan Peyton kmp_int32
1430*7cc577a4SJonathan Peyton __kmpc_omp_task( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task)
1431*7cc577a4SJonathan Peyton {
1432*7cc577a4SJonathan Peyton     kmp_int32 res;
1433*7cc577a4SJonathan Peyton     KMP_SET_THREAD_STATE_BLOCK(EXPLICIT_TASK);
1434*7cc577a4SJonathan Peyton 
1435*7cc577a4SJonathan Peyton #if KMP_DEBUG
1436*7cc577a4SJonathan Peyton     kmp_taskdata_t * new_taskdata = KMP_TASK_TO_TASKDATA(new_task);
1437*7cc577a4SJonathan Peyton #endif
1438*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task(enter): T#%d loc=%p task=%p\n",
1439*7cc577a4SJonathan Peyton                   gtid, loc_ref, new_taskdata ) );
1440*7cc577a4SJonathan Peyton 
1441*7cc577a4SJonathan Peyton     res =  __kmp_omp_task(gtid,new_task,true);
1442*7cc577a4SJonathan Peyton 
1443*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_task(exit): T#%d returning TASK_CURRENT_NOT_QUEUED: loc=%p task=%p\n",
1444*7cc577a4SJonathan Peyton                   gtid, loc_ref, new_taskdata ) );
1445*7cc577a4SJonathan Peyton     return res;
1446*7cc577a4SJonathan Peyton }
1447*7cc577a4SJonathan Peyton 
1448*7cc577a4SJonathan Peyton //-------------------------------------------------------------------------------------
1449*7cc577a4SJonathan Peyton // __kmpc_omp_taskwait: Wait until all tasks generated by the current task are complete
1450*7cc577a4SJonathan Peyton 
1451*7cc577a4SJonathan Peyton kmp_int32
1452*7cc577a4SJonathan Peyton __kmpc_omp_taskwait( ident_t *loc_ref, kmp_int32 gtid )
1453*7cc577a4SJonathan Peyton {
1454*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata;
1455*7cc577a4SJonathan Peyton     kmp_info_t * thread;
1456*7cc577a4SJonathan Peyton     int thread_finished = FALSE;
1457*7cc577a4SJonathan Peyton     KMP_SET_THREAD_STATE_BLOCK(TASKWAIT);
1458*7cc577a4SJonathan Peyton 
1459*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_taskwait(enter): T#%d loc=%p\n", gtid, loc_ref) );
1460*7cc577a4SJonathan Peyton 
1461*7cc577a4SJonathan Peyton     if ( __kmp_tasking_mode != tskm_immediate_exec ) {
1462*7cc577a4SJonathan Peyton         // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark begin wait?
1463*7cc577a4SJonathan Peyton 
1464*7cc577a4SJonathan Peyton         thread = __kmp_threads[ gtid ];
1465*7cc577a4SJonathan Peyton         taskdata = thread -> th.th_current_task;
1466*7cc577a4SJonathan Peyton 
1467*7cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
1468*7cc577a4SJonathan Peyton         ompt_task_id_t my_task_id;
1469*7cc577a4SJonathan Peyton         ompt_parallel_id_t my_parallel_id;
1470*7cc577a4SJonathan Peyton 
1471*7cc577a4SJonathan Peyton         if (ompt_enabled) {
1472*7cc577a4SJonathan Peyton             kmp_team_t *team = thread->th.th_team;
1473*7cc577a4SJonathan Peyton             my_task_id = taskdata->ompt_task_info.task_id;
1474*7cc577a4SJonathan Peyton             my_parallel_id = team->t.ompt_team_info.parallel_id;
1475*7cc577a4SJonathan Peyton 
1476*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.frame.reenter_runtime_frame = __builtin_frame_address(1);
1477*7cc577a4SJonathan Peyton             if (ompt_callbacks.ompt_callback(ompt_event_taskwait_begin)) {
1478*7cc577a4SJonathan Peyton                 ompt_callbacks.ompt_callback(ompt_event_taskwait_begin)(
1479*7cc577a4SJonathan Peyton                                 my_parallel_id, my_task_id);
1480*7cc577a4SJonathan Peyton             }
1481*7cc577a4SJonathan Peyton         }
1482*7cc577a4SJonathan Peyton #endif
1483*7cc577a4SJonathan Peyton 
1484*7cc577a4SJonathan Peyton         // Debugger: The taskwait is active. Store location and thread encountered the taskwait.
1485*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1486*7cc577a4SJonathan Peyton         // Note: These values are used by ITT events as well.
1487*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1488*7cc577a4SJonathan Peyton         taskdata->td_taskwait_counter += 1;
1489*7cc577a4SJonathan Peyton         taskdata->td_taskwait_ident    = loc_ref;
1490*7cc577a4SJonathan Peyton         taskdata->td_taskwait_thread   = gtid + 1;
1491*7cc577a4SJonathan Peyton 
1492*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1493*7cc577a4SJonathan Peyton         void * itt_sync_obj = __kmp_itt_taskwait_object( gtid );
1494*7cc577a4SJonathan Peyton         if ( itt_sync_obj != NULL )
1495*7cc577a4SJonathan Peyton             __kmp_itt_taskwait_starting( gtid, itt_sync_obj );
1496*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1497*7cc577a4SJonathan Peyton 
1498*7cc577a4SJonathan Peyton         bool must_wait = ! taskdata->td_flags.team_serial && ! taskdata->td_flags.final;
1499*7cc577a4SJonathan Peyton 
1500*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1501*7cc577a4SJonathan Peyton         must_wait = must_wait || (thread->th.th_task_team != NULL && thread->th.th_task_team->tt.tt_found_proxy_tasks);
1502*7cc577a4SJonathan Peyton #endif
1503*7cc577a4SJonathan Peyton         if (must_wait)
1504*7cc577a4SJonathan Peyton         {
1505*7cc577a4SJonathan Peyton             kmp_flag_32 flag(&(taskdata->td_incomplete_child_tasks), 0U);
1506*7cc577a4SJonathan Peyton             while ( TCR_4(taskdata -> td_incomplete_child_tasks) != 0 ) {
1507*7cc577a4SJonathan Peyton                 flag.execute_tasks(thread, gtid, FALSE, &thread_finished
1508*7cc577a4SJonathan Peyton                                    USE_ITT_BUILD_ARG(itt_sync_obj), __kmp_task_stealing_constraint );
1509*7cc577a4SJonathan Peyton             }
1510*7cc577a4SJonathan Peyton         }
1511*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1512*7cc577a4SJonathan Peyton         if ( itt_sync_obj != NULL )
1513*7cc577a4SJonathan Peyton             __kmp_itt_taskwait_finished( gtid, itt_sync_obj );
1514*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1515*7cc577a4SJonathan Peyton 
1516*7cc577a4SJonathan Peyton         // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark end of wait?
1517*7cc577a4SJonathan Peyton         // Debugger:  The taskwait is completed. Location remains, but thread is negated.
1518*7cc577a4SJonathan Peyton         taskdata->td_taskwait_thread = - taskdata->td_taskwait_thread;
1519*7cc577a4SJonathan Peyton 
1520*7cc577a4SJonathan Peyton #if OMPT_SUPPORT && OMPT_TRACE
1521*7cc577a4SJonathan Peyton         if (ompt_enabled) {
1522*7cc577a4SJonathan Peyton             if (ompt_callbacks.ompt_callback(ompt_event_taskwait_end)) {
1523*7cc577a4SJonathan Peyton                 ompt_callbacks.ompt_callback(ompt_event_taskwait_end)(
1524*7cc577a4SJonathan Peyton                                 my_parallel_id, my_task_id);
1525*7cc577a4SJonathan Peyton             }
1526*7cc577a4SJonathan Peyton             taskdata->ompt_task_info.frame.reenter_runtime_frame = NULL;
1527*7cc577a4SJonathan Peyton         }
1528*7cc577a4SJonathan Peyton #endif
1529*7cc577a4SJonathan Peyton         ANNOTATE_HAPPENS_AFTER(taskdata);
1530*7cc577a4SJonathan Peyton     }
1531*7cc577a4SJonathan Peyton 
1532*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_taskwait(exit): T#%d task %p finished waiting, "
1533*7cc577a4SJonathan Peyton                   "returning TASK_CURRENT_NOT_QUEUED\n", gtid, taskdata) );
1534*7cc577a4SJonathan Peyton 
1535*7cc577a4SJonathan Peyton     return TASK_CURRENT_NOT_QUEUED;
1536*7cc577a4SJonathan Peyton }
1537*7cc577a4SJonathan Peyton 
1538*7cc577a4SJonathan Peyton 
1539*7cc577a4SJonathan Peyton //-------------------------------------------------
1540*7cc577a4SJonathan Peyton // __kmpc_omp_taskyield: switch to a different task
1541*7cc577a4SJonathan Peyton 
1542*7cc577a4SJonathan Peyton kmp_int32
1543*7cc577a4SJonathan Peyton __kmpc_omp_taskyield( ident_t *loc_ref, kmp_int32 gtid, int end_part )
1544*7cc577a4SJonathan Peyton {
1545*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata;
1546*7cc577a4SJonathan Peyton     kmp_info_t * thread;
1547*7cc577a4SJonathan Peyton     int thread_finished = FALSE;
1548*7cc577a4SJonathan Peyton 
1549*7cc577a4SJonathan Peyton     KMP_COUNT_BLOCK(OMP_TASKYIELD);
1550*7cc577a4SJonathan Peyton     KMP_SET_THREAD_STATE_BLOCK(TASKYIELD);
1551*7cc577a4SJonathan Peyton 
1552*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_taskyield(enter): T#%d loc=%p end_part = %d\n",
1553*7cc577a4SJonathan Peyton                   gtid, loc_ref, end_part) );
1554*7cc577a4SJonathan Peyton 
1555*7cc577a4SJonathan Peyton     if ( __kmp_tasking_mode != tskm_immediate_exec && __kmp_init_parallel ) {
1556*7cc577a4SJonathan Peyton         // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark begin wait?
1557*7cc577a4SJonathan Peyton 
1558*7cc577a4SJonathan Peyton         thread = __kmp_threads[ gtid ];
1559*7cc577a4SJonathan Peyton         taskdata = thread -> th.th_current_task;
1560*7cc577a4SJonathan Peyton         // Should we model this as a task wait or not?
1561*7cc577a4SJonathan Peyton         // Debugger: The taskwait is active. Store location and thread encountered the taskwait.
1562*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1563*7cc577a4SJonathan Peyton         // Note: These values are used by ITT events as well.
1564*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1565*7cc577a4SJonathan Peyton         taskdata->td_taskwait_counter += 1;
1566*7cc577a4SJonathan Peyton         taskdata->td_taskwait_ident    = loc_ref;
1567*7cc577a4SJonathan Peyton         taskdata->td_taskwait_thread   = gtid + 1;
1568*7cc577a4SJonathan Peyton 
1569*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1570*7cc577a4SJonathan Peyton         void * itt_sync_obj = __kmp_itt_taskwait_object( gtid );
1571*7cc577a4SJonathan Peyton         if ( itt_sync_obj != NULL )
1572*7cc577a4SJonathan Peyton             __kmp_itt_taskwait_starting( gtid, itt_sync_obj );
1573*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1574*7cc577a4SJonathan Peyton         if ( ! taskdata->td_flags.team_serial ) {
1575*7cc577a4SJonathan Peyton             kmp_task_team_t * task_team = thread->th.th_task_team;
1576*7cc577a4SJonathan Peyton             if (task_team != NULL) {
1577*7cc577a4SJonathan Peyton                 if (KMP_TASKING_ENABLED(task_team)) {
1578*7cc577a4SJonathan Peyton                     __kmp_execute_tasks_32( thread, gtid, NULL, FALSE, &thread_finished
1579*7cc577a4SJonathan Peyton                                             USE_ITT_BUILD_ARG(itt_sync_obj), __kmp_task_stealing_constraint );
1580*7cc577a4SJonathan Peyton                 }
1581*7cc577a4SJonathan Peyton             }
1582*7cc577a4SJonathan Peyton         }
1583*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1584*7cc577a4SJonathan Peyton         if ( itt_sync_obj != NULL )
1585*7cc577a4SJonathan Peyton             __kmp_itt_taskwait_finished( gtid, itt_sync_obj );
1586*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1587*7cc577a4SJonathan Peyton 
1588*7cc577a4SJonathan Peyton         // GEH TODO: shouldn't we have some sort of OMPRAP API calls here to mark end of wait?
1589*7cc577a4SJonathan Peyton         // Debugger:  The taskwait is completed. Location remains, but thread is negated.
1590*7cc577a4SJonathan Peyton         taskdata->td_taskwait_thread = - taskdata->td_taskwait_thread;
1591*7cc577a4SJonathan Peyton     }
1592*7cc577a4SJonathan Peyton 
1593*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_omp_taskyield(exit): T#%d task %p resuming, "
1594*7cc577a4SJonathan Peyton                   "returning TASK_CURRENT_NOT_QUEUED\n", gtid, taskdata) );
1595*7cc577a4SJonathan Peyton 
1596*7cc577a4SJonathan Peyton     return TASK_CURRENT_NOT_QUEUED;
1597*7cc577a4SJonathan Peyton }
1598*7cc577a4SJonathan Peyton 
1599*7cc577a4SJonathan Peyton 
1600*7cc577a4SJonathan Peyton #if OMP_40_ENABLED
1601*7cc577a4SJonathan Peyton //-------------------------------------------------------------------------------------
1602*7cc577a4SJonathan Peyton // __kmpc_taskgroup: Start a new taskgroup
1603*7cc577a4SJonathan Peyton 
1604*7cc577a4SJonathan Peyton void
1605*7cc577a4SJonathan Peyton __kmpc_taskgroup( ident_t* loc, int gtid )
1606*7cc577a4SJonathan Peyton {
1607*7cc577a4SJonathan Peyton     kmp_info_t      * thread = __kmp_threads[ gtid ];
1608*7cc577a4SJonathan Peyton     kmp_taskdata_t  * taskdata = thread->th.th_current_task;
1609*7cc577a4SJonathan Peyton     kmp_taskgroup_t * tg_new =
1610*7cc577a4SJonathan Peyton         (kmp_taskgroup_t *)__kmp_thread_malloc( thread, sizeof( kmp_taskgroup_t ) );
1611*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_taskgroup: T#%d loc=%p group=%p\n", gtid, loc, tg_new) );
1612*7cc577a4SJonathan Peyton     tg_new->count = 0;
1613*7cc577a4SJonathan Peyton     tg_new->cancel_request = cancel_noreq;
1614*7cc577a4SJonathan Peyton     tg_new->parent = taskdata->td_taskgroup;
1615*7cc577a4SJonathan Peyton     taskdata->td_taskgroup = tg_new;
1616*7cc577a4SJonathan Peyton }
1617*7cc577a4SJonathan Peyton 
1618*7cc577a4SJonathan Peyton 
1619*7cc577a4SJonathan Peyton //-------------------------------------------------------------------------------------
1620*7cc577a4SJonathan Peyton // __kmpc_end_taskgroup: Wait until all tasks generated by the current task
1621*7cc577a4SJonathan Peyton //                       and its descendants are complete
1622*7cc577a4SJonathan Peyton 
1623*7cc577a4SJonathan Peyton void
1624*7cc577a4SJonathan Peyton __kmpc_end_taskgroup( ident_t* loc, int gtid )
1625*7cc577a4SJonathan Peyton {
1626*7cc577a4SJonathan Peyton     kmp_info_t      * thread = __kmp_threads[ gtid ];
1627*7cc577a4SJonathan Peyton     kmp_taskdata_t  * taskdata = thread->th.th_current_task;
1628*7cc577a4SJonathan Peyton     kmp_taskgroup_t * taskgroup = taskdata->td_taskgroup;
1629*7cc577a4SJonathan Peyton     int thread_finished = FALSE;
1630*7cc577a4SJonathan Peyton 
1631*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_end_taskgroup(enter): T#%d loc=%p\n", gtid, loc) );
1632*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskgroup != NULL );
1633*7cc577a4SJonathan Peyton     KMP_SET_THREAD_STATE_BLOCK(TASKGROUP);
1634*7cc577a4SJonathan Peyton 
1635*7cc577a4SJonathan Peyton     if ( __kmp_tasking_mode != tskm_immediate_exec ) {
1636*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1637*7cc577a4SJonathan Peyton         // For ITT the taskgroup wait is similar to taskwait until we need to distinguish them
1638*7cc577a4SJonathan Peyton         void * itt_sync_obj = __kmp_itt_taskwait_object( gtid );
1639*7cc577a4SJonathan Peyton         if ( itt_sync_obj != NULL )
1640*7cc577a4SJonathan Peyton             __kmp_itt_taskwait_starting( gtid, itt_sync_obj );
1641*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1642*7cc577a4SJonathan Peyton 
1643*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1644*7cc577a4SJonathan Peyton         if ( ! taskdata->td_flags.team_serial || (thread->th.th_task_team != NULL && thread->th.th_task_team->tt.tt_found_proxy_tasks) )
1645*7cc577a4SJonathan Peyton #else
1646*7cc577a4SJonathan Peyton         if ( ! taskdata->td_flags.team_serial )
1647*7cc577a4SJonathan Peyton #endif
1648*7cc577a4SJonathan Peyton         {
1649*7cc577a4SJonathan Peyton             kmp_flag_32 flag(&(taskgroup->count), 0U);
1650*7cc577a4SJonathan Peyton             while ( TCR_4(taskgroup->count) != 0 ) {
1651*7cc577a4SJonathan Peyton                 flag.execute_tasks(thread, gtid, FALSE, &thread_finished
1652*7cc577a4SJonathan Peyton                                    USE_ITT_BUILD_ARG(itt_sync_obj), __kmp_task_stealing_constraint );
1653*7cc577a4SJonathan Peyton             }
1654*7cc577a4SJonathan Peyton         }
1655*7cc577a4SJonathan Peyton 
1656*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1657*7cc577a4SJonathan Peyton         if ( itt_sync_obj != NULL )
1658*7cc577a4SJonathan Peyton             __kmp_itt_taskwait_finished( gtid, itt_sync_obj );
1659*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1660*7cc577a4SJonathan Peyton     }
1661*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskgroup->count == 0 );
1662*7cc577a4SJonathan Peyton 
1663*7cc577a4SJonathan Peyton     // Restore parent taskgroup for the current task
1664*7cc577a4SJonathan Peyton     taskdata->td_taskgroup = taskgroup->parent;
1665*7cc577a4SJonathan Peyton     __kmp_thread_free( thread, taskgroup );
1666*7cc577a4SJonathan Peyton 
1667*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_end_taskgroup(exit): T#%d task %p finished waiting\n", gtid, taskdata) );
1668*7cc577a4SJonathan Peyton     ANNOTATE_HAPPENS_AFTER(taskdata);
1669*7cc577a4SJonathan Peyton }
1670*7cc577a4SJonathan Peyton #endif
1671*7cc577a4SJonathan Peyton 
1672*7cc577a4SJonathan Peyton 
1673*7cc577a4SJonathan Peyton //------------------------------------------------------
1674*7cc577a4SJonathan Peyton // __kmp_remove_my_task: remove a task from my own deque
1675*7cc577a4SJonathan Peyton 
1676*7cc577a4SJonathan Peyton static kmp_task_t *
1677*7cc577a4SJonathan Peyton __kmp_remove_my_task( kmp_info_t * thread, kmp_int32 gtid, kmp_task_team_t *task_team,
1678*7cc577a4SJonathan Peyton                       kmp_int32 is_constrained )
1679*7cc577a4SJonathan Peyton {
1680*7cc577a4SJonathan Peyton     kmp_task_t * task;
1681*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata;
1682*7cc577a4SJonathan Peyton     kmp_thread_data_t *thread_data;
1683*7cc577a4SJonathan Peyton     kmp_uint32 tail;
1684*7cc577a4SJonathan Peyton 
1685*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
1686*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_team -> tt.tt_threads_data != NULL ); // Caller should check this condition
1687*7cc577a4SJonathan Peyton 
1688*7cc577a4SJonathan Peyton         thread_data = & task_team -> tt.tt_threads_data[ __kmp_tid_from_gtid( gtid ) ];
1689*7cc577a4SJonathan Peyton 
1690*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_remove_my_task(enter): T#%d ntasks=%d head=%u tail=%u\n",
1691*7cc577a4SJonathan Peyton                   gtid, thread_data->td.td_deque_ntasks, thread_data->td.td_deque_head,
1692*7cc577a4SJonathan Peyton                   thread_data->td.td_deque_tail) );
1693*7cc577a4SJonathan Peyton 
1694*7cc577a4SJonathan Peyton     if (TCR_4(thread_data -> td.td_deque_ntasks) == 0) {
1695*7cc577a4SJonathan Peyton         KA_TRACE(10, ("__kmp_remove_my_task(exit #1): T#%d No tasks to remove: ntasks=%d head=%u tail=%u\n",
1696*7cc577a4SJonathan Peyton                       gtid, thread_data->td.td_deque_ntasks, thread_data->td.td_deque_head,
1697*7cc577a4SJonathan Peyton                       thread_data->td.td_deque_tail) );
1698*7cc577a4SJonathan Peyton         return NULL;
1699*7cc577a4SJonathan Peyton     }
1700*7cc577a4SJonathan Peyton 
1701*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & thread_data -> td.td_deque_lock );
1702*7cc577a4SJonathan Peyton 
1703*7cc577a4SJonathan Peyton     if (TCR_4(thread_data -> td.td_deque_ntasks) == 0) {
1704*7cc577a4SJonathan Peyton         __kmp_release_bootstrap_lock( & thread_data -> td.td_deque_lock );
1705*7cc577a4SJonathan Peyton         KA_TRACE(10, ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: ntasks=%d head=%u tail=%u\n",
1706*7cc577a4SJonathan Peyton                       gtid, thread_data->td.td_deque_ntasks, thread_data->td.td_deque_head,
1707*7cc577a4SJonathan Peyton                       thread_data->td.td_deque_tail) );
1708*7cc577a4SJonathan Peyton         return NULL;
1709*7cc577a4SJonathan Peyton     }
1710*7cc577a4SJonathan Peyton 
1711*7cc577a4SJonathan Peyton     tail = ( thread_data -> td.td_deque_tail - 1 ) & TASK_DEQUE_MASK(thread_data->td);  // Wrap index.
1712*7cc577a4SJonathan Peyton     taskdata = thread_data -> td.td_deque[ tail ];
1713*7cc577a4SJonathan Peyton 
1714*7cc577a4SJonathan Peyton     if (is_constrained && (taskdata->td_flags.tiedness == TASK_TIED)) {
1715*7cc577a4SJonathan Peyton         // we need to check if the candidate obeys task scheduling constraint:
1716*7cc577a4SJonathan Peyton         // only child of current task can be scheduled
1717*7cc577a4SJonathan Peyton         kmp_taskdata_t * current = thread->th.th_current_task;
1718*7cc577a4SJonathan Peyton         kmp_int32        level = current->td_level;
1719*7cc577a4SJonathan Peyton         kmp_taskdata_t * parent = taskdata->td_parent;
1720*7cc577a4SJonathan Peyton         while ( parent != current && parent->td_level > level ) {
1721*7cc577a4SJonathan Peyton             parent = parent->td_parent;  // check generation up to the level of the current task
1722*7cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(parent != NULL);
1723*7cc577a4SJonathan Peyton         }
1724*7cc577a4SJonathan Peyton         if ( parent != current ) {
1725*7cc577a4SJonathan Peyton             // If the tail task is not a child, then no other child can appear in the deque.
1726*7cc577a4SJonathan Peyton             __kmp_release_bootstrap_lock( & thread_data -> td.td_deque_lock );
1727*7cc577a4SJonathan Peyton             KA_TRACE(10, ("__kmp_remove_my_task(exit #2): T#%d No tasks to remove: ntasks=%d head=%u tail=%u\n",
1728*7cc577a4SJonathan Peyton                           gtid, thread_data->td.td_deque_ntasks, thread_data->td.td_deque_head,
1729*7cc577a4SJonathan Peyton                           thread_data->td.td_deque_tail) );
1730*7cc577a4SJonathan Peyton             return NULL;
1731*7cc577a4SJonathan Peyton         }
1732*7cc577a4SJonathan Peyton     }
1733*7cc577a4SJonathan Peyton 
1734*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_tail = tail;
1735*7cc577a4SJonathan Peyton     TCW_4(thread_data -> td.td_deque_ntasks, thread_data -> td.td_deque_ntasks - 1);
1736*7cc577a4SJonathan Peyton 
1737*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & thread_data->td.td_deque_lock );
1738*7cc577a4SJonathan Peyton 
1739*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_remove_my_task(exit #2): T#%d task %p removed: ntasks=%d head=%u tail=%u\n",
1740*7cc577a4SJonathan Peyton                   gtid, taskdata, thread_data->td.td_deque_ntasks, thread_data->td.td_deque_head,
1741*7cc577a4SJonathan Peyton                   thread_data->td.td_deque_tail) );
1742*7cc577a4SJonathan Peyton 
1743*7cc577a4SJonathan Peyton     task = KMP_TASKDATA_TO_TASK( taskdata );
1744*7cc577a4SJonathan Peyton     return task;
1745*7cc577a4SJonathan Peyton }
1746*7cc577a4SJonathan Peyton 
1747*7cc577a4SJonathan Peyton 
1748*7cc577a4SJonathan Peyton //-----------------------------------------------------------
1749*7cc577a4SJonathan Peyton // __kmp_steal_task: remove a task from another thread's deque
1750*7cc577a4SJonathan Peyton // Assume that calling thread has already checked existence of
1751*7cc577a4SJonathan Peyton // task_team thread_data before calling this routine.
1752*7cc577a4SJonathan Peyton 
1753*7cc577a4SJonathan Peyton static kmp_task_t *
1754*7cc577a4SJonathan Peyton __kmp_steal_task( kmp_info_t *victim, kmp_int32 gtid, kmp_task_team_t *task_team,
1755*7cc577a4SJonathan Peyton                   volatile kmp_uint32 *unfinished_threads, int *thread_finished,
1756*7cc577a4SJonathan Peyton                   kmp_int32 is_constrained )
1757*7cc577a4SJonathan Peyton {
1758*7cc577a4SJonathan Peyton     kmp_task_t * task;
1759*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata;
1760*7cc577a4SJonathan Peyton     kmp_thread_data_t *victim_td, *threads_data;
1761*7cc577a4SJonathan Peyton     kmp_int32 victim_tid;
1762*7cc577a4SJonathan Peyton 
1763*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
1764*7cc577a4SJonathan Peyton 
1765*7cc577a4SJonathan Peyton     threads_data = task_team -> tt.tt_threads_data;
1766*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( threads_data != NULL );  // Caller should check this condition
1767*7cc577a4SJonathan Peyton 
1768*7cc577a4SJonathan Peyton     victim_tid = victim->th.th_info.ds.ds_tid;
1769*7cc577a4SJonathan Peyton     victim_td = & threads_data[ victim_tid ];
1770*7cc577a4SJonathan Peyton 
1771*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_steal_task(enter): T#%d try to steal from T#%d: task_team=%p ntasks=%d "
1772*7cc577a4SJonathan Peyton                   "head=%u tail=%u\n",
1773*7cc577a4SJonathan Peyton                   gtid, __kmp_gtid_from_thread( victim ), task_team, victim_td->td.td_deque_ntasks,
1774*7cc577a4SJonathan Peyton                   victim_td->td.td_deque_head, victim_td->td.td_deque_tail) );
1775*7cc577a4SJonathan Peyton 
1776*7cc577a4SJonathan Peyton     if ( (TCR_4(victim_td -> td.td_deque_ntasks) == 0) || // Caller should not check this condition
1777*7cc577a4SJonathan Peyton          (TCR_PTR(victim->th.th_task_team) != task_team)) // GEH: why would this happen?
1778*7cc577a4SJonathan Peyton     {
1779*7cc577a4SJonathan Peyton         KA_TRACE(10, ("__kmp_steal_task(exit #1): T#%d could not steal from T#%d: task_team=%p "
1780*7cc577a4SJonathan Peyton                       "ntasks=%d head=%u tail=%u\n",
1781*7cc577a4SJonathan Peyton                       gtid, __kmp_gtid_from_thread( victim ), task_team, victim_td->td.td_deque_ntasks,
1782*7cc577a4SJonathan Peyton                       victim_td->td.td_deque_head, victim_td->td.td_deque_tail) );
1783*7cc577a4SJonathan Peyton         return NULL;
1784*7cc577a4SJonathan Peyton     }
1785*7cc577a4SJonathan Peyton 
1786*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & victim_td -> td.td_deque_lock );
1787*7cc577a4SJonathan Peyton 
1788*7cc577a4SJonathan Peyton     // Check again after we acquire the lock
1789*7cc577a4SJonathan Peyton     if ( (TCR_4(victim_td -> td.td_deque_ntasks) == 0) ||
1790*7cc577a4SJonathan Peyton          (TCR_PTR(victim->th.th_task_team) != task_team)) // GEH: why would this happen?
1791*7cc577a4SJonathan Peyton     {
1792*7cc577a4SJonathan Peyton         __kmp_release_bootstrap_lock( & victim_td -> td.td_deque_lock );
1793*7cc577a4SJonathan Peyton         KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: task_team=%p "
1794*7cc577a4SJonathan Peyton                       "ntasks=%d head=%u tail=%u\n",
1795*7cc577a4SJonathan Peyton                       gtid, __kmp_gtid_from_thread( victim ), task_team, victim_td->td.td_deque_ntasks,
1796*7cc577a4SJonathan Peyton                       victim_td->td.td_deque_head, victim_td->td.td_deque_tail) );
1797*7cc577a4SJonathan Peyton         return NULL;
1798*7cc577a4SJonathan Peyton     }
1799*7cc577a4SJonathan Peyton 
1800*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( victim_td -> td.td_deque != NULL );
1801*7cc577a4SJonathan Peyton 
1802*7cc577a4SJonathan Peyton     taskdata = victim_td->td.td_deque[victim_td->td.td_deque_head];
1803*7cc577a4SJonathan Peyton     if ( is_constrained ) {
1804*7cc577a4SJonathan Peyton         // we need to check if the candidate obeys task scheduling constraint:
1805*7cc577a4SJonathan Peyton         // only descendant of current task can be scheduled
1806*7cc577a4SJonathan Peyton         kmp_taskdata_t * current = __kmp_threads[ gtid ]->th.th_current_task;
1807*7cc577a4SJonathan Peyton         kmp_int32        level = current->td_level;
1808*7cc577a4SJonathan Peyton         kmp_taskdata_t * parent = taskdata->td_parent;
1809*7cc577a4SJonathan Peyton         while ( parent != current && parent->td_level > level ) {
1810*7cc577a4SJonathan Peyton             parent = parent->td_parent;  // check generation up to the level of the current task
1811*7cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT(parent != NULL);
1812*7cc577a4SJonathan Peyton         }
1813*7cc577a4SJonathan Peyton         if ( parent != current ) {
1814*7cc577a4SJonathan Peyton             // If the head task is not a descendant of the current task then do not
1815*7cc577a4SJonathan Peyton             // steal it. No other task in victim's deque can be a descendant of the
1816*7cc577a4SJonathan Peyton             // current task.
1817*7cc577a4SJonathan Peyton             __kmp_release_bootstrap_lock( & victim_td -> td.td_deque_lock );
1818*7cc577a4SJonathan Peyton             KA_TRACE(10, ("__kmp_steal_task(exit #2): T#%d could not steal from T#%d: task_team=%p "
1819*7cc577a4SJonathan Peyton                           "ntasks=%d head=%u tail=%u\n",
1820*7cc577a4SJonathan Peyton                           gtid, __kmp_gtid_from_thread( threads_data[victim_tid].td.td_thr ),
1821*7cc577a4SJonathan Peyton                           task_team, victim_td->td.td_deque_ntasks,
1822*7cc577a4SJonathan Peyton                           victim_td->td.td_deque_head, victim_td->td.td_deque_tail) );
1823*7cc577a4SJonathan Peyton             return NULL;
1824*7cc577a4SJonathan Peyton         }
1825*7cc577a4SJonathan Peyton     }
1826*7cc577a4SJonathan Peyton     // Bump head pointer and Wrap.
1827*7cc577a4SJonathan Peyton     victim_td->td.td_deque_head = (victim_td->td.td_deque_head + 1) & TASK_DEQUE_MASK(victim_td->td);
1828*7cc577a4SJonathan Peyton     if (*thread_finished) {
1829*7cc577a4SJonathan Peyton         // We need to un-mark this victim as a finished victim.  This must be done before
1830*7cc577a4SJonathan Peyton         // releasing the lock, or else other threads (starting with the master victim)
1831*7cc577a4SJonathan Peyton         // might be prematurely released from the barrier!!!
1832*7cc577a4SJonathan Peyton         kmp_uint32 count;
1833*7cc577a4SJonathan Peyton 
1834*7cc577a4SJonathan Peyton         count = KMP_TEST_THEN_INC32( (kmp_int32 *)unfinished_threads );
1835*7cc577a4SJonathan Peyton 
1836*7cc577a4SJonathan Peyton         KA_TRACE(20, ("__kmp_steal_task: T#%d inc unfinished_threads to %d: task_team=%p\n",
1837*7cc577a4SJonathan Peyton                       gtid, count + 1, task_team) );
1838*7cc577a4SJonathan Peyton 
1839*7cc577a4SJonathan Peyton         *thread_finished = FALSE;
1840*7cc577a4SJonathan Peyton     }
1841*7cc577a4SJonathan Peyton     TCW_4(victim_td -> td.td_deque_ntasks, TCR_4(victim_td -> td.td_deque_ntasks) - 1);
1842*7cc577a4SJonathan Peyton 
1843*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & victim_td -> td.td_deque_lock );
1844*7cc577a4SJonathan Peyton 
1845*7cc577a4SJonathan Peyton     KMP_COUNT_BLOCK(TASK_stolen);
1846*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_steal_task(exit #3): T#%d stole task %p from T#%d: task_team=%p "
1847*7cc577a4SJonathan Peyton                   "ntasks=%d head=%u tail=%u\n",
1848*7cc577a4SJonathan Peyton                   gtid, taskdata, __kmp_gtid_from_thread( victim ), task_team,
1849*7cc577a4SJonathan Peyton                   victim_td->td.td_deque_ntasks, victim_td->td.td_deque_head,
1850*7cc577a4SJonathan Peyton                   victim_td->td.td_deque_tail) );
1851*7cc577a4SJonathan Peyton 
1852*7cc577a4SJonathan Peyton     task = KMP_TASKDATA_TO_TASK( taskdata );
1853*7cc577a4SJonathan Peyton     return task;
1854*7cc577a4SJonathan Peyton }
1855*7cc577a4SJonathan Peyton 
1856*7cc577a4SJonathan Peyton 
1857*7cc577a4SJonathan Peyton //-----------------------------------------------------------------------------
1858*7cc577a4SJonathan Peyton // __kmp_execute_tasks_template: Choose and execute tasks until either the condition
1859*7cc577a4SJonathan Peyton // is statisfied (return true) or there are none left (return false).
1860*7cc577a4SJonathan Peyton // final_spin is TRUE if this is the spin at the release barrier.
1861*7cc577a4SJonathan Peyton // thread_finished indicates whether the thread is finished executing all
1862*7cc577a4SJonathan Peyton // the tasks it has on its deque, and is at the release barrier.
1863*7cc577a4SJonathan Peyton // spinner is the location on which to spin.
1864*7cc577a4SJonathan Peyton // spinner == NULL means only execute a single task and return.
1865*7cc577a4SJonathan Peyton // checker is the value to check to terminate the spin.
1866*7cc577a4SJonathan Peyton template <class C>
1867*7cc577a4SJonathan Peyton static inline int __kmp_execute_tasks_template(kmp_info_t *thread, kmp_int32 gtid, C *flag, int final_spin,
1868*7cc577a4SJonathan Peyton                                                int *thread_finished
1869*7cc577a4SJonathan Peyton                                                USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained)
1870*7cc577a4SJonathan Peyton {
1871*7cc577a4SJonathan Peyton     kmp_task_team_t *     task_team = thread->th.th_task_team;
1872*7cc577a4SJonathan Peyton     kmp_thread_data_t *   threads_data;
1873*7cc577a4SJonathan Peyton     kmp_task_t *          task;
1874*7cc577a4SJonathan Peyton     kmp_info_t *          other_thread;
1875*7cc577a4SJonathan Peyton     kmp_taskdata_t *      current_task = thread -> th.th_current_task;
1876*7cc577a4SJonathan Peyton     volatile kmp_uint32 * unfinished_threads;
1877*7cc577a4SJonathan Peyton     kmp_int32             nthreads, victim=-2, use_own_tasks=1, new_victim=0, tid=thread->th.th_info.ds.ds_tid;
1878*7cc577a4SJonathan Peyton 
1879*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
1880*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( thread == __kmp_threads[ gtid ] );
1881*7cc577a4SJonathan Peyton 
1882*7cc577a4SJonathan Peyton     if (task_team == NULL) return FALSE;
1883*7cc577a4SJonathan Peyton 
1884*7cc577a4SJonathan Peyton     KA_TRACE(15, ("__kmp_execute_tasks_template(enter): T#%d final_spin=%d *thread_finished=%d\n",
1885*7cc577a4SJonathan Peyton                   gtid, final_spin, *thread_finished) );
1886*7cc577a4SJonathan Peyton 
1887*7cc577a4SJonathan Peyton     threads_data = (kmp_thread_data_t *)TCR_PTR(task_team -> tt.tt_threads_data);
1888*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( threads_data != NULL );
1889*7cc577a4SJonathan Peyton 
1890*7cc577a4SJonathan Peyton     nthreads = task_team -> tt.tt_nproc;
1891*7cc577a4SJonathan Peyton     unfinished_threads = &(task_team -> tt.tt_unfinished_threads);
1892*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
1893*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( nthreads > 1 || task_team->tt.tt_found_proxy_tasks);
1894*7cc577a4SJonathan Peyton #else
1895*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( nthreads > 1 );
1896*7cc577a4SJonathan Peyton #endif
1897*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( (int)(TCR_4(*unfinished_threads)) >= 0 );
1898*7cc577a4SJonathan Peyton 
1899*7cc577a4SJonathan Peyton     while (1) { // Outer loop keeps trying to find tasks in case of single thread getting tasks from target constructs
1900*7cc577a4SJonathan Peyton         while (1) { // Inner loop to find a task and execute it
1901*7cc577a4SJonathan Peyton             task = NULL;
1902*7cc577a4SJonathan Peyton             if (use_own_tasks) { // check on own queue first
1903*7cc577a4SJonathan Peyton                 task = __kmp_remove_my_task( thread, gtid, task_team, is_constrained );
1904*7cc577a4SJonathan Peyton             }
1905*7cc577a4SJonathan Peyton             if ((task == NULL) && (nthreads > 1)) { // Steal a task
1906*7cc577a4SJonathan Peyton                 int asleep = 1;
1907*7cc577a4SJonathan Peyton                 use_own_tasks = 0;
1908*7cc577a4SJonathan Peyton                 // Try to steal from the last place I stole from successfully.
1909*7cc577a4SJonathan Peyton                 if (victim == -2) { // haven't stolen anything yet
1910*7cc577a4SJonathan Peyton                     victim = threads_data[tid].td.td_deque_last_stolen;
1911*7cc577a4SJonathan Peyton                     if (victim != -1) // if we have a last stolen from victim, get the thread
1912*7cc577a4SJonathan Peyton                         other_thread = threads_data[victim].td.td_thr;
1913*7cc577a4SJonathan Peyton                 }
1914*7cc577a4SJonathan Peyton                 if (victim != -1) { // found last victim
1915*7cc577a4SJonathan Peyton                     asleep = 0;
1916*7cc577a4SJonathan Peyton                 }
1917*7cc577a4SJonathan Peyton                 else if (!new_victim) { // no recent steals and we haven't already used a new victim; select a random thread
1918*7cc577a4SJonathan Peyton                     do { // Find a different thread to steal work from.
1919*7cc577a4SJonathan Peyton                         // Pick a random thread. Initial plan was to cycle through all the threads, and only return if
1920*7cc577a4SJonathan Peyton                         // we tried to steal from every thread, and failed.  Arch says that's not such a great idea.
1921*7cc577a4SJonathan Peyton                         victim = __kmp_get_random(thread) % (nthreads - 1);
1922*7cc577a4SJonathan Peyton                         if (victim >= tid) {
1923*7cc577a4SJonathan Peyton                             ++victim;  // Adjusts random distribution to exclude self
1924*7cc577a4SJonathan Peyton                         }
1925*7cc577a4SJonathan Peyton                         // Found a potential victim
1926*7cc577a4SJonathan Peyton                         other_thread = threads_data[victim].td.td_thr;
1927*7cc577a4SJonathan Peyton                         // There is a slight chance that __kmp_enable_tasking() did not wake up all threads
1928*7cc577a4SJonathan Peyton                         // waiting at the barrier.  If victim is sleeping, then wake it up.  Since we were going to
1929*7cc577a4SJonathan Peyton                         // pay the cache miss penalty for referencing another thread's kmp_info_t struct anyway,
1930*7cc577a4SJonathan Peyton                         // the check shouldn't cost too much performance at this point. In extra barrier mode, tasks
1931*7cc577a4SJonathan Peyton                         // do not sleep at the separate tasking barrier, so this isn't a problem.
1932*7cc577a4SJonathan Peyton                         asleep = 0;
1933*7cc577a4SJonathan Peyton                         if ( ( __kmp_tasking_mode == tskm_task_teams ) &&
1934*7cc577a4SJonathan Peyton                              (__kmp_dflt_blocktime != KMP_MAX_BLOCKTIME) &&
1935*7cc577a4SJonathan Peyton                              (TCR_PTR(other_thread->th.th_sleep_loc) != NULL)) {
1936*7cc577a4SJonathan Peyton                             asleep = 1;
1937*7cc577a4SJonathan Peyton                             __kmp_null_resume_wrapper(__kmp_gtid_from_thread(other_thread), other_thread->th.th_sleep_loc);
1938*7cc577a4SJonathan Peyton                             // A sleeping thread should not have any tasks on it's queue. There is a slight
1939*7cc577a4SJonathan Peyton                             // possibility that it resumes, steals a task from another thread, which spawns more
1940*7cc577a4SJonathan Peyton                             // tasks, all in the time that it takes this thread to check => don't write an assertion
1941*7cc577a4SJonathan Peyton                             // that the victim's queue is empty.  Try stealing from a different thread.
1942*7cc577a4SJonathan Peyton                         }
1943*7cc577a4SJonathan Peyton                     } while (asleep);
1944*7cc577a4SJonathan Peyton                 }
1945*7cc577a4SJonathan Peyton 
1946*7cc577a4SJonathan Peyton                 if (!asleep) {
1947*7cc577a4SJonathan Peyton                     // We have a victim to try to steal from
1948*7cc577a4SJonathan Peyton                     task = __kmp_steal_task(other_thread, gtid, task_team, unfinished_threads, thread_finished, is_constrained);
1949*7cc577a4SJonathan Peyton                 }
1950*7cc577a4SJonathan Peyton                 if (task != NULL) { // set last stolen to victim
1951*7cc577a4SJonathan Peyton                     if (threads_data[tid].td.td_deque_last_stolen != victim) {
1952*7cc577a4SJonathan Peyton                         threads_data[tid].td.td_deque_last_stolen = victim;
1953*7cc577a4SJonathan Peyton                         // The pre-refactored code did not try more than 1 successful new vicitm,
1954*7cc577a4SJonathan Peyton                         // unless the last one generated more local tasks; new_victim keeps track of this
1955*7cc577a4SJonathan Peyton                         new_victim = 1;
1956*7cc577a4SJonathan Peyton                     }
1957*7cc577a4SJonathan Peyton                 }
1958*7cc577a4SJonathan Peyton                 else { // No tasks found; unset last_stolen
1959*7cc577a4SJonathan Peyton                     KMP_CHECK_UPDATE(threads_data[tid].td.td_deque_last_stolen, -1);
1960*7cc577a4SJonathan Peyton                     victim = -2; // no successful victim found
1961*7cc577a4SJonathan Peyton                 }
1962*7cc577a4SJonathan Peyton             }
1963*7cc577a4SJonathan Peyton 
1964*7cc577a4SJonathan Peyton             if (task == NULL) // break out of tasking loop
1965*7cc577a4SJonathan Peyton                 break;
1966*7cc577a4SJonathan Peyton 
1967*7cc577a4SJonathan Peyton             // Found a task; execute it
1968*7cc577a4SJonathan Peyton #if USE_ITT_BUILD && USE_ITT_NOTIFY
1969*7cc577a4SJonathan Peyton             if ( __itt_sync_create_ptr || KMP_ITT_DEBUG ) {
1970*7cc577a4SJonathan Peyton                 if ( itt_sync_obj == NULL ) { // we are at fork barrier where we could not get the object reliably
1971*7cc577a4SJonathan Peyton                     itt_sync_obj = __kmp_itt_barrier_object( gtid, bs_forkjoin_barrier );
1972*7cc577a4SJonathan Peyton                 }
1973*7cc577a4SJonathan Peyton                 __kmp_itt_task_starting( itt_sync_obj );
1974*7cc577a4SJonathan Peyton             }
1975*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD && USE_ITT_NOTIFY */
1976*7cc577a4SJonathan Peyton             __kmp_invoke_task( gtid, task, current_task );
1977*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
1978*7cc577a4SJonathan Peyton             if ( itt_sync_obj != NULL ) __kmp_itt_task_finished( itt_sync_obj );
1979*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
1980*7cc577a4SJonathan Peyton             // If this thread is only partway through the barrier and the condition is met, then return now,
1981*7cc577a4SJonathan Peyton             // so that the barrier gather/release pattern can proceed. If this thread is in the last spin loop
1982*7cc577a4SJonathan Peyton             // in the barrier, waiting to be released, we know that the termination condition will not be
1983*7cc577a4SJonathan Peyton             // satisified, so don't waste any cycles checking it.
1984*7cc577a4SJonathan Peyton             if (flag == NULL || (!final_spin && flag->done_check())) {
1985*7cc577a4SJonathan Peyton                 KA_TRACE(15, ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n", gtid) );
1986*7cc577a4SJonathan Peyton                 return TRUE;
1987*7cc577a4SJonathan Peyton             }
1988*7cc577a4SJonathan Peyton             if (thread->th.th_task_team == NULL) {
1989*7cc577a4SJonathan Peyton                 break;
1990*7cc577a4SJonathan Peyton             }
1991*7cc577a4SJonathan Peyton             KMP_YIELD( __kmp_library == library_throughput );   // Yield before executing next task
1992*7cc577a4SJonathan Peyton             // If execution of a stolen task results in more tasks being placed on our run queue, reset use_own_tasks
1993*7cc577a4SJonathan Peyton             if (!use_own_tasks && TCR_4(threads_data[tid].td.td_deque_ntasks) != 0) {
1994*7cc577a4SJonathan Peyton                 KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d stolen task spawned other tasks, restart\n", gtid));
1995*7cc577a4SJonathan Peyton                 use_own_tasks = 1;
1996*7cc577a4SJonathan Peyton                 new_victim = 0;
1997*7cc577a4SJonathan Peyton             }
1998*7cc577a4SJonathan Peyton         }
1999*7cc577a4SJonathan Peyton 
2000*7cc577a4SJonathan Peyton         // The task source has been exhausted. If in final spin loop of barrier, check if termination condition is satisfied.
2001*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
2002*7cc577a4SJonathan Peyton         // The work queue may be empty but there might be proxy tasks still executing
2003*7cc577a4SJonathan Peyton         if (final_spin && TCR_4(current_task->td_incomplete_child_tasks) == 0)
2004*7cc577a4SJonathan Peyton #else
2005*7cc577a4SJonathan Peyton         if (final_spin)
2006*7cc577a4SJonathan Peyton #endif
2007*7cc577a4SJonathan Peyton         {
2008*7cc577a4SJonathan Peyton             // First, decrement the #unfinished threads, if that has not already been done.  This decrement
2009*7cc577a4SJonathan Peyton             // might be to the spin location, and result in the termination condition being satisfied.
2010*7cc577a4SJonathan Peyton             if (! *thread_finished) {
2011*7cc577a4SJonathan Peyton                 kmp_uint32 count;
2012*7cc577a4SJonathan Peyton 
2013*7cc577a4SJonathan Peyton                 count = KMP_TEST_THEN_DEC32( (kmp_int32 *)unfinished_threads ) - 1;
2014*7cc577a4SJonathan Peyton                 KA_TRACE(20, ("__kmp_execute_tasks_template: T#%d dec unfinished_threads to %d task_team=%p\n",
2015*7cc577a4SJonathan Peyton                               gtid, count, task_team) );
2016*7cc577a4SJonathan Peyton                 *thread_finished = TRUE;
2017*7cc577a4SJonathan Peyton             }
2018*7cc577a4SJonathan Peyton 
2019*7cc577a4SJonathan Peyton             // It is now unsafe to reference thread->th.th_team !!!
2020*7cc577a4SJonathan Peyton             // Decrementing task_team->tt.tt_unfinished_threads can allow the master thread to pass through
2021*7cc577a4SJonathan Peyton             // the barrier, where it might reset each thread's th.th_team field for the next parallel region.
2022*7cc577a4SJonathan Peyton             // If we can steal more work, we know that this has not happened yet.
2023*7cc577a4SJonathan Peyton             if (flag != NULL && flag->done_check()) {
2024*7cc577a4SJonathan Peyton                 KA_TRACE(15, ("__kmp_execute_tasks_template: T#%d spin condition satisfied\n", gtid) );
2025*7cc577a4SJonathan Peyton                 return TRUE;
2026*7cc577a4SJonathan Peyton             }
2027*7cc577a4SJonathan Peyton         }
2028*7cc577a4SJonathan Peyton 
2029*7cc577a4SJonathan Peyton         // If this thread's task team is NULL, master has recognized that there are no more tasks; bail out
2030*7cc577a4SJonathan Peyton         if (thread->th.th_task_team == NULL) {
2031*7cc577a4SJonathan Peyton             KA_TRACE(15, ("__kmp_execute_tasks_template: T#%d no more tasks\n", gtid) );
2032*7cc577a4SJonathan Peyton             return FALSE;
2033*7cc577a4SJonathan Peyton         }
2034*7cc577a4SJonathan Peyton 
2035*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
2036*7cc577a4SJonathan Peyton         // We could be getting tasks from target constructs; if this is the only thread, keep trying to execute
2037*7cc577a4SJonathan Peyton         // tasks from own queue
2038*7cc577a4SJonathan Peyton         if (nthreads == 1)
2039*7cc577a4SJonathan Peyton             use_own_tasks = 1;
2040*7cc577a4SJonathan Peyton         else
2041*7cc577a4SJonathan Peyton #endif
2042*7cc577a4SJonathan Peyton         {
2043*7cc577a4SJonathan Peyton             KA_TRACE(15, ("__kmp_execute_tasks_template: T#%d can't find work\n", gtid) );
2044*7cc577a4SJonathan Peyton             return FALSE;
2045*7cc577a4SJonathan Peyton         }
2046*7cc577a4SJonathan Peyton     }
2047*7cc577a4SJonathan Peyton }
2048*7cc577a4SJonathan Peyton 
2049*7cc577a4SJonathan Peyton int __kmp_execute_tasks_32(kmp_info_t *thread, kmp_int32 gtid, kmp_flag_32 *flag, int final_spin,
2050*7cc577a4SJonathan Peyton                            int *thread_finished
2051*7cc577a4SJonathan Peyton                            USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained)
2052*7cc577a4SJonathan Peyton {
2053*7cc577a4SJonathan Peyton     return __kmp_execute_tasks_template(thread, gtid, flag, final_spin, thread_finished
2054*7cc577a4SJonathan Peyton                                         USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
2055*7cc577a4SJonathan Peyton }
2056*7cc577a4SJonathan Peyton 
2057*7cc577a4SJonathan Peyton int __kmp_execute_tasks_64(kmp_info_t *thread, kmp_int32 gtid, kmp_flag_64 *flag, int final_spin,
2058*7cc577a4SJonathan Peyton                            int *thread_finished
2059*7cc577a4SJonathan Peyton                            USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained)
2060*7cc577a4SJonathan Peyton {
2061*7cc577a4SJonathan Peyton     return __kmp_execute_tasks_template(thread, gtid, flag, final_spin, thread_finished
2062*7cc577a4SJonathan Peyton                                         USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
2063*7cc577a4SJonathan Peyton }
2064*7cc577a4SJonathan Peyton 
2065*7cc577a4SJonathan Peyton int __kmp_execute_tasks_oncore(kmp_info_t *thread, kmp_int32 gtid, kmp_flag_oncore *flag, int final_spin,
2066*7cc577a4SJonathan Peyton                                int *thread_finished
2067*7cc577a4SJonathan Peyton                                USE_ITT_BUILD_ARG(void * itt_sync_obj), kmp_int32 is_constrained)
2068*7cc577a4SJonathan Peyton {
2069*7cc577a4SJonathan Peyton     return __kmp_execute_tasks_template(thread, gtid, flag, final_spin, thread_finished
2070*7cc577a4SJonathan Peyton                                         USE_ITT_BUILD_ARG(itt_sync_obj), is_constrained);
2071*7cc577a4SJonathan Peyton }
2072*7cc577a4SJonathan Peyton 
2073*7cc577a4SJonathan Peyton 
2074*7cc577a4SJonathan Peyton 
2075*7cc577a4SJonathan Peyton //-----------------------------------------------------------------------------
2076*7cc577a4SJonathan Peyton // __kmp_enable_tasking: Allocate task team and resume threads sleeping at the
2077*7cc577a4SJonathan Peyton // next barrier so they can assist in executing enqueued tasks.
2078*7cc577a4SJonathan Peyton // First thread in allocates the task team atomically.
2079*7cc577a4SJonathan Peyton 
2080*7cc577a4SJonathan Peyton static void
2081*7cc577a4SJonathan Peyton __kmp_enable_tasking( kmp_task_team_t *task_team, kmp_info_t *this_thr )
2082*7cc577a4SJonathan Peyton {
2083*7cc577a4SJonathan Peyton     kmp_thread_data_t *threads_data;
2084*7cc577a4SJonathan Peyton     int nthreads, i, is_init_thread;
2085*7cc577a4SJonathan Peyton 
2086*7cc577a4SJonathan Peyton     KA_TRACE( 10, ( "__kmp_enable_tasking(enter): T#%d\n",
2087*7cc577a4SJonathan Peyton                     __kmp_gtid_from_thread( this_thr ) ) );
2088*7cc577a4SJonathan Peyton 
2089*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(task_team != NULL);
2090*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(this_thr->th.th_team != NULL);
2091*7cc577a4SJonathan Peyton 
2092*7cc577a4SJonathan Peyton     nthreads = task_team->tt.tt_nproc;
2093*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(nthreads > 0);
2094*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(nthreads == this_thr->th.th_team->t.t_nproc);
2095*7cc577a4SJonathan Peyton 
2096*7cc577a4SJonathan Peyton     // Allocate or increase the size of threads_data if necessary
2097*7cc577a4SJonathan Peyton     is_init_thread = __kmp_realloc_task_threads_data( this_thr, task_team );
2098*7cc577a4SJonathan Peyton 
2099*7cc577a4SJonathan Peyton     if (!is_init_thread) {
2100*7cc577a4SJonathan Peyton         // Some other thread already set up the array.
2101*7cc577a4SJonathan Peyton         KA_TRACE( 20, ( "__kmp_enable_tasking(exit): T#%d: threads array already set up.\n",
2102*7cc577a4SJonathan Peyton                         __kmp_gtid_from_thread( this_thr ) ) );
2103*7cc577a4SJonathan Peyton         return;
2104*7cc577a4SJonathan Peyton     }
2105*7cc577a4SJonathan Peyton     threads_data = (kmp_thread_data_t *)TCR_PTR(task_team -> tt.tt_threads_data);
2106*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( threads_data != NULL );
2107*7cc577a4SJonathan Peyton 
2108*7cc577a4SJonathan Peyton     if ( ( __kmp_tasking_mode == tskm_task_teams ) &&
2109*7cc577a4SJonathan Peyton          ( __kmp_dflt_blocktime != KMP_MAX_BLOCKTIME ) )
2110*7cc577a4SJonathan Peyton     {
2111*7cc577a4SJonathan Peyton         // Release any threads sleeping at the barrier, so that they can steal
2112*7cc577a4SJonathan Peyton         // tasks and execute them.  In extra barrier mode, tasks do not sleep
2113*7cc577a4SJonathan Peyton         // at the separate tasking barrier, so this isn't a problem.
2114*7cc577a4SJonathan Peyton         for (i = 0; i < nthreads; i++) {
2115*7cc577a4SJonathan Peyton             volatile void *sleep_loc;
2116*7cc577a4SJonathan Peyton             kmp_info_t *thread = threads_data[i].td.td_thr;
2117*7cc577a4SJonathan Peyton 
2118*7cc577a4SJonathan Peyton             if (i == this_thr->th.th_info.ds.ds_tid) {
2119*7cc577a4SJonathan Peyton                 continue;
2120*7cc577a4SJonathan Peyton             }
2121*7cc577a4SJonathan Peyton             // Since we haven't locked the thread's suspend mutex lock at this
2122*7cc577a4SJonathan Peyton             // point, there is a small window where a thread might be putting
2123*7cc577a4SJonathan Peyton             // itself to sleep, but hasn't set the th_sleep_loc field yet.
2124*7cc577a4SJonathan Peyton             // To work around this, __kmp_execute_tasks_template() periodically checks
2125*7cc577a4SJonathan Peyton             // see if other threads are sleeping (using the same random
2126*7cc577a4SJonathan Peyton             // mechanism that is used for task stealing) and awakens them if
2127*7cc577a4SJonathan Peyton             // they are.
2128*7cc577a4SJonathan Peyton             if ( ( sleep_loc = TCR_PTR( thread -> th.th_sleep_loc) ) != NULL )
2129*7cc577a4SJonathan Peyton             {
2130*7cc577a4SJonathan Peyton                 KF_TRACE( 50, ( "__kmp_enable_tasking: T#%d waking up thread T#%d\n",
2131*7cc577a4SJonathan Peyton                                  __kmp_gtid_from_thread( this_thr ),
2132*7cc577a4SJonathan Peyton                                  __kmp_gtid_from_thread( thread ) ) );
2133*7cc577a4SJonathan Peyton                 __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc);
2134*7cc577a4SJonathan Peyton             }
2135*7cc577a4SJonathan Peyton             else {
2136*7cc577a4SJonathan Peyton                 KF_TRACE( 50, ( "__kmp_enable_tasking: T#%d don't wake up thread T#%d\n",
2137*7cc577a4SJonathan Peyton                                  __kmp_gtid_from_thread( this_thr ),
2138*7cc577a4SJonathan Peyton                                  __kmp_gtid_from_thread( thread ) ) );
2139*7cc577a4SJonathan Peyton             }
2140*7cc577a4SJonathan Peyton         }
2141*7cc577a4SJonathan Peyton     }
2142*7cc577a4SJonathan Peyton 
2143*7cc577a4SJonathan Peyton     KA_TRACE( 10, ( "__kmp_enable_tasking(exit): T#%d\n",
2144*7cc577a4SJonathan Peyton                     __kmp_gtid_from_thread( this_thr ) ) );
2145*7cc577a4SJonathan Peyton }
2146*7cc577a4SJonathan Peyton 
2147*7cc577a4SJonathan Peyton 
2148*7cc577a4SJonathan Peyton /* ------------------------------------------------------------------------ */
2149*7cc577a4SJonathan Peyton /* // TODO: Check the comment consistency
2150*7cc577a4SJonathan Peyton  * Utility routines for "task teams".  A task team (kmp_task_t) is kind of
2151*7cc577a4SJonathan Peyton  * like a shadow of the kmp_team_t data struct, with a different lifetime.
2152*7cc577a4SJonathan Peyton  * After a child * thread checks into a barrier and calls __kmp_release() from
2153*7cc577a4SJonathan Peyton  * the particular variant of __kmp_<barrier_kind>_barrier_gather(), it can no
2154*7cc577a4SJonathan Peyton  * longer assume that the kmp_team_t structure is intact (at any moment, the
2155*7cc577a4SJonathan Peyton  * master thread may exit the barrier code and free the team data structure,
2156*7cc577a4SJonathan Peyton  * and return the threads to the thread pool).
2157*7cc577a4SJonathan Peyton  *
2158*7cc577a4SJonathan Peyton  * This does not work with the the tasking code, as the thread is still
2159*7cc577a4SJonathan Peyton  * expected to participate in the execution of any tasks that may have been
2160*7cc577a4SJonathan Peyton  * spawned my a member of the team, and the thread still needs access to all
2161*7cc577a4SJonathan Peyton  * to each thread in the team, so that it can steal work from it.
2162*7cc577a4SJonathan Peyton  *
2163*7cc577a4SJonathan Peyton  * Enter the existence of the kmp_task_team_t struct.  It employs a reference
2164*7cc577a4SJonathan Peyton  * counting mechanims, and is allocated by the master thread before calling
2165*7cc577a4SJonathan Peyton  * __kmp_<barrier_kind>_release, and then is release by the last thread to
2166*7cc577a4SJonathan Peyton  * exit __kmp_<barrier_kind>_release at the next barrier.  I.e. the lifetimes
2167*7cc577a4SJonathan Peyton  * of the kmp_task_team_t structs for consecutive barriers can overlap
2168*7cc577a4SJonathan Peyton  * (and will, unless the master thread is the last thread to exit the barrier
2169*7cc577a4SJonathan Peyton  * release phase, which is not typical).
2170*7cc577a4SJonathan Peyton  *
2171*7cc577a4SJonathan Peyton  * The existence of such a struct is useful outside the context of tasking,
2172*7cc577a4SJonathan Peyton  * but for now, I'm trying to keep it specific to the OMP_30_ENABLED macro,
2173*7cc577a4SJonathan Peyton  * so that any performance differences show up when comparing the 2.5 vs. 3.0
2174*7cc577a4SJonathan Peyton  * libraries.
2175*7cc577a4SJonathan Peyton  *
2176*7cc577a4SJonathan Peyton  * We currently use the existence of the threads array as an indicator that
2177*7cc577a4SJonathan Peyton  * tasks were spawned since the last barrier.  If the structure is to be
2178*7cc577a4SJonathan Peyton  * useful outside the context of tasking, then this will have to change, but
2179*7cc577a4SJonathan Peyton  * not settting the field minimizes the performance impact of tasking on
2180*7cc577a4SJonathan Peyton  * barriers, when no explicit tasks were spawned (pushed, actually).
2181*7cc577a4SJonathan Peyton  */
2182*7cc577a4SJonathan Peyton 
2183*7cc577a4SJonathan Peyton 
2184*7cc577a4SJonathan Peyton static kmp_task_team_t *__kmp_free_task_teams = NULL;           // Free list for task_team data structures
2185*7cc577a4SJonathan Peyton // Lock for task team data structures
2186*7cc577a4SJonathan Peyton static kmp_bootstrap_lock_t __kmp_task_team_lock = KMP_BOOTSTRAP_LOCK_INITIALIZER( __kmp_task_team_lock );
2187*7cc577a4SJonathan Peyton 
2188*7cc577a4SJonathan Peyton 
2189*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2190*7cc577a4SJonathan Peyton // __kmp_alloc_task_deque:
2191*7cc577a4SJonathan Peyton // Allocates a task deque for a particular thread, and initialize the necessary
2192*7cc577a4SJonathan Peyton // data structures relating to the deque.  This only happens once per thread
2193*7cc577a4SJonathan Peyton // per task team since task teams are recycled.
2194*7cc577a4SJonathan Peyton // No lock is needed during allocation since each thread allocates its own
2195*7cc577a4SJonathan Peyton // deque.
2196*7cc577a4SJonathan Peyton 
2197*7cc577a4SJonathan Peyton static void
2198*7cc577a4SJonathan Peyton __kmp_alloc_task_deque( kmp_info_t *thread, kmp_thread_data_t *thread_data )
2199*7cc577a4SJonathan Peyton {
2200*7cc577a4SJonathan Peyton     __kmp_init_bootstrap_lock( & thread_data -> td.td_deque_lock );
2201*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( thread_data -> td.td_deque == NULL );
2202*7cc577a4SJonathan Peyton 
2203*7cc577a4SJonathan Peyton     // Initialize last stolen task field to "none"
2204*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_last_stolen = -1;
2205*7cc577a4SJonathan Peyton 
2206*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( TCR_4(thread_data -> td.td_deque_ntasks) == 0 );
2207*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( thread_data -> td.td_deque_head == 0 );
2208*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( thread_data -> td.td_deque_tail == 0 );
2209*7cc577a4SJonathan Peyton 
2210*7cc577a4SJonathan Peyton     KE_TRACE( 10, ( "__kmp_alloc_task_deque: T#%d allocating deque[%d] for thread_data %p\n",
2211*7cc577a4SJonathan Peyton                    __kmp_gtid_from_thread( thread ), INITIAL_TASK_DEQUE_SIZE, thread_data ) );
2212*7cc577a4SJonathan Peyton     // Allocate space for task deque, and zero the deque
2213*7cc577a4SJonathan Peyton     // Cannot use __kmp_thread_calloc() because threads not around for
2214*7cc577a4SJonathan Peyton     // kmp_reap_task_team( ).
2215*7cc577a4SJonathan Peyton     thread_data -> td.td_deque = (kmp_taskdata_t **)
2216*7cc577a4SJonathan Peyton             __kmp_allocate( INITIAL_TASK_DEQUE_SIZE * sizeof(kmp_taskdata_t *));
2217*7cc577a4SJonathan Peyton 	thread_data -> td.td_deque_size = INITIAL_TASK_DEQUE_SIZE;
2218*7cc577a4SJonathan Peyton }
2219*7cc577a4SJonathan Peyton 
2220*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2221*7cc577a4SJonathan Peyton // __kmp_realloc_task_deque:
2222*7cc577a4SJonathan Peyton // Re-allocates a task deque for a particular thread, copies the content from the old deque
2223*7cc577a4SJonathan Peyton // and adjusts the necessary data structures relating to the deque.
2224*7cc577a4SJonathan Peyton // This operation must be done with a the deque_lock being held
2225*7cc577a4SJonathan Peyton 
2226*7cc577a4SJonathan Peyton static void __kmp_realloc_task_deque ( kmp_info_t *thread, kmp_thread_data_t *thread_data )
2227*7cc577a4SJonathan Peyton {
2228*7cc577a4SJonathan Peyton     kmp_int32 size = TASK_DEQUE_SIZE(thread_data->td);
2229*7cc577a4SJonathan Peyton     kmp_int32 new_size = 2 * size;
2230*7cc577a4SJonathan Peyton 
2231*7cc577a4SJonathan Peyton     KE_TRACE( 10, ( "__kmp_realloc_task_deque: T#%d reallocating deque[from %d to %d] for thread_data %p\n",
2232*7cc577a4SJonathan Peyton                   __kmp_gtid_from_thread( thread ), size, new_size, thread_data ) );
2233*7cc577a4SJonathan Peyton 
2234*7cc577a4SJonathan Peyton     kmp_taskdata_t ** new_deque = (kmp_taskdata_t **) __kmp_allocate( new_size * sizeof(kmp_taskdata_t *));
2235*7cc577a4SJonathan Peyton 
2236*7cc577a4SJonathan Peyton     int i,j;
2237*7cc577a4SJonathan Peyton     for ( i = thread_data->td.td_deque_head, j = 0; j < size; i = (i+1) & TASK_DEQUE_MASK(thread_data->td), j++ )
2238*7cc577a4SJonathan Peyton        new_deque[j] = thread_data->td.td_deque[i];
2239*7cc577a4SJonathan Peyton 
2240*7cc577a4SJonathan Peyton     __kmp_free(thread_data->td.td_deque);
2241*7cc577a4SJonathan Peyton 
2242*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_head = 0;
2243*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_tail = size;
2244*7cc577a4SJonathan Peyton     thread_data -> td.td_deque = new_deque;
2245*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_size = new_size;
2246*7cc577a4SJonathan Peyton }
2247*7cc577a4SJonathan Peyton 
2248*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2249*7cc577a4SJonathan Peyton // __kmp_free_task_deque:
2250*7cc577a4SJonathan Peyton // Deallocates a task deque for a particular thread.
2251*7cc577a4SJonathan Peyton // Happens at library deallocation so don't need to reset all thread data fields.
2252*7cc577a4SJonathan Peyton 
2253*7cc577a4SJonathan Peyton static void
2254*7cc577a4SJonathan Peyton __kmp_free_task_deque( kmp_thread_data_t *thread_data )
2255*7cc577a4SJonathan Peyton {
2256*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & thread_data -> td.td_deque_lock );
2257*7cc577a4SJonathan Peyton 
2258*7cc577a4SJonathan Peyton     if ( thread_data -> td.td_deque != NULL ) {
2259*7cc577a4SJonathan Peyton         TCW_4(thread_data -> td.td_deque_ntasks, 0);
2260*7cc577a4SJonathan Peyton          __kmp_free( thread_data -> td.td_deque );
2261*7cc577a4SJonathan Peyton         thread_data -> td.td_deque = NULL;
2262*7cc577a4SJonathan Peyton     }
2263*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & thread_data -> td.td_deque_lock );
2264*7cc577a4SJonathan Peyton 
2265*7cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
2266*7cc577a4SJonathan Peyton     // GEH: Figure out what to do here for td_susp_tied_tasks
2267*7cc577a4SJonathan Peyton     if ( thread_data -> td.td_susp_tied_tasks.ts_entries != TASK_STACK_EMPTY ) {
2268*7cc577a4SJonathan Peyton         __kmp_free_task_stack( __kmp_thread_from_gtid( gtid ), thread_data );
2269*7cc577a4SJonathan Peyton     }
2270*7cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK
2271*7cc577a4SJonathan Peyton }
2272*7cc577a4SJonathan Peyton 
2273*7cc577a4SJonathan Peyton 
2274*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2275*7cc577a4SJonathan Peyton // __kmp_realloc_task_threads_data:
2276*7cc577a4SJonathan Peyton // Allocates a threads_data array for a task team, either by allocating an initial
2277*7cc577a4SJonathan Peyton // array or enlarging an existing array.  Only the first thread to get the lock
2278*7cc577a4SJonathan Peyton // allocs or enlarges the array and re-initializes the array eleemnts.
2279*7cc577a4SJonathan Peyton // That thread returns "TRUE", the rest return "FALSE".
2280*7cc577a4SJonathan Peyton // Assumes that the new array size is given by task_team -> tt.tt_nproc.
2281*7cc577a4SJonathan Peyton // The current size is given by task_team -> tt.tt_max_threads.
2282*7cc577a4SJonathan Peyton 
2283*7cc577a4SJonathan Peyton static int
2284*7cc577a4SJonathan Peyton __kmp_realloc_task_threads_data( kmp_info_t *thread, kmp_task_team_t *task_team )
2285*7cc577a4SJonathan Peyton {
2286*7cc577a4SJonathan Peyton     kmp_thread_data_t ** threads_data_p;
2287*7cc577a4SJonathan Peyton     kmp_int32            nthreads, maxthreads;
2288*7cc577a4SJonathan Peyton     int                  is_init_thread = FALSE;
2289*7cc577a4SJonathan Peyton 
2290*7cc577a4SJonathan Peyton     if ( TCR_4(task_team -> tt.tt_found_tasks) ) {
2291*7cc577a4SJonathan Peyton         // Already reallocated and initialized.
2292*7cc577a4SJonathan Peyton         return FALSE;
2293*7cc577a4SJonathan Peyton     }
2294*7cc577a4SJonathan Peyton 
2295*7cc577a4SJonathan Peyton     threads_data_p = & task_team -> tt.tt_threads_data;
2296*7cc577a4SJonathan Peyton     nthreads   = task_team -> tt.tt_nproc;
2297*7cc577a4SJonathan Peyton     maxthreads = task_team -> tt.tt_max_threads;
2298*7cc577a4SJonathan Peyton 
2299*7cc577a4SJonathan Peyton     // All threads must lock when they encounter the first task of the implicit task
2300*7cc577a4SJonathan Peyton     // region to make sure threads_data fields are (re)initialized before used.
2301*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & task_team -> tt.tt_threads_lock );
2302*7cc577a4SJonathan Peyton 
2303*7cc577a4SJonathan Peyton     if ( ! TCR_4(task_team -> tt.tt_found_tasks) ) {
2304*7cc577a4SJonathan Peyton         // first thread to enable tasking
2305*7cc577a4SJonathan Peyton         kmp_team_t *team = thread -> th.th_team;
2306*7cc577a4SJonathan Peyton         int i;
2307*7cc577a4SJonathan Peyton 
2308*7cc577a4SJonathan Peyton         is_init_thread = TRUE;
2309*7cc577a4SJonathan Peyton         if ( maxthreads < nthreads ) {
2310*7cc577a4SJonathan Peyton 
2311*7cc577a4SJonathan Peyton             if ( *threads_data_p != NULL ) {
2312*7cc577a4SJonathan Peyton                 kmp_thread_data_t *old_data = *threads_data_p;
2313*7cc577a4SJonathan Peyton                 kmp_thread_data_t *new_data = NULL;
2314*7cc577a4SJonathan Peyton 
2315*7cc577a4SJonathan Peyton                 KE_TRACE( 10, ( "__kmp_realloc_task_threads_data: T#%d reallocating "
2316*7cc577a4SJonathan Peyton                                "threads data for task_team %p, new_size = %d, old_size = %d\n",
2317*7cc577a4SJonathan Peyton                                __kmp_gtid_from_thread( thread ), task_team,
2318*7cc577a4SJonathan Peyton                                nthreads, maxthreads ) );
2319*7cc577a4SJonathan Peyton                 // Reallocate threads_data to have more elements than current array
2320*7cc577a4SJonathan Peyton                 // Cannot use __kmp_thread_realloc() because threads not around for
2321*7cc577a4SJonathan Peyton                 // kmp_reap_task_team( ).  Note all new array entries are initialized
2322*7cc577a4SJonathan Peyton                 // to zero by __kmp_allocate().
2323*7cc577a4SJonathan Peyton                 new_data = (kmp_thread_data_t *)
2324*7cc577a4SJonathan Peyton                             __kmp_allocate( nthreads * sizeof(kmp_thread_data_t) );
2325*7cc577a4SJonathan Peyton                 // copy old data to new data
2326*7cc577a4SJonathan Peyton                 KMP_MEMCPY_S( (void *) new_data, nthreads * sizeof(kmp_thread_data_t),
2327*7cc577a4SJonathan Peyton                               (void *) old_data,
2328*7cc577a4SJonathan Peyton                               maxthreads * sizeof(kmp_taskdata_t *) );
2329*7cc577a4SJonathan Peyton 
2330*7cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
2331*7cc577a4SJonathan Peyton                 // GEH: Figure out if this is the right thing to do
2332*7cc577a4SJonathan Peyton                 for (i = maxthreads; i < nthreads; i++) {
2333*7cc577a4SJonathan Peyton                     kmp_thread_data_t *thread_data = & (*threads_data_p)[i];
2334*7cc577a4SJonathan Peyton                     __kmp_init_task_stack( __kmp_gtid_from_thread( thread ), thread_data );
2335*7cc577a4SJonathan Peyton                 }
2336*7cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK
2337*7cc577a4SJonathan Peyton                 // Install the new data and free the old data
2338*7cc577a4SJonathan Peyton                 (*threads_data_p) = new_data;
2339*7cc577a4SJonathan Peyton                 __kmp_free( old_data );
2340*7cc577a4SJonathan Peyton             }
2341*7cc577a4SJonathan Peyton             else {
2342*7cc577a4SJonathan Peyton                 KE_TRACE( 10, ( "__kmp_realloc_task_threads_data: T#%d allocating "
2343*7cc577a4SJonathan Peyton                                "threads data for task_team %p, size = %d\n",
2344*7cc577a4SJonathan Peyton                                __kmp_gtid_from_thread( thread ), task_team, nthreads ) );
2345*7cc577a4SJonathan Peyton                 // Make the initial allocate for threads_data array, and zero entries
2346*7cc577a4SJonathan Peyton                 // Cannot use __kmp_thread_calloc() because threads not around for
2347*7cc577a4SJonathan Peyton                 // kmp_reap_task_team( ).
2348*7cc577a4SJonathan Peyton                 ANNOTATE_IGNORE_WRITES_BEGIN();
2349*7cc577a4SJonathan Peyton                 *threads_data_p = (kmp_thread_data_t *)
2350*7cc577a4SJonathan Peyton                                   __kmp_allocate( nthreads * sizeof(kmp_thread_data_t) );
2351*7cc577a4SJonathan Peyton                 ANNOTATE_IGNORE_WRITES_END();
2352*7cc577a4SJonathan Peyton #ifdef BUILD_TIED_TASK_STACK
2353*7cc577a4SJonathan Peyton                 // GEH: Figure out if this is the right thing to do
2354*7cc577a4SJonathan Peyton                 for (i = 0; i < nthreads; i++) {
2355*7cc577a4SJonathan Peyton                     kmp_thread_data_t *thread_data = & (*threads_data_p)[i];
2356*7cc577a4SJonathan Peyton                     __kmp_init_task_stack( __kmp_gtid_from_thread( thread ), thread_data );
2357*7cc577a4SJonathan Peyton                 }
2358*7cc577a4SJonathan Peyton #endif // BUILD_TIED_TASK_STACK
2359*7cc577a4SJonathan Peyton             }
2360*7cc577a4SJonathan Peyton             task_team -> tt.tt_max_threads = nthreads;
2361*7cc577a4SJonathan Peyton         }
2362*7cc577a4SJonathan Peyton         else {
2363*7cc577a4SJonathan Peyton             // If array has (more than) enough elements, go ahead and use it
2364*7cc577a4SJonathan Peyton             KMP_DEBUG_ASSERT( *threads_data_p != NULL );
2365*7cc577a4SJonathan Peyton         }
2366*7cc577a4SJonathan Peyton 
2367*7cc577a4SJonathan Peyton         // initialize threads_data pointers back to thread_info structures
2368*7cc577a4SJonathan Peyton         for (i = 0; i < nthreads; i++) {
2369*7cc577a4SJonathan Peyton             kmp_thread_data_t *thread_data = & (*threads_data_p)[i];
2370*7cc577a4SJonathan Peyton             thread_data -> td.td_thr = team -> t.t_threads[i];
2371*7cc577a4SJonathan Peyton 
2372*7cc577a4SJonathan Peyton             if ( thread_data -> td.td_deque_last_stolen >= nthreads) {
2373*7cc577a4SJonathan Peyton                 // The last stolen field survives across teams / barrier, and the number
2374*7cc577a4SJonathan Peyton                 // of threads may have changed.  It's possible (likely?) that a new
2375*7cc577a4SJonathan Peyton                 // parallel region will exhibit the same behavior as the previous region.
2376*7cc577a4SJonathan Peyton                 thread_data -> td.td_deque_last_stolen = -1;
2377*7cc577a4SJonathan Peyton             }
2378*7cc577a4SJonathan Peyton         }
2379*7cc577a4SJonathan Peyton 
2380*7cc577a4SJonathan Peyton         KMP_MB();
2381*7cc577a4SJonathan Peyton         TCW_SYNC_4(task_team -> tt.tt_found_tasks, TRUE);
2382*7cc577a4SJonathan Peyton     }
2383*7cc577a4SJonathan Peyton 
2384*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & task_team -> tt.tt_threads_lock );
2385*7cc577a4SJonathan Peyton     return is_init_thread;
2386*7cc577a4SJonathan Peyton }
2387*7cc577a4SJonathan Peyton 
2388*7cc577a4SJonathan Peyton 
2389*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2390*7cc577a4SJonathan Peyton // __kmp_free_task_threads_data:
2391*7cc577a4SJonathan Peyton // Deallocates a threads_data array for a task team, including any attached
2392*7cc577a4SJonathan Peyton // tasking deques.  Only occurs at library shutdown.
2393*7cc577a4SJonathan Peyton 
2394*7cc577a4SJonathan Peyton static void
2395*7cc577a4SJonathan Peyton __kmp_free_task_threads_data( kmp_task_team_t *task_team )
2396*7cc577a4SJonathan Peyton {
2397*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & task_team -> tt.tt_threads_lock );
2398*7cc577a4SJonathan Peyton     if ( task_team -> tt.tt_threads_data != NULL ) {
2399*7cc577a4SJonathan Peyton         int i;
2400*7cc577a4SJonathan Peyton         for (i = 0; i < task_team->tt.tt_max_threads; i++ ) {
2401*7cc577a4SJonathan Peyton             __kmp_free_task_deque( & task_team -> tt.tt_threads_data[i] );
2402*7cc577a4SJonathan Peyton         }
2403*7cc577a4SJonathan Peyton         __kmp_free( task_team -> tt.tt_threads_data );
2404*7cc577a4SJonathan Peyton         task_team -> tt.tt_threads_data = NULL;
2405*7cc577a4SJonathan Peyton     }
2406*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & task_team -> tt.tt_threads_lock );
2407*7cc577a4SJonathan Peyton }
2408*7cc577a4SJonathan Peyton 
2409*7cc577a4SJonathan Peyton 
2410*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2411*7cc577a4SJonathan Peyton // __kmp_allocate_task_team:
2412*7cc577a4SJonathan Peyton // Allocates a task team associated with a specific team, taking it from
2413*7cc577a4SJonathan Peyton // the global task team free list if possible.  Also initializes data structures.
2414*7cc577a4SJonathan Peyton 
2415*7cc577a4SJonathan Peyton static kmp_task_team_t *
2416*7cc577a4SJonathan Peyton __kmp_allocate_task_team( kmp_info_t *thread, kmp_team_t *team )
2417*7cc577a4SJonathan Peyton {
2418*7cc577a4SJonathan Peyton     kmp_task_team_t *task_team = NULL;
2419*7cc577a4SJonathan Peyton     int nthreads;
2420*7cc577a4SJonathan Peyton 
2421*7cc577a4SJonathan Peyton     KA_TRACE( 20, ( "__kmp_allocate_task_team: T#%d entering; team = %p\n",
2422*7cc577a4SJonathan Peyton                     (thread ? __kmp_gtid_from_thread( thread ) : -1), team ) );
2423*7cc577a4SJonathan Peyton 
2424*7cc577a4SJonathan Peyton     if (TCR_PTR(__kmp_free_task_teams) != NULL) {
2425*7cc577a4SJonathan Peyton         // Take a task team from the task team pool
2426*7cc577a4SJonathan Peyton         __kmp_acquire_bootstrap_lock( &__kmp_task_team_lock );
2427*7cc577a4SJonathan Peyton         if (__kmp_free_task_teams != NULL) {
2428*7cc577a4SJonathan Peyton             task_team = __kmp_free_task_teams;
2429*7cc577a4SJonathan Peyton             TCW_PTR(__kmp_free_task_teams, task_team -> tt.tt_next);
2430*7cc577a4SJonathan Peyton             task_team -> tt.tt_next = NULL;
2431*7cc577a4SJonathan Peyton         }
2432*7cc577a4SJonathan Peyton         __kmp_release_bootstrap_lock( &__kmp_task_team_lock );
2433*7cc577a4SJonathan Peyton     }
2434*7cc577a4SJonathan Peyton 
2435*7cc577a4SJonathan Peyton     if (task_team == NULL) {
2436*7cc577a4SJonathan Peyton         KE_TRACE( 10, ( "__kmp_allocate_task_team: T#%d allocating "
2437*7cc577a4SJonathan Peyton                        "task team for team %p\n",
2438*7cc577a4SJonathan Peyton                        __kmp_gtid_from_thread( thread ), team ) );
2439*7cc577a4SJonathan Peyton         // Allocate a new task team if one is not available.
2440*7cc577a4SJonathan Peyton         // Cannot use __kmp_thread_malloc() because threads not around for
2441*7cc577a4SJonathan Peyton         // kmp_reap_task_team( ).
2442*7cc577a4SJonathan Peyton         task_team = (kmp_task_team_t *) __kmp_allocate( sizeof(kmp_task_team_t) );
2443*7cc577a4SJonathan Peyton         __kmp_init_bootstrap_lock( & task_team -> tt.tt_threads_lock );
2444*7cc577a4SJonathan Peyton         //task_team -> tt.tt_threads_data = NULL;   // AC: __kmp_allocate zeroes returned memory
2445*7cc577a4SJonathan Peyton         //task_team -> tt.tt_max_threads = 0;
2446*7cc577a4SJonathan Peyton         //task_team -> tt.tt_next = NULL;
2447*7cc577a4SJonathan Peyton     }
2448*7cc577a4SJonathan Peyton 
2449*7cc577a4SJonathan Peyton     TCW_4(task_team -> tt.tt_found_tasks, FALSE);
2450*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
2451*7cc577a4SJonathan Peyton     TCW_4(task_team -> tt.tt_found_proxy_tasks, FALSE);
2452*7cc577a4SJonathan Peyton #endif
2453*7cc577a4SJonathan Peyton     task_team -> tt.tt_nproc = nthreads = team->t.t_nproc;
2454*7cc577a4SJonathan Peyton 
2455*7cc577a4SJonathan Peyton     TCW_4( task_team -> tt.tt_unfinished_threads, nthreads );
2456*7cc577a4SJonathan Peyton     TCW_4( task_team -> tt.tt_active, TRUE );
2457*7cc577a4SJonathan Peyton 
2458*7cc577a4SJonathan Peyton     KA_TRACE( 20, ( "__kmp_allocate_task_team: T#%d exiting; task_team = %p unfinished_threads init'd to %d\n",
2459*7cc577a4SJonathan Peyton                     (thread ? __kmp_gtid_from_thread( thread ) : -1), task_team, task_team -> tt.tt_unfinished_threads) );
2460*7cc577a4SJonathan Peyton     return task_team;
2461*7cc577a4SJonathan Peyton }
2462*7cc577a4SJonathan Peyton 
2463*7cc577a4SJonathan Peyton 
2464*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2465*7cc577a4SJonathan Peyton // __kmp_free_task_team:
2466*7cc577a4SJonathan Peyton // Frees the task team associated with a specific thread, and adds it
2467*7cc577a4SJonathan Peyton // to the global task team free list.
2468*7cc577a4SJonathan Peyton 
2469*7cc577a4SJonathan Peyton void
2470*7cc577a4SJonathan Peyton __kmp_free_task_team( kmp_info_t *thread, kmp_task_team_t *task_team )
2471*7cc577a4SJonathan Peyton {
2472*7cc577a4SJonathan Peyton     KA_TRACE( 20, ( "__kmp_free_task_team: T#%d task_team = %p\n",
2473*7cc577a4SJonathan Peyton                     thread ? __kmp_gtid_from_thread( thread ) : -1, task_team ) );
2474*7cc577a4SJonathan Peyton 
2475*7cc577a4SJonathan Peyton     // Put task team back on free list
2476*7cc577a4SJonathan Peyton     __kmp_acquire_bootstrap_lock( & __kmp_task_team_lock );
2477*7cc577a4SJonathan Peyton 
2478*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_team -> tt.tt_next == NULL );
2479*7cc577a4SJonathan Peyton     task_team -> tt.tt_next = __kmp_free_task_teams;
2480*7cc577a4SJonathan Peyton     TCW_PTR(__kmp_free_task_teams, task_team);
2481*7cc577a4SJonathan Peyton 
2482*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & __kmp_task_team_lock );
2483*7cc577a4SJonathan Peyton }
2484*7cc577a4SJonathan Peyton 
2485*7cc577a4SJonathan Peyton 
2486*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2487*7cc577a4SJonathan Peyton // __kmp_reap_task_teams:
2488*7cc577a4SJonathan Peyton // Free all the task teams on the task team free list.
2489*7cc577a4SJonathan Peyton // Should only be done during library shutdown.
2490*7cc577a4SJonathan Peyton // Cannot do anything that needs a thread structure or gtid since they are already gone.
2491*7cc577a4SJonathan Peyton 
2492*7cc577a4SJonathan Peyton void
2493*7cc577a4SJonathan Peyton __kmp_reap_task_teams( void )
2494*7cc577a4SJonathan Peyton {
2495*7cc577a4SJonathan Peyton     kmp_task_team_t   *task_team;
2496*7cc577a4SJonathan Peyton 
2497*7cc577a4SJonathan Peyton     if ( TCR_PTR(__kmp_free_task_teams) != NULL ) {
2498*7cc577a4SJonathan Peyton         // Free all task_teams on the free list
2499*7cc577a4SJonathan Peyton         __kmp_acquire_bootstrap_lock( &__kmp_task_team_lock );
2500*7cc577a4SJonathan Peyton         while ( ( task_team = __kmp_free_task_teams ) != NULL ) {
2501*7cc577a4SJonathan Peyton             __kmp_free_task_teams = task_team -> tt.tt_next;
2502*7cc577a4SJonathan Peyton             task_team -> tt.tt_next = NULL;
2503*7cc577a4SJonathan Peyton 
2504*7cc577a4SJonathan Peyton             // Free threads_data if necessary
2505*7cc577a4SJonathan Peyton             if ( task_team -> tt.tt_threads_data != NULL ) {
2506*7cc577a4SJonathan Peyton                 __kmp_free_task_threads_data( task_team );
2507*7cc577a4SJonathan Peyton             }
2508*7cc577a4SJonathan Peyton             __kmp_free( task_team );
2509*7cc577a4SJonathan Peyton         }
2510*7cc577a4SJonathan Peyton         __kmp_release_bootstrap_lock( &__kmp_task_team_lock );
2511*7cc577a4SJonathan Peyton     }
2512*7cc577a4SJonathan Peyton }
2513*7cc577a4SJonathan Peyton 
2514*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2515*7cc577a4SJonathan Peyton // __kmp_wait_to_unref_task_teams:
2516*7cc577a4SJonathan Peyton // Some threads could still be in the fork barrier release code, possibly
2517*7cc577a4SJonathan Peyton // trying to steal tasks.  Wait for each thread to unreference its task team.
2518*7cc577a4SJonathan Peyton //
2519*7cc577a4SJonathan Peyton void
2520*7cc577a4SJonathan Peyton __kmp_wait_to_unref_task_teams(void)
2521*7cc577a4SJonathan Peyton {
2522*7cc577a4SJonathan Peyton     kmp_info_t *thread;
2523*7cc577a4SJonathan Peyton     kmp_uint32 spins;
2524*7cc577a4SJonathan Peyton     int done;
2525*7cc577a4SJonathan Peyton 
2526*7cc577a4SJonathan Peyton     KMP_INIT_YIELD( spins );
2527*7cc577a4SJonathan Peyton 
2528*7cc577a4SJonathan Peyton     for (;;) {
2529*7cc577a4SJonathan Peyton         done = TRUE;
2530*7cc577a4SJonathan Peyton 
2531*7cc577a4SJonathan Peyton         // TODO: GEH - this may be is wrong because some sync would be necessary
2532*7cc577a4SJonathan Peyton         //             in case threads are added to the pool during the traversal.
2533*7cc577a4SJonathan Peyton         //             Need to verify that lock for thread pool is held when calling
2534*7cc577a4SJonathan Peyton         //             this routine.
2535*7cc577a4SJonathan Peyton         for (thread = (kmp_info_t *)__kmp_thread_pool;
2536*7cc577a4SJonathan Peyton              thread != NULL;
2537*7cc577a4SJonathan Peyton              thread = thread->th.th_next_pool)
2538*7cc577a4SJonathan Peyton         {
2539*7cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
2540*7cc577a4SJonathan Peyton             DWORD exit_val;
2541*7cc577a4SJonathan Peyton #endif
2542*7cc577a4SJonathan Peyton             if ( TCR_PTR(thread->th.th_task_team) == NULL ) {
2543*7cc577a4SJonathan Peyton                 KA_TRACE( 10, ("__kmp_wait_to_unref_task_team: T#%d task_team == NULL\n",
2544*7cc577a4SJonathan Peyton                                __kmp_gtid_from_thread( thread ) ) );
2545*7cc577a4SJonathan Peyton                 continue;
2546*7cc577a4SJonathan Peyton             }
2547*7cc577a4SJonathan Peyton #if KMP_OS_WINDOWS
2548*7cc577a4SJonathan Peyton             // TODO: GEH - add this check for Linux* OS / OS X* as well?
2549*7cc577a4SJonathan Peyton             if (!__kmp_is_thread_alive(thread, &exit_val)) {
2550*7cc577a4SJonathan Peyton                 thread->th.th_task_team = NULL;
2551*7cc577a4SJonathan Peyton                 continue;
2552*7cc577a4SJonathan Peyton             }
2553*7cc577a4SJonathan Peyton #endif
2554*7cc577a4SJonathan Peyton 
2555*7cc577a4SJonathan Peyton             done = FALSE;  // Because th_task_team pointer is not NULL for this thread
2556*7cc577a4SJonathan Peyton 
2557*7cc577a4SJonathan Peyton             KA_TRACE( 10, ("__kmp_wait_to_unref_task_team: Waiting for T#%d to unreference task_team\n",
2558*7cc577a4SJonathan Peyton                            __kmp_gtid_from_thread( thread ) ) );
2559*7cc577a4SJonathan Peyton 
2560*7cc577a4SJonathan Peyton             if ( __kmp_dflt_blocktime != KMP_MAX_BLOCKTIME ) {
2561*7cc577a4SJonathan Peyton                 volatile void *sleep_loc;
2562*7cc577a4SJonathan Peyton                 // If the thread is sleeping, awaken it.
2563*7cc577a4SJonathan Peyton                 if ( ( sleep_loc = TCR_PTR( thread->th.th_sleep_loc) ) != NULL ) {
2564*7cc577a4SJonathan Peyton                     KA_TRACE( 10, ( "__kmp_wait_to_unref_task_team: T#%d waking up thread T#%d\n",
2565*7cc577a4SJonathan Peyton                                     __kmp_gtid_from_thread( thread ), __kmp_gtid_from_thread( thread ) ) );
2566*7cc577a4SJonathan Peyton                     __kmp_null_resume_wrapper(__kmp_gtid_from_thread(thread), sleep_loc);
2567*7cc577a4SJonathan Peyton                 }
2568*7cc577a4SJonathan Peyton             }
2569*7cc577a4SJonathan Peyton         }
2570*7cc577a4SJonathan Peyton         if (done) {
2571*7cc577a4SJonathan Peyton             break;
2572*7cc577a4SJonathan Peyton         }
2573*7cc577a4SJonathan Peyton 
2574*7cc577a4SJonathan Peyton         // If we are oversubscribed,
2575*7cc577a4SJonathan Peyton         // or have waited a bit (and library mode is throughput), yield.
2576*7cc577a4SJonathan Peyton         // Pause is in the following code.
2577*7cc577a4SJonathan Peyton         KMP_YIELD( TCR_4(__kmp_nth) > __kmp_avail_proc );
2578*7cc577a4SJonathan Peyton         KMP_YIELD_SPIN( spins );        // Yields only if KMP_LIBRARY=throughput
2579*7cc577a4SJonathan Peyton     }
2580*7cc577a4SJonathan Peyton }
2581*7cc577a4SJonathan Peyton 
2582*7cc577a4SJonathan Peyton 
2583*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2584*7cc577a4SJonathan Peyton // __kmp_task_team_setup:  Create a task_team for the current team, but use
2585*7cc577a4SJonathan Peyton // an already created, unused one if it already exists.
2586*7cc577a4SJonathan Peyton void
2587*7cc577a4SJonathan Peyton __kmp_task_team_setup( kmp_info_t *this_thr, kmp_team_t *team, int always )
2588*7cc577a4SJonathan Peyton {
2589*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
2590*7cc577a4SJonathan Peyton 
2591*7cc577a4SJonathan Peyton     // If this task_team hasn't been created yet, allocate it. It will be used in the region after the next.
2592*7cc577a4SJonathan Peyton     // If it exists, it is the current task team and shouldn't be touched yet as it may still be in use.
2593*7cc577a4SJonathan Peyton     if (team->t.t_task_team[this_thr->th.th_task_state] == NULL && (always || team->t.t_nproc > 1) ) {
2594*7cc577a4SJonathan Peyton         team->t.t_task_team[this_thr->th.th_task_state] = __kmp_allocate_task_team( this_thr, team );
2595*7cc577a4SJonathan Peyton         KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created new task_team %p for team %d at parity=%d\n",
2596*7cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(this_thr), team->t.t_task_team[this_thr->th.th_task_state],
2597*7cc577a4SJonathan Peyton                       ((team != NULL) ? team->t.t_id : -1), this_thr->th.th_task_state));
2598*7cc577a4SJonathan Peyton     }
2599*7cc577a4SJonathan Peyton 
2600*7cc577a4SJonathan Peyton     // After threads exit the release, they will call sync, and then point to this other task_team; make sure it is
2601*7cc577a4SJonathan Peyton     // allocated and properly initialized. As threads spin in the barrier release phase, they will continue to use the
2602*7cc577a4SJonathan Peyton     // previous task_team struct(above), until they receive the signal to stop checking for tasks (they can't safely
2603*7cc577a4SJonathan Peyton     // reference the kmp_team_t struct, which could be reallocated by the master thread). No task teams are formed for
2604*7cc577a4SJonathan Peyton     // serialized teams.
2605*7cc577a4SJonathan Peyton     if (team->t.t_nproc > 1) {
2606*7cc577a4SJonathan Peyton         int other_team = 1 - this_thr->th.th_task_state;
2607*7cc577a4SJonathan Peyton         if (team->t.t_task_team[other_team] == NULL) { // setup other team as well
2608*7cc577a4SJonathan Peyton                 team->t.t_task_team[other_team] = __kmp_allocate_task_team( this_thr, team );
2609*7cc577a4SJonathan Peyton                 KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d created second new task_team %p for team %d at parity=%d\n",
2610*7cc577a4SJonathan Peyton                                 __kmp_gtid_from_thread( this_thr ), team->t.t_task_team[other_team],
2611*7cc577a4SJonathan Peyton                               ((team != NULL) ? team->t.t_id : -1), other_team ));
2612*7cc577a4SJonathan Peyton         }
2613*7cc577a4SJonathan Peyton         else { // Leave the old task team struct in place for the upcoming region; adjust as needed
2614*7cc577a4SJonathan Peyton             kmp_task_team_t *task_team = team->t.t_task_team[other_team];
2615*7cc577a4SJonathan Peyton             if (!task_team->tt.tt_active || team->t.t_nproc != task_team->tt.tt_nproc) {
2616*7cc577a4SJonathan Peyton                 TCW_4(task_team->tt.tt_nproc, team->t.t_nproc);
2617*7cc577a4SJonathan Peyton                 TCW_4(task_team->tt.tt_found_tasks, FALSE);
2618*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
2619*7cc577a4SJonathan Peyton                 TCW_4(task_team->tt.tt_found_proxy_tasks, FALSE);
2620*7cc577a4SJonathan Peyton #endif
2621*7cc577a4SJonathan Peyton                 TCW_4(task_team->tt.tt_unfinished_threads, team->t.t_nproc );
2622*7cc577a4SJonathan Peyton                 TCW_4(task_team->tt.tt_active, TRUE );
2623*7cc577a4SJonathan Peyton             }
2624*7cc577a4SJonathan Peyton             // if team size has changed, the first thread to enable tasking will realloc threads_data if necessary
2625*7cc577a4SJonathan Peyton             KA_TRACE(20, ("__kmp_task_team_setup: Master T#%d reset next task_team %p for team %d at parity=%d\n",
2626*7cc577a4SJonathan Peyton                           __kmp_gtid_from_thread( this_thr ), team->t.t_task_team[other_team],
2627*7cc577a4SJonathan Peyton                           ((team != NULL) ? team->t.t_id : -1), other_team ));
2628*7cc577a4SJonathan Peyton         }
2629*7cc577a4SJonathan Peyton     }
2630*7cc577a4SJonathan Peyton }
2631*7cc577a4SJonathan Peyton 
2632*7cc577a4SJonathan Peyton 
2633*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2634*7cc577a4SJonathan Peyton // __kmp_task_team_sync: Propagation of task team data from team to threads
2635*7cc577a4SJonathan Peyton // which happens just after the release phase of a team barrier.  This may be
2636*7cc577a4SJonathan Peyton // called by any thread, but only for teams with # threads > 1.
2637*7cc577a4SJonathan Peyton 
2638*7cc577a4SJonathan Peyton void
2639*7cc577a4SJonathan Peyton __kmp_task_team_sync( kmp_info_t *this_thr, kmp_team_t *team )
2640*7cc577a4SJonathan Peyton {
2641*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
2642*7cc577a4SJonathan Peyton 
2643*7cc577a4SJonathan Peyton     // Toggle the th_task_state field, to switch which task_team this thread refers to
2644*7cc577a4SJonathan Peyton     this_thr->th.th_task_state = 1 - this_thr->th.th_task_state;
2645*7cc577a4SJonathan Peyton     // It is now safe to propagate the task team pointer from the team struct to the current thread.
2646*7cc577a4SJonathan Peyton     TCW_PTR(this_thr->th.th_task_team, team->t.t_task_team[this_thr->th.th_task_state]);
2647*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_task_team_sync: Thread T#%d task team switched to task_team %p from Team #%d (parity=%d)\n",
2648*7cc577a4SJonathan Peyton                   __kmp_gtid_from_thread( this_thr ), this_thr->th.th_task_team,
2649*7cc577a4SJonathan Peyton                   ((team != NULL) ? team->t.t_id : -1), this_thr->th.th_task_state));
2650*7cc577a4SJonathan Peyton }
2651*7cc577a4SJonathan Peyton 
2652*7cc577a4SJonathan Peyton 
2653*7cc577a4SJonathan Peyton //--------------------------------------------------------------------------------------------
2654*7cc577a4SJonathan Peyton // __kmp_task_team_wait: Master thread waits for outstanding tasks after the barrier gather
2655*7cc577a4SJonathan Peyton // phase.  Only called by master thread if #threads in team > 1 or if proxy tasks were created.
2656*7cc577a4SJonathan Peyton // wait is a flag that defaults to 1 (see kmp.h), but waiting can be turned off by passing in 0
2657*7cc577a4SJonathan Peyton // optionally as the last argument. When wait is zero, master thread does not wait for
2658*7cc577a4SJonathan Peyton // unfinished_threads to reach 0.
2659*7cc577a4SJonathan Peyton void
2660*7cc577a4SJonathan Peyton __kmp_task_team_wait( kmp_info_t *this_thr, kmp_team_t *team
2661*7cc577a4SJonathan Peyton                       USE_ITT_BUILD_ARG(void * itt_sync_obj)
2662*7cc577a4SJonathan Peyton                       , int wait)
2663*7cc577a4SJonathan Peyton {
2664*7cc577a4SJonathan Peyton     kmp_task_team_t *task_team = team->t.t_task_team[this_thr->th.th_task_state];
2665*7cc577a4SJonathan Peyton 
2666*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode != tskm_immediate_exec );
2667*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_team == this_thr->th.th_task_team );
2668*7cc577a4SJonathan Peyton 
2669*7cc577a4SJonathan Peyton     if ( ( task_team != NULL ) && KMP_TASKING_ENABLED(task_team) ) {
2670*7cc577a4SJonathan Peyton         if (wait) {
2671*7cc577a4SJonathan Peyton             KA_TRACE(20, ("__kmp_task_team_wait: Master T#%d waiting for all tasks (for unfinished_threads to reach 0) on task_team = %p\n",
2672*7cc577a4SJonathan Peyton                           __kmp_gtid_from_thread(this_thr), task_team));
2673*7cc577a4SJonathan Peyton             // Worker threads may have dropped through to release phase, but could still be executing tasks. Wait
2674*7cc577a4SJonathan Peyton             // here for tasks to complete. To avoid memory contention, only master thread checks termination condition.
2675*7cc577a4SJonathan Peyton             kmp_flag_32 flag(&task_team->tt.tt_unfinished_threads, 0U);
2676*7cc577a4SJonathan Peyton             flag.wait(this_thr, TRUE
2677*7cc577a4SJonathan Peyton                       USE_ITT_BUILD_ARG(itt_sync_obj));
2678*7cc577a4SJonathan Peyton         }
2679*7cc577a4SJonathan Peyton         // Deactivate the old task team, so that the worker threads will stop referencing it while spinning.
2680*7cc577a4SJonathan Peyton         KA_TRACE(20, ("__kmp_task_team_wait: Master T#%d deactivating task_team %p: "
2681*7cc577a4SJonathan Peyton                       "setting active to false, setting local and team's pointer to NULL\n",
2682*7cc577a4SJonathan Peyton                       __kmp_gtid_from_thread(this_thr), task_team));
2683*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
2684*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( task_team->tt.tt_nproc > 1 || task_team->tt.tt_found_proxy_tasks == TRUE );
2685*7cc577a4SJonathan Peyton         TCW_SYNC_4( task_team->tt.tt_found_proxy_tasks, FALSE );
2686*7cc577a4SJonathan Peyton #else
2687*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( task_team->tt.tt_nproc > 1 );
2688*7cc577a4SJonathan Peyton #endif
2689*7cc577a4SJonathan Peyton         TCW_SYNC_4( task_team->tt.tt_active, FALSE );
2690*7cc577a4SJonathan Peyton         KMP_MB();
2691*7cc577a4SJonathan Peyton 
2692*7cc577a4SJonathan Peyton         TCW_PTR(this_thr->th.th_task_team, NULL);
2693*7cc577a4SJonathan Peyton     }
2694*7cc577a4SJonathan Peyton }
2695*7cc577a4SJonathan Peyton 
2696*7cc577a4SJonathan Peyton 
2697*7cc577a4SJonathan Peyton //------------------------------------------------------------------------------
2698*7cc577a4SJonathan Peyton // __kmp_tasking_barrier:
2699*7cc577a4SJonathan Peyton // This routine may only called when __kmp_tasking_mode == tskm_extra_barrier.
2700*7cc577a4SJonathan Peyton // Internal function to execute all tasks prior to a regular barrier or a
2701*7cc577a4SJonathan Peyton // join barrier.  It is a full barrier itself, which unfortunately turns
2702*7cc577a4SJonathan Peyton // regular barriers into double barriers and join barriers into 1 1/2
2703*7cc577a4SJonathan Peyton // barriers.
2704*7cc577a4SJonathan Peyton void
2705*7cc577a4SJonathan Peyton __kmp_tasking_barrier( kmp_team_t *team, kmp_info_t *thread, int gtid )
2706*7cc577a4SJonathan Peyton {
2707*7cc577a4SJonathan Peyton     volatile kmp_uint32 *spin = &team->t.t_task_team[thread->th.th_task_state]->tt.tt_unfinished_threads;
2708*7cc577a4SJonathan Peyton     int flag = FALSE;
2709*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( __kmp_tasking_mode == tskm_extra_barrier );
2710*7cc577a4SJonathan Peyton 
2711*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
2712*7cc577a4SJonathan Peyton     KMP_FSYNC_SPIN_INIT( spin, (kmp_uint32*) NULL );
2713*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
2714*7cc577a4SJonathan Peyton     kmp_flag_32 spin_flag(spin, 0U);
2715*7cc577a4SJonathan Peyton     while (! spin_flag.execute_tasks(thread, gtid, TRUE, &flag
2716*7cc577a4SJonathan Peyton                                      USE_ITT_BUILD_ARG(NULL), 0 ) ) {
2717*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
2718*7cc577a4SJonathan Peyton         // TODO: What about itt_sync_obj??
2719*7cc577a4SJonathan Peyton         KMP_FSYNC_SPIN_PREPARE( spin );
2720*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
2721*7cc577a4SJonathan Peyton 
2722*7cc577a4SJonathan Peyton         if( TCR_4(__kmp_global.g.g_done) ) {
2723*7cc577a4SJonathan Peyton             if( __kmp_global.g.g_abort )
2724*7cc577a4SJonathan Peyton                 __kmp_abort_thread( );
2725*7cc577a4SJonathan Peyton             break;
2726*7cc577a4SJonathan Peyton         }
2727*7cc577a4SJonathan Peyton         KMP_YIELD( TRUE );       // GH: We always yield here
2728*7cc577a4SJonathan Peyton     }
2729*7cc577a4SJonathan Peyton #if USE_ITT_BUILD
2730*7cc577a4SJonathan Peyton     KMP_FSYNC_SPIN_ACQUIRED( (void*) spin );
2731*7cc577a4SJonathan Peyton #endif /* USE_ITT_BUILD */
2732*7cc577a4SJonathan Peyton }
2733*7cc577a4SJonathan Peyton 
2734*7cc577a4SJonathan Peyton 
2735*7cc577a4SJonathan Peyton #if OMP_45_ENABLED
2736*7cc577a4SJonathan Peyton 
2737*7cc577a4SJonathan Peyton /* __kmp_give_task puts a task into a given thread queue if:
2738*7cc577a4SJonathan Peyton     - the queue for that thread was created
2739*7cc577a4SJonathan Peyton     - there's space in that queue
2740*7cc577a4SJonathan Peyton 
2741*7cc577a4SJonathan Peyton     Because of this, __kmp_push_task needs to check if there's space after getting the lock
2742*7cc577a4SJonathan Peyton  */
2743*7cc577a4SJonathan Peyton static bool __kmp_give_task ( kmp_info_t *thread, kmp_int32 tid, kmp_task_t * task, kmp_int32 pass )
2744*7cc577a4SJonathan Peyton {
2745*7cc577a4SJonathan Peyton     kmp_taskdata_t *    taskdata = KMP_TASK_TO_TASKDATA(task);
2746*7cc577a4SJonathan Peyton     kmp_task_team_t *	task_team = taskdata->td_task_team;
2747*7cc577a4SJonathan Peyton 
2748*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_give_task: trying to give task %p to thread %d.\n", taskdata, tid ) );
2749*7cc577a4SJonathan Peyton 
2750*7cc577a4SJonathan Peyton     // If task_team is NULL something went really bad...
2751*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task_team != NULL );
2752*7cc577a4SJonathan Peyton 
2753*7cc577a4SJonathan Peyton     bool result = false;
2754*7cc577a4SJonathan Peyton     kmp_thread_data_t * thread_data = & task_team -> tt.tt_threads_data[ tid ];
2755*7cc577a4SJonathan Peyton 
2756*7cc577a4SJonathan Peyton     if (thread_data -> td.td_deque == NULL ) {
2757*7cc577a4SJonathan Peyton         // There's no queue in this thread, go find another one
2758*7cc577a4SJonathan Peyton         // We're guaranteed that at least one thread has a queue
2759*7cc577a4SJonathan Peyton         KA_TRACE(30, ("__kmp_give_task: thread %d has no queue while giving task %p.\n", tid, taskdata ) );
2760*7cc577a4SJonathan Peyton         return result;
2761*7cc577a4SJonathan Peyton     }
2762*7cc577a4SJonathan Peyton 
2763*7cc577a4SJonathan Peyton     if ( TCR_4(thread_data -> td.td_deque_ntasks) >= TASK_DEQUE_SIZE(thread_data->td) )
2764*7cc577a4SJonathan Peyton     {
2765*7cc577a4SJonathan Peyton         KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to thread %d.\n", taskdata, tid ) );
2766*7cc577a4SJonathan Peyton 
2767*7cc577a4SJonathan Peyton         // if this deque is bigger than the pass ratio give a chance to another thread
2768*7cc577a4SJonathan Peyton         if ( TASK_DEQUE_SIZE(thread_data->td)/INITIAL_TASK_DEQUE_SIZE >= pass ) return result;
2769*7cc577a4SJonathan Peyton 
2770*7cc577a4SJonathan Peyton         __kmp_acquire_bootstrap_lock( & thread_data-> td.td_deque_lock );
2771*7cc577a4SJonathan Peyton         __kmp_realloc_task_deque(thread,thread_data);
2772*7cc577a4SJonathan Peyton 
2773*7cc577a4SJonathan Peyton     } else {
2774*7cc577a4SJonathan Peyton 
2775*7cc577a4SJonathan Peyton        __kmp_acquire_bootstrap_lock( & thread_data-> td.td_deque_lock );
2776*7cc577a4SJonathan Peyton 
2777*7cc577a4SJonathan Peyton        if ( TCR_4(thread_data -> td.td_deque_ntasks) >= TASK_DEQUE_SIZE(thread_data->td) )
2778*7cc577a4SJonathan Peyton        {
2779*7cc577a4SJonathan Peyton            KA_TRACE(30, ("__kmp_give_task: queue is full while giving task %p to thread %d.\n", taskdata, tid ) );
2780*7cc577a4SJonathan Peyton 
2781*7cc577a4SJonathan Peyton            // if this deque is bigger than the pass ratio give a chance to another thread
2782*7cc577a4SJonathan Peyton            if ( TASK_DEQUE_SIZE(thread_data->td)/INITIAL_TASK_DEQUE_SIZE >= pass )
2783*7cc577a4SJonathan Peyton               goto release_and_exit;
2784*7cc577a4SJonathan Peyton 
2785*7cc577a4SJonathan Peyton            __kmp_realloc_task_deque(thread,thread_data);
2786*7cc577a4SJonathan Peyton        }
2787*7cc577a4SJonathan Peyton     }
2788*7cc577a4SJonathan Peyton 
2789*7cc577a4SJonathan Peyton     // lock is held here, and there is space in the deque
2790*7cc577a4SJonathan Peyton 
2791*7cc577a4SJonathan Peyton     thread_data -> td.td_deque[ thread_data -> td.td_deque_tail ] = taskdata;
2792*7cc577a4SJonathan Peyton     // Wrap index.
2793*7cc577a4SJonathan Peyton     thread_data -> td.td_deque_tail = ( thread_data -> td.td_deque_tail + 1 ) & TASK_DEQUE_MASK(thread_data->td);
2794*7cc577a4SJonathan Peyton     TCW_4(thread_data -> td.td_deque_ntasks, TCR_4(thread_data -> td.td_deque_ntasks) + 1);
2795*7cc577a4SJonathan Peyton 
2796*7cc577a4SJonathan Peyton     result = true;
2797*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_give_task: successfully gave task %p to thread %d.\n", taskdata, tid ) );
2798*7cc577a4SJonathan Peyton 
2799*7cc577a4SJonathan Peyton release_and_exit:
2800*7cc577a4SJonathan Peyton     __kmp_release_bootstrap_lock( & thread_data-> td.td_deque_lock );
2801*7cc577a4SJonathan Peyton 
2802*7cc577a4SJonathan Peyton      return result;
2803*7cc577a4SJonathan Peyton }
2804*7cc577a4SJonathan Peyton 
2805*7cc577a4SJonathan Peyton 
2806*7cc577a4SJonathan Peyton /* The finish of the a proxy tasks is divided in two pieces:
2807*7cc577a4SJonathan Peyton     - the top half is the one that can be done from a thread outside the team
2808*7cc577a4SJonathan Peyton     - the bottom half must be run from a them within the team
2809*7cc577a4SJonathan Peyton 
2810*7cc577a4SJonathan Peyton     In order to run the bottom half the task gets queued back into one of the threads of the team.
2811*7cc577a4SJonathan Peyton     Once the td_incomplete_child_task counter of the parent is decremented the threads can leave the barriers.
2812*7cc577a4SJonathan Peyton     So, the bottom half needs to be queued before the counter is decremented. The top half is therefore divided in two parts:
2813*7cc577a4SJonathan Peyton     - things that can be run before queuing the bottom half
2814*7cc577a4SJonathan Peyton     - things that must be run after queuing the bottom half
2815*7cc577a4SJonathan Peyton 
2816*7cc577a4SJonathan Peyton     This creates a second race as the bottom half can free the task before the second top half is executed. To avoid this
2817*7cc577a4SJonathan Peyton     we use the td_incomplete_child_task of the proxy task to synchronize the top and bottom half.
2818*7cc577a4SJonathan Peyton */
2819*7cc577a4SJonathan Peyton 
2820*7cc577a4SJonathan Peyton static void __kmp_first_top_half_finish_proxy( kmp_taskdata_t * taskdata )
2821*7cc577a4SJonathan Peyton {
2822*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.tasktype == TASK_EXPLICIT );
2823*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.proxy == TASK_PROXY );
2824*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.complete == 0 );
2825*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.freed == 0 );
2826*7cc577a4SJonathan Peyton 
2827*7cc577a4SJonathan Peyton     taskdata -> td_flags.complete = 1;   // mark the task as completed
2828*7cc577a4SJonathan Peyton 
2829*7cc577a4SJonathan Peyton     if ( taskdata->td_taskgroup )
2830*7cc577a4SJonathan Peyton        KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata->td_taskgroup->count) );
2831*7cc577a4SJonathan Peyton 
2832*7cc577a4SJonathan Peyton     // Create an imaginary children for this task so the bottom half cannot release the task before we have completed the second top half
2833*7cc577a4SJonathan Peyton     TCI_4(taskdata->td_incomplete_child_tasks);
2834*7cc577a4SJonathan Peyton }
2835*7cc577a4SJonathan Peyton 
2836*7cc577a4SJonathan Peyton static void __kmp_second_top_half_finish_proxy( kmp_taskdata_t * taskdata )
2837*7cc577a4SJonathan Peyton {
2838*7cc577a4SJonathan Peyton     kmp_int32 children = 0;
2839*7cc577a4SJonathan Peyton 
2840*7cc577a4SJonathan Peyton     // Predecrement simulated by "- 1" calculation
2841*7cc577a4SJonathan Peyton     children = KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata -> td_parent -> td_incomplete_child_tasks) ) - 1;
2842*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( children >= 0 );
2843*7cc577a4SJonathan Peyton 
2844*7cc577a4SJonathan Peyton     // Remove the imaginary children
2845*7cc577a4SJonathan Peyton     TCD_4(taskdata->td_incomplete_child_tasks);
2846*7cc577a4SJonathan Peyton }
2847*7cc577a4SJonathan Peyton 
2848*7cc577a4SJonathan Peyton static void __kmp_bottom_half_finish_proxy( kmp_int32 gtid, kmp_task_t * ptask )
2849*7cc577a4SJonathan Peyton {
2850*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(ptask);
2851*7cc577a4SJonathan Peyton     kmp_info_t * thread = __kmp_threads[ gtid ];
2852*7cc577a4SJonathan Peyton 
2853*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.proxy == TASK_PROXY );
2854*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata -> td_flags.complete == 1 ); // top half must run before bottom half
2855*7cc577a4SJonathan Peyton 
2856*7cc577a4SJonathan Peyton     // We need to wait to make sure the top half is finished
2857*7cc577a4SJonathan Peyton     // Spinning here should be ok as this should happen quickly
2858*7cc577a4SJonathan Peyton     while ( TCR_4(taskdata->td_incomplete_child_tasks) > 0 ) ;
2859*7cc577a4SJonathan Peyton 
2860*7cc577a4SJonathan Peyton     __kmp_release_deps(gtid,taskdata);
2861*7cc577a4SJonathan Peyton     __kmp_free_task_and_ancestors(gtid, taskdata, thread);
2862*7cc577a4SJonathan Peyton }
2863*7cc577a4SJonathan Peyton 
2864*7cc577a4SJonathan Peyton /*!
2865*7cc577a4SJonathan Peyton @ingroup TASKING
2866*7cc577a4SJonathan Peyton @param gtid Global Thread ID of encountering thread
2867*7cc577a4SJonathan Peyton @param ptask Task which execution is completed
2868*7cc577a4SJonathan Peyton 
2869*7cc577a4SJonathan Peyton Execute the completation of a proxy task from a thread of that is part of the team. Run first and bottom halves directly.
2870*7cc577a4SJonathan Peyton */
2871*7cc577a4SJonathan Peyton void __kmpc_proxy_task_completed( kmp_int32 gtid, kmp_task_t *ptask )
2872*7cc577a4SJonathan Peyton {
2873*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( ptask != NULL );
2874*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(ptask);
2875*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_proxy_task_completed(enter): T#%d proxy task %p completing\n", gtid, taskdata ) );
2876*7cc577a4SJonathan Peyton 
2877*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.proxy == TASK_PROXY );
2878*7cc577a4SJonathan Peyton 
2879*7cc577a4SJonathan Peyton     __kmp_first_top_half_finish_proxy(taskdata);
2880*7cc577a4SJonathan Peyton     __kmp_second_top_half_finish_proxy(taskdata);
2881*7cc577a4SJonathan Peyton     __kmp_bottom_half_finish_proxy(gtid,ptask);
2882*7cc577a4SJonathan Peyton 
2883*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_proxy_task_completed(exit): T#%d proxy task %p completing\n", gtid, taskdata ) );
2884*7cc577a4SJonathan Peyton }
2885*7cc577a4SJonathan Peyton 
2886*7cc577a4SJonathan Peyton /*!
2887*7cc577a4SJonathan Peyton @ingroup TASKING
2888*7cc577a4SJonathan Peyton @param ptask Task which execution is completed
2889*7cc577a4SJonathan Peyton 
2890*7cc577a4SJonathan Peyton Execute the completation of a proxy task from a thread that could not belong to the team.
2891*7cc577a4SJonathan Peyton */
2892*7cc577a4SJonathan Peyton void __kmpc_proxy_task_completed_ooo ( kmp_task_t *ptask )
2893*7cc577a4SJonathan Peyton {
2894*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( ptask != NULL );
2895*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(ptask);
2896*7cc577a4SJonathan Peyton 
2897*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_proxy_task_completed_ooo(enter): proxy task completing ooo %p\n", taskdata ) );
2898*7cc577a4SJonathan Peyton 
2899*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata->td_flags.proxy == TASK_PROXY );
2900*7cc577a4SJonathan Peyton 
2901*7cc577a4SJonathan Peyton     __kmp_first_top_half_finish_proxy(taskdata);
2902*7cc577a4SJonathan Peyton 
2903*7cc577a4SJonathan Peyton     // Enqueue task to complete bottom half completion from a thread within the corresponding team
2904*7cc577a4SJonathan Peyton     kmp_team_t * team = taskdata->td_team;
2905*7cc577a4SJonathan Peyton     kmp_int32 nthreads = team->t.t_nproc;
2906*7cc577a4SJonathan Peyton     kmp_info_t *thread;
2907*7cc577a4SJonathan Peyton 
2908*7cc577a4SJonathan Peyton     //This should be similar to start_k = __kmp_get_random( thread ) % nthreads but we cannot use __kmp_get_random here
2909*7cc577a4SJonathan Peyton     kmp_int32 start_k = 0;
2910*7cc577a4SJonathan Peyton     kmp_int32 pass = 1;
2911*7cc577a4SJonathan Peyton     kmp_int32 k = start_k;
2912*7cc577a4SJonathan Peyton 
2913*7cc577a4SJonathan Peyton     do {
2914*7cc577a4SJonathan Peyton         //For now we're just linearly trying to find a thread
2915*7cc577a4SJonathan Peyton         thread = team->t.t_threads[k];
2916*7cc577a4SJonathan Peyton         k = (k+1) % nthreads;
2917*7cc577a4SJonathan Peyton 
2918*7cc577a4SJonathan Peyton         // we did a full pass through all the threads
2919*7cc577a4SJonathan Peyton         if ( k == start_k ) pass = pass << 1;
2920*7cc577a4SJonathan Peyton 
2921*7cc577a4SJonathan Peyton     } while ( !__kmp_give_task( thread, k,  ptask, pass ) );
2922*7cc577a4SJonathan Peyton 
2923*7cc577a4SJonathan Peyton     __kmp_second_top_half_finish_proxy(taskdata);
2924*7cc577a4SJonathan Peyton 
2925*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_proxy_task_completed_ooo(exit): proxy task completing ooo %p\n", taskdata ) );
2926*7cc577a4SJonathan Peyton }
2927*7cc577a4SJonathan Peyton 
2928*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------------
2929*7cc577a4SJonathan Peyton // __kmp_task_dup_alloc: Allocate the taskdata and make a copy of source task for taskloop
2930*7cc577a4SJonathan Peyton //
2931*7cc577a4SJonathan Peyton // thread:   allocating thread
2932*7cc577a4SJonathan Peyton // task_src: pointer to source task to be duplicated
2933*7cc577a4SJonathan Peyton // returns:  a pointer to the allocated kmp_task_t structure (task).
2934*7cc577a4SJonathan Peyton kmp_task_t *
2935*7cc577a4SJonathan Peyton __kmp_task_dup_alloc( kmp_info_t *thread, kmp_task_t *task_src )
2936*7cc577a4SJonathan Peyton {
2937*7cc577a4SJonathan Peyton     kmp_task_t     *task;
2938*7cc577a4SJonathan Peyton     kmp_taskdata_t *taskdata;
2939*7cc577a4SJonathan Peyton     kmp_taskdata_t *taskdata_src;
2940*7cc577a4SJonathan Peyton     kmp_taskdata_t *parent_task = thread->th.th_current_task;
2941*7cc577a4SJonathan Peyton     size_t shareds_offset;
2942*7cc577a4SJonathan Peyton     size_t task_size;
2943*7cc577a4SJonathan Peyton 
2944*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmp_task_dup_alloc(enter): Th %p, source task %p\n", thread, task_src) );
2945*7cc577a4SJonathan Peyton     taskdata_src = KMP_TASK_TO_TASKDATA( task_src );
2946*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata_src->td_flags.proxy == TASK_FULL ); // it should not be proxy task
2947*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( taskdata_src->td_flags.tasktype == TASK_EXPLICIT );
2948*7cc577a4SJonathan Peyton     task_size = taskdata_src->td_size_alloc;
2949*7cc577a4SJonathan Peyton 
2950*7cc577a4SJonathan Peyton     // Allocate a kmp_taskdata_t block and a kmp_task_t block.
2951*7cc577a4SJonathan Peyton     KA_TRACE(30, ("__kmp_task_dup_alloc: Th %p, malloc size %ld\n", thread, task_size) );
2952*7cc577a4SJonathan Peyton     #if USE_FAST_MEMORY
2953*7cc577a4SJonathan Peyton     taskdata = (kmp_taskdata_t *)__kmp_fast_allocate( thread, task_size );
2954*7cc577a4SJonathan Peyton     #else
2955*7cc577a4SJonathan Peyton     taskdata = (kmp_taskdata_t *)__kmp_thread_malloc( thread, task_size );
2956*7cc577a4SJonathan Peyton     #endif /* USE_FAST_MEMORY */
2957*7cc577a4SJonathan Peyton     KMP_MEMCPY(taskdata, taskdata_src, task_size);
2958*7cc577a4SJonathan Peyton 
2959*7cc577a4SJonathan Peyton     task = KMP_TASKDATA_TO_TASK(taskdata);
2960*7cc577a4SJonathan Peyton 
2961*7cc577a4SJonathan Peyton     // Initialize new task (only specific fields not affected by memcpy)
2962*7cc577a4SJonathan Peyton     taskdata->td_task_id = KMP_GEN_TASK_ID();
2963*7cc577a4SJonathan Peyton     if( task->shareds != NULL ) { // need setup shareds pointer
2964*7cc577a4SJonathan Peyton         shareds_offset = (char*)task_src->shareds - (char*)taskdata_src;
2965*7cc577a4SJonathan Peyton         task->shareds = &((char*)taskdata)[shareds_offset];
2966*7cc577a4SJonathan Peyton         KMP_DEBUG_ASSERT( (((kmp_uintptr_t)task->shareds) & (sizeof(void*)-1)) == 0 );
2967*7cc577a4SJonathan Peyton     }
2968*7cc577a4SJonathan Peyton     taskdata->td_alloc_thread = thread;
2969*7cc577a4SJonathan Peyton     taskdata->td_taskgroup = parent_task->td_taskgroup; // task inherits the taskgroup from the parent task
2970*7cc577a4SJonathan Peyton 
2971*7cc577a4SJonathan Peyton     // Only need to keep track of child task counts if team parallel and tasking not serialized
2972*7cc577a4SJonathan Peyton     if ( !( taskdata->td_flags.team_serial || taskdata->td_flags.tasking_ser ) ) {
2973*7cc577a4SJonathan Peyton         KMP_TEST_THEN_INC32( (kmp_int32 *)(& parent_task->td_incomplete_child_tasks) );
2974*7cc577a4SJonathan Peyton         if ( parent_task->td_taskgroup )
2975*7cc577a4SJonathan Peyton             KMP_TEST_THEN_INC32( (kmp_int32 *)(& parent_task->td_taskgroup->count) );
2976*7cc577a4SJonathan Peyton         // Only need to keep track of allocated child tasks for explicit tasks since implicit not deallocated
2977*7cc577a4SJonathan Peyton         if ( taskdata->td_parent->td_flags.tasktype == TASK_EXPLICIT )
2978*7cc577a4SJonathan Peyton             KMP_TEST_THEN_INC32( (kmp_int32 *)(& taskdata->td_parent->td_allocated_child_tasks) );
2979*7cc577a4SJonathan Peyton     }
2980*7cc577a4SJonathan Peyton 
2981*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmp_task_dup_alloc(exit): Th %p, created task %p, parent=%p\n",
2982*7cc577a4SJonathan Peyton                   thread, taskdata, taskdata->td_parent) );
2983*7cc577a4SJonathan Peyton #if OMPT_SUPPORT
2984*7cc577a4SJonathan Peyton     __kmp_task_init_ompt(taskdata, thread->th.th_info.ds.ds_gtid, (void*)task->routine);
2985*7cc577a4SJonathan Peyton #endif
2986*7cc577a4SJonathan Peyton     return task;
2987*7cc577a4SJonathan Peyton }
2988*7cc577a4SJonathan Peyton 
2989*7cc577a4SJonathan Peyton // Routine optionally generated by th ecompiler for setting the lastprivate flag
2990*7cc577a4SJonathan Peyton // and calling needed constructors for private/firstprivate objects
2991*7cc577a4SJonathan Peyton // (used to form taskloop tasks from pattern task)
2992*7cc577a4SJonathan Peyton typedef void(*p_task_dup_t)(kmp_task_t *, kmp_task_t *, kmp_int32);
2993*7cc577a4SJonathan Peyton 
2994*7cc577a4SJonathan Peyton //---------------------------------------------------------------------------------
2995*7cc577a4SJonathan Peyton // __kmp_taskloop_linear: Start tasks of the taskloop linearly
2996*7cc577a4SJonathan Peyton //
2997*7cc577a4SJonathan Peyton // loc       Source location information
2998*7cc577a4SJonathan Peyton // gtid      Global thread ID
2999*7cc577a4SJonathan Peyton // task      Task with whole loop iteration range
3000*7cc577a4SJonathan Peyton // lb        Pointer to loop lower bound
3001*7cc577a4SJonathan Peyton // ub        Pointer to loop upper bound
3002*7cc577a4SJonathan Peyton // st        Loop stride
3003*7cc577a4SJonathan Peyton // sched     Schedule specified 0/1/2 for none/grainsize/num_tasks
3004*7cc577a4SJonathan Peyton // grainsize Schedule value if specified
3005*7cc577a4SJonathan Peyton // task_dup  Tasks duplication routine
3006*7cc577a4SJonathan Peyton void
3007*7cc577a4SJonathan Peyton __kmp_taskloop_linear(ident_t *loc, int gtid, kmp_task_t *task,
3008*7cc577a4SJonathan Peyton                 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
3009*7cc577a4SJonathan Peyton                 int sched, kmp_uint64 grainsize, void *task_dup )
3010*7cc577a4SJonathan Peyton {
3011*7cc577a4SJonathan Peyton     KMP_COUNT_BLOCK(OMP_TASKLOOP);
3012*7cc577a4SJonathan Peyton     KMP_TIME_PARTITIONED_BLOCK(OMP_taskloop_scheduling);
3013*7cc577a4SJonathan Peyton     p_task_dup_t ptask_dup = (p_task_dup_t)task_dup;
3014*7cc577a4SJonathan Peyton     kmp_uint64 tc;
3015*7cc577a4SJonathan Peyton     kmp_uint64 lower = *lb; // compiler provides global bounds here
3016*7cc577a4SJonathan Peyton     kmp_uint64 upper = *ub;
3017*7cc577a4SJonathan Peyton     kmp_uint64 i, num_tasks = 0, extras = 0;
3018*7cc577a4SJonathan Peyton     kmp_info_t *thread = __kmp_threads[gtid];
3019*7cc577a4SJonathan Peyton     kmp_taskdata_t *current_task = thread->th.th_current_task;
3020*7cc577a4SJonathan Peyton     kmp_task_t *next_task;
3021*7cc577a4SJonathan Peyton     kmp_int32 lastpriv = 0;
3022*7cc577a4SJonathan Peyton     size_t lower_offset = (char*)lb - (char*)task; // remember offset of lb in the task structure
3023*7cc577a4SJonathan Peyton     size_t upper_offset = (char*)ub - (char*)task; // remember offset of ub in the task structure
3024*7cc577a4SJonathan Peyton 
3025*7cc577a4SJonathan Peyton     // compute trip count
3026*7cc577a4SJonathan Peyton     if ( st == 1 ) {   // most common case
3027*7cc577a4SJonathan Peyton         tc = upper - lower + 1;
3028*7cc577a4SJonathan Peyton     } else if ( st < 0 ) {
3029*7cc577a4SJonathan Peyton         tc = (lower - upper) / (-st) + 1;
3030*7cc577a4SJonathan Peyton     } else {       // st > 0
3031*7cc577a4SJonathan Peyton         tc = (upper - lower) / st + 1;
3032*7cc577a4SJonathan Peyton     }
3033*7cc577a4SJonathan Peyton     if(tc == 0) {
3034*7cc577a4SJonathan Peyton         KA_TRACE(20, ("__kmpc_taskloop(exit): T#%d zero-trip loop\n", gtid));
3035*7cc577a4SJonathan Peyton         // free the pattern task and exit
3036*7cc577a4SJonathan Peyton         __kmp_task_start( gtid, task, current_task );
3037*7cc577a4SJonathan Peyton         // do not execute anything for zero-trip loop
3038*7cc577a4SJonathan Peyton         __kmp_task_finish( gtid, task, current_task );
3039*7cc577a4SJonathan Peyton         return;
3040*7cc577a4SJonathan Peyton     }
3041*7cc577a4SJonathan Peyton 
3042*7cc577a4SJonathan Peyton     // compute num_tasks/grainsize based on the input provided
3043*7cc577a4SJonathan Peyton     switch( sched ) {
3044*7cc577a4SJonathan Peyton     case 0: // no schedule clause specified, we can choose the default
3045*7cc577a4SJonathan Peyton             // let's try to schedule (team_size*10) tasks
3046*7cc577a4SJonathan Peyton         grainsize = thread->th.th_team_nproc * 10;
3047*7cc577a4SJonathan Peyton     case 2: // num_tasks provided
3048*7cc577a4SJonathan Peyton         if( grainsize > tc ) {
3049*7cc577a4SJonathan Peyton             num_tasks = tc;   // too big num_tasks requested, adjust values
3050*7cc577a4SJonathan Peyton             grainsize = 1;
3051*7cc577a4SJonathan Peyton             extras = 0;
3052*7cc577a4SJonathan Peyton         } else {
3053*7cc577a4SJonathan Peyton             num_tasks = grainsize;
3054*7cc577a4SJonathan Peyton             grainsize = tc / num_tasks;
3055*7cc577a4SJonathan Peyton             extras = tc % num_tasks;
3056*7cc577a4SJonathan Peyton         }
3057*7cc577a4SJonathan Peyton         break;
3058*7cc577a4SJonathan Peyton     case 1: // grainsize provided
3059*7cc577a4SJonathan Peyton         if( grainsize > tc ) {
3060*7cc577a4SJonathan Peyton             num_tasks = 1;    // too big grainsize requested, adjust values
3061*7cc577a4SJonathan Peyton             grainsize = tc;
3062*7cc577a4SJonathan Peyton             extras = 0;
3063*7cc577a4SJonathan Peyton         } else {
3064*7cc577a4SJonathan Peyton             num_tasks = tc / grainsize;
3065*7cc577a4SJonathan Peyton             grainsize = tc / num_tasks; // adjust grainsize for balanced distribution of iterations
3066*7cc577a4SJonathan Peyton             extras = tc % num_tasks;
3067*7cc577a4SJonathan Peyton         }
3068*7cc577a4SJonathan Peyton         break;
3069*7cc577a4SJonathan Peyton     default:
3070*7cc577a4SJonathan Peyton         KMP_ASSERT2(0, "unknown scheduling of taskloop");
3071*7cc577a4SJonathan Peyton     }
3072*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(tc == num_tasks * grainsize + extras);
3073*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(num_tasks > extras);
3074*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT(num_tasks > 0);
3075*7cc577a4SJonathan Peyton     KA_TRACE(20, ("__kmpc_taskloop: T#%d will launch: num_tasks %lld, grainsize %lld, extras %lld\n",
3076*7cc577a4SJonathan Peyton                   gtid, num_tasks, grainsize, extras));
3077*7cc577a4SJonathan Peyton 
3078*7cc577a4SJonathan Peyton     // Main loop, launch num_tasks tasks, assign grainsize iterations each task
3079*7cc577a4SJonathan Peyton     for( i = 0; i < num_tasks; ++i ) {
3080*7cc577a4SJonathan Peyton         kmp_uint64 chunk_minus_1;
3081*7cc577a4SJonathan Peyton         if( extras == 0 ) {
3082*7cc577a4SJonathan Peyton             chunk_minus_1 = grainsize - 1;
3083*7cc577a4SJonathan Peyton         } else {
3084*7cc577a4SJonathan Peyton             chunk_minus_1 = grainsize;
3085*7cc577a4SJonathan Peyton             --extras; // first extras iterations get bigger chunk (grainsize+1)
3086*7cc577a4SJonathan Peyton         }
3087*7cc577a4SJonathan Peyton         upper = lower + st * chunk_minus_1;
3088*7cc577a4SJonathan Peyton         if( i == num_tasks - 1 ) {
3089*7cc577a4SJonathan Peyton             // schedule the last task, set lastprivate flag
3090*7cc577a4SJonathan Peyton             lastpriv = 1;
3091*7cc577a4SJonathan Peyton #if KMP_DEBUG
3092*7cc577a4SJonathan Peyton             if( st == 1 )
3093*7cc577a4SJonathan Peyton                 KMP_DEBUG_ASSERT(upper == *ub);
3094*7cc577a4SJonathan Peyton             else if( st > 0 )
3095*7cc577a4SJonathan Peyton                 KMP_DEBUG_ASSERT(upper+st > *ub);
3096*7cc577a4SJonathan Peyton             else
3097*7cc577a4SJonathan Peyton                 KMP_DEBUG_ASSERT(upper+st < *ub);
3098*7cc577a4SJonathan Peyton #endif
3099*7cc577a4SJonathan Peyton         }
3100*7cc577a4SJonathan Peyton         next_task = __kmp_task_dup_alloc(thread, task); // allocate new task
3101*7cc577a4SJonathan Peyton         *(kmp_uint64*)((char*)next_task + lower_offset) = lower; // adjust task-specific bounds
3102*7cc577a4SJonathan Peyton         *(kmp_uint64*)((char*)next_task + upper_offset) = upper;
3103*7cc577a4SJonathan Peyton         if( ptask_dup != NULL )
3104*7cc577a4SJonathan Peyton             ptask_dup(next_task, task, lastpriv); // set lastprivate flag, construct fistprivates, etc.
3105*7cc577a4SJonathan Peyton         KA_TRACE(20, ("__kmpc_taskloop: T#%d schedule task %p: lower %lld, upper %lld (offsets %p %p)\n",
3106*7cc577a4SJonathan Peyton                       gtid, next_task, lower, upper, lower_offset, upper_offset));
3107*7cc577a4SJonathan Peyton         __kmp_omp_task(gtid, next_task, true); // schedule new task
3108*7cc577a4SJonathan Peyton         lower = upper + st; // adjust lower bound for the next iteration
3109*7cc577a4SJonathan Peyton     }
3110*7cc577a4SJonathan Peyton     // free the pattern task and exit
3111*7cc577a4SJonathan Peyton     __kmp_task_start( gtid, task, current_task );
3112*7cc577a4SJonathan Peyton     // do not execute the pattern task, just do bookkeeping
3113*7cc577a4SJonathan Peyton     __kmp_task_finish( gtid, task, current_task );
3114*7cc577a4SJonathan Peyton }
3115*7cc577a4SJonathan Peyton 
3116*7cc577a4SJonathan Peyton /*!
3117*7cc577a4SJonathan Peyton @ingroup TASKING
3118*7cc577a4SJonathan Peyton @param loc       Source location information
3119*7cc577a4SJonathan Peyton @param gtid      Global thread ID
3120*7cc577a4SJonathan Peyton @param task      Task structure
3121*7cc577a4SJonathan Peyton @param if_val    Value of the if clause
3122*7cc577a4SJonathan Peyton @param lb        Pointer to loop lower bound
3123*7cc577a4SJonathan Peyton @param ub        Pointer to loop upper bound
3124*7cc577a4SJonathan Peyton @param st        Loop stride
3125*7cc577a4SJonathan Peyton @param nogroup   Flag, 1 if nogroup clause specified, 0 otherwise
3126*7cc577a4SJonathan Peyton @param sched     Schedule specified 0/1/2 for none/grainsize/num_tasks
3127*7cc577a4SJonathan Peyton @param grainsize Schedule value if specified
3128*7cc577a4SJonathan Peyton @param task_dup  Tasks duplication routine
3129*7cc577a4SJonathan Peyton 
3130*7cc577a4SJonathan Peyton Execute the taskloop construct.
3131*7cc577a4SJonathan Peyton */
3132*7cc577a4SJonathan Peyton void
3133*7cc577a4SJonathan Peyton __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
3134*7cc577a4SJonathan Peyton                 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
3135*7cc577a4SJonathan Peyton                 int nogroup, int sched, kmp_uint64 grainsize, void *task_dup )
3136*7cc577a4SJonathan Peyton {
3137*7cc577a4SJonathan Peyton     kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(task);
3138*7cc577a4SJonathan Peyton     KMP_DEBUG_ASSERT( task != NULL );
3139*7cc577a4SJonathan Peyton 
3140*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_taskloop(enter): T#%d, pattern task %p, lb %lld ub %lld st %lld, grain %llu(%d)\n",
3141*7cc577a4SJonathan Peyton         gtid, taskdata, *lb, *ub, st, grainsize, sched));
3142*7cc577a4SJonathan Peyton 
3143*7cc577a4SJonathan Peyton     // check if clause value first
3144*7cc577a4SJonathan Peyton     if( if_val == 0 ) { // if(0) specified, mark task as serial
3145*7cc577a4SJonathan Peyton         taskdata->td_flags.task_serial = 1;
3146*7cc577a4SJonathan Peyton         taskdata->td_flags.tiedness = TASK_TIED; // AC: serial task cannot be untied
3147*7cc577a4SJonathan Peyton     }
3148*7cc577a4SJonathan Peyton     if( nogroup == 0 ) {
3149*7cc577a4SJonathan Peyton         __kmpc_taskgroup( loc, gtid );
3150*7cc577a4SJonathan Peyton     }
3151*7cc577a4SJonathan Peyton 
3152*7cc577a4SJonathan Peyton     if( 1 /* AC: use some heuristic here to choose task scheduling method */ ) {
3153*7cc577a4SJonathan Peyton         __kmp_taskloop_linear( loc, gtid, task, lb, ub, st, sched, grainsize, task_dup );
3154*7cc577a4SJonathan Peyton     }
3155*7cc577a4SJonathan Peyton 
3156*7cc577a4SJonathan Peyton     if( nogroup == 0 ) {
3157*7cc577a4SJonathan Peyton         __kmpc_end_taskgroup( loc, gtid );
3158*7cc577a4SJonathan Peyton     }
3159*7cc577a4SJonathan Peyton     KA_TRACE(10, ("__kmpc_taskloop(exit): T#%d\n", gtid));
3160*7cc577a4SJonathan Peyton }
3161*7cc577a4SJonathan Peyton 
3162*7cc577a4SJonathan Peyton #endif
3163