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