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