Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/openmp/runtime/src/kmp_cancel.cpp
35258 views
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
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 = 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
124
/*!
125
@ingroup CANCELLATION
126
@param loc_ref location of the original task directive
127
@param gtid Global thread ID of encountering thread
128
@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)
129
130
@return returns true if a matching cancellation request has been flagged in the
131
RTL and the encountering thread has to cancel..
132
133
Cancellation point for the encountering thread.
134
*/
135
kmp_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
231
/*!
232
@ingroup CANCELLATION
233
@param loc_ref location of the original task directive
234
@param gtid Global thread ID of encountering thread
235
236
@return returns true if a matching cancellation request has been flagged in the
237
RTL and the encountering thread has to cancel..
238
239
Barrier with cancellation point to send threads from the barrier to the
240
end of the parallel region. Needs a special code pattern as documented
241
in the design document for the cancellation feature.
242
*/
243
kmp_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
293
/*!
294
@ingroup CANCELLATION
295
@param loc_ref location of the original task directive
296
@param gtid Global thread ID of encountering thread
297
298
@return returns true if a matching cancellation request has been flagged in the
299
RTL and the encountering thread has to cancel..
300
301
Query function to query the current status of cancellation requests.
302
Can be used to implement the following pattern:
303
304
if (kmp_get_cancellation_status(kmp_cancel_parallel)) {
305
perform_cleanup();
306
#pragma omp cancellation point parallel
307
}
308
*/
309
int __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
}
332
333