1 2 //===----------------------------------------------------------------------===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is dual licensed under the MIT and the University of Illinois Open 7 // Source Licenses. See LICENSE.txt for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 12 #include "kmp.h" 13 #include "kmp_i18n.h" 14 #include "kmp_io.h" 15 #include "kmp_str.h" 16 17 #if OMP_40_ENABLED 18 19 /*! 20 @ingroup CANCELLATION 21 @param loc_ref location of the original task directive 22 @param gtid Global thread ID of encountering thread 23 @param cncl_kind Cancellation kind (parallel, for, sections, taskgroup) 24 25 @return returns true if the cancellation request has been activated and the execution thread 26 needs to proceed to the end of the canceled region. 27 28 Request cancellation of the binding OpenMP region. 29 */ 30 kmp_int32 __kmpc_cancel(ident_t* loc_ref, kmp_int32 gtid, kmp_int32 cncl_kind) { 31 kmp_info_t *this_thr = __kmp_threads [ gtid ]; 32 33 KC_TRACE( 10, ("__kmpc_cancel: T#%d request %d OMP_CANCELLATION=%d\n", gtid, cncl_kind, __kmp_omp_cancellation) ); 34 35 KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq); 36 KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop || 37 cncl_kind == cancel_sections || cncl_kind == cancel_taskgroup); 38 KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid); 39 40 if (__kmp_omp_cancellation) { 41 switch (cncl_kind) { 42 case cancel_parallel: 43 case cancel_loop: 44 case cancel_sections: 45 // cancellation requests for parallel and worksharing constructs 46 // are handled through the team structure 47 { 48 kmp_team_t *this_team = this_thr->th.th_team; 49 KMP_DEBUG_ASSERT(this_team); 50 kmp_int32 old = KMP_COMPARE_AND_STORE_RET32(&(this_team->t.t_cancel_request), cancel_noreq, cncl_kind); 51 if (old == cancel_noreq || old == cncl_kind) { 52 //printf("__kmpc_cancel: this_team->t.t_cancel_request=%d @ %p\n", 53 // this_team->t.t_cancel_request, &(this_team->t.t_cancel_request)); 54 // we do not have a cancellation request in this team or we do have one 55 // that matches the current request -> cancel 56 return 1 /* true */; 57 } 58 break; 59 } 60 case cancel_taskgroup: 61 // cancellation requests for a task group 62 // are handled through the taskgroup structure 63 { 64 kmp_taskdata_t* task; 65 kmp_taskgroup_t* taskgroup; 66 67 task = this_thr->th.th_current_task; 68 KMP_DEBUG_ASSERT( task ); 69 70 taskgroup = task->td_taskgroup; 71 if (taskgroup) { 72 kmp_int32 old = KMP_COMPARE_AND_STORE_RET32(&(taskgroup->cancel_request), cancel_noreq, cncl_kind); 73 if (old == cancel_noreq || old == cncl_kind) { 74 // we do not have a cancellation request in this taskgroup or we do have one 75 // that matches the current request -> cancel 76 return 1 /* true */; 77 } 78 } 79 else { 80 // TODO: what needs to happen here? 81 // the specification disallows cancellation w/o taskgroups 82 // so we might do anything here, let's abort for now 83 KMP_ASSERT( 0 /* false */); 84 } 85 } 86 break; 87 default: 88 KMP_ASSERT (0 /* false */); 89 } 90 } 91 92 // ICV OMP_CANCELLATION=false, so we ignored this cancel request 93 KMP_DEBUG_ASSERT(!__kmp_omp_cancellation); 94 return 0 /* false */; 95 } 96 97 /*! 98 @ingroup CANCELLATION 99 @param loc_ref location of the original task directive 100 @param gtid Global thread ID of encountering thread 101 @param cncl_kind Cancellation kind (parallel, for, sections, taskgroup) 102 103 @return returns true if a matching cancellation request has been flagged in the RTL and the 104 encountering thread has to cancel.. 105 106 Cancellation point for the encountering thread. 107 */ 108 kmp_int32 __kmpc_cancellationpoint(ident_t* loc_ref, kmp_int32 gtid, kmp_int32 cncl_kind) { 109 kmp_info_t *this_thr = __kmp_threads [ gtid ]; 110 111 KC_TRACE( 10, ("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n", gtid, cncl_kind, __kmp_omp_cancellation) ); 112 113 KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq); 114 KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop || 115 cncl_kind == cancel_sections || cncl_kind == cancel_taskgroup); 116 KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid); 117 118 if (__kmp_omp_cancellation) { 119 switch (cncl_kind) { 120 case cancel_parallel: 121 case cancel_loop: 122 case cancel_sections: 123 // cancellation requests for parallel and worksharing constructs 124 // are handled through the team structure 125 { 126 kmp_team_t *this_team = this_thr->th.th_team; 127 KMP_DEBUG_ASSERT(this_team); 128 if (this_team->t.t_cancel_request) { 129 if (cncl_kind == this_team->t.t_cancel_request) { 130 // the request in the team structure matches the type of 131 // cancellation point so we can cancel 132 return 1 /* true */; 133 } 134 KMP_ASSERT( 0 /* false */); 135 } 136 else { 137 // we do not have a cancellation request pending, so we just 138 // ignore this cancellation point 139 return 0; 140 } 141 break; 142 } 143 case cancel_taskgroup: 144 // cancellation requests for a task group 145 // are handled through the taskgroup structure 146 { 147 kmp_taskdata_t* task; 148 kmp_taskgroup_t* taskgroup; 149 150 task = this_thr->th.th_current_task; 151 KMP_DEBUG_ASSERT( task ); 152 153 taskgroup = task->td_taskgroup; 154 if (taskgroup) { 155 // return the current status of cancellation for the 156 // taskgroup 157 return !!taskgroup->cancel_request; 158 } 159 else { 160 // if a cancellation point is encountered by a task 161 // that does not belong to a taskgroup, it is OK 162 // to ignore it 163 return 0 /* false */; 164 } 165 } 166 default: 167 KMP_ASSERT (0 /* false */); 168 } 169 } 170 171 // ICV OMP_CANCELLATION=false, so we ignore the cancellation point 172 KMP_DEBUG_ASSERT(!__kmp_omp_cancellation); 173 return 0 /* false */; 174 } 175 176 /*! 177 @ingroup CANCELLATION 178 @param loc_ref location of the original task directive 179 @param gtid Global thread ID of encountering thread 180 181 @return returns true if a matching cancellation request has been flagged in the RTL and the 182 encountering thread has to cancel.. 183 184 Barrier with cancellation point to send threads from the barrier to the 185 end of the parallel region. Needs a special code pattern as documented 186 in the design document for the cancellation feature. 187 */ 188 kmp_int32 189 __kmpc_cancel_barrier(ident_t *loc, kmp_int32 gtid) { 190 int ret = 0 /* false */; 191 kmp_info_t *this_thr = __kmp_threads [ gtid ]; 192 kmp_team_t *this_team = this_thr->th.th_team; 193 194 KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid); 195 196 // call into the standard barrier 197 __kmpc_barrier(loc, gtid); 198 199 // if cancellation is active, check cancellation flag 200 if (__kmp_omp_cancellation) { 201 // depending on which construct to cancel, check the flag and 202 // reset the flag 203 switch (this_team->t.t_cancel_request) { 204 case cancel_parallel: 205 ret = 1; 206 // ensure that threads have checked the flag, when 207 // leaving the above barrier 208 __kmpc_barrier(loc, gtid); 209 this_team->t.t_cancel_request = cancel_noreq; 210 // the next barrier is the fork/join barrier, which 211 // synchronizes the threads leaving here 212 break; 213 case cancel_loop: 214 case cancel_sections: 215 ret = 1; 216 // ensure that threads have checked the flag, when 217 // leaving the above barrier 218 __kmpc_barrier(loc, gtid); 219 this_team->t.t_cancel_request = cancel_noreq; 220 // synchronize the threads again to make sure we 221 // do not have any run-away threads that cause a race 222 // on the cancellation flag 223 __kmpc_barrier(loc, gtid); 224 break; 225 case cancel_taskgroup: 226 // this case should not occur 227 KMP_ASSERT (0 /* false */ ); 228 break; 229 case cancel_noreq: 230 // do nothing 231 break; 232 default: 233 KMP_ASSERT ( 0 /* false */); 234 } 235 } 236 237 return ret; 238 } 239 240 /*! 241 @ingroup CANCELLATION 242 @param loc_ref location of the original task directive 243 @param gtid Global thread ID of encountering thread 244 245 @return returns true if a matching cancellation request has been flagged in the RTL and the 246 encountering thread has to cancel.. 247 248 Query function to query the current status of cancellation requests. 249 Can be used to implement the following pattern: 250 251 if (kmp_get_cancellation_status(kmp_cancel_parallel)) { 252 perform_cleanup(); 253 #pragma omp cancellation point parallel 254 } 255 */ 256 int __kmp_get_cancellation_status(int cancel_kind) { 257 if (__kmp_omp_cancellation) { 258 kmp_info_t *this_thr = __kmp_entry_thread(); 259 260 switch (cancel_kind) { 261 case cancel_parallel: 262 case cancel_loop: 263 case cancel_sections: 264 { 265 kmp_team_t *this_team = this_thr->th.th_team; 266 return this_team->t.t_cancel_request == cancel_kind; 267 } 268 case cancel_taskgroup: 269 { 270 kmp_taskdata_t* task; 271 kmp_taskgroup_t* taskgroup; 272 task = this_thr->th.th_current_task; 273 taskgroup = task->td_taskgroup; 274 return taskgroup && taskgroup->cancel_request; 275 } 276 } 277 } 278 279 return 0 /* false */; 280 } 281 282 #endif 283