2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
15 #include "ompt-specific.h"
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)
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.
27 Request cancellation of the binding OpenMP region.
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
];
32 KC_TRACE(10, ("__kmpc_cancel: T#%d request %d OMP_CANCELLATION=%d\n", gtid
,
33 cncl_kind
, __kmp_omp_cancellation
));
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
);
41 if (__kmp_omp_cancellation
) {
46 // cancellation requests for parallel and worksharing constructs
47 // are handled through the team structure
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
,
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));
72 #endif // OMPT_SUPPORT && OMPT_OPTIONAL
77 case cancel_taskgroup
:
78 // cancellation requests for a task group
79 // are handled through the taskgroup structure
82 kmp_taskgroup_t
*taskgroup
;
84 task
= this_thr
->th
.th_current_task
;
85 KMP_DEBUG_ASSERT(task
);
87 taskgroup
= task
->td_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
,
99 ompt_callbacks
.ompt_callback(ompt_callback_cancel
)(
100 task_data
, ompt_cancel_taskgroup
| ompt_cancel_activated
,
101 OMPT_GET_RETURN_ADDRESS(0));
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 */);
115 KMP_ASSERT(0 /* false */);
119 // ICV OMP_CANCELLATION=false, so we ignored this cancel request
120 KMP_DEBUG_ASSERT(!__kmp_omp_cancellation
);
121 return 0 /* false */;
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)
130 @return returns true if a matching cancellation request has been flagged in the
131 RTL and the encountering thread has to cancel..
133 Cancellation point for the encountering thread.
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
];
140 ("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n",
141 gtid
, cncl_kind
, __kmp_omp_cancellation
));
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
);
149 if (__kmp_omp_cancellation
) {
151 case cancel_parallel
:
153 case cancel_sections
:
154 // cancellation requests for parallel and worksharing constructs
155 // are handled through the team structure
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
,
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));
182 KMP_ASSERT(0 /* false */);
184 // we do not have a cancellation request pending, so we just
185 // ignore this cancellation point
190 case cancel_taskgroup
:
191 // cancellation requests for a task group
192 // are handled through the taskgroup structure
194 kmp_taskdata_t
*task
;
195 kmp_taskgroup_t
*taskgroup
;
197 task
= this_thr
->th
.th_current_task
;
198 KMP_DEBUG_ASSERT(task
);
200 taskgroup
= task
->td_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
,
209 ompt_callbacks
.ompt_callback(ompt_callback_cancel
)(
210 task_data
, ompt_cancel_taskgroup
| ompt_cancel_detected
,
211 OMPT_GET_RETURN_ADDRESS(0));
214 return !!taskgroup
->cancel_request
;
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 */;
222 KMP_ASSERT(0 /* false */);
226 // ICV OMP_CANCELLATION=false, so we ignore the cancellation point
227 KMP_DEBUG_ASSERT(!__kmp_omp_cancellation
);
228 return 0 /* false */;
232 @ingroup CANCELLATION
233 @param loc_ref location of the original task directive
234 @param gtid Global thread ID of encountering thread
236 @return returns true if a matching cancellation request has been flagged in the
237 RTL and the encountering thread has to cancel..
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.
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
;
248 KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid
);
250 // call into the standard barrier
251 __kmpc_barrier(loc
, gtid
);
253 // if cancellation is active, check cancellation flag
254 if (__kmp_omp_cancellation
) {
255 // depending on which construct to cancel, check the flag and
257 switch (KMP_ATOMIC_LD_RLX(&(this_team
->t
.t_cancel_request
))) {
258 case cancel_parallel
:
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
268 case cancel_sections
:
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
);
278 case cancel_taskgroup
:
279 // this case should not occur
280 KMP_ASSERT(0 /* false */);
286 KMP_ASSERT(0 /* false */);
294 @ingroup CANCELLATION
295 @param loc_ref location of the original task directive
296 @param gtid Global thread ID of encountering thread
298 @return returns true if a matching cancellation request has been flagged in the
299 RTL and the encountering thread has to cancel..
301 Query function to query the current status of cancellation requests.
302 Can be used to implement the following pattern:
304 if (kmp_get_cancellation_status(kmp_cancel_parallel)) {
306 #pragma omp cancellation point parallel
309 int __kmp_get_cancellation_status(int cancel_kind
) {
310 if (__kmp_omp_cancellation
) {
311 kmp_info_t
*this_thr
= __kmp_entry_thread();
313 switch (cancel_kind
) {
314 case cancel_parallel
:
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
;
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
;
330 return 0 /* false */;