aboutsummaryrefslogtreecommitdiff
path: root/src/yue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yue.cpp')
-rw-r--r--src/yue.cpp132
1 files changed, 105 insertions, 27 deletions
diff --git a/src/yue.cpp b/src/yue.cpp
index 4bb4e70..8fe2aba 100644
--- a/src/yue.cpp
+++ b/src/yue.cpp
@@ -9,18 +9,25 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
9#include "yuescript/yue_compiler.h" 9#include "yuescript/yue_compiler.h"
10#include "yuescript/yue_parser.h" 10#include "yuescript/yue_parser.h"
11 11
12#include <algorithm>
12#include <chrono> 13#include <chrono>
14#include <condition_variable>
13#include <cstdlib> 15#include <cstdlib>
16#include <deque>
14#include <fstream> 17#include <fstream>
18#include <functional>
15#include <future> 19#include <future>
16#include <iomanip> 20#include <iomanip>
17#include <iostream> 21#include <iostream>
18#include <limits> 22#include <limits>
19#include <memory> 23#include <memory>
24#include <mutex>
20#include <sstream> 25#include <sstream>
26#include <stdexcept>
21#include <string_view> 27#include <string_view>
22#include <thread> 28#include <thread>
23#include <tuple> 29#include <tuple>
30#include <vector>
24using namespace std::string_view_literals; 31using namespace std::string_view_literals;
25using namespace std::string_literals; 32using namespace std::string_literals;
26using namespace std::chrono_literals; 33using namespace std::chrono_literals;
@@ -32,35 +39,102 @@ using namespace std::chrono_literals;
32 39
33#if __has_include(<pthread.h>) 40#if __has_include(<pthread.h>)
34#include <pthread.h> 41#include <pthread.h>
35template<class R> 42#endif
36std::future<R> async(const std::function<R()>& f) {
37 using Fn = std::packaged_task<R()>;
38 auto task = new Fn(f);
39 std::future<R> fut = task->get_future();
40 43
41 pthread_attr_t attr; 44class AsyncPool {
42 pthread_attr_init(&attr); 45public:
43 pthread_attr_setstacksize(&attr, 8 * 1024 * 1024); 46 explicit AsyncPool(size_t workerCount) {
47 workerCount = std::max<size_t>(workerCount, 1);
48#if __has_include(<pthread.h>)
49 pthread_attr_t attr;
50 pthread_attr_init(&attr);
51 pthread_attr_setstacksize(&attr, 8 * 1024 * 1024);
52 _workers.reserve(workerCount);
53 for (size_t i = 0; i < workerCount; i++) {
54 pthread_t worker;
55 const int result = pthread_create(&worker, &attr, [](void* data) -> void* {
56 static_cast<AsyncPool*>(data)->run();
57 return nullptr;
58 }, this);
59 if (result != 0) {
60 {
61 std::lock_guard<std::mutex> lock(_mutex);
62 _stopping = true;
63 }
64 _condition.notify_all();
65 for (auto createdWorker : _workers) {
66 pthread_join(createdWorker, nullptr);
67 }
68 pthread_attr_destroy(&attr);
69 throw std::runtime_error("failed to create compiler worker thread");
70 }
71 _workers.push_back(worker);
72 }
73 pthread_attr_destroy(&attr);
74#else
75 _workers.reserve(workerCount);
76 for (size_t i = 0; i < workerCount; i++) {
77 _workers.emplace_back([this]() { run(); });
78 }
79#endif
80 }
44 81
45 pthread_t th; 82 ~AsyncPool() {
46 pthread_create(&th, &attr, 83 {
47 [](void* p)->void* { 84 std::lock_guard<std::mutex> lock(_mutex);
48 std::unique_ptr<Fn> fn(static_cast<Fn*>(p)); 85 _stopping = true;
49 (*fn)(); 86 }
50 return nullptr; 87 _condition.notify_all();
51 }, 88#if __has_include(<pthread.h>)
52 task); 89 for (auto worker : _workers) {
53 pthread_attr_destroy(&attr); 90 pthread_join(worker, nullptr);
54 pthread_detach(th); 91 }
55 return fut;
56}
57#else 92#else
58template<class R> 93 for (auto& worker : _workers) {
59std::future<R> async(const std::function<R()>& f) { 94 worker.join();
60 // fallback: ignore stack size 95 }
61 return std::async(std::launch::async, f);
62}
63#endif 96#endif
97 }
98
99 template<class R>
100 std::future<R> async(const std::function<R()>& f) {
101 auto task = std::make_shared<std::packaged_task<R()>>(f);
102 auto result = task->get_future();
103 {
104 std::lock_guard<std::mutex> lock(_mutex);
105 _tasks.emplace_back([task]() { (*task)(); });
106 }
107 _condition.notify_one();
108 return result;
109 }
110
111private:
112 void run() {
113 while (true) {
114 std::function<void()> task;
115 {
116 std::unique_lock<std::mutex> lock(_mutex);
117 _condition.wait(lock, [this]() {
118 return _stopping || !_tasks.empty();
119 });
120 if (_stopping && _tasks.empty()) return;
121 task = std::move(_tasks.front());
122 _tasks.pop_front();
123 }
124 task();
125 }
126 }
127
128 std::mutex _mutex;
129 std::condition_variable _condition;
130 std::deque<std::function<void()>> _tasks;
131 bool _stopping = false;
132#if __has_include(<pthread.h>)
133 std::vector<pthread_t> _workers;
134#else
135 std::vector<std::thread> _workers;
136#endif
137};
64 138
65#if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) 139#if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY)
66#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ 140#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \
@@ -823,6 +897,10 @@ int main(int narg, const char** args) {
823 } 897 }
824 } 898 }
825#endif // YUE_COMPILER_ONLY 899#endif // YUE_COMPILER_ONLY
900 const size_t workerCount = std::min(
901 files.size(),
902 static_cast<size_t>(std::max(1u, std::thread::hardware_concurrency())));
903 AsyncPool pool(workerCount);
826#ifndef YUE_NO_WATCHER 904#ifndef YUE_NO_WATCHER
827 if (watchFiles) { 905 if (watchFiles) {
828 auto fullWorkPath = fs::absolute(fs::path(workPath)).string(); 906 auto fullWorkPath = fs::absolute(fs::path(workPath)).string();
@@ -832,7 +910,7 @@ int main(int narg, const char** args) {
832 } 910 }
833 std::list<std::future<std::string>> results; 911 std::list<std::future<std::string>> results;
834 for (const auto& file : files) { 912 for (const auto& file : files) {
835 auto task = async<std::string>([=]() { 913 auto task = pool.async<std::string>([=]() {
836#ifndef YUE_COMPILER_ONLY 914#ifndef YUE_COMPILER_ONLY
837 return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite); 915 return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite);
838#else 916#else
@@ -870,7 +948,7 @@ int main(int narg, const char** args) {
870#endif // YUE_NO_WATCHER 948#endif // YUE_NO_WATCHER
871 std::list<std::future<std::tuple<int, std::string, std::string>>> results; 949 std::list<std::future<std::tuple<int, std::string, std::string>>> results;
872 for (const auto& file : files) { 950 for (const auto& file : files) {
873 auto task = async<std::tuple<int, std::string, std::string>>([=]() { 951 auto task = pool.async<std::tuple<int, std::string, std::string>>([=]() {
874 std::ifstream input(file.first, std::ios::in); 952 std::ifstream input(file.first, std::ios::in);
875 if (input) { 953 if (input) {
876 std::string s( 954 std::string s(