@@ -444,6 +444,8 @@ struct Taskgroup final : DataPoolEntry<Taskgroup> {
444444 Taskgroup (DataPool<Taskgroup> *dp) : DataPoolEntry<Taskgroup>(dp) {}
445445};
446446
447+ enum ArcherTaskFlag { ArcherTaskFulfilled = 0x00010000 };
448+
447449struct TaskData ;
448450typedef DataPool<TaskData> TaskDataPool;
449451template <> __thread TaskDataPool *TaskDataPool::ThreadDataPool = nullptr ;
@@ -460,6 +462,9 @@ struct TaskData final : DataPoolEntry<TaskData> {
460462 // / Child tasks use its address to model omp_all_memory dependencies
461463 ompt_tsan_clockid AllMemory[2 ]{0 };
462464
465+ // / Index of which barrier to use next.
466+ char BarrierIndex{0 };
467+
463468 // / Whether this task is currently executing a barrier.
464469 bool InBarrier{false };
465470
@@ -469,18 +474,12 @@ struct TaskData final : DataPoolEntry<TaskData> {
469474 // / count execution phase
470475 int execution{0 };
471476
472- // / Index of which barrier to use next.
473- char BarrierIndex{0 };
474-
475477 // / Count how often this structure has been put into child tasks + 1.
476478 std::atomic_int RefCount{1 };
477479
478480 // / Reference to the parent that created this task.
479481 TaskData *Parent{nullptr };
480482
481- // / Reference to the implicit task in the stack above this task.
482- TaskData *ImplicitTask{nullptr };
483-
484483 // / Reference to the team of this task.
485484 ParallelData *Team{nullptr };
486485
@@ -515,6 +514,9 @@ struct TaskData final : DataPoolEntry<TaskData> {
515514 bool isInitial () { return TaskType & ompt_task_initial; }
516515 bool isTarget () { return TaskType & ompt_task_target; }
517516
517+ bool isFulfilled () { return TaskType & ArcherTaskFulfilled; }
518+ void setFulfilled () { TaskType |= ArcherTaskFulfilled; }
519+
518520 void setAllMemoryDep () { AllMemory[0 ] = 1 ; }
519521 bool hasAllMemoryDep () { return AllMemory[0 ]; }
520522
@@ -529,6 +531,7 @@ struct TaskData final : DataPoolEntry<TaskData> {
529531 TaskType = taskType;
530532 Parent = parent;
531533 Team = Parent->Team ;
534+ BarrierIndex = Parent->BarrierIndex ;
532535 if (Parent != nullptr ) {
533536 Parent->RefCount ++;
534537 // Copy over pointer to taskgroup. This task may set up its own stack
@@ -541,7 +544,6 @@ struct TaskData final : DataPoolEntry<TaskData> {
541544 TaskData *Init (ParallelData *team, int taskType) {
542545 TaskType = taskType;
543546 execution = 1 ;
544- ImplicitTask = this ;
545547 Team = team;
546548 return this ;
547549 }
@@ -553,7 +555,6 @@ struct TaskData final : DataPoolEntry<TaskData> {
553555 BarrierIndex = 0 ;
554556 RefCount = 1 ;
555557 Parent = nullptr ;
556- ImplicitTask = nullptr ;
557558 Team = nullptr ;
558559 TaskGroup = nullptr ;
559560 if (DependencyMap) {
@@ -584,7 +585,9 @@ struct TaskData final : DataPoolEntry<TaskData> {
584585} // namespace
585586
586587static inline TaskData *ToTaskData (ompt_data_t *task_data) {
587- return reinterpret_cast <TaskData *>(task_data->ptr );
588+ if (task_data)
589+ return reinterpret_cast <TaskData *>(task_data->ptr );
590+ return nullptr ;
588591}
589592
590593// / Store a mutex for each wait_id to resolve race condition with callbacks.
@@ -899,6 +902,79 @@ static void acquireDependencies(TaskData *task) {
899902 }
900903}
901904
905+ static void completeTask (TaskData *FromTask) {
906+ if (!FromTask)
907+ return ;
908+ // Task-end happens after a possible omp_fulfill_event call
909+ if (FromTask->isFulfilled ())
910+ TsanHappensAfter (FromTask->GetTaskPtr ());
911+ // Included tasks are executed sequentially, no need to track
912+ // synchronization
913+ if (!FromTask->isIncluded ()) {
914+ // Task will finish before a barrier in the surrounding parallel region
915+ // ...
916+ ParallelData *PData = FromTask->Team ;
917+ TsanHappensBefore (PData->GetBarrierPtr (FromTask->BarrierIndex ));
918+
919+ // ... and before an eventual taskwait by the parent thread.
920+ TsanHappensBefore (FromTask->Parent ->GetTaskwaitPtr ());
921+
922+ if (FromTask->TaskGroup != nullptr ) {
923+ // This task is part of a taskgroup, so it will finish before the
924+ // corresponding taskgroup_end.
925+ TsanHappensBefore (FromTask->TaskGroup ->GetPtr ());
926+ }
927+ }
928+ // release dependencies
929+ releaseDependencies (FromTask);
930+ }
931+
932+ static void suspendTask (TaskData *FromTask) {
933+ if (!FromTask)
934+ return ;
935+ // Task may be resumed at a later point in time.
936+ TsanHappensBefore (FromTask->GetTaskPtr ());
937+ }
938+
939+ static void switchTasks (TaskData *FromTask, TaskData *ToTask) {
940+ // Legacy handling for missing reduction callback
941+ if (hasReductionCallback < ompt_set_always) {
942+ if (FromTask && FromTask->InBarrier ) {
943+ // We want to ignore writes in the runtime code during barriers,
944+ // but not when executing tasks with user code!
945+ TsanIgnoreWritesEnd ();
946+ }
947+ if (ToTask && ToTask->InBarrier ) {
948+ // We want to ignore writes in the runtime code during barriers,
949+ // but not when executing tasks with user code!
950+ TsanIgnoreWritesBegin ();
951+ }
952+ }
953+ // // Not yet used
954+ // if (FromTask)
955+ // FromTask->deactivate();
956+ // if (ToTask)
957+ // ToTask->activate();
958+ }
959+
960+ static void endTask (TaskData *FromTask) {
961+ if (!FromTask)
962+ return ;
963+ }
964+
965+ static void startTask (TaskData *ToTask) {
966+ if (!ToTask)
967+ return ;
968+ // Handle dependencies on first execution of the task
969+ if (ToTask->execution == 0 ) {
970+ ToTask->execution ++;
971+ acquireDependencies (ToTask);
972+ }
973+ // 1. Task will begin execution after it has been created.
974+ // 2. Task will resume after it has been switched away.
975+ TsanHappensAfter (ToTask->GetTaskPtr ());
976+ }
977+
902978static void ompt_tsan_task_schedule (ompt_data_t *first_task_data,
903979 ompt_task_status_t prior_task_status,
904980 ompt_data_t *second_task_data) {
@@ -916,88 +992,62 @@ static void ompt_tsan_task_schedule(ompt_data_t *first_task_data,
916992 // ompt_task_cancel = 3,
917993 // -> first completed, first freed, second starts
918994 //
995+ // ompt_taskwait_complete = 8,
996+ // -> first starts, first completes, first freed, second ignored
997+ //
919998 // ompt_task_detach = 4,
920999 // ompt_task_yield = 2,
9211000 // ompt_task_switch = 7
9221001 // -> first suspended, second starts
9231002 //
9241003
925- if (prior_task_status == ompt_task_early_fulfill)
926- return ;
927-
9281004 TaskData *FromTask = ToTaskData (first_task_data);
1005+ TaskData *ToTask = ToTaskData (second_task_data);
9291006
930- // Legacy handling for missing reduction callback
931- if (hasReductionCallback < ompt_set_always && FromTask->InBarrier ) {
932- // We want to ignore writes in the runtime code during barriers,
933- // but not when executing tasks with user code!
934- TsanIgnoreWritesEnd ();
935- }
936-
937- // The late fulfill happens after the detached task finished execution
938- if (prior_task_status == ompt_task_late_fulfill)
1007+ switch (prior_task_status) {
1008+ case ompt_task_early_fulfill:
1009+ TsanHappensBefore (FromTask->GetTaskPtr ());
1010+ FromTask->setFulfilled ();
1011+ return ;
1012+ case ompt_task_late_fulfill:
9391013 TsanHappensAfter (FromTask->GetTaskPtr ());
940-
941- // task completed execution
942- if (prior_task_status == ompt_task_complete ||
943- prior_task_status == ompt_task_cancel ||
944- prior_task_status == ompt_task_late_fulfill) {
945- // Included tasks are executed sequentially, no need to track
946- // synchronization
947- if (!FromTask->isIncluded ()) {
948- // Task will finish before a barrier in the surrounding parallel region
949- // ...
950- ParallelData *PData = FromTask->Team ;
951- TsanHappensBefore (
952- PData->GetBarrierPtr (FromTask->ImplicitTask ->BarrierIndex ));
953-
954- // ... and before an eventual taskwait by the parent thread.
955- TsanHappensBefore (FromTask->Parent ->GetTaskwaitPtr ());
956-
957- if (FromTask->TaskGroup != nullptr ) {
958- // This task is part of a taskgroup, so it will finish before the
959- // corresponding taskgroup_end.
960- TsanHappensBefore (FromTask->TaskGroup ->GetPtr ());
961- }
962- }
963-
964- // release dependencies
965- releaseDependencies (FromTask);
966- // free the previously running task
1014+ completeTask (FromTask);
9671015 freeTask (FromTask);
968- }
969-
970- // For late fulfill of detached task, there is no task to schedule to
971- if (prior_task_status == ompt_task_late_fulfill) {
1016+ return ;
1017+ case ompt_taskwait_complete:
1018+ acquireDependencies (FromTask);
1019+ freeTask (FromTask);
1020+ return ;
1021+ case ompt_task_complete:
1022+ completeTask (FromTask);
1023+ endTask (FromTask);
1024+ switchTasks (FromTask, ToTask);
1025+ freeTask (FromTask);
1026+ return ;
1027+ case ompt_task_cancel:
1028+ completeTask (FromTask);
1029+ endTask (FromTask);
1030+ switchTasks (FromTask, ToTask);
1031+ freeTask (FromTask);
1032+ startTask (ToTask);
1033+ return ;
1034+ case ompt_task_detach:
1035+ endTask (FromTask);
1036+ suspendTask (FromTask);
1037+ switchTasks (FromTask, ToTask);
1038+ startTask (ToTask);
1039+ return ;
1040+ case ompt_task_yield:
1041+ suspendTask (FromTask);
1042+ switchTasks (FromTask, ToTask);
1043+ startTask (ToTask);
1044+ return ;
1045+ case ompt_task_switch:
1046+ suspendTask (FromTask);
1047+ switchTasks (FromTask, ToTask);
1048+ startTask (ToTask);
9721049 return ;
9731050 }
974-
975- TaskData *ToTask = ToTaskData (second_task_data);
976- // Legacy handling for missing reduction callback
977- if (hasReductionCallback < ompt_set_always && ToTask->InBarrier ) {
978- // We re-enter runtime code which currently performs a barrier.
979- TsanIgnoreWritesBegin ();
980- }
981-
982- // task suspended
983- if (prior_task_status == ompt_task_switch ||
984- prior_task_status == ompt_task_yield ||
985- prior_task_status == ompt_task_detach) {
986- // Task may be resumed at a later point in time.
987- TsanHappensBefore (FromTask->GetTaskPtr ());
988- ToTask->ImplicitTask = FromTask->ImplicitTask ;
989- assert (ToTask->ImplicitTask != NULL &&
990- " A task belongs to a team and has an implicit task on the stack" );
991- }
992-
993- // Handle dependencies on first execution of the task
994- if (ToTask->execution == 0 ) {
995- ToTask->execution ++;
996- acquireDependencies (ToTask);
997- }
998- // 1. Task will begin execution after it has been created.
999- // 2. Task will resume after it has been switched away.
1000- TsanHappensAfter (ToTask->GetTaskPtr ());
10011051}
10021052
10031053static void ompt_tsan_dependences (ompt_data_t *task_data,
0 commit comments