Index: runtime/src/kmp.h =================================================================== --- runtime/src/kmp.h +++ runtime/src/kmp.h @@ -2189,6 +2189,7 @@ /* Currently not used except for perhaps IDB */ kmp_taskdata_t * td_parent; /* parent task */ kmp_int32 td_level; /* task nesting level */ + kmp_int32 td_untied_count; /* untied task active parts counter */ ident_t * td_ident; /* task identifier */ // Taskwait data. ident_t * td_taskwait_ident; Index: runtime/src/kmp_tasking.c =================================================================== --- runtime/src/kmp_tasking.c +++ runtime/src/kmp_tasking.c @@ -284,6 +284,13 @@ KA_TRACE(20, ("__kmp_push_task: T#%d trying to push task %p.\n", gtid, taskdata ) ); + if ( taskdata->td_flags.tiedness == TASK_UNTIED ) { + // untied task needs to increment counter so that the task structure is not freed prematurely + kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count); + KA_TRACE(20, ( "__kmp_push_task: T#%d untied_count (%d) incremented for task %p\n", + gtid, counter, taskdata ) ); + } + // The first check avoids building task_team thread data if serialized if ( taskdata->td_flags.task_serial ) { KA_TRACE(20, ( "__kmp_push_task: T#%d team serialized; returning TASK_NOT_PUSHED for task %p\n", @@ -436,8 +443,8 @@ // mark starting task as executing and as current task thread -> th.th_current_task = taskdata; - KMP_DEBUG_ASSERT( taskdata -> td_flags.started == 0 ); - KMP_DEBUG_ASSERT( taskdata -> td_flags.executing == 0 ); + KMP_DEBUG_ASSERT( taskdata->td_flags.started == 0 || taskdata->td_flags.tiedness == TASK_UNTIED ); + KMP_DEBUG_ASSERT( taskdata->td_flags.executing == 0 || taskdata->td_flags.tiedness == TASK_UNTIED ); taskdata -> td_flags.started = 1; taskdata -> td_flags.executing = 1; KMP_DEBUG_ASSERT( taskdata -> td_flags.complete == 0 ); @@ -498,6 +505,13 @@ KA_TRACE(10, ("__kmpc_omp_task_begin_if0(enter): T#%d loc=%p task=%p current_task=%p\n", gtid, loc_ref, taskdata, current_task ) ); + if ( taskdata->td_flags.tiedness == TASK_UNTIED ) { + // untied task needs to increment counter so that the task structure is not freed prematurely + kmp_int32 counter = 1 + KMP_TEST_THEN_INC32(&taskdata->td_untied_count); + KA_TRACE(20, ( "__kmpc_omp_task_begin_if0: T#%d untied_count (%d) incremented for task %p\n", + gtid, counter, taskdata ) ); + } + taskdata -> td_flags.task_serial = 1; // Execute this task immediately, not deferred. __kmp_task_start( gtid, task, current_task ); @@ -646,6 +660,25 @@ } #endif /* BUILD_TIED_TASK_STACK */ + if ( taskdata->td_flags.tiedness == TASK_UNTIED ) { + // untied task needs to check the counter so that the task structure is not freed prematurely + kmp_int32 counter = KMP_TEST_THEN_DEC32(&taskdata->td_untied_count) - 1; + KA_TRACE(20, ( "__kmp_task_finish: T#%d untied_count (%d) decremented for task %p\n", + gtid, counter, taskdata ) ); + if ( counter > 0 ) { + // untied task is not done, to be continued possibly by other thread, do not free it now + if (resumed_task == NULL) { + KMP_DEBUG_ASSERT( taskdata->td_flags.task_serial ); + resumed_task = taskdata->td_parent; // In a serialized task, the resumed task is the parent + } + thread->th.th_current_task = resumed_task; // restore current_task + resumed_task->td_flags.executing = 1; // resume previous task + KA_TRACE(10, ("__kmp_task_finish(exit): T#%d partially done task %p, resuming task %p\n", + gtid, taskdata, resumed_task) ); + return; + } + } + KMP_DEBUG_ASSERT( taskdata -> td_flags.complete == 0 ); taskdata -> td_flags.complete = 1; // mark the task as completed KMP_DEBUG_ASSERT( taskdata -> td_flags.started == 1 ); @@ -980,6 +1013,7 @@ taskdata->td_alloc_thread = thread; taskdata->td_parent = parent_task; taskdata->td_level = parent_task->td_level + 1; // increment nesting level + taskdata->td_untied_count = 0; taskdata->td_ident = loc_ref; taskdata->td_taskwait_ident = NULL; taskdata->td_taskwait_counter = 0;