Index: openmp/runtime/src/kmp_tasking.cpp =================================================================== --- openmp/runtime/src/kmp_tasking.cpp +++ openmp/runtime/src/kmp_tasking.cpp @@ -3896,8 +3896,9 @@ // We need to wait to make sure the top half is finished // Spinning here should be ok as this should happen quickly - while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) > 0) - ; + if (!taskdata->td_flags.detachable) + while (KMP_ATOMIC_LD_ACQ(&taskdata->td_incomplete_child_tasks) > 0) + ; __kmp_release_deps(gtid, taskdata); __kmp_free_task_and_ancestors(gtid, taskdata, thread); Index: openmp/runtime/test/tasking/detach_nested_task.c =================================================================== --- /dev/null +++ openmp/runtime/test/tasking/detach_nested_task.c @@ -0,0 +1,54 @@ +// RUN: %libomp-compile-and-run + +// The outer detachable task creates multiple child tasks with dependencies +// when the last inner task incremented ret, the task calls omp_fulfill_event +// to release the outer task. + +#include +#include + +int *buf; + +int foo(int n) +{ + int ret = 0; + for (int i = 0; i < n; ++i) { + omp_event_handle_t event; + #pragma omp task detach(event) firstprivate(i,n,event) shared(ret) default(none) + { + for (int j = 0; j < n; ++j) { + #pragma omp task firstprivate(event,i,j,n) shared(ret) default(none) depend(out:ret) + { + //printf("Task %i, %i: %i\n", i, j, omp_get_thread_num()); + #pragma omp atomic + ret++; +#if _OPENMP + if (j == n-1) { + //printf("Task %i, %i: omp_fulfill_event()\n", i, j); + omp_fulfill_event(event); + } +#endif + } + } + } + } + // the taskwait only guarantees the outer tasks to complete. + #pragma omp taskwait + + return ret; +} + + +int main() +{ + int ret; +#pragma omp parallel +#pragma omp master + { + ret = foo(8); + } + printf("%i\n", ret); + //CHECK: 64 + return 0; +} +