Files
mob/src/tasks/task.cpp
T

624 lines
9.3 KiB
C++
Raw Normal View History

2020-04-29 22:10:55 -04:00
#include "pch.h"
#include "task.h"
2020-05-02 04:03:20 -04:00
#include "../conf.h"
#include "../op.h"
2020-05-03 03:46:58 -04:00
#include "../tools/tools.h"
2020-04-29 22:10:55 -04:00
2020-05-02 03:12:34 -04:00
namespace mob
2020-04-29 22:10:55 -04:00
{
class interrupted {};
2020-05-06 15:00:36 -04:00
static std::vector<std::unique_ptr<task>> g_tasks;
static std::vector<task*> g_all_tasks;
2020-05-16 13:09:16 -04:00
static std::atomic<bool> g_interrupt = false;
2020-04-29 22:10:55 -04:00
std::mutex task::interrupt_mutex_;
void add_task(std::unique_ptr<task> t)
{
g_tasks.push_back(std::move(t));
}
2020-05-20 05:41:19 -04:00
const std::vector<task*>& get_all_tasks()
{
return g_all_tasks;
}
2020-05-06 14:07:45 -04:00
void list_tasks(bool err)
{
2020-05-06 15:00:36 -04:00
for (auto&& t : g_all_tasks)
2020-05-06 14:07:45 -04:00
{
if (err)
2020-05-11 05:25:37 -04:00
u8cerr << " - " << join(t->names(), ", ") << "\n";
2020-05-06 14:07:45 -04:00
else
2020-05-11 05:25:37 -04:00
u8cout << " - " << join(t->names(), ", ") << "\n";
2020-05-06 14:07:45 -04:00
}
}
task* find_task(const std::string& name)
2020-04-29 22:10:55 -04:00
{
2020-05-06 15:00:36 -04:00
for (auto&& t : g_all_tasks)
2020-04-29 22:10:55 -04:00
{
2020-05-03 03:32:40 -04:00
for (auto&& n : t->names())
2020-04-29 22:10:55 -04:00
{
2020-05-03 03:32:40 -04:00
if (n == name)
2020-05-06 15:00:36 -04:00
return t;
2020-04-29 22:10:55 -04:00
}
}
2020-05-11 05:25:37 -04:00
u8cout << "task " << name << " not found\n";
u8cout << "valid tasks:\n";
2020-05-06 14:07:45 -04:00
list_tasks(true);
2020-04-29 22:10:55 -04:00
throw bailed("");
2020-04-29 22:10:55 -04:00
}
2020-05-06 15:00:36 -04:00
void run_tasks(const std::vector<task*> tasks)
{
2020-05-16 13:09:16 -04:00
try
2020-05-06 15:00:36 -04:00
{
2020-05-16 13:09:16 -04:00
{
std::set<task*> set(tasks.begin(), tasks.end());
MOB_ASSERT(set.size() == tasks.size());
}
for (auto* t : tasks)
{
t->fetch();
if (g_interrupt)
throw interrupted();
}
for (auto* t : tasks)
{
t->join();
if (g_interrupt)
throw interrupted();
t->build_and_install();
if (g_interrupt)
throw interrupted();
t->join();
if (g_interrupt)
throw interrupted();
}
2020-05-06 15:00:36 -04:00
}
2020-05-16 13:09:16 -04:00
catch(interrupted&)
{
}
}
2020-05-06 15:00:36 -04:00
void gather_super_tasks(std::vector<task*>& tasks, std::set<task*>& seen)
2020-05-06 13:39:47 -04:00
{
for (auto& t : g_tasks)
{
if (t->is_super())
2020-05-06 15:00:36 -04:00
{
if (!seen.contains(t.get()))
{
tasks.push_back(t.get());
seen.insert(t.get());
}
}
2020-05-06 13:39:47 -04:00
}
}
void run_task(const std::string& name)
{
run_tasks({find_task(name)});
}
void run_tasks(const std::vector<std::string>& names)
2020-05-06 03:39:45 -04:00
{
if (names.empty())
return;
2020-05-06 03:39:45 -04:00
if (names.size() == 1)
2020-05-11 07:44:37 -04:00
gcx().debug(context::generic, "specified task: {}", names[0]);
2020-05-06 03:39:45 -04:00
else
2020-05-11 07:44:37 -04:00
gcx().debug(context::generic, "specified tasks: {}", join(names, " "));
2020-05-06 03:39:45 -04:00
2020-05-06 15:00:36 -04:00
std::vector<task*> tasks;
std::set<task*> seen;
for (auto&& name : names)
2020-05-06 13:39:47 -04:00
{
if (name == "super")
2020-05-06 15:00:36 -04:00
{
gather_super_tasks(tasks, seen);
}
2020-05-06 13:39:47 -04:00
else
2020-05-06 15:00:36 -04:00
{
auto* t = find_task(name);
if (!seen.contains(t))
{
tasks.push_back(t);
seen.insert(t);
}
}
2020-05-06 13:39:47 -04:00
}
2020-05-06 03:39:45 -04:00
run_tasks(tasks);
2020-05-06 03:39:45 -04:00
}
void run_all_tasks()
2020-04-29 22:10:55 -04:00
{
2020-05-06 15:00:36 -04:00
std::vector<task*> tasks;
2020-04-29 22:10:55 -04:00
for (auto&& t : g_tasks)
2020-05-06 15:00:36 -04:00
tasks.push_back(t.get());
2020-05-06 03:39:45 -04:00
run_tasks(tasks);
2020-04-29 22:10:55 -04:00
}
2020-05-17 21:23:43 -04:00
bool task_exists(const std::string& name)
{
if (name == "super")
return true;
for (auto&& t : g_all_tasks)
{
for (auto&& n : t->names())
{
if (n == name)
return true;
}
}
return false;
}
bool is_super_task(const std::string& name)
{
for (auto& t : g_all_tasks)
{
for (auto&& tn : t->names())
{
if (tn == name)
return t->is_super();
}
}
return false;
}
2020-04-29 22:10:55 -04:00
2020-05-16 13:09:16 -04:00
struct task::thread_context
{
std::thread::id tid;
context cx;
thread_context(std::thread::id tid, context cx)
: tid(tid), cx(std::move(cx))
{
}
};
2020-05-17 21:23:43 -04:00
task_conf_holder::task_conf_holder(const task& t)
: task_(t)
{
}
2020-05-20 21:27:27 -04:00
std::string task_conf_holder::mo_org() const
2020-05-17 21:23:43 -04:00
{
return conf::option_by_name(task_.names(), "mo_org");
}
2020-05-20 21:27:27 -04:00
std::string task_conf_holder::mo_branch() const
2020-05-17 21:23:43 -04:00
{
return conf::option_by_name(task_.names(), "mo_branch");
}
2020-05-20 21:27:27 -04:00
bool task_conf_holder::no_pull() const
2020-05-17 21:23:43 -04:00
{
return conf::bool_option_by_name(task_.names(), "no_pull");
}
2020-05-20 21:27:27 -04:00
bool task_conf_holder::revert_ts() const
{
return conf::bool_option_by_name(task_.names(), "revert_ts");
}
bool task_conf_holder::ignore_ts()const
{
return conf::bool_option_by_name(task_.names(), "ignore_ts");
}
std::string task_conf_holder::git_user() const
{
return conf::option_by_name(task_.names(), "git_username");
}
std::string task_conf_holder::git_email() const
{
return conf::option_by_name(task_.names(), "git_email");
}
bool task_conf_holder::set_origin_remote() const
{
return conf::bool_option_by_name(task_.names(), "set_origin_remote");
}
std::string task_conf_holder::remote_org() const
{
return conf::option_by_name(task_.names(), "remote_org");
}
std::string task_conf_holder::remote_key() const
{
return conf::option_by_name(task_.names(), "remote_key");
}
bool task_conf_holder::remote_no_push_upstream() const
{
return conf::bool_option_by_name(task_.names(), "remote_no_push_upstream");
}
bool task_conf_holder::remote_push_default_origin() const
{
return conf::bool_option_by_name(task_.names(), "remote_push_default_origin");
}
git task_conf_holder::make_git(git::ops o) const
2020-05-17 21:23:43 -04:00
{
2020-05-19 16:54:10 -04:00
if (o == git::ops::none)
{
if (no_pull())
o = git::ops::clone;
else
o = git::ops::clone_or_pull;
}
git g(o);
2020-05-17 21:23:43 -04:00
2020-05-20 21:27:27 -04:00
g.ignore_ts_on_clone(ignore_ts());
g.revert_ts_on_pull(revert_ts());
g.credentials(git_user(), git_email());
2020-05-17 21:23:43 -04:00
2020-05-20 21:27:27 -04:00
if (set_origin_remote())
2020-05-17 21:23:43 -04:00
{
g.remote(
2020-05-20 21:27:27 -04:00
remote_org(), remote_key(),
remote_no_push_upstream(),
remote_push_default_origin());
2020-05-17 21:23:43 -04:00
}
return g;
}
2020-05-03 03:32:40 -04:00
task::task(std::vector<std::string> names)
2020-05-04 05:38:23 -04:00
: names_(std::move(names)), interrupted_(false)
2020-05-03 03:32:40 -04:00
{
2020-05-04 05:38:23 -04:00
contexts_.push_back(std::make_unique<thread_context>(
std::this_thread::get_id(), context(name())));
2020-05-06 15:00:36 -04:00
2020-05-16 13:09:16 -04:00
if (name() != "parallel")
g_all_tasks.push_back(this);
2020-05-03 03:32:40 -04:00
}
2020-04-29 22:10:55 -04:00
task::~task()
{
try
{
join();
}
catch(bailed)
{
// ignore
}
}
2020-05-06 13:39:47 -04:00
bool task::is_super() const
{
return false;
}
2020-05-04 05:38:23 -04:00
const context& task::cx() const
{
static const context bad("?");
{
std::scoped_lock lock(contexts_mutex_);
for (auto& td : contexts_)
{
if (td->tid == std::this_thread::get_id())
return td->cx;
}
}
return bad;
}
2020-05-06 12:29:38 -04:00
void task::add_name(std::string s)
{
names_.push_back(s);
}
2020-04-29 22:10:55 -04:00
void task::interrupt_all()
{
std::scoped_lock lock(interrupt_mutex_);
2020-05-16 13:09:16 -04:00
g_interrupt = true;
2020-04-29 22:10:55 -04:00
for (auto&& t : g_tasks)
t->interrupt();
}
const std::string& task::name() const
{
2020-05-03 03:32:40 -04:00
return names_[0];
}
const std::vector<std::string>& task::names() const
{
return names_;
2020-04-29 22:10:55 -04:00
}
2020-05-04 05:38:23 -04:00
void task::threaded_run(std::string thread_name, std::function<void ()> f)
{
try
{
{
std::scoped_lock lock(contexts_mutex_);
contexts_.push_back(std::make_unique<thread_context>(
std::this_thread::get_id(), context(thread_name)));
}
guard g([&]
{
std::scoped_lock lock(contexts_mutex_);
for (auto itor=contexts_.begin(); itor!=contexts_.end(); ++itor)
{
if ((*itor)->tid == std::this_thread::get_id())
{
contexts_.erase(itor);
break;
}
}
});
f();
}
catch(bailed e)
{
2020-05-11 07:44:37 -04:00
error("{} bailed out, interrupting all tasks", name());
2020-05-04 05:38:23 -04:00
interrupt_all();
}
catch(interrupted)
{
return;
}
}
2020-05-16 13:09:16 -04:00
void task::parallel(std::vector<std::pair<std::string, std::function<void ()>>> v)
{
std::vector<std::thread> ts;
for (auto&& [name, f] : v)
{
cx().trace(context::generic, "running in parallel: {}", name);
ts.push_back(start_thread([this, name, f]
{
threaded_run(name, f);
}));
}
for (auto&& t : ts)
t.join();
}
2020-05-17 16:22:04 -04:00
task_conf_holder task::task_conf() const
{
2020-05-17 21:23:43 -04:00
return task_conf_holder(*this);
2020-05-17 16:22:04 -04:00
}
2020-04-29 22:10:55 -04:00
void task::run()
{
2020-05-07 07:55:25 -04:00
threaded_run(name(), [&]
{
cx().info(context::generic, "running task");
2020-04-29 22:10:55 -04:00
2020-05-07 07:55:25 -04:00
fetch();
join();
2020-05-02 04:03:20 -04:00
2020-05-16 13:09:16 -04:00
check_interrupted();
2020-05-07 07:55:25 -04:00
build_and_install();
join();
2020-05-04 03:02:33 -04:00
2020-05-16 13:09:16 -04:00
check_interrupted();
2020-05-07 07:55:25 -04:00
});
2020-04-29 22:10:55 -04:00
}
void task::interrupt()
{
2020-05-04 05:38:23 -04:00
std::scoped_lock lock(tools_mutex_);
2020-04-29 22:10:55 -04:00
interrupted_ = true;
2020-05-04 05:38:23 -04:00
for (auto* t : tools_)
t->interrupt();
2020-04-29 22:10:55 -04:00
}
2020-05-20 05:41:19 -04:00
task::times_t task::times() const
{
return times_;
}
2020-04-29 22:10:55 -04:00
void task::join()
{
if (thread_.joinable())
thread_.join();
}
void task::fetch()
{
2020-05-14 16:07:28 -04:00
thread_ = start_thread([&]
{
threaded_run(name(), [&]
{
if (conf::rebuild())
clean_for_rebuild();
2020-04-29 22:10:55 -04:00
check_interrupted();
cx().info(context::generic, "fetching");
do_fetch();
check_interrupted();
2020-05-06 05:22:42 -04:00
if (!get_source_path().empty())
{
2020-05-06 07:43:15 -04:00
cx().debug(context::generic, "patching");
2020-05-06 05:22:42 -04:00
run_tool(patcher()
2020-05-07 11:16:29 -04:00
.task(name(), get_prebuilt())
2020-05-06 05:22:42 -04:00
.root(get_source_path()));
}
check_interrupted();
});
});
2020-04-29 22:10:55 -04:00
}
void task::build_and_install()
{
2020-05-14 16:07:28 -04:00
thread_ = start_thread([&]
{
threaded_run(name(), [&]
{
check_interrupted();
cx().info(context::generic, "build and install");
do_build_and_install();
check_interrupted();
});
});
2020-04-29 22:10:55 -04:00
}
void task::clean_for_rebuild()
2020-05-02 04:03:20 -04:00
{
cx().info(context::rebuild, "cleaning");
do_clean_for_rebuild();
2020-05-02 04:03:20 -04:00
}
2020-04-29 22:10:55 -04:00
void task::check_interrupted()
{
if (interrupted_)
throw interrupted();
}
2020-05-04 05:38:23 -04:00
void task::run_tool_impl(tool* t)
2020-05-03 03:32:40 -04:00
{
2020-05-04 05:38:23 -04:00
{
std::scoped_lock lock(tools_mutex_);
tools_.push_back(t);
}
guard g([&]
{
std::scoped_lock lock(tools_mutex_);
for (auto itor=tools_.begin(); itor!=tools_.end(); ++itor)
{
if (*itor == t)
{
tools_.erase(itor);
break;
}
}
});
2020-05-11 07:44:37 -04:00
cx().debug(context::generic, "running tool {}", t->name());
2020-05-04 05:38:23 -04:00
context cxcopy(cx());
2020-05-03 05:42:56 -04:00
2020-05-03 03:32:40 -04:00
check_interrupted();
2020-05-04 05:38:23 -04:00
t->run(cxcopy);
2020-05-03 03:32:40 -04:00
check_interrupted();
}
2020-05-06 15:00:36 -04:00
parallel_tasks::parallel_tasks(bool super)
: task("parallel"), super_(super)
{
}
bool parallel_tasks::is_super() const
{
return super_;
}
void parallel_tasks::run()
{
for (auto& t : children_)
{
2020-05-14 16:07:28 -04:00
threads_.push_back(start_thread([&]
2020-05-06 15:00:36 -04:00
{
t->run();
}));
}
join();
}
2020-05-07 07:55:25 -04:00
2020-05-06 15:00:36 -04:00
void parallel_tasks::interrupt()
{
for (auto& t : children_)
t->interrupt();
}
void parallel_tasks::join()
{
for (auto& t : threads_)
t.join();
threads_.clear();
}
void parallel_tasks::fetch()
{
// no-op
}
void parallel_tasks::build_and_install()
2020-05-06 15:00:36 -04:00
{
2020-05-07 07:55:25 -04:00
threaded_run(name(), [&]
2020-05-06 15:00:36 -04:00
{
2020-05-07 07:55:25 -04:00
for (auto& t : children_)
2020-05-06 15:00:36 -04:00
{
2020-05-14 16:07:28 -04:00
threads_.push_back(start_thread([&]
2020-05-07 07:55:25 -04:00
{
t->run();
}));
}
});
2020-05-06 15:00:36 -04:00
}
void parallel_tasks::do_fetch()
{
}
void parallel_tasks::do_build_and_install()
{
}
void parallel_tasks::do_clean_for_rebuild()
{
}
2020-04-29 22:10:55 -04:00
} // namespace