Path: blob/main/contrib/llvm-project/openmp/runtime/src/kmp_cancel.cpp
35258 views
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//89#include "kmp.h"10#include "kmp_i18n.h"11#include "kmp_io.h"12#include "kmp_str.h"13#if OMPT_SUPPORT14#include "ompt-specific.h"15#endif1617/*!18@ingroup CANCELLATION19@param loc_ref location of the original task directive20@param gtid Global thread ID of encountering thread21@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)2223@return returns true if the cancellation request has been activated and the24execution thread needs to proceed to the end of the canceled region.2526Request cancellation of the binding OpenMP region.27*/28kmp_int32 __kmpc_cancel(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 cncl_kind) {29kmp_info_t *this_thr = __kmp_threads[gtid];3031KC_TRACE(10, ("__kmpc_cancel: T#%d request %d OMP_CANCELLATION=%d\n", gtid,32cncl_kind, __kmp_omp_cancellation));3334KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);35KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||36cncl_kind == cancel_sections ||37cncl_kind == cancel_taskgroup);38KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);3940if (__kmp_omp_cancellation) {41switch (cncl_kind) {42case cancel_parallel:43case cancel_loop:44case cancel_sections:45// cancellation requests for parallel and worksharing constructs46// are handled through the team structure47{48kmp_team_t *this_team = this_thr->th.th_team;49KMP_DEBUG_ASSERT(this_team);50kmp_int32 old = cancel_noreq;51this_team->t.t_cancel_request.compare_exchange_strong(old, cncl_kind);52if (old == cancel_noreq || old == cncl_kind) {53// we do not have a cancellation request in this team or we do have54// one that matches the current request -> cancel55#if OMPT_SUPPORT && OMPT_OPTIONAL56if (ompt_enabled.ompt_callback_cancel) {57ompt_data_t *task_data;58__ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,59NULL);60ompt_cancel_flag_t type = ompt_cancel_parallel;61if (cncl_kind == cancel_parallel)62type = ompt_cancel_parallel;63else if (cncl_kind == cancel_loop)64type = ompt_cancel_loop;65else if (cncl_kind == cancel_sections)66type = ompt_cancel_sections;67ompt_callbacks.ompt_callback(ompt_callback_cancel)(68task_data, type | ompt_cancel_activated,69OMPT_GET_RETURN_ADDRESS(0));70}71#endif // OMPT_SUPPORT && OMPT_OPTIONAL72return 1 /* true */;73}74break;75}76case cancel_taskgroup:77// cancellation requests for a task group78// are handled through the taskgroup structure79{80kmp_taskdata_t *task;81kmp_taskgroup_t *taskgroup;8283task = this_thr->th.th_current_task;84KMP_DEBUG_ASSERT(task);8586taskgroup = task->td_taskgroup;87if (taskgroup) {88kmp_int32 old = cancel_noreq;89taskgroup->cancel_request.compare_exchange_strong(old, cncl_kind);90if (old == cancel_noreq || old == cncl_kind) {91// we do not have a cancellation request in this taskgroup or we do92// have one that matches the current request -> cancel93#if OMPT_SUPPORT && OMPT_OPTIONAL94if (ompt_enabled.ompt_callback_cancel) {95ompt_data_t *task_data;96__ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,97NULL);98ompt_callbacks.ompt_callback(ompt_callback_cancel)(99task_data, ompt_cancel_taskgroup | ompt_cancel_activated,100OMPT_GET_RETURN_ADDRESS(0));101}102#endif103return 1 /* true */;104}105} else {106// TODO: what needs to happen here?107// the specification disallows cancellation w/o taskgroups108// so we might do anything here, let's abort for now109KMP_ASSERT(0 /* false */);110}111}112break;113default:114KMP_ASSERT(0 /* false */);115}116}117118// ICV OMP_CANCELLATION=false, so we ignored this cancel request119KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);120return 0 /* false */;121}122123/*!124@ingroup CANCELLATION125@param loc_ref location of the original task directive126@param gtid Global thread ID of encountering thread127@param cncl_kind Cancellation kind (parallel, for, sections, taskgroup)128129@return returns true if a matching cancellation request has been flagged in the130RTL and the encountering thread has to cancel..131132Cancellation point for the encountering thread.133*/134kmp_int32 __kmpc_cancellationpoint(ident_t *loc_ref, kmp_int32 gtid,135kmp_int32 cncl_kind) {136kmp_info_t *this_thr = __kmp_threads[gtid];137138KC_TRACE(10,139("__kmpc_cancellationpoint: T#%d request %d OMP_CANCELLATION=%d\n",140gtid, cncl_kind, __kmp_omp_cancellation));141142KMP_DEBUG_ASSERT(cncl_kind != cancel_noreq);143KMP_DEBUG_ASSERT(cncl_kind == cancel_parallel || cncl_kind == cancel_loop ||144cncl_kind == cancel_sections ||145cncl_kind == cancel_taskgroup);146KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);147148if (__kmp_omp_cancellation) {149switch (cncl_kind) {150case cancel_parallel:151case cancel_loop:152case cancel_sections:153// cancellation requests for parallel and worksharing constructs154// are handled through the team structure155{156kmp_team_t *this_team = this_thr->th.th_team;157KMP_DEBUG_ASSERT(this_team);158if (this_team->t.t_cancel_request) {159if (cncl_kind == this_team->t.t_cancel_request) {160// the request in the team structure matches the type of161// cancellation point so we can cancel162#if OMPT_SUPPORT && OMPT_OPTIONAL163if (ompt_enabled.ompt_callback_cancel) {164ompt_data_t *task_data;165__ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,166NULL);167ompt_cancel_flag_t type = ompt_cancel_parallel;168if (cncl_kind == cancel_parallel)169type = ompt_cancel_parallel;170else if (cncl_kind == cancel_loop)171type = ompt_cancel_loop;172else if (cncl_kind == cancel_sections)173type = ompt_cancel_sections;174ompt_callbacks.ompt_callback(ompt_callback_cancel)(175task_data, type | ompt_cancel_detected,176OMPT_GET_RETURN_ADDRESS(0));177}178#endif179return 1 /* true */;180}181KMP_ASSERT(0 /* false */);182} else {183// we do not have a cancellation request pending, so we just184// ignore this cancellation point185return 0;186}187break;188}189case cancel_taskgroup:190// cancellation requests for a task group191// are handled through the taskgroup structure192{193kmp_taskdata_t *task;194kmp_taskgroup_t *taskgroup;195196task = this_thr->th.th_current_task;197KMP_DEBUG_ASSERT(task);198199taskgroup = task->td_taskgroup;200if (taskgroup) {201// return the current status of cancellation for the taskgroup202#if OMPT_SUPPORT && OMPT_OPTIONAL203if (ompt_enabled.ompt_callback_cancel &&204!!taskgroup->cancel_request) {205ompt_data_t *task_data;206__ompt_get_task_info_internal(0, NULL, &task_data, NULL, NULL,207NULL);208ompt_callbacks.ompt_callback(ompt_callback_cancel)(209task_data, ompt_cancel_taskgroup | ompt_cancel_detected,210OMPT_GET_RETURN_ADDRESS(0));211}212#endif213return !!taskgroup->cancel_request;214} else {215// if a cancellation point is encountered by a task that does not216// belong to a taskgroup, it is OK to ignore it217return 0 /* false */;218}219}220default:221KMP_ASSERT(0 /* false */);222}223}224225// ICV OMP_CANCELLATION=false, so we ignore the cancellation point226KMP_DEBUG_ASSERT(!__kmp_omp_cancellation);227return 0 /* false */;228}229230/*!231@ingroup CANCELLATION232@param loc_ref location of the original task directive233@param gtid Global thread ID of encountering thread234235@return returns true if a matching cancellation request has been flagged in the236RTL and the encountering thread has to cancel..237238Barrier with cancellation point to send threads from the barrier to the239end of the parallel region. Needs a special code pattern as documented240in the design document for the cancellation feature.241*/242kmp_int32 __kmpc_cancel_barrier(ident_t *loc, kmp_int32 gtid) {243int ret = 0 /* false */;244kmp_info_t *this_thr = __kmp_threads[gtid];245kmp_team_t *this_team = this_thr->th.th_team;246247KMP_DEBUG_ASSERT(__kmp_get_gtid() == gtid);248249// call into the standard barrier250__kmpc_barrier(loc, gtid);251252// if cancellation is active, check cancellation flag253if (__kmp_omp_cancellation) {254// depending on which construct to cancel, check the flag and255// reset the flag256switch (KMP_ATOMIC_LD_RLX(&(this_team->t.t_cancel_request))) {257case cancel_parallel:258ret = 1;259// ensure that threads have checked the flag, when260// leaving the above barrier261__kmpc_barrier(loc, gtid);262this_team->t.t_cancel_request = cancel_noreq;263// the next barrier is the fork/join barrier, which264// synchronizes the threads leaving here265break;266case cancel_loop:267case cancel_sections:268ret = 1;269// ensure that threads have checked the flag, when270// leaving the above barrier271__kmpc_barrier(loc, gtid);272this_team->t.t_cancel_request = cancel_noreq;273// synchronize the threads again to make sure we do not have any run-away274// threads that cause a race on the cancellation flag275__kmpc_barrier(loc, gtid);276break;277case cancel_taskgroup:278// this case should not occur279KMP_ASSERT(0 /* false */);280break;281case cancel_noreq:282// do nothing283break;284default:285KMP_ASSERT(0 /* false */);286}287}288289return ret;290}291292/*!293@ingroup CANCELLATION294@param loc_ref location of the original task directive295@param gtid Global thread ID of encountering thread296297@return returns true if a matching cancellation request has been flagged in the298RTL and the encountering thread has to cancel..299300Query function to query the current status of cancellation requests.301Can be used to implement the following pattern:302303if (kmp_get_cancellation_status(kmp_cancel_parallel)) {304perform_cleanup();305#pragma omp cancellation point parallel306}307*/308int __kmp_get_cancellation_status(int cancel_kind) {309if (__kmp_omp_cancellation) {310kmp_info_t *this_thr = __kmp_entry_thread();311312switch (cancel_kind) {313case cancel_parallel:314case cancel_loop:315case cancel_sections: {316kmp_team_t *this_team = this_thr->th.th_team;317return this_team->t.t_cancel_request == cancel_kind;318}319case cancel_taskgroup: {320kmp_taskdata_t *task;321kmp_taskgroup_t *taskgroup;322task = this_thr->th.th_current_task;323taskgroup = task->td_taskgroup;324return taskgroup && taskgroup->cancel_request;325}326}327}328329return 0 /* false */;330}331332333