150 lines · cpp
1//===-- lib/runtime/work-queue.cpp ------------------------------*- C++ -*-===//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//===----------------------------------------------------------------------===//8 9#include "flang-rt/runtime/work-queue.h"10#include "flang-rt/runtime/environment.h"11#include "flang-rt/runtime/memory.h"12#include "flang-rt/runtime/type-info.h"13#include "flang/Common/visit.h"14 15namespace Fortran::runtime {16 17#if !defined(RT_DEVICE_COMPILATION) && !defined(OMP_OFFLOAD_BUILD)18// FLANG_RT_DEBUG code is disabled when false.19static constexpr bool enableDebugOutput{false};20#endif21 22RT_OFFLOAD_API_GROUP_BEGIN23 24RT_API_ATTRS int Ticket::Continue(WorkQueue &workQueue) {25 if (!begun) {26 begun = true;27 return common::visit(28 [&workQueue](29 auto &specificTicket) { return specificTicket.Begin(workQueue); },30 u);31 } else {32 return common::visit(33 [&workQueue](auto &specificTicket) {34 return specificTicket.Continue(workQueue);35 },36 u);37 }38}39 40RT_API_ATTRS WorkQueue::~WorkQueue() {41 if (anyDynamicAllocation_) {42 if (last_) {43 if ((last_->next = firstFree_)) {44 last_->next->previous = last_;45 }46 firstFree_ = first_;47 first_ = last_ = nullptr;48 }49 while (firstFree_) {50 TicketList *next{firstFree_->next};51 if (!firstFree_->isStatic) {52 FreeMemory(firstFree_);53 }54 firstFree_ = next;55 }56 }57}58 59RT_API_ATTRS Ticket &WorkQueue::StartTicket() {60 if (!firstFree_) {61 void *p{AllocateMemoryOrCrash(terminator_, sizeof(TicketList))};62 firstFree_ = new (p) TicketList;63 firstFree_->isStatic = false;64 anyDynamicAllocation_ = true;65 }66 TicketList *newTicket{firstFree_};67 if ((firstFree_ = newTicket->next)) {68 firstFree_->previous = nullptr;69 }70 TicketList *after{insertAfter_ ? insertAfter_->next : nullptr};71 if ((newTicket->previous = insertAfter_ ? insertAfter_ : last_)) {72 newTicket->previous->next = newTicket;73 } else {74 first_ = newTicket;75 }76 if ((newTicket->next = after)) {77 after->previous = newTicket;78 } else {79 last_ = newTicket;80 }81 newTicket->ticket.begun = false;82#if !defined(RT_DEVICE_COMPILATION) && !defined(OMP_OFFLOAD_BUILD)83 if (enableDebugOutput &&84 (executionEnvironment.internalDebugging &85 ExecutionEnvironment::WorkQueue)) {86 std::fprintf(stderr, "WQ: new ticket\n");87 }88#endif89 return newTicket->ticket;90}91 92RT_API_ATTRS int WorkQueue::Run() {93 while (last_) {94 TicketList *at{last_};95 insertAfter_ = last_;96#if !defined(RT_DEVICE_COMPILATION) && !defined(OMP_OFFLOAD_BUILD)97 if (enableDebugOutput &&98 (executionEnvironment.internalDebugging &99 ExecutionEnvironment::WorkQueue)) {100 std::fprintf(stderr, "WQ: %zd %s\n", at->ticket.u.index(),101 at->ticket.begun ? "Continue" : "Begin");102 }103#endif104 int stat{at->ticket.Continue(*this)};105#if !defined(RT_DEVICE_COMPILATION) && !defined(OMP_OFFLOAD_BUILD)106 if (enableDebugOutput &&107 (executionEnvironment.internalDebugging &108 ExecutionEnvironment::WorkQueue)) {109 std::fprintf(stderr, "WQ: ... stat %d\n", stat);110 }111#endif112 insertAfter_ = nullptr;113 if (stat == StatOk) {114 if (at->previous) {115 at->previous->next = at->next;116 } else {117 first_ = at->next;118 }119 if (at->next) {120 at->next->previous = at->previous;121 } else {122 last_ = at->previous;123 }124 if ((at->next = firstFree_)) {125 at->next->previous = at;126 }127 at->previous = nullptr;128 firstFree_ = at;129 } else if (stat != StatContinue) {130 Stop();131 return stat;132 }133 }134 return StatOk;135}136 137RT_API_ATTRS void WorkQueue::Stop() {138 if (last_) {139 if ((last_->next = firstFree_)) {140 last_->next->previous = last_;141 }142 firstFree_ = first_;143 first_ = last_ = nullptr;144 }145}146 147RT_OFFLOAD_API_GROUP_END148 149} // namespace Fortran::runtime150