1// RUN: %libomp-compile-and-run
2// RUN: %libomp-cxx-compile-and-run
3// UNSUPPORTED: gcc
4
5// Tests OMP 5.0 task dependences "mutexinoutset" and 5.1 "inoutset",
6// emulates compiler codegen for new dep kinds
7// Mutually exclusive tasks get same input dependency info array
8//
9// Task tree created:
10// task0 - task1 (in)
11// \
12// task2 - task3 (inoutset)
13// /
14// task3 - task4 (in)
15// /
16// task6 <-->task7 (mutexinoutset)
17// \ /
18// task8 (in)
19//
20#include <stdio.h>
21#include <omp.h>
22
23#ifdef _WIN32
24#include <windows.h>
25#define mysleep(n) Sleep(n)
26#else
27#include <unistd.h>
28#define mysleep(n) usleep((n)*1000)
29#endif
30
31// to check the # of concurrent tasks (must be 1 for MTX, <3 for other kinds)
32static int volatile checker = 0;
33static int err = 0;
34#ifndef DELAY
35#define DELAY 100
36#endif
37
38// ---------------------------------------------------------------------------
39// internal data to emulate compiler codegen
40typedef struct DEP {
41 size_t addr;
42 size_t len;
43 unsigned char flags;
44} dep;
45typedef struct task {
46 void** shareds;
47 void* entry;
48 int part_id;
49 void* destr_thunk;
50 int priority;
51 long long device_id;
52 int f_priv;
53} task_t;
54#define TIED 1
55typedef int(*entry_t)(int, task_t*);
56typedef struct ID {
57 int reserved_1;
58 int flags;
59 int reserved_2;
60 int reserved_3;
61 char *psource;
62} id;
63// thunk routine for tasks with MTX dependency
64int thunk_m(int gtid, task_t* ptask) {
65 int th = omp_get_thread_num();
66 #pragma omp atomic
67 ++checker;
68 printf(format: "task _%d, th %d\n", ptask->f_priv, th);
69 if (checker != 1) { // no more than 1 task at a time
70 err++;
71 printf(format: "Error1, checker %d != 1\n", checker);
72 }
73 mysleep(DELAY);
74 if (checker != 1) { // no more than 1 task at a time
75 err++;
76 printf(format: "Error2, checker %d != 1\n", checker);
77 }
78 #pragma omp atomic
79 --checker;
80 return 0;
81}
82// thunk routine for tasks with inoutset dependency
83int thunk_s(int gtid, task_t* ptask) {
84 int th = omp_get_thread_num();
85 #pragma omp atomic
86 ++checker;
87 printf(format: "task _%d, th %d\n", ptask->f_priv, th);
88 if (checker > 2) { // no more than 2 tasks concurrently
89 err++;
90 printf(format: "Error1, checker %d > 2\n", checker);
91 }
92 mysleep(DELAY);
93 if (checker > 2) { // no more than 2 tasks concurrently
94 err++;
95 printf(format: "Error2, checker %d > 2\n", checker);
96 }
97 #pragma omp atomic
98 --checker;
99 return 0;
100}
101
102#ifdef __cplusplus
103extern "C" {
104#endif
105int __kmpc_global_thread_num(id*);
106extern task_t* __kmpc_omp_task_alloc(id *loc, int gtid, int flags,
107 size_t sz, size_t shar, entry_t rtn);
108int
109__kmpc_omp_task_with_deps(id *loc, int gtid, task_t *task, int nd, dep *dep_lst,
110 int nd_noalias, dep *noalias_dep_lst);
111static id loc = {0, 2, 0, 0, ";file;func;0;0;;"};
112#ifdef __cplusplus
113} // extern "C"
114#endif
115// End of internal data
116// ---------------------------------------------------------------------------
117
118int main()
119{
120 int i1,i2,i3;
121 omp_set_num_threads(4);
122 omp_set_dynamic(0);
123 #pragma omp parallel
124 {
125 #pragma omp single nowait
126 {
127 dep sdep[2];
128 task_t *ptr;
129 int gtid = __kmpc_global_thread_num(&loc);
130 int t = omp_get_thread_num();
131 #pragma omp task depend(in: i1, i2)
132 { int th = omp_get_thread_num();
133 printf(format: "task 0_%d, th %d\n", t, th);
134 #pragma omp atomic
135 ++checker;
136 if (checker > 2) { // no more than 2 tasks concurrently
137 err++;
138 printf(format: "Error1, checker %d > 2\n", checker);
139 }
140 mysleep(DELAY);
141 if (checker > 2) { // no more than 2 tasks concurrently
142 err++;
143 printf(format: "Error1, checker %d > 2\n", checker);
144 }
145 #pragma omp atomic
146 --checker;
147 }
148 #pragma omp task depend(in: i1, i2)
149 { int th = omp_get_thread_num();
150 printf(format: "task 1_%d, th %d\n", t, th);
151 #pragma omp atomic
152 ++checker;
153 if (checker > 2) { // no more than 2 tasks concurrently
154 err++;
155 printf(format: "Error1, checker %d > 2\n", checker);
156 }
157 mysleep(DELAY);
158 if (checker > 2) { // no more than 2 tasks concurrently
159 err++;
160 printf(format: "Error1, checker %d > 2\n", checker);
161 }
162 #pragma omp atomic
163 --checker;
164 }
165// compiler codegen start
166 // task2
167 ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(task_t), shar: 0, rtn: thunk_s);
168 sdep[0].addr = (size_t)&i1;
169 sdep[0].len = 0; // not used
170 sdep[0].flags = 1; // IN
171 sdep[1].addr = (size_t)&i2;
172 sdep[1].len = 0; // not used
173 sdep[1].flags = 8; // INOUTSET
174 ptr->f_priv = t + 10; // init single first-private variable
175 __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, nd: 2, dep_lst: sdep, nd_noalias: 0, noalias_dep_lst: 0);
176
177 // task3
178 ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(task_t), shar: 0, rtn: thunk_s);
179 ptr->f_priv = t + 20; // init single first-private variable
180 __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, nd: 2, dep_lst: sdep, nd_noalias: 0, noalias_dep_lst: 0);
181// compiler codegen end
182 t = omp_get_thread_num();
183 #pragma omp task depend(in: i1, i2)
184 { int th = omp_get_thread_num();
185 printf(format: "task 4_%d, th %d\n", t, th);
186 #pragma omp atomic
187 ++checker;
188 if (checker > 2) { // no more than 2 tasks concurrently
189 err++;
190 printf(format: "Error1, checker %d > 2\n", checker);
191 }
192 mysleep(DELAY);
193 if (checker > 2) { // no more than 2 tasks concurrently
194 err++;
195 printf(format: "Error1, checker %d > 2\n", checker);
196 }
197 #pragma omp atomic
198 --checker;
199 }
200 #pragma omp task depend(in: i1, i2)
201 { int th = omp_get_thread_num();
202 printf(format: "task 5_%d, th %d\n", t, th);
203 #pragma omp atomic
204 ++checker;
205 if (checker > 2) { // no more than 2 tasks concurrently
206 err++;
207 printf(format: "Error1, checker %d > 2\n", checker);
208 }
209 mysleep(DELAY);
210 if (checker > 2) { // no more than 2 tasks concurrently
211 err++;
212 printf(format: "Error1, checker %d > 2\n", checker);
213 }
214 #pragma omp atomic
215 --checker;
216 }
217// compiler codegen start
218 // task6
219 ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(task_t), shar: 0, rtn: thunk_m);
220 sdep[0].addr = (size_t)&i1;
221 sdep[0].len = 0; // not used
222 sdep[0].flags = 4; // MUTEXINOUTSET
223 sdep[1].addr = (size_t)&i3;
224 sdep[1].len = 0; // not used
225 sdep[1].flags = 4; // MUTEXINOUTSET
226 ptr->f_priv = t + 30; // init single first-private variable
227 __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, nd: 2, dep_lst: sdep, nd_noalias: 0, noalias_dep_lst: 0);
228
229 // task7
230 ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(task_t), shar: 0, rtn: thunk_m);
231 ptr->f_priv = t + 40; // init single first-private variable
232 __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, nd: 2, dep_lst: sdep, nd_noalias: 0, noalias_dep_lst: 0);
233// compiler codegen end
234 #pragma omp task depend(in: i3)
235 { int th = omp_get_thread_num();
236 printf(format: "task 8_%d, th %d\n", t, th);
237 #pragma omp atomic
238 ++checker;
239 if (checker != 1) { // last task should run exclusively
240 err++;
241 printf(format: "Error1, checker %d != 1\n", checker); }
242 mysleep(DELAY);
243 if (checker != 1) { // last task should run exclusively
244 err++;
245 printf(format: "Error1, checker %d != 1\n", checker); }
246 #pragma omp atomic
247 --checker;
248 }
249 } // single
250 } // parallel
251 if (err == 0) {
252 printf(format: "passed\n");
253 return 0;
254 } else {
255 printf(format: "failed\n");
256 return 1;
257 }
258}
259

source code of openmp/runtime/test/tasking/omp51_task_dep_inoutset.c