// RUN: %libomp-compile-and-run // Tests OMP 5.0 task dependences "mutexinoutset", emulates compiler codegen // Mutually exclusive tasks get input dependency info array sorted differently // // Task tree created: // task0 task1 // \ / \ // task2 task5 // / \ // task3 task4 // / \ // task6 <-->task7 (these two are mutually exclusive) // \ / // task8 // #include #include #ifdef _WIN32 #include #define mysleep(n) Sleep(n) #else #include #define mysleep(n) usleep((n)*1000) #endif static int checker = 0; // to check if two tasks run simultaneously static int err = 0; #ifndef DELAY #define DELAY 100 #endif // --------------------------------------------------------------------------- // internal data to emulate compiler codegen typedef int(*entry_t)(int, int**); typedef struct DEP { size_t addr; size_t len; int flags; } dep; typedef struct ID { int reserved_1; int flags; int reserved_2; int reserved_3; char *psource; } id; int thunk(int gtid, int** pshareds) { int t = **pshareds; int th = omp_get_thread_num(); #pragma omp atomic ++checker; printf("task __%d, th %d\n", t, th); if (checker != 1) { err++; printf("Error1, checker %d != 1\n", checker); } mysleep(DELAY); if (checker != 1) { err++; printf("Error2, checker %d != 1\n", checker); } #pragma omp atomic --checker; return 0; } #ifdef __cplusplus extern "C" { #endif int __kmpc_global_thread_num(id*); extern int** __kmpc_omp_task_alloc(id *loc, int gtid, int flags, size_t sz, size_t shar, entry_t rtn); int __kmpc_omp_task_with_deps(id *loc, int gtid, int **task, int nd, dep *dep_lst, int nd_noalias, dep *noalias_dep_lst); static id loc = {0, 2, 0, 0, ";file;func;0;0;;"}; #ifdef __cplusplus } // extern "C" #endif // End of internal data // --------------------------------------------------------------------------- int main() { int i1,i2,i3,i4; omp_set_num_threads(2); #pragma omp parallel { #pragma omp single nowait { dep sdep[2]; int **ptr; int gtid = __kmpc_global_thread_num(&loc); int t = omp_get_thread_num(); #pragma omp task depend(in: i1, i2) { int th = omp_get_thread_num(); printf("task 0_%d, th %d\n", t, th); mysleep(DELAY); } #pragma omp task depend(in: i1, i3) { int th = omp_get_thread_num(); printf("task 1_%d, th %d\n", t, th); mysleep(DELAY); } #pragma omp task depend(in: i2) depend(out: i1) { int th = omp_get_thread_num(); printf("task 2_%d, th %d\n", t, th); mysleep(DELAY); } #pragma omp task depend(in: i1) { int th = omp_get_thread_num(); printf("task 3_%d, th %d\n", t, th); mysleep(DELAY); } #pragma omp task depend(out: i2) { int th = omp_get_thread_num(); printf("task 4_%d, th %d\n", t, th); mysleep(DELAY+5); } // wait a bit longer than task 3 #pragma omp task depend(out: i3) { int th = omp_get_thread_num(); printf("task 5_%d, th %d\n", t, th); mysleep(DELAY); } // compiler codegen start // task1 ptr = __kmpc_omp_task_alloc(&loc, gtid, 0, 28, 16, thunk); sdep[0].addr = (size_t)&i1; sdep[0].len = 0; // not used sdep[0].flags = 4; // mx sdep[1].addr = (size_t)&i4; sdep[1].len = 0; // not used sdep[1].flags = 4; // mx **ptr = t + 10; // init single shared variable __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0); // task2 ptr = __kmpc_omp_task_alloc(&loc, gtid, 0, 28, 16, thunk); // reverse pointers - library should sort them uniquely sdep[0].addr = (size_t)&i4; sdep[1].addr = (size_t)&i1; **ptr = t + 20; // init single shared variable __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0); // compiler codegen end #pragma omp task depend(in: i1) { int th = omp_get_thread_num(); printf("task 8_%d, th %d\n", t, th); mysleep(DELAY); } } // single } // parallel if (err == 0) { printf("passed\n"); return 0; } else { printf("failed\n"); return 1; } }