xref: /llvm-project/openmp/runtime/test/tasking/bug_proxy_task_dep_waiting.c (revision 110141b37813dc48af33de5e1407231e56acdfc5)
1 // RUN: %libomp-compile-and-run
2 // The runtime currently does not get dependency information from GCC.
3 // UNSUPPORTED: gcc
4 
5 // Very flaky on openmp-clang-x86_64-linux-debian.
6 // https://bugs.llvm.org/show_bug.cgi?id=45397
7 // UNSUPPORTED: linux
8 
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <omp.h>
12 #include "omp_testsuite.h"
13 #include "omp_my_sleep.h"
14 
15 /*
16  An explicit task can have a dependency on a target task. If it is not
17  directly satisfied, the runtime should not wait but resume execution.
18 */
19 
20 // Compiler-generated code (emulation)
21 typedef intptr_t kmp_intptr_t;
22 typedef int32_t kmp_int32;
23 typedef uint8_t kmp_uint8;
24 
25 typedef char bool;
26 
27 // These structs need to match the implementation within libomp, in kmp.h.
28 
29 typedef struct ident {
30     kmp_int32 reserved_1;   /**<  might be used in Fortran; see above  */
31     kmp_int32 flags;        /**<  also f.flags; KMP_IDENT_xxx flags; KMP_IDENT_KMPC identifies this union member  */
32     kmp_int32 reserved_2;   /**<  not really used in Fortran any more; see above */
33 #if USE_ITT_BUILD
34                             /*  but currently used for storing region-specific ITT */
35                             /*  contextual information. */
36 #endif /* USE_ITT_BUILD */
37     kmp_int32 reserved_3;   /**< source[4] in Fortran, do not use for C++  */
38     char const *psource;    /**< String describing the source location.
39                             The string is composed of semi-colon separated fields which describe the source file,
40                             the function and a pair of line numbers that delimit the construct.
41                              */
42 } ident_t;
43 
44 typedef struct kmp_depend_info {
45      kmp_intptr_t               base_addr;
46      size_t                     len;
47      union {
48         kmp_uint8 flag; // flag as an unsigned char
49         struct { // flag as a set of 8 bits
50 #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
51           unsigned all : 1;
52           unsigned unused : 3;
53           unsigned set : 1;
54           unsigned mtx : 1;
55           unsigned out : 1;
56           unsigned in : 1;
57 #else
58           unsigned in : 1;
59           unsigned out : 1;
60           unsigned mtx : 1;
61           unsigned set : 1;
62           unsigned unused : 3;
63           unsigned all : 1;
64 #endif
65         } flags;
66     };
67 } kmp_depend_info_t;
68 
69 struct kmp_task;
70 typedef kmp_int32 (* kmp_routine_entry_t)( kmp_int32, struct kmp_task * );
71 
72 typedef struct kmp_task {                   /* GEH: Shouldn't this be aligned somehow? */
73     void *              shareds;            /**< pointer to block of pointers to shared vars   */
74     kmp_routine_entry_t routine;            /**< pointer to routine to call for executing task */
75     kmp_int32           part_id;            /**< part id for the task                          */
76 } kmp_task_t;
77 
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
81 kmp_int32  __kmpc_global_thread_num  ( ident_t * );
82 kmp_task_t*
83 __kmpc_omp_task_alloc( ident_t *loc_ref, kmp_int32 gtid, kmp_int32 flags,
84                        size_t sizeof_kmp_task_t, size_t sizeof_shareds,
85                        kmp_routine_entry_t task_entry );
86 void __kmpc_proxy_task_completed_ooo ( kmp_task_t *ptask );
87 kmp_int32 __kmpc_omp_task_with_deps ( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task,
88                                       kmp_int32 ndeps, kmp_depend_info_t *dep_list,
89                                       kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list );
90 kmp_int32
91 __kmpc_omp_task( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task );
92 #ifdef __cplusplus
93 }
94 #endif
95 
target(void * task)96 void *target(void *task)
97 {
98     my_sleep( 0.1 );
99     __kmpc_proxy_task_completed_ooo((kmp_task_t*) task);
100     return NULL;
101 }
102 
103 pthread_t target_thread;
104 
105 // User's code
task_entry(kmp_int32 gtid,kmp_task_t * task)106 int task_entry(kmp_int32 gtid, kmp_task_t *task)
107 {
108     pthread_create(&target_thread, NULL, &target, task);
109     return 0;
110 }
111 
main()112 int main()
113 {
114     int dep;
115 
116 /*
117  *  Corresponds to:
118     #pragma omp target nowait depend(out: dep)
119     {
120         my_sleep( 0.1 );
121     }
122 */
123     kmp_depend_info_t dep_info = { 0 };
124     dep_info.base_addr = (kmp_intptr_t) &dep;
125     dep_info.len = sizeof(int);
126     // out = inout per spec and runtime expects this
127     dep_info.flags.in = 1;
128     dep_info.flags.out = 1;
129 
130     kmp_int32 gtid = __kmpc_global_thread_num(NULL);
131     kmp_task_t *proxy_task = __kmpc_omp_task_alloc(NULL,gtid,17,sizeof(kmp_task_t),0,&task_entry);
132     __kmpc_omp_task_with_deps(NULL,gtid,proxy_task,1,&dep_info,0,NULL);
133 
134     int first_task_finished = 0;
135     #pragma omp task shared(first_task_finished) depend(inout: dep)
136     {
137         first_task_finished = 1;
138     }
139 
140     int second_task_finished = 0;
141     #pragma omp task shared(second_task_finished) depend(in: dep)
142     {
143         second_task_finished = 1;
144     }
145 
146     // check that execution has been resumed and the runtime has not waited
147     // for the dependencies to be satisfied.
148     int error = (first_task_finished == 1);
149     error += (second_task_finished == 1);
150 
151     #pragma omp taskwait
152 
153     // by now all tasks should have finished
154     error += (first_task_finished != 1);
155     error += (second_task_finished != 1);
156 
157     return error;
158 }
159