LLVM OpenMP* Runtime Library
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 
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 
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 
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 
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 }
KMP_EXPORT void __kmpc_barrier(ident_t *, kmp_int32 global_tid)
Definition: kmp.h:233