LLVM OpenMP* Runtime Library
kmp_cancel.cpp
1 
2 //===----------------------------------------------------------------------===//
3 //
4 // The LLVM Compiler Infrastructure
5 //
6 // This file is dual licensed under the MIT and the University of Illinois Open
7 // Source Licenses. See LICENSE.txt for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 
12 #include "kmp.h"
13 #include "kmp_i18n.h"
14 #include "kmp_io.h"
15 #include "kmp_str.h"
16 
17 #if OMP_40_ENABLED
18 
30 kmp_int32 __kmpc_cancel(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 cncl_kind) {
31  kmp_info_t *this_thr = __kmp_threads[gtid];
32 
33  KC_TRACE(10, ("__kmpc_cancel: T#%d request %d OMP_CANCELLATION=%d\n", gtid,
34  cncl_kind, __kmp_omp_cancellation));
35 
36  KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);
37  KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||
38  cncl_kind == cancel_sections ||
39  cncl_kind == cancel_taskgroup);
40  KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
41 
42  if (__kmp_omp_cancellation) {
43  switch (cncl_kind) {
44  case cancel_parallel:
45  case cancel_loop:
46  case cancel_sections:
47  // cancellation requests for parallel and worksharing constructs
48  // are handled through the team structure
49  {
50  kmp_team_t *this_team = this_thr->th.th_team;
51  KMP_DEBUG_ASSERT(this_team);
52  kmp_int32 old = KMP_COMPARE_AND_STORE_RET32(
53  &(this_team->t.t_cancel_request), cancel_noreq, cncl_kind);
54  if (old == cancel_noreq || old == cncl_kind) {
55  // printf("__kmpc_cancel: this_team->t.t_cancel_request=%d @ %p\n",
56  // this_team->t.t_cancel_request,
57  // &(this_team->t.t_cancel_request));
58  // we do not have a cancellation request in this team or we do have
59  // one that matches the current request -> cancel
60  return 1 /* true */;
61  }
62  break;
63  }
64  case cancel_taskgroup:
65  // cancellation requests for a task group
66  // are handled through the taskgroup structure
67  {
68  kmp_taskdata_t *task;
69  kmp_taskgroup_t *taskgroup;
70 
71  task = this_thr->th.th_current_task;
72  KMP_DEBUG_ASSERT(task);
73 
74  taskgroup = task->td_taskgroup;
75  if (taskgroup) {
76  kmp_int32 old = KMP_COMPARE_AND_STORE_RET32(
77  &(taskgroup->cancel_request), cancel_noreq, cncl_kind);
78  if (old == cancel_noreq || old == cncl_kind) {
79  // we do not have a cancellation request in this taskgroup or we do
80  // have one that matches the current request -> cancel
81  return 1 /* true */;
82  }
83  } else {
84  // TODO: what needs to happen here?
85  // the specification disallows cancellation w/o taskgroups
86  // so we might do anything here, let's abort for now
87  KMP_ASSERT(0 /* false */);
88  }
89  }
90  break;
91  default:
92  KMP_ASSERT(0 /* false */);
93  }
94  }
95 
96  // ICV OMP_CANCELLATION=false, so we ignored this cancel request
97  KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);
98  return 0 /* false */;
99 }
100 
112 kmp_int32 __kmpc_cancellationpoint(ident_t *loc_ref, kmp_int32 gtid,
113  kmp_int32 cncl_kind) {
114  kmp_info_t *this_thr = __kmp_threads[gtid];
115 
116  KC_TRACE(10,
117  ("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n",
118  gtid, cncl_kind, __kmp_omp_cancellation));
119 
120  KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);
121  KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||
122  cncl_kind == cancel_sections ||
123  cncl_kind == cancel_taskgroup);
124  KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
125 
126  if (__kmp_omp_cancellation) {
127  switch (cncl_kind) {
128  case cancel_parallel:
129  case cancel_loop:
130  case cancel_sections:
131  // cancellation requests for parallel and worksharing constructs
132  // are handled through the team structure
133  {
134  kmp_team_t *this_team = this_thr->th.th_team;
135  KMP_DEBUG_ASSERT(this_team);
136  if (this_team->t.t_cancel_request) {
137  if (cncl_kind == this_team->t.t_cancel_request) {
138  // the request in the team structure matches the type of
139  // cancellation point so we can cancel
140  return 1 /* true */;
141  }
142  KMP_ASSERT(0 /* false */);
143  } else {
144  // we do not have a cancellation request pending, so we just
145  // ignore this cancellation point
146  return 0;
147  }
148  break;
149  }
150  case cancel_taskgroup:
151  // cancellation requests for a task group
152  // are handled through the taskgroup structure
153  {
154  kmp_taskdata_t *task;
155  kmp_taskgroup_t *taskgroup;
156 
157  task = this_thr->th.th_current_task;
158  KMP_DEBUG_ASSERT(task);
159 
160  taskgroup = task->td_taskgroup;
161  if (taskgroup) {
162  // return the current status of cancellation for the taskgroup
163  return !!taskgroup->cancel_request;
164  } else {
165  // if a cancellation point is encountered by a task that does not
166  // belong to a taskgroup, it is OK to ignore it
167  return 0 /* false */;
168  }
169  }
170  default:
171  KMP_ASSERT(0 /* false */);
172  }
173  }
174 
175  // ICV OMP_CANCELLATION=false, so we ignore the cancellation point
176  KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);
177  return 0 /* false */;
178 }
179 
192 kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32 gtid) {
193  int ret = 0 /* false */;
194  kmp_info_t *this_thr = __kmp_threads[gtid];
195  kmp_team_t *this_team = this_thr->th.th_team;
196 
197  KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
198 
199  // call into the standard barrier
200  __kmpc_barrier(loc, gtid);
201 
202  // if cancellation is active, check cancellation flag
203  if (__kmp_omp_cancellation) {
204  // depending on which construct to cancel, check the flag and
205  // reset the flag
206  switch (this_team->t.t_cancel_request) {
207  case cancel_parallel:
208  ret = 1;
209  // ensure that threads have checked the flag, when
210  // leaving the above barrier
211  __kmpc_barrier(loc, gtid);
212  this_team->t.t_cancel_request = cancel_noreq;
213  // the next barrier is the fork/join barrier, which
214  // synchronizes the threads leaving here
215  break;
216  case cancel_loop:
217  case cancel_sections:
218  ret = 1;
219  // ensure that threads have checked the flag, when
220  // leaving the above barrier
221  __kmpc_barrier(loc, gtid);
222  this_team->t.t_cancel_request = cancel_noreq;
223  // synchronize the threads again to make sure we do not have any run-away
224  // threads that cause a race on the cancellation flag
225  __kmpc_barrier(loc, gtid);
226  break;
227  case cancel_taskgroup:
228  // this case should not occur
229  KMP_ASSERT(0 /* false */);
230  break;
231  case cancel_noreq:
232  // do nothing
233  break;
234  default:
235  KMP_ASSERT(0 /* false */);
236  }
237  }
238 
239  return ret;
240 }
241 
258 int __kmp_get_cancellation_status(int cancel_kind) {
259  if (__kmp_omp_cancellation) {
260  kmp_info_t *this_thr = __kmp_entry_thread();
261 
262  switch (cancel_kind) {
263  case cancel_parallel:
264  case cancel_loop:
265  case cancel_sections: {
266  kmp_team_t *this_team = this_thr->th.th_team;
267  return this_team->t.t_cancel_request == cancel_kind;
268  }
269  case cancel_taskgroup: {
270  kmp_taskdata_t *task;
271  kmp_taskgroup_t *taskgroup;
272  task = this_thr->th.th_current_task;
273  taskgroup = task->td_taskgroup;
274  return taskgroup && taskgroup->cancel_request;
275  }
276  }
277  }
278 
279  return 0 /* false */;
280 }
281 
282 #endif
Definition: kmp.h:208
KMP_EXPORT void __kmpc_barrier(ident_t *, kmp_int32 global_tid)