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