allow flexible make task types via factory funcs

master
Daniel Kolesa 2018-04-23 21:23:56 +02:00
parent 4fd81d83ef
commit 846b11e4d1
1 changed files with 67 additions and 42 deletions

View File

@ -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;
}; };