allow flexible make task types via factory funcs
parent
4fd81d83ef
commit
846b11e4d1
|
@ -213,48 +213,70 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct make_task {
|
struct make_task {
|
||||||
make_task() = delete;
|
make_task() {}
|
||||||
make_task(
|
virtual ~make_task();
|
||||||
string_range target, std::vector<string_range> deps, make_rule &rl
|
|
||||||
) {
|
virtual bool done() const = 0;
|
||||||
p_coro = std::make_unique<coroutine<void()>>(
|
virtual void resume() = 0;
|
||||||
|
virtual void add_task(std::future<void> f) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
struct make_task_coro: make_task {
|
||||||
|
make_task_coro() = delete;
|
||||||
|
|
||||||
|
make_task_coro(
|
||||||
|
string_range target, std::vector<string_range> deps, make_rule &rl
|
||||||
|
): p_coro(
|
||||||
[target, deps = std::move(deps), &rl](auto) mutable {
|
[target, deps = std::move(deps), &rl](auto) mutable {
|
||||||
rl.call(target, iterator_range<string_range *>(
|
rl.call(target, iterator_range<string_range *>(
|
||||||
deps.data(), deps.data() + deps.size()
|
deps.data(), deps.data() + deps.size()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
);
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
bool done() const {
|
bool done() const {
|
||||||
return !*p_coro;
|
return !p_coro;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resume() {
|
void resume() {
|
||||||
p_coro->resume();
|
p_coro.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_task(std::future<void> f) {
|
void add_task(std::future<void> f) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto fs = f.wait_for(std::chrono::seconds(0));
|
auto fs = f.wait_for(std::chrono::seconds(0));
|
||||||
if (fs != std::future_status::ready) {
|
if (fs != std::future_status::ready) {
|
||||||
/* keep yielding until ready */
|
/* keep yielding until ready */
|
||||||
auto &cc = static_cast<coroutine<void()> &>(
|
auto &cc = static_cast<coroutine<void()> &>(
|
||||||
*coroutine_context::current()
|
*coroutine_context::current()
|
||||||
);
|
);
|
||||||
(coroutine<void()>::yield_type(cc))();
|
(coroutine<void()>::yield_type(cc))();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<coroutine<void()>> p_coro{};
|
coroutine<void()> p_coro;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline make_task *make_task_coroutine(
|
||||||
|
string_range target, std::vector<string_range> deps, make_rule &rl
|
||||||
|
) {
|
||||||
|
return new detail::make_task_coro{target, std::move(deps), rl};
|
||||||
|
}
|
||||||
|
|
||||||
struct make {
|
struct make {
|
||||||
make(int threads = std::thread::hardware_concurrency()) {
|
using task_factory = std::function<
|
||||||
|
make_task *(string_range, std::vector<string_range>, make_rule &)
|
||||||
|
>;
|
||||||
|
|
||||||
|
make(
|
||||||
|
task_factory factory, int threads = std::thread::hardware_concurrency()
|
||||||
|
): p_factory(factory) {
|
||||||
p_tpool.start(threads);
|
p_tpool.start(threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +314,7 @@ private:
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void wait_for(F func) {
|
void wait_for(F func) {
|
||||||
std::queue<make_task> tasks;
|
std::queue<std::unique_ptr<make_task>> tasks;
|
||||||
p_waiting.push(&tasks);
|
p_waiting.push(&tasks);
|
||||||
try {
|
try {
|
||||||
func();
|
func();
|
||||||
|
@ -310,16 +332,16 @@ private:
|
||||||
while (!p_avail) {
|
while (!p_avail) {
|
||||||
p_cond.wait(lk);
|
p_cond.wait(lk);
|
||||||
}
|
}
|
||||||
std::queue<make_task> atasks;
|
std::queue<std::unique_ptr<make_task>> atasks;
|
||||||
while (!tasks.empty()) {
|
while (!tasks.empty()) {
|
||||||
p_avail = false;
|
p_avail = false;
|
||||||
while (!tasks.empty()) {
|
while (!tasks.empty()) {
|
||||||
try {
|
try {
|
||||||
auto t = std::move(tasks.front());
|
auto t = std::move(tasks.front());
|
||||||
tasks.pop();
|
tasks.pop();
|
||||||
p_current = &t;
|
p_current = t.get();
|
||||||
t.resume();
|
t->resume();
|
||||||
if (!t.done()) {
|
if (!t->done()) {
|
||||||
/* still not dead, re-push */
|
/* still not dead, re-push */
|
||||||
atasks.push(std::move(t));
|
atasks.push(std::move(t));
|
||||||
}
|
}
|
||||||
|
@ -329,9 +351,9 @@ private:
|
||||||
try {
|
try {
|
||||||
auto t = std::move(tasks.front());
|
auto t = std::move(tasks.front());
|
||||||
tasks.pop();
|
tasks.pop();
|
||||||
while (!t.done()) {
|
while (!t->done()) {
|
||||||
p_current = &t;
|
p_current = t.get();
|
||||||
t.resume();
|
t->resume();
|
||||||
}
|
}
|
||||||
} catch (make_error const &) {
|
} catch (make_error const &) {
|
||||||
/* no rethrow */
|
/* no rethrow */
|
||||||
|
@ -371,10 +393,12 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rl && (rl->action() || detail::check_exec(tname, rdeps))) {
|
if (rl && (rl->action() || detail::check_exec(tname, rdeps))) {
|
||||||
make_task t{tname, std::move(rdeps), *rl};
|
std::unique_ptr<make_task> t{
|
||||||
p_current = &t;
|
p_factory(tname, std::move(rdeps), *rl)
|
||||||
t.resume();
|
};
|
||||||
if (!t.done()) {
|
p_current = t.get();
|
||||||
|
t->resume();
|
||||||
|
if (!t->done()) {
|
||||||
p_waiting.top()->push(std::move(t));
|
p_waiting.top()->push(std::move(t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,7 +497,8 @@ private:
|
||||||
|
|
||||||
std::mutex p_mtx{};
|
std::mutex p_mtx{};
|
||||||
std::condition_variable p_cond{};
|
std::condition_variable p_cond{};
|
||||||
std::stack<std::queue<make_task> *> p_waiting{};
|
std::stack<std::queue<std::unique_ptr<make_task>> *> p_waiting{};
|
||||||
|
task_factory p_factory{};
|
||||||
make_task *p_current = nullptr;
|
make_task *p_current = nullptr;
|
||||||
bool p_avail = false;
|
bool p_avail = false;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue