xref: /llvm-project/openmp/tools/archer/tests/task/omp_task_depend_all.c (revision 73d411d1b2c9c842bbaa167606720fed6ffc2243)
1*73d411d1SJoachim Jenke // RUN--: %libarcher-compile-and-run | FileCheck %s --check-prefix=NOENV
2*73d411d1SJoachim Jenke // RUN: %libarcher-compile && env ARCHER_OPTIONS="all_memory=1" \
3*73d411d1SJoachim Jenke // RUN:   %libarcher-run | FileCheck %s --check-prefix=ENV
4*73d411d1SJoachim Jenke // REQUIRES: tsan
5*73d411d1SJoachim Jenke 
6*73d411d1SJoachim Jenke // The runtime currently does not get dependency information from GCC.
7*73d411d1SJoachim Jenke // UNSUPPORTED: gcc
8*73d411d1SJoachim Jenke 
9*73d411d1SJoachim Jenke // Tests OMP 5.x task dependence "omp_all_memory",
10*73d411d1SJoachim Jenke // emulates compiler codegen versions for new dep kind
11*73d411d1SJoachim Jenke //
12*73d411d1SJoachim Jenke // Task tree created:
13*73d411d1SJoachim Jenke //      task0 - task1 (in: i1, i2)
14*73d411d1SJoachim Jenke //             \
15*73d411d1SJoachim Jenke //        task2 (inoutset: i2), (in: i1)
16*73d411d1SJoachim Jenke //             /
17*73d411d1SJoachim Jenke //        task3 (omp_all_memory) via flag=0x80
18*73d411d1SJoachim Jenke //             /
19*73d411d1SJoachim Jenke //      task4 - task5 (in: i1, i2)
20*73d411d1SJoachim Jenke //           /
21*73d411d1SJoachim Jenke //       task6 (omp_all_memory) via addr=-1
22*73d411d1SJoachim Jenke //           /
23*73d411d1SJoachim Jenke //       task7 (omp_all_memory) via flag=0x80
24*73d411d1SJoachim Jenke //           /
25*73d411d1SJoachim Jenke //       task8 (in: i3)
26*73d411d1SJoachim Jenke //
27*73d411d1SJoachim Jenke 
28*73d411d1SJoachim Jenke #include <omp.h>
29*73d411d1SJoachim Jenke #include <stdio.h>
30*73d411d1SJoachim Jenke 
31*73d411d1SJoachim Jenke #ifdef _WIN32
32*73d411d1SJoachim Jenke #include <windows.h>
33*73d411d1SJoachim Jenke #define mysleep(n) Sleep(n)
34*73d411d1SJoachim Jenke #else
35*73d411d1SJoachim Jenke #include <unistd.h>
36*73d411d1SJoachim Jenke #define mysleep(n) usleep((n)*1000)
37*73d411d1SJoachim Jenke #endif
38*73d411d1SJoachim Jenke 
39*73d411d1SJoachim Jenke // to check the # of concurrent tasks (must be 1 for MTX, <3 for other kinds)
40*73d411d1SJoachim Jenke static int checker = 0;
41*73d411d1SJoachim Jenke static int err = 0;
42*73d411d1SJoachim Jenke #ifndef DELAY
43*73d411d1SJoachim Jenke #define DELAY 100
44*73d411d1SJoachim Jenke #endif
45*73d411d1SJoachim Jenke 
46*73d411d1SJoachim Jenke // ---------------------------------------------------------------------------
47*73d411d1SJoachim Jenke // internal data to emulate compiler codegen
48*73d411d1SJoachim Jenke typedef struct DEP {
49*73d411d1SJoachim Jenke   size_t addr;
50*73d411d1SJoachim Jenke   size_t len;
51*73d411d1SJoachim Jenke   unsigned char flags;
52*73d411d1SJoachim Jenke } dep;
53*73d411d1SJoachim Jenke #define DEP_ALL_MEM 0x80
54*73d411d1SJoachim Jenke typedef struct task {
55*73d411d1SJoachim Jenke   void **shareds;
56*73d411d1SJoachim Jenke   void *entry;
57*73d411d1SJoachim Jenke   int part_id;
58*73d411d1SJoachim Jenke   void *destr_thunk;
59*73d411d1SJoachim Jenke   int priority;
60*73d411d1SJoachim Jenke   long long device_id;
61*73d411d1SJoachim Jenke   int f_priv;
62*73d411d1SJoachim Jenke } task_t;
63*73d411d1SJoachim Jenke #define TIED 1
64*73d411d1SJoachim Jenke typedef int (*entry_t)(int, task_t *);
65*73d411d1SJoachim Jenke typedef struct ID {
66*73d411d1SJoachim Jenke   int reserved_1;
67*73d411d1SJoachim Jenke   int flags;
68*73d411d1SJoachim Jenke   int reserved_2;
69*73d411d1SJoachim Jenke   int reserved_3;
70*73d411d1SJoachim Jenke   char *psource;
71*73d411d1SJoachim Jenke } id;
72*73d411d1SJoachim Jenke // thunk routine for tasks with ALL dependency
thunk_m(int gtid,task_t * ptask)73*73d411d1SJoachim Jenke int thunk_m(int gtid, task_t *ptask) {
74*73d411d1SJoachim Jenke   int lcheck, th;
75*73d411d1SJoachim Jenke #pragma omp atomic capture
76*73d411d1SJoachim Jenke   lcheck = ++checker;
77*73d411d1SJoachim Jenke   th = omp_get_thread_num();
78*73d411d1SJoachim Jenke   printf("task m_%d, th %d, checker %d\n", ptask->f_priv, th, lcheck);
79*73d411d1SJoachim Jenke   if (lcheck != 1) { // no more than 1 task at a time
80*73d411d1SJoachim Jenke     err++;
81*73d411d1SJoachim Jenke     printf("Error m1, checker %d != 1\n", lcheck);
82*73d411d1SJoachim Jenke   }
83*73d411d1SJoachim Jenke   mysleep(DELAY);
84*73d411d1SJoachim Jenke #pragma omp atomic read
85*73d411d1SJoachim Jenke   lcheck = checker; // must still be equal to 1
86*73d411d1SJoachim Jenke   if (lcheck != 1) {
87*73d411d1SJoachim Jenke     err++;
88*73d411d1SJoachim Jenke     printf("Error m2, checker %d != 1\n", lcheck);
89*73d411d1SJoachim Jenke   }
90*73d411d1SJoachim Jenke #pragma omp atomic
91*73d411d1SJoachim Jenke   --checker;
92*73d411d1SJoachim Jenke   return 0;
93*73d411d1SJoachim Jenke }
94*73d411d1SJoachim Jenke // thunk routine for tasks with inoutset dependency
thunk_s(int gtid,task_t * ptask)95*73d411d1SJoachim Jenke int thunk_s(int gtid, task_t *ptask) {
96*73d411d1SJoachim Jenke   int lcheck, th;
97*73d411d1SJoachim Jenke #pragma omp atomic capture
98*73d411d1SJoachim Jenke   lcheck = ++checker; // 1
99*73d411d1SJoachim Jenke   th = omp_get_thread_num();
100*73d411d1SJoachim Jenke   printf("task 2_%d, th %d, checker %d\n", ptask->f_priv, th, lcheck);
101*73d411d1SJoachim Jenke   if (lcheck != 1) { // no more than 1 task at a time
102*73d411d1SJoachim Jenke     err++;
103*73d411d1SJoachim Jenke     printf("Error s1, checker %d != 1\n", lcheck);
104*73d411d1SJoachim Jenke   }
105*73d411d1SJoachim Jenke   mysleep(DELAY);
106*73d411d1SJoachim Jenke #pragma omp atomic read
107*73d411d1SJoachim Jenke   lcheck = checker; // must still be equal to 1
108*73d411d1SJoachim Jenke   if (lcheck != 1) {
109*73d411d1SJoachim Jenke     err++;
110*73d411d1SJoachim Jenke     printf("Error s2, checker %d != 1\n", lcheck);
111*73d411d1SJoachim Jenke   }
112*73d411d1SJoachim Jenke #pragma omp atomic
113*73d411d1SJoachim Jenke   --checker;
114*73d411d1SJoachim Jenke   return 0;
115*73d411d1SJoachim Jenke }
116*73d411d1SJoachim Jenke 
117*73d411d1SJoachim Jenke #ifdef __cplusplus
118*73d411d1SJoachim Jenke extern "C" {
119*73d411d1SJoachim Jenke #endif
120*73d411d1SJoachim Jenke int __kmpc_global_thread_num(id *);
121*73d411d1SJoachim Jenke task_t *__kmpc_omp_task_alloc(id *loc, int gtid, int flags, size_t sz,
122*73d411d1SJoachim Jenke                               size_t shar, entry_t rtn);
123*73d411d1SJoachim Jenke int __kmpc_omp_task_with_deps(id *loc, int gtid, task_t *task, int ndeps,
124*73d411d1SJoachim Jenke                               dep *dep_lst, int nd_noalias, dep *noalias_lst);
125*73d411d1SJoachim Jenke static id loc = {0, 2, 0, 0, ";file;func;0;0;;"};
126*73d411d1SJoachim Jenke #ifdef __cplusplus
127*73d411d1SJoachim Jenke } // extern "C"
128*73d411d1SJoachim Jenke #endif
129*73d411d1SJoachim Jenke // End of internal data
130*73d411d1SJoachim Jenke // ---------------------------------------------------------------------------
131*73d411d1SJoachim Jenke 
main()132*73d411d1SJoachim Jenke int main() {
133*73d411d1SJoachim Jenke   char *ompx_all_memory = (void *)0xffffffffffffffff;
134*73d411d1SJoachim Jenke   int i1, i2, i3;
135*73d411d1SJoachim Jenke   omp_set_num_threads(8);
136*73d411d1SJoachim Jenke   omp_set_dynamic(0);
137*73d411d1SJoachim Jenke #pragma omp parallel
138*73d411d1SJoachim Jenke   {
139*73d411d1SJoachim Jenke #pragma omp single nowait
140*73d411d1SJoachim Jenke     {
141*73d411d1SJoachim Jenke       dep sdep[2];
142*73d411d1SJoachim Jenke       task_t *ptr;
143*73d411d1SJoachim Jenke       int gtid = __kmpc_global_thread_num(&loc);
144*73d411d1SJoachim Jenke       int t = omp_get_thread_num();
145*73d411d1SJoachim Jenke #pragma omp task depend(in : i1, i2)
146*73d411d1SJoachim Jenke       { // task 0
147*73d411d1SJoachim Jenke         int lcheck, th;
148*73d411d1SJoachim Jenke #pragma omp atomic capture
149*73d411d1SJoachim Jenke         lcheck = ++checker; // 1 or 2
150*73d411d1SJoachim Jenke         th = omp_get_thread_num();
151*73d411d1SJoachim Jenke         printf("task 0_%d, th %d, checker %d\n", t, th, lcheck);
152*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
153*73d411d1SJoachim Jenke           err++; // no more than 2 tasks concurrently
154*73d411d1SJoachim Jenke           printf("Error1, checker %d, not 1 or 2\n", lcheck);
155*73d411d1SJoachim Jenke         }
156*73d411d1SJoachim Jenke         mysleep(DELAY);
157*73d411d1SJoachim Jenke #pragma omp atomic read
158*73d411d1SJoachim Jenke         lcheck = checker; // 1 or 2
159*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
160*73d411d1SJoachim Jenke #pragma omp atomic
161*73d411d1SJoachim Jenke           err++;
162*73d411d1SJoachim Jenke           printf("Error2, checker %d, not 1 or 2\n", lcheck);
163*73d411d1SJoachim Jenke         }
164*73d411d1SJoachim Jenke #pragma omp atomic
165*73d411d1SJoachim Jenke         --checker;
166*73d411d1SJoachim Jenke       }
167*73d411d1SJoachim Jenke #pragma omp task depend(in : i1, i2)
168*73d411d1SJoachim Jenke       { // task 1
169*73d411d1SJoachim Jenke         int lcheck, th;
170*73d411d1SJoachim Jenke #pragma omp atomic capture
171*73d411d1SJoachim Jenke         lcheck = ++checker; // 1 or 2
172*73d411d1SJoachim Jenke         th = omp_get_thread_num();
173*73d411d1SJoachim Jenke         printf("task 1_%d, th %d, checker %d\n", t, th, lcheck);
174*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
175*73d411d1SJoachim Jenke           err++; // no more than 2 tasks concurrently
176*73d411d1SJoachim Jenke           printf("Error3, checker %d, not 1 or 2\n", lcheck);
177*73d411d1SJoachim Jenke         }
178*73d411d1SJoachim Jenke         mysleep(DELAY);
179*73d411d1SJoachim Jenke #pragma omp atomic read
180*73d411d1SJoachim Jenke         lcheck = checker; // 1 or 2
181*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
182*73d411d1SJoachim Jenke           err++;
183*73d411d1SJoachim Jenke           printf("Error4, checker %d, not 1 or 2\n", lcheck);
184*73d411d1SJoachim Jenke         }
185*73d411d1SJoachim Jenke #pragma omp atomic
186*73d411d1SJoachim Jenke         --checker;
187*73d411d1SJoachim Jenke       }
188*73d411d1SJoachim Jenke       // compiler codegen start
189*73d411d1SJoachim Jenke       // task2
190*73d411d1SJoachim Jenke       ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_s);
191*73d411d1SJoachim Jenke       sdep[0].addr = (size_t)&i1;
192*73d411d1SJoachim Jenke       sdep[0].len = 0;   // not used
193*73d411d1SJoachim Jenke       sdep[0].flags = 1; // IN
194*73d411d1SJoachim Jenke       sdep[1].addr = (size_t)&i2;
195*73d411d1SJoachim Jenke       sdep[1].len = 0;      // not used
196*73d411d1SJoachim Jenke       sdep[1].flags = 8;    // INOUTSET
197*73d411d1SJoachim Jenke       ptr->f_priv = t + 10; // init single first-private variable
198*73d411d1SJoachim Jenke       __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
199*73d411d1SJoachim Jenke 
200*73d411d1SJoachim Jenke // task3
201*73d411d1SJoachim Jenke #pragma omp task depend(in : i1) depend(inout : ompx_all_memory[0])
202*73d411d1SJoachim Jenke       {
203*73d411d1SJoachim Jenke         int lcheck, th;
204*73d411d1SJoachim Jenke #pragma omp atomic capture
205*73d411d1SJoachim Jenke         lcheck = ++checker;
206*73d411d1SJoachim Jenke         th = omp_get_thread_num();
207*73d411d1SJoachim Jenke         printf("task 3_%d, th %d, checker %d\n", t, th, lcheck);
208*73d411d1SJoachim Jenke         if (lcheck != 1) { // no more than 1 task at a time
209*73d411d1SJoachim Jenke           err++;
210*73d411d1SJoachim Jenke           printf("Error m1, checker %d != 1\n", lcheck);
211*73d411d1SJoachim Jenke         }
212*73d411d1SJoachim Jenke         mysleep(DELAY);
213*73d411d1SJoachim Jenke #pragma omp atomic read
214*73d411d1SJoachim Jenke         lcheck = checker; // must still be equal to 1
215*73d411d1SJoachim Jenke         if (lcheck != 1) {
216*73d411d1SJoachim Jenke           err++;
217*73d411d1SJoachim Jenke           printf("Error m2, checker %d != 1\n", lcheck);
218*73d411d1SJoachim Jenke         }
219*73d411d1SJoachim Jenke #pragma omp atomic
220*73d411d1SJoachim Jenke         --checker;
221*73d411d1SJoachim Jenke       }
222*73d411d1SJoachim Jenke       // compiler codegen end
223*73d411d1SJoachim Jenke #pragma omp task depend(in : i1, i2)
224*73d411d1SJoachim Jenke       { // task 4
225*73d411d1SJoachim Jenke         int lcheck, th;
226*73d411d1SJoachim Jenke #pragma omp atomic capture
227*73d411d1SJoachim Jenke         lcheck = ++checker; // 1 or 2
228*73d411d1SJoachim Jenke         th = omp_get_thread_num();
229*73d411d1SJoachim Jenke         printf("task 4_%d, th %d, checker %d\n", t, th, lcheck);
230*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
231*73d411d1SJoachim Jenke           err++; // no more than 2 tasks concurrently
232*73d411d1SJoachim Jenke           printf("Error5, checker %d, not 1 or 2\n", lcheck);
233*73d411d1SJoachim Jenke         }
234*73d411d1SJoachim Jenke         mysleep(DELAY);
235*73d411d1SJoachim Jenke #pragma omp atomic read
236*73d411d1SJoachim Jenke         lcheck = checker; // 1 or 2
237*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
238*73d411d1SJoachim Jenke           err++;
239*73d411d1SJoachim Jenke           printf("Error6, checker %d, not 1 or 2\n", lcheck);
240*73d411d1SJoachim Jenke         }
241*73d411d1SJoachim Jenke #pragma omp atomic
242*73d411d1SJoachim Jenke         --checker;
243*73d411d1SJoachim Jenke       }
244*73d411d1SJoachim Jenke #pragma omp task depend(in : i1, i2)
245*73d411d1SJoachim Jenke       { // task 5
246*73d411d1SJoachim Jenke         int lcheck, th;
247*73d411d1SJoachim Jenke #pragma omp atomic capture
248*73d411d1SJoachim Jenke         lcheck = ++checker; // 1 or 2
249*73d411d1SJoachim Jenke         th = omp_get_thread_num();
250*73d411d1SJoachim Jenke         printf("task 5_%d, th %d, checker %d\n", t, th, lcheck);
251*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
252*73d411d1SJoachim Jenke           err++; // no more than 2 tasks concurrently
253*73d411d1SJoachim Jenke           printf("Error7, checker %d, not 1 or 2\n", lcheck);
254*73d411d1SJoachim Jenke         }
255*73d411d1SJoachim Jenke         mysleep(DELAY);
256*73d411d1SJoachim Jenke #pragma omp atomic read
257*73d411d1SJoachim Jenke         lcheck = checker; // 1 or 2
258*73d411d1SJoachim Jenke         if (lcheck > 2 || lcheck < 1) {
259*73d411d1SJoachim Jenke           err++;
260*73d411d1SJoachim Jenke           printf("Error8, checker %d, not 1 or 2\n", lcheck);
261*73d411d1SJoachim Jenke         }
262*73d411d1SJoachim Jenke #pragma omp atomic
263*73d411d1SJoachim Jenke         --checker;
264*73d411d1SJoachim Jenke       }
265*73d411d1SJoachim Jenke // task6
266*73d411d1SJoachim Jenke #pragma omp task depend(inout : ompx_all_memory[0])
267*73d411d1SJoachim Jenke       {
268*73d411d1SJoachim Jenke         int lcheck, th;
269*73d411d1SJoachim Jenke #pragma omp atomic capture
270*73d411d1SJoachim Jenke         lcheck = ++checker;
271*73d411d1SJoachim Jenke         th = omp_get_thread_num();
272*73d411d1SJoachim Jenke         printf("task 6_%d, th %d, checker %d\n", t, th, lcheck);
273*73d411d1SJoachim Jenke         if (lcheck != 1) { // no more than 1 task at a time
274*73d411d1SJoachim Jenke           err++;
275*73d411d1SJoachim Jenke           printf("Error m1, checker %d != 1\n", lcheck);
276*73d411d1SJoachim Jenke         }
277*73d411d1SJoachim Jenke         mysleep(DELAY);
278*73d411d1SJoachim Jenke #pragma omp atomic read
279*73d411d1SJoachim Jenke         lcheck = checker; // must still be equal to 1
280*73d411d1SJoachim Jenke         if (lcheck != 1) {
281*73d411d1SJoachim Jenke           err++;
282*73d411d1SJoachim Jenke           printf("Error m2, checker %d != 1\n", lcheck);
283*73d411d1SJoachim Jenke         }
284*73d411d1SJoachim Jenke #pragma omp atomic
285*73d411d1SJoachim Jenke         --checker;
286*73d411d1SJoachim Jenke       }
287*73d411d1SJoachim Jenke // task7
288*73d411d1SJoachim Jenke #pragma omp task depend(inout : ompx_all_memory[0]) depend(mutexinoutset : i3)
289*73d411d1SJoachim Jenke       {
290*73d411d1SJoachim Jenke         int lcheck, th;
291*73d411d1SJoachim Jenke #pragma omp atomic capture
292*73d411d1SJoachim Jenke         lcheck = ++checker;
293*73d411d1SJoachim Jenke         th = omp_get_thread_num();
294*73d411d1SJoachim Jenke         printf("task 7_%d, th %d, checker %d\n", t, th, lcheck);
295*73d411d1SJoachim Jenke         if (lcheck != 1) { // no more than 1 task at a time
296*73d411d1SJoachim Jenke           err++;
297*73d411d1SJoachim Jenke           printf("Error m1, checker %d != 1\n", lcheck);
298*73d411d1SJoachim Jenke         }
299*73d411d1SJoachim Jenke         mysleep(DELAY);
300*73d411d1SJoachim Jenke #pragma omp atomic read
301*73d411d1SJoachim Jenke         lcheck = checker; // must still be equal to 1
302*73d411d1SJoachim Jenke         if (lcheck != 1) {
303*73d411d1SJoachim Jenke           err++;
304*73d411d1SJoachim Jenke           printf("Error m2, checker %d != 1\n", lcheck);
305*73d411d1SJoachim Jenke         }
306*73d411d1SJoachim Jenke #pragma omp atomic
307*73d411d1SJoachim Jenke         --checker;
308*73d411d1SJoachim Jenke       }
309*73d411d1SJoachim Jenke #pragma omp task depend(in : i3)
310*73d411d1SJoachim Jenke       { // task 8
311*73d411d1SJoachim Jenke         int lcheck, th;
312*73d411d1SJoachim Jenke #pragma omp atomic capture
313*73d411d1SJoachim Jenke         lcheck = ++checker; // 1
314*73d411d1SJoachim Jenke         th = omp_get_thread_num();
315*73d411d1SJoachim Jenke         printf("task 8_%d, th %d, checker %d\n", t, th, lcheck);
316*73d411d1SJoachim Jenke         if (lcheck != 1) {
317*73d411d1SJoachim Jenke           err++;
318*73d411d1SJoachim Jenke           printf("Error9, checker %d, != 1\n", lcheck);
319*73d411d1SJoachim Jenke         }
320*73d411d1SJoachim Jenke         mysleep(DELAY);
321*73d411d1SJoachim Jenke #pragma omp atomic read
322*73d411d1SJoachim Jenke         lcheck = checker;
323*73d411d1SJoachim Jenke         if (lcheck != 1) {
324*73d411d1SJoachim Jenke           err++;
325*73d411d1SJoachim Jenke           printf("Error10, checker %d, != 1\n", lcheck);
326*73d411d1SJoachim Jenke         }
327*73d411d1SJoachim Jenke #pragma omp atomic
328*73d411d1SJoachim Jenke         --checker;
329*73d411d1SJoachim Jenke       }
330*73d411d1SJoachim Jenke     } // single
331*73d411d1SJoachim Jenke   }   // parallel
332*73d411d1SJoachim Jenke   if (err == 0 && checker == 0) {
333*73d411d1SJoachim Jenke     printf("passed\n");
334*73d411d1SJoachim Jenke     return 0;
335*73d411d1SJoachim Jenke   } else {
336*73d411d1SJoachim Jenke     printf("failed, err = %d, checker = %d\n", err, checker);
337*73d411d1SJoachim Jenke     return 1;
338*73d411d1SJoachim Jenke   }
339*73d411d1SJoachim Jenke }
340*73d411d1SJoachim Jenke 
341*73d411d1SJoachim Jenke // NOENV-NOT: ThreadSanitizer: data race
342*73d411d1SJoachim Jenke // NOENV-NOT: ThreadSanitizer: reported
343*73d411d1SJoachim Jenke // NOENV: omp_all_memory
344*73d411d1SJoachim Jenke // NOENV-NOT: ThreadSanitizer: data race
345*73d411d1SJoachim Jenke // NOENV-NOT: ThreadSanitizer: reported
346*73d411d1SJoachim Jenke // NOENV: passed
347*73d411d1SJoachim Jenke 
348*73d411d1SJoachim Jenke // ENV-NOT: ThreadSanitizer: data race
349*73d411d1SJoachim Jenke // ENV-NOT: ThreadSanitizer: reported
350*73d411d1SJoachim Jenke // ENV: passed
351