LLVM OpenMP* Runtime Library
Loading...
Searching...
No Matches
kmp_cancel.cpp
1
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "kmp.h"
11#include "kmp_i18n.h"
12#include "kmp_io.h"
13#include "kmp_str.h"
14#if OMPT_SUPPORT
15#include "ompt-specific.h"
16#endif
17
29kmp_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 = cancel_noreq;
52 this_team->t.t_cancel_request.compare_exchange_strong(old, cncl_kind);
53 if (old == cancel_noreq || old == cncl_kind) {
54// we do not have a cancellation request in this team or we do have
55// one that matches the current request -> cancel
56#if OMPT_SUPPORT && OMPT_OPTIONAL
57 if (ompt_enabled.ompt_callback_cancel) {
58 ompt_data_t *task_data;
59 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
60 NULL);
61 ompt_cancel_flag_t type = ompt_cancel_parallel;
62 if (cncl_kind == cancel_parallel)
63 type = ompt_cancel_parallel;
64 else if (cncl_kind == cancel_loop)
65 type = ompt_cancel_loop;
66 else if (cncl_kind == cancel_sections)
67 type = ompt_cancel_sections;
68 ompt_callbacks.ompt_callback(ompt_callback_cancel)(
69 task_data, type | ompt_cancel_activated,
70 OMPT_GET_RETURN_ADDRESS(0));
71 }
72#endif // OMPT_SUPPORT && OMPT_OPTIONAL
73 return 1 /* true */;
74 }
75 break;
76 }
77 case cancel_taskgroup:
78 // cancellation requests for a task group
79 // are handled through the taskgroup structure
80 {
81 kmp_taskdata_t *task;
82 kmp_taskgroup_t *taskgroup;
83
84 task = this_thr->th.th_current_task;
85 KMP_DEBUG_ASSERT(task);
86
87 taskgroup = task->td_taskgroup;
88 if (taskgroup) {
89 kmp_int32 old = cancel_noreq;
90 taskgroup->cancel_request.compare_exchange_strong(old, cncl_kind);
91 if (old == cancel_noreq || old == cncl_kind) {
92// we do not have a cancellation request in this taskgroup or we do
93// have one that matches the current request -> cancel
94#if OMPT_SUPPORT && OMPT_OPTIONAL
95 if (ompt_enabled.ompt_callback_cancel) {
96 ompt_data_t *task_data;
97 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
98 NULL);
99 ompt_callbacks.ompt_callback(ompt_callback_cancel)(
100 task_data, ompt_cancel_taskgroup | ompt_cancel_activated,
101 OMPT_GET_RETURN_ADDRESS(0));
102 }
103#endif
104 return 1 /* true */;
105 }
106 } else {
107 // TODO: what needs to happen here?
108 // the specification disallows cancellation w/o taskgroups
109 // so we might do anything here, let's abort for now
110 KMP_ASSERT(0 /* false */);
111 }
112 }
113 break;
114 default:
115 KMP_ASSERT(0 /* false */);
116 }
117 }
118
119 // ICV OMP_CANCELLATION=false, so we ignored this cancel request
120 KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);
121 return 0 /* false */;
122}
123
135kmp_int32 __kmpc_cancellationpoint(ident_t *loc_ref, kmp_int32 gtid,
136 kmp_int32 cncl_kind) {
137 kmp_info_t *this_thr = __kmp_threads[gtid];
138
139 KC_TRACE(10,
140 ("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n",
141 gtid, cncl_kind, __kmp_omp_cancellation));
142
143 KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);
144 KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||
145 cncl_kind == cancel_sections ||
146 cncl_kind == cancel_taskgroup);
147 KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
148
149 if (__kmp_omp_cancellation) {
150 switch (cncl_kind) {
151 case cancel_parallel:
152 case cancel_loop:
153 case cancel_sections:
154 // cancellation requests for parallel and worksharing constructs
155 // are handled through the team structure
156 {
157 kmp_team_t *this_team = this_thr->th.th_team;
158 KMP_DEBUG_ASSERT(this_team);
159 if (this_team->t.t_cancel_request) {
160 if (cncl_kind == this_team->t.t_cancel_request) {
161// the request in the team structure matches the type of
162// cancellation point so we can cancel
163#if OMPT_SUPPORT && OMPT_OPTIONAL
164 if (ompt_enabled.ompt_callback_cancel) {
165 ompt_data_t *task_data;
166 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
167 NULL);
168 ompt_cancel_flag_t type = ompt_cancel_parallel;
169 if (cncl_kind == cancel_parallel)
170 type = ompt_cancel_parallel;
171 else if (cncl_kind == cancel_loop)
172 type = ompt_cancel_loop;
173 else if (cncl_kind == cancel_sections)
174 type = ompt_cancel_sections;
175 ompt_callbacks.ompt_callback(ompt_callback_cancel)(
176 task_data, type | ompt_cancel_detected,
177 OMPT_GET_RETURN_ADDRESS(0));
178 }
179#endif
180 return 1 /* true */;
181 }
182 KMP_ASSERT(0 /* false */);
183 } else {
184 // we do not have a cancellation request pending, so we just
185 // ignore this cancellation point
186 return 0;
187 }
188 break;
189 }
190 case cancel_taskgroup:
191 // cancellation requests for a task group
192 // are handled through the taskgroup structure
193 {
194 kmp_taskdata_t *task;
195 kmp_taskgroup_t *taskgroup;
196
197 task = this_thr->th.th_current_task;
198 KMP_DEBUG_ASSERT(task);
199
200 taskgroup = task->td_taskgroup;
201 if (taskgroup) {
202// return the current status of cancellation for the taskgroup
203#if OMPT_SUPPORT && OMPT_OPTIONAL
204 if (ompt_enabled.ompt_callback_cancel &&
205 !!taskgroup->cancel_request) {
206 ompt_data_t *task_data;
207 __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
208 NULL);
209 ompt_callbacks.ompt_callback(ompt_callback_cancel)(
210 task_data, ompt_cancel_taskgroup | ompt_cancel_detected,
211 OMPT_GET_RETURN_ADDRESS(0));
212 }
213#endif
214 return !!taskgroup->cancel_request;
215 } else {
216 // if a cancellation point is encountered by a task that does not
217 // belong to a taskgroup, it is OK to ignore it
218 return 0 /* false */;
219 }
220 }
221 default:
222 KMP_ASSERT(0 /* false */);
223 }
224 }
225
226 // ICV OMP_CANCELLATION=false, so we ignore the cancellation point
227 KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);
228 return 0 /* false */;
229}
230
243kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32 gtid) {
244 int ret = 0 /* false */;
245 kmp_info_t *this_thr = __kmp_threads[gtid];
246 kmp_team_t *this_team = this_thr->th.th_team;
247
248 KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
249
250 // call into the standard barrier
251 __kmpc_barrier(loc, gtid);
252
253 // if cancellation is active, check cancellation flag
254 if (__kmp_omp_cancellation) {
255 // depending on which construct to cancel, check the flag and
256 // reset the flag
257 switch (KMP_ATOMIC_LD_RLX(&(this_team->t.t_cancel_request))) {
258 case cancel_parallel:
259 ret = 1;
260 // ensure that threads have checked the flag, when
261 // leaving the above barrier
262 __kmpc_barrier(loc, gtid);
263 this_team->t.t_cancel_request = cancel_noreq;
264 // the next barrier is the fork/join barrier, which
265 // synchronizes the threads leaving here
266 break;
267 case cancel_loop:
268 case cancel_sections:
269 ret = 1;
270 // ensure that threads have checked the flag, when
271 // leaving the above barrier
272 __kmpc_barrier(loc, gtid);
273 this_team->t.t_cancel_request = cancel_noreq;
274 // synchronize the threads again to make sure we do not have any run-away
275 // threads that cause a race on the cancellation flag
276 __kmpc_barrier(loc, gtid);
277 break;
278 case cancel_taskgroup:
279 // this case should not occur
280 KMP_ASSERT(0 /* false */);
281 break;
282 case cancel_noreq:
283 // do nothing
284 break;
285 default:
286 KMP_ASSERT(0 /* false */);
287 }
288 }
289
290 return ret;
291}
292
309int __kmp_get_cancellation_status(int cancel_kind) {
310 if (__kmp_omp_cancellation) {
311 kmp_info_t *this_thr = __kmp_entry_thread();
312
313 switch (cancel_kind) {
314 case cancel_parallel:
315 case cancel_loop:
316 case cancel_sections: {
317 kmp_team_t *this_team = this_thr->th.th_team;
318 return this_team->t.t_cancel_request == cancel_kind;
319 }
320 case cancel_taskgroup: {
321 kmp_taskdata_t *task;
322 kmp_taskgroup_t *taskgroup;
323 task = this_thr->th.th_current_task;
324 taskgroup = task->td_taskgroup;
325 return taskgroup && taskgroup->cancel_request;
326 }
327 }
328 }
329
330 return 0 /* false */;
331}
KMP_EXPORT void __kmpc_barrier(ident_t *, kmp_int32 global_tid)
Definition kmp.h:246