1/* 2 * Copyright (c) 2021 - 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "compileQueue.h" 17 18#include "varbinder/varbinder.h" 19#include "varbinder/scope.h" 20#include "compiler/core/emitter.h" 21#include "compiler/core/function.h" 22#include "compiler/core/pandagen.h" 23#include "public/public.h" 24 25namespace ark::es2panda::compiler { 26CompileQueue::CompileQueue(size_t threadCount) 27{ 28 threads_.reserve(threadCount); 29 30 for (size_t i = 0; i < threadCount; i++) { 31 threads_.push_back(os::thread::ThreadStart(Worker, this)); 32 } 33} 34 35CompileQueue::~CompileQueue() 36{ 37 void *retval = nullptr; 38 39 std::unique_lock<std::mutex> lock(m_); 40 terminate_ = true; 41 lock.unlock(); 42 jobsAvailable_.notify_all(); 43 44 for (const auto handleId : threads_) { 45 os::thread::ThreadJoin(handleId, &retval); 46 } 47} 48 49void CompileQueue::Schedule(public_lib::Context *context) 50{ 51 ASSERT(jobsCount_ == 0); 52 std::unique_lock<std::mutex> lock(m_); 53 const auto &functions = context->parserProgram->VarBinder()->Functions(); 54 jobs_ = new CompileJob[functions.size()](); 55 56 for (auto *function : functions) { 57 jobs_[jobsCount_++].SetContext(context, function); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 58 } 59 60 totalJobsCount_ = jobsCount_; 61 62 lock.unlock(); 63 jobsAvailable_.notify_all(); 64} 65 66void CompileQueue::Worker(CompileQueue *queue) 67{ 68 while (true) { 69 std::unique_lock<std::mutex> lock(queue->m_); 70 queue->jobsAvailable_.wait(lock, [queue]() { return queue->terminate_ || queue->jobsCount_ != 0; }); 71 72 if (queue->terminate_) { 73 return; 74 } 75 76 lock.unlock(); 77 78 queue->Consume(); 79 queue->jobsFinished_.notify_one(); 80 } 81} 82 83void CompileQueue::Consume() 84{ 85 std::unique_lock<std::mutex> lock(m_); 86 activeWorkers_++; 87 88 while (jobsCount_ > 0) { 89 --jobsCount_; 90 auto &job = jobs_[jobsCount_]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 91 92 lock.unlock(); 93 94 try { 95 job.Run(); 96 } catch (const Error &e) { 97 lock.lock(); 98 errors_.push_back(e); 99 lock.unlock(); 100 } 101 102 lock.lock(); 103 } 104 105 activeWorkers_--; 106} 107 108void CompileQueue::Wait(const JobsFinishedCb &onFinishedCb) 109{ 110 std::unique_lock<std::mutex> lock(m_); 111 jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; }); 112 113 if (!errors_.empty()) { 114 delete[] jobs_; 115 // NOLINTNEXTLINE 116 throw errors_.front(); 117 } 118 119 for (uint32_t i = 0; i < totalJobsCount_; i++) { 120 onFinishedCb(jobs_ + i); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 121 } 122 123 delete[] jobs_; 124} 125} // namespace ark::es2panda::compiler 126