xref: /llvm-project/openmp/runtime/test/tasking/omp50_taskwait_depend.c (revision 80256605f8c6aab8cb33ac3a3784aacd005087a3)
1 // RUN: %libomp-compile-and-run
2 // UNSUPPORTED: gcc-4, gcc-5, gcc-6, gcc-7, gcc-8
3 
4 // support for taskwait with depend clause introduced in clang-14
5 // UNSUPPORTED: clang-5, clang-6, clang-6, clang-8, clang-9, clang-10, clang-11,
6 // clang-12, clang-13
7 
8 // icc does not yet support taskwait with depend clause
9 // XFAIL: icc
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <omp.h>
14 #include "omp_my_sleep.h"
15 
16 int a = 0, b = 0;
17 int task_grabbed = 0, task_can_proceed = 0;
18 int task2_grabbed = 0, task2_can_proceed = 0;
19 
wait_on_flag(int * flag)20 static void wait_on_flag(int *flag) {
21   int flag_value;
22   int timelimit = 30;
23   int secs = 0;
24   do {
25     #pragma omp atomic read
26     flag_value = *flag;
27     my_sleep(1.0);
28     secs++;
29     if (secs == timelimit) {
30       fprintf(stderr, "error: timeout in wait_on_flag()\n");
31       exit(EXIT_FAILURE);
32     }
33   } while (flag_value == 0);
34 }
35 
signal_flag(int * flag)36 static void signal_flag(int *flag) {
37   #pragma omp atomic
38   (*flag)++;
39 }
40 
main(int argc,char ** argv)41 int main(int argc, char** argv) {
42 
43   // Ensure two threads are running
44   int num_threads = omp_get_max_threads();
45   if (num_threads < 2)
46     omp_set_num_threads(2);
47 
48   #pragma omp parallel shared(a)
49   {
50     int a_value;
51     // Let us be extra safe here
52     if (omp_get_num_threads() > 1) {
53       #pragma omp single nowait
54       {
55         // Schedule independent child task that
56         // waits to be flagged after sebsequent taskwait depend()
57         #pragma omp task
58         {
59           signal_flag(&task_grabbed);
60           wait_on_flag(&task_can_proceed);
61         }
62         // Let another worker thread grab the task to execute
63         wait_on_flag(&task_grabbed);
64         // This should be ignored since the task above has
65         // no dependency information
66         #pragma omp taskwait depend(inout: a)
67         // Signal the independent task to proceed
68         signal_flag(&task_can_proceed);
69 
70         // Schedule child task with dependencies that taskwait does
71         // not care about
72         #pragma omp task depend(inout: b)
73         {
74           signal_flag(&task2_grabbed);
75           wait_on_flag(&task2_can_proceed);
76           #pragma omp atomic
77           b++;
78         }
79         // Let another worker thread grab the task to execute
80         wait_on_flag(&task2_grabbed);
81         // This should be ignored since the task above has
82         // dependency information on b instead of a
83         #pragma omp taskwait depend(inout: a)
84         // Signal the task to proceed
85         signal_flag(&task2_can_proceed);
86 
87         // Generate one child task for taskwait
88         #pragma omp task shared(a) depend(inout: a)
89         {
90           my_sleep(1.0);
91           #pragma omp atomic
92           a++;
93         }
94         #pragma omp taskwait depend(inout: a)
95 
96         #pragma omp atomic read
97         a_value = a;
98 
99         if (a_value != 1) {
100           fprintf(stderr, "error: dependent task was not executed before "
101                           "taskwait finished\n");
102           exit(EXIT_FAILURE);
103         }
104       } // #pragma omp single
105     } // if (num_threads > 1)
106   } // #pragma omp parallel
107 
108   return EXIT_SUCCESS;
109 }
110