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