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