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-exception
6//
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)
18// FLANG_RT_DEBUG code is disabled when false.
19static constexpr bool enableDebugOutput{false};
20#endif
21
22RT_OFFLOAD_API_GROUP_BEGIN
23
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)
83 if (enableDebugOutput &&
84 (executionEnvironment.internalDebugging &
85 ExecutionEnvironment::WorkQueue)) {
86 std::fprintf(stderr, "WQ: new ticket\n");
87 }
88#endif
89 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)
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#endif
104 int stat{at->ticket.Continue(*this)};
105#if !defined(RT_DEVICE_COMPILATION)
106 if (enableDebugOutput &&
107 (executionEnvironment.internalDebugging &
108 ExecutionEnvironment::WorkQueue)) {
109 std::fprintf(stderr, "WQ: ... stat %d\n", stat);
110 }
111#endif
112 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_END
148
149} // namespace Fortran::runtime
150

source code of flang-rt/lib/runtime/work-queue.cpp