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