1 // RUN: %libomp-compile-and-run
2 // RUN: %libomp-compile && env KMP_TASKLOOP_MIN_TASKS=1 %libomp-run
3 // REQUIRES: openmp-4.5
4 #include <stdio.h>
5 #include <omp.h>
6 #include "omp_my_sleep.h"
7 
8 #define N 4
9 #define GRAIN 10
10 #define STRIDE 3
11 
12 // globals
13 int th_counter[N];
14 int counter;
15 
16 
17 // Compiler-generated code (emulation)
18 typedef struct ident {
19     void* dummy;
20 } ident_t;
21 
22 typedef struct shar {
23     int(*pth_counter)[N];
24     int *pcounter;
25     int *pj;
26 } *pshareds;
27 
28 typedef struct task {
29     pshareds shareds;
30     int(* routine)(int,struct task*);
31     int part_id;
32 // privates:
33     unsigned long long lb; // library always uses ULONG
34     unsigned long long ub;
35     int st;
36     int last;
37     int i;
38     int j;
39     int th;
40 } *ptask, kmp_task_t;
41 
42 typedef int(* task_entry_t)( int, ptask );
43 
44 void
__task_dup_entry(ptask task_dst,ptask task_src,int lastpriv)45 __task_dup_entry(ptask task_dst, ptask task_src, int lastpriv)
46 {
47 // setup lastprivate flag
48     task_dst->last = lastpriv;
49 // could be constructor calls here...
50 }
51 
52 
53 // OpenMP RTL interfaces
54 typedef unsigned long long kmp_uint64;
55 typedef long long kmp_int64;
56 
57 #ifdef __cplusplus
58 extern "C" {
59 #endif
60 void
61 __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val,
62                 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st,
63                 int nogroup, int sched, kmp_int64 grainsize, void *task_dup );
64 ptask
65 __kmpc_omp_task_alloc( ident_t *loc, int gtid, int flags,
66                   size_t sizeof_kmp_task_t, size_t sizeof_shareds,
67                   task_entry_t task_entry );
68 void __kmpc_atomic_fixed4_add(void *id_ref, int gtid, int * lhs, int rhs);
69 int  __kmpc_global_thread_num(void *id_ref);
70 #ifdef __cplusplus
71 }
72 #endif
73 
74 
75 // User's code
task_entry(int gtid,ptask task)76 int task_entry(int gtid, ptask task)
77 {
78     pshareds pshar = task->shareds;
79     for( task->i = task->lb; task->i <= (int)task->ub; task->i += task->st ) {
80         task->th = omp_get_thread_num();
81         __kmpc_atomic_fixed4_add(NULL,gtid,pshar->pcounter,1);
82         __kmpc_atomic_fixed4_add(NULL,gtid,&((*pshar->pth_counter)[task->th]),1);
83         task->j = task->i;
84     }
85     my_sleep( 0.1 ); // sleep 100 ms in order to allow other threads to steal tasks
86     if( task->last ) {
87         *(pshar->pj) = task->j; // lastprivate
88     }
89     return 0;
90 }
91 
main()92 int main()
93 {
94     int i, j, gtid = __kmpc_global_thread_num(NULL);
95     ptask task;
96     pshareds psh;
97     omp_set_dynamic(0);
98     counter = 0;
99     for( i=0; i<N; ++i )
100         th_counter[i] = 0;
101     #pragma omp parallel num_threads(N)
102     {
103       #pragma omp master
104       {
105         int gtid = __kmpc_global_thread_num(NULL);
106 /*
107  *  This is what the OpenMP runtime calls correspond to:
108     #pragma omp taskloop num_tasks(N) lastprivate(j)
109     for( i=0; i<N*GRAIN*STRIDE-1; i+=STRIDE )
110     {
111         int th = omp_get_thread_num();
112         #pragma omp atomic
113             counter++;
114         #pragma omp atomic
115             th_counter[th]++;
116         j = i;
117     }
118 */
119     task = __kmpc_omp_task_alloc(NULL,gtid,1,sizeof(struct task),sizeof(struct shar),&task_entry);
120     psh = task->shareds;
121     psh->pth_counter = &th_counter;
122     psh->pcounter = &counter;
123     psh->pj = &j;
124     task->lb = 0;
125     task->ub = N*GRAIN*STRIDE-2;
126     task->st = STRIDE;
127 
128     __kmpc_taskloop(
129         NULL,             // location
130         gtid,             // gtid
131         task,             // task structure
132         1,                // if clause value
133         &task->lb,        // lower bound
134         &task->ub,        // upper bound
135         STRIDE,           // loop increment
136         0,                // 1 if nogroup specified
137         2,                // schedule type: 0-none, 1-grainsize, 2-num_tasks
138         N,                // schedule value (ignored for type 0)
139         (void*)&__task_dup_entry // tasks duplication routine
140         );
141       } // end master
142     } // end parallel
143 // check results
144     if( j != N*GRAIN*STRIDE-STRIDE ) {
145         printf("Error in lastprivate, %d != %d\n",j,N*GRAIN*STRIDE-STRIDE);
146         return 1;
147     }
148     if( counter != N*GRAIN ) {
149         printf("Error, counter %d != %d\n",counter,N*GRAIN);
150         return 1;
151     }
152     for( i=0; i<N; ++i ) {
153         if( th_counter[i] % GRAIN ) {
154             printf("Error, th_counter[%d] = %d\n",i,th_counter[i]);
155             return 1;
156         }
157     }
158     printf("passed\n");
159     return 0;
160 }
161