1 | // RUN: %libomp-compile-and-run |
2 | |
3 | // Tests OMP 5.0 task dependences "mutexinoutset", emulates compiler codegen |
4 | // Mutually exclusive tasks get input dependency info array sorted differently |
5 | // |
6 | // Task tree created: |
7 | // task0 task1 |
8 | // \ / \ |
9 | // task2 task5 |
10 | // / \ |
11 | // task3 task4 |
12 | // / \ |
13 | // task6 <-->task7 (these two are mutually exclusive) |
14 | // \ / |
15 | // task8 |
16 | // |
17 | #include <stdio.h> |
18 | #include <omp.h> |
19 | |
20 | #ifdef _WIN32 |
21 | #include <windows.h> |
22 | #define mysleep(n) Sleep(n) |
23 | #else |
24 | #include <unistd.h> |
25 | #define mysleep(n) usleep((n)*1000) |
26 | #endif |
27 | |
28 | static int checker = 0; // to check if two tasks run simultaneously |
29 | static int err = 0; |
30 | #ifndef DELAY |
31 | #define DELAY 100 |
32 | #endif |
33 | |
34 | // --------------------------------------------------------------------------- |
35 | // internal data to emulate compiler codegen |
36 | typedef int(*entry_t)(int, int**); |
37 | typedef struct DEP { |
38 | size_t addr; |
39 | size_t len; |
40 | unsigned char flags; |
41 | } dep; |
42 | typedef struct ID { |
43 | int reserved_1; |
44 | int flags; |
45 | int reserved_2; |
46 | int reserved_3; |
47 | char *psource; |
48 | } id; |
49 | |
50 | int thunk(int gtid, int** pshareds) { |
51 | int t = **pshareds; |
52 | int th = omp_get_thread_num(); |
53 | #pragma omp atomic |
54 | ++checker; |
55 | printf(format: "task __%d, th %d\n" , t, th); |
56 | if (checker != 1) { |
57 | err++; |
58 | printf(format: "Error1, checker %d != 1\n" , checker); |
59 | } |
60 | mysleep(DELAY); |
61 | if (checker != 1) { |
62 | err++; |
63 | printf(format: "Error2, checker %d != 1\n" , checker); |
64 | } |
65 | #pragma omp atomic |
66 | --checker; |
67 | return 0; |
68 | } |
69 | |
70 | #ifdef __cplusplus |
71 | extern "C" { |
72 | #endif |
73 | int __kmpc_global_thread_num(id*); |
74 | extern int** __kmpc_omp_task_alloc(id *loc, int gtid, int flags, |
75 | size_t sz, size_t shar, entry_t rtn); |
76 | int |
77 | __kmpc_omp_task_with_deps(id *loc, int gtid, int **task, int nd, dep *dep_lst, |
78 | int nd_noalias, dep *noalias_dep_lst); |
79 | static id loc = {0, 2, 0, 0, ";file;func;0;0;;" }; |
80 | #ifdef __cplusplus |
81 | } // extern "C" |
82 | #endif |
83 | // End of internal data |
84 | // --------------------------------------------------------------------------- |
85 | |
86 | int main() |
87 | { |
88 | int i1,i2,i3,i4; |
89 | omp_set_num_threads(2); |
90 | #pragma omp parallel |
91 | { |
92 | #pragma omp single nowait |
93 | { |
94 | dep sdep[2]; |
95 | int **ptr; |
96 | int gtid = __kmpc_global_thread_num(&loc); |
97 | int t = omp_get_thread_num(); |
98 | #pragma omp task depend(in: i1, i2) |
99 | { int th = omp_get_thread_num(); |
100 | printf(format: "task 0_%d, th %d\n" , t, th); |
101 | mysleep(DELAY); } |
102 | #pragma omp task depend(in: i1, i3) |
103 | { int th = omp_get_thread_num(); |
104 | printf(format: "task 1_%d, th %d\n" , t, th); |
105 | mysleep(DELAY); } |
106 | #pragma omp task depend(in: i2) depend(out: i1) |
107 | { int th = omp_get_thread_num(); |
108 | printf(format: "task 2_%d, th %d\n" , t, th); |
109 | mysleep(DELAY); } |
110 | #pragma omp task depend(in: i1) |
111 | { int th = omp_get_thread_num(); |
112 | printf(format: "task 3_%d, th %d\n" , t, th); |
113 | mysleep(DELAY); } |
114 | #pragma omp task depend(out: i2) |
115 | { int th = omp_get_thread_num(); |
116 | printf(format: "task 4_%d, th %d\n" , t, th); |
117 | mysleep(DELAY+5); } // wait a bit longer than task 3 |
118 | #pragma omp task depend(out: i3) |
119 | { int th = omp_get_thread_num(); |
120 | printf(format: "task 5_%d, th %d\n" , t, th); |
121 | mysleep(DELAY); } |
122 | // compiler codegen start |
123 | // task1 |
124 | ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, flags: 0, sz: 28, shar: 16, rtn: thunk); |
125 | sdep[0].addr = (size_t)&i1; |
126 | sdep[0].len = 0; // not used |
127 | sdep[0].flags = 4; // mx |
128 | sdep[1].addr = (size_t)&i4; |
129 | sdep[1].len = 0; // not used |
130 | sdep[1].flags = 4; // mx |
131 | **ptr = t + 10; // init single shared variable |
132 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, nd: 2, dep_lst: sdep, nd_noalias: 0, noalias_dep_lst: 0); |
133 | |
134 | // task2 |
135 | ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, flags: 0, sz: 28, shar: 16, rtn: thunk); |
136 | // reverse pointers - library should sort them uniquely |
137 | sdep[0].addr = (size_t)&i4; |
138 | sdep[1].addr = (size_t)&i1; |
139 | **ptr = t + 20; // init single shared variable |
140 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, nd: 2, dep_lst: sdep, nd_noalias: 0, noalias_dep_lst: 0); |
141 | // compiler codegen end |
142 | #pragma omp task depend(in: i1) |
143 | { int th = omp_get_thread_num(); |
144 | printf(format: "task 8_%d, th %d\n" , t, th); |
145 | mysleep(DELAY); } |
146 | } // single |
147 | } // parallel |
148 | if (err == 0) { |
149 | printf(format: "passed\n" ); |
150 | return 0; |
151 | } else { |
152 | printf(format: "failed\n" ); |
153 | return 1; |
154 | } |
155 | } |
156 | |