aboutsummaryrefslogtreecommitdiff
path: root/final/runtime/src/kmp_cancel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'final/runtime/src/kmp_cancel.cpp')
-rw-r--r--final/runtime/src/kmp_cancel.cpp336
1 files changed, 336 insertions, 0 deletions
diff --git a/final/runtime/src/kmp_cancel.cpp b/final/runtime/src/kmp_cancel.cpp
new file mode 100644
index 0000000..3895f97
--- /dev/null
+++ b/final/runtime/src/kmp_cancel.cpp
@@ -0,0 +1,336 @@
+
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.txt for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "kmp.h"
+#include "kmp_i18n.h"
+#include "kmp_io.h"
+#include "kmp_str.h"
+#if OMPT_SUPPORT
+#include "ompt-specific.h"
+#endif
+
+#if OMP_40_ENABLED
+
+/*!
+@ingroup CANCELLATION
+@param loc_ref location of the original task directive
+@param gtid Global thread ID of encountering thread
+@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)
+
+@return returns true if the cancellation request has been activated and the
+execution thread needs to proceed to the end of the canceled region.
+
+Request cancellation of the binding OpenMP region.
+*/
+kmp_int32 __kmpc_cancel(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 cncl_kind) {
+ kmp_info_t *this_thr = __kmp_threads[gtid];
+
+ KC_TRACE(10, ("__kmpc_cancel: T#%d request %d OMP_CANCELLATION=%d\n", gtid,
+ cncl_kind, __kmp_omp_cancellation));
+
+ KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);
+ KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||
+ cncl_kind == cancel_sections ||
+ cncl_kind == cancel_taskgroup);
+ KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
+
+ if (__kmp_omp_cancellation) {
+ switch (cncl_kind) {
+ case cancel_parallel:
+ case cancel_loop:
+ case cancel_sections:
+ // cancellation requests for parallel and worksharing constructs
+ // are handled through the team structure
+ {
+ kmp_team_t *this_team = this_thr->th.th_team;
+ KMP_DEBUG_ASSERT(this_team);
+ kmp_int32 old = cancel_noreq;
+ this_team->t.t_cancel_request.compare_exchange_strong(old, cncl_kind);
+ if (old == cancel_noreq || old == cncl_kind) {
+// we do not have a cancellation request in this team or we do have
+// one that matches the current request -> cancel
+#if OMPT_SUPPORT && OMPT_OPTIONAL
+ if (ompt_enabled.ompt_callback_cancel) {
+ ompt_data_t *task_data;
+ __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
+ NULL);
+ ompt_cancel_flag_t type = ompt_cancel_parallel;
+ if (cncl_kind == cancel_parallel)
+ type = ompt_cancel_parallel;
+ else if (cncl_kind == cancel_loop)
+ type = ompt_cancel_do;
+ else if (cncl_kind == cancel_sections)
+ type = ompt_cancel_sections;
+ ompt_callbacks.ompt_callback(ompt_callback_cancel)(
+ task_data, type | ompt_cancel_activated,
+ OMPT_GET_RETURN_ADDRESS(0));
+ }
+#endif
+ return 1 /* true */;
+ }
+ break;
+ }
+ case cancel_taskgroup:
+ // cancellation requests for a task group
+ // are handled through the taskgroup structure
+ {
+ kmp_taskdata_t *task;
+ kmp_taskgroup_t *taskgroup;
+
+ task = this_thr->th.th_current_task;
+ KMP_DEBUG_ASSERT(task);
+
+ taskgroup = task->td_taskgroup;
+ if (taskgroup) {
+ kmp_int32 old = cancel_noreq;
+ taskgroup->cancel_request.compare_exchange_strong(old, cncl_kind);
+ if (old == cancel_noreq || old == cncl_kind) {
+// we do not have a cancellation request in this taskgroup or we do
+// have one that matches the current request -> cancel
+#if OMPT_SUPPORT && OMPT_OPTIONAL
+ if (ompt_enabled.ompt_callback_cancel) {
+ ompt_data_t *task_data;
+ __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
+ NULL);
+ ompt_callbacks.ompt_callback(ompt_callback_cancel)(
+ task_data, ompt_cancel_taskgroup | ompt_cancel_activated,
+ OMPT_GET_RETURN_ADDRESS(0));
+ }
+#endif
+ return 1 /* true */;
+ }
+ } else {
+ // TODO: what needs to happen here?
+ // the specification disallows cancellation w/o taskgroups
+ // so we might do anything here, let's abort for now
+ KMP_ASSERT(0 /* false */);
+ }
+ }
+ break;
+ default:
+ KMP_ASSERT(0 /* false */);
+ }
+ }
+
+ // ICV OMP_CANCELLATION=false, so we ignored this cancel request
+ KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);
+ return 0 /* false */;
+}
+
+/*!
+@ingroup CANCELLATION
+@param loc_ref location of the original task directive
+@param gtid Global thread ID of encountering thread
+@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)
+
+@return returns true if a matching cancellation request has been flagged in the
+RTL and the encountering thread has to cancel..
+
+Cancellation point for the encountering thread.
+*/
+kmp_int32 __kmpc_cancellationpoint(ident_t *loc_ref, kmp_int32 gtid,
+ kmp_int32 cncl_kind) {
+ kmp_info_t *this_thr = __kmp_threads[gtid];
+
+ KC_TRACE(10,
+ ("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n",
+ gtid, cncl_kind, __kmp_omp_cancellation));
+
+ KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);
+ KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||
+ cncl_kind == cancel_sections ||
+ cncl_kind == cancel_taskgroup);
+ KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
+
+ if (__kmp_omp_cancellation) {
+ switch (cncl_kind) {
+ case cancel_parallel:
+ case cancel_loop:
+ case cancel_sections:
+ // cancellation requests for parallel and worksharing constructs
+ // are handled through the team structure
+ {
+ kmp_team_t *this_team = this_thr->th.th_team;
+ KMP_DEBUG_ASSERT(this_team);
+ if (this_team->t.t_cancel_request) {
+ if (cncl_kind == this_team->t.t_cancel_request) {
+// the request in the team structure matches the type of
+// cancellation point so we can cancel
+#if OMPT_SUPPORT && OMPT_OPTIONAL
+ if (ompt_enabled.ompt_callback_cancel) {
+ ompt_data_t *task_data;
+ __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
+ NULL);
+ ompt_cancel_flag_t type = ompt_cancel_parallel;
+ if (cncl_kind == cancel_parallel)
+ type = ompt_cancel_parallel;
+ else if (cncl_kind == cancel_loop)
+ type = ompt_cancel_do;
+ else if (cncl_kind == cancel_sections)
+ type = ompt_cancel_sections;
+ ompt_callbacks.ompt_callback(ompt_callback_cancel)(
+ task_data, type | ompt_cancel_detected,
+ OMPT_GET_RETURN_ADDRESS(0));
+ }
+#endif
+ return 1 /* true */;
+ }
+ KMP_ASSERT(0 /* false */);
+ } else {
+ // we do not have a cancellation request pending, so we just
+ // ignore this cancellation point
+ return 0;
+ }
+ break;
+ }
+ case cancel_taskgroup:
+ // cancellation requests for a task group
+ // are handled through the taskgroup structure
+ {
+ kmp_taskdata_t *task;
+ kmp_taskgroup_t *taskgroup;
+
+ task = this_thr->th.th_current_task;
+ KMP_DEBUG_ASSERT(task);
+
+ taskgroup = task->td_taskgroup;
+ if (taskgroup) {
+// return the current status of cancellation for the taskgroup
+#if OMPT_SUPPORT && OMPT_OPTIONAL
+ if (ompt_enabled.ompt_callback_cancel &&
+ !!taskgroup->cancel_request) {
+ ompt_data_t *task_data;
+ __ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,
+ NULL);
+ ompt_callbacks.ompt_callback(ompt_callback_cancel)(
+ task_data, ompt_cancel_taskgroup | ompt_cancel_detected,
+ OMPT_GET_RETURN_ADDRESS(0));
+ }
+#endif
+ return !!taskgroup->cancel_request;
+ } else {
+ // if a cancellation point is encountered by a task that does not
+ // belong to a taskgroup, it is OK to ignore it
+ return 0 /* false */;
+ }
+ }
+ default:
+ KMP_ASSERT(0 /* false */);
+ }
+ }
+
+ // ICV OMP_CANCELLATION=false, so we ignore the cancellation point
+ KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);
+ return 0 /* false */;
+}
+
+/*!
+@ingroup CANCELLATION
+@param loc_ref location of the original task directive
+@param gtid Global thread ID of encountering thread
+
+@return returns true if a matching cancellation request has been flagged in the
+RTL and the encountering thread has to cancel..
+
+Barrier with cancellation point to send threads from the barrier to the
+end of the parallel region. Needs a special code pattern as documented
+in the design document for the cancellation feature.
+*/
+kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32 gtid) {
+ int ret = 0 /* false */;
+ kmp_info_t *this_thr = __kmp_threads[gtid];
+ kmp_team_t *this_team = this_thr->th.th_team;
+
+ KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);
+
+ // call into the standard barrier
+ __kmpc_barrier(loc, gtid);
+
+ // if cancellation is active, check cancellation flag
+ if (__kmp_omp_cancellation) {
+ // depending on which construct to cancel, check the flag and
+ // reset the flag
+ switch (KMP_ATOMIC_LD_RLX(&(this_team->t.t_cancel_request))) {
+ case cancel_parallel:
+ ret = 1;
+ // ensure that threads have checked the flag, when
+ // leaving the above barrier
+ __kmpc_barrier(loc, gtid);
+ this_team->t.t_cancel_request = cancel_noreq;
+ // the next barrier is the fork/join barrier, which
+ // synchronizes the threads leaving here
+ break;
+ case cancel_loop:
+ case cancel_sections:
+ ret = 1;
+ // ensure that threads have checked the flag, when
+ // leaving the above barrier
+ __kmpc_barrier(loc, gtid);
+ this_team->t.t_cancel_request = cancel_noreq;
+ // synchronize the threads again to make sure we do not have any run-away
+ // threads that cause a race on the cancellation flag
+ __kmpc_barrier(loc, gtid);
+ break;
+ case cancel_taskgroup:
+ // this case should not occur
+ KMP_ASSERT(0 /* false */);
+ break;
+ case cancel_noreq:
+ // do nothing
+ break;
+ default:
+ KMP_ASSERT(0 /* false */);
+ }
+ }
+
+ return ret;
+}
+
+/*!
+@ingroup CANCELLATION
+@param loc_ref location of the original task directive
+@param gtid Global thread ID of encountering thread
+
+@return returns true if a matching cancellation request has been flagged in the
+RTL and the encountering thread has to cancel..
+
+Query function to query the current status of cancellation requests.
+Can be used to implement the following pattern:
+
+if (kmp_get_cancellation_status(kmp_cancel_parallel)) {
+ perform_cleanup();
+ #pragma omp cancellation point parallel
+}
+*/
+int __kmp_get_cancellation_status(int cancel_kind) {
+ if (__kmp_omp_cancellation) {
+ kmp_info_t *this_thr = __kmp_entry_thread();
+
+ switch (cancel_kind) {
+ case cancel_parallel:
+ case cancel_loop:
+ case cancel_sections: {
+ kmp_team_t *this_team = this_thr->th.th_team;
+ return this_team->t.t_cancel_request == cancel_kind;
+ }
+ case cancel_taskgroup: {
+ kmp_taskdata_t *task;
+ kmp_taskgroup_t *taskgroup;
+ task = this_thr->th.th_current_task;
+ taskgroup = task->td_taskgroup;
+ return taskgroup && taskgroup->cancel_request;
+ }
+ }
+ }
+
+ return 0 /* false */;
+}
+
+#endif