aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-04-05 08:07:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-04-05 08:07:47 +0200
commit2905180c48e4b8974d4dee1949a00fc8e7bcafc6 (patch)
tree0dde0185bcbe36da05200c64ab12bb3b9af528c6
parent8b9701d2ad76a9a571c445b318557261a4922758 (diff)
Allow creating context with bare minimum of initializations
This is used by bpkg to detect forwarded configurations without incurring the full context creation overhead.
-rw-r--r--libbuild2/adhoc-rule-cxx.cxx2
-rw-r--r--libbuild2/algorithm.cxx50
-rw-r--r--libbuild2/algorithm.ixx6
-rw-r--r--libbuild2/cc/compile-rule.cxx8
-rw-r--r--libbuild2/cc/link-rule.cxx4
-rw-r--r--libbuild2/context.cxx68
-rw-r--r--libbuild2/context.hxx17
-rw-r--r--libbuild2/context.ixx2
-rw-r--r--libbuild2/diagnostics.cxx14
-rw-r--r--libbuild2/module.cxx12
-rw-r--r--libbuild2/operation.cxx8
-rw-r--r--libbuild2/script/run.cxx2
-rw-r--r--libbuild2/test/rule.cxx32
-rw-r--r--libbuild2/test/script/parser.cxx26
-rw-r--r--libbuild2/variable.cxx4
-rw-r--r--libbuild2/variable.txx4
16 files changed, 153 insertions, 106 deletions
diff --git a/libbuild2/adhoc-rule-cxx.cxx b/libbuild2/adhoc-rule-cxx.cxx
index fbe967e..db5c5ab 100644
--- a/libbuild2/adhoc-rule-cxx.cxx
+++ b/libbuild2/adhoc-rule-cxx.cxx
@@ -302,7 +302,7 @@ namespace build2
//
auto_thread_env penv (nullptr);
context& ctx (*t.ctx.module_context);
- scheduler::phase_guard pg (ctx.sched);
+ scheduler::phase_guard pg (*ctx.sched);
uint16_t verbosity (3); // Project creation command verbosity.
diff --git a/libbuild2/algorithm.cxx b/libbuild2/algorithm.cxx
index 597ab6c..4489e2b 100644
--- a/libbuild2/algorithm.cxx
+++ b/libbuild2/algorithm.cxx
@@ -278,7 +278,7 @@ namespace build2
// unless we release the phase.
//
phase_unlock u (ct.ctx, true /* unlock */, true /* delay */);
- e = ctx.sched.wait (busy - 1, task_count, u, *wq);
+ e = ctx.sched->wait (busy - 1, task_count, u, *wq);
}
// We don't lock already applied or executed targets.
@@ -327,7 +327,7 @@ namespace build2
// this target.
//
task_count.store (offset + ctx.count_base (), memory_order_release);
- ctx.sched.resume (task_count);
+ ctx.sched->resume (task_count);
}
target&
@@ -1101,7 +1101,7 @@ namespace build2
// Also pass our diagnostics and lock stacks (this is safe since we
// expect the caller to wait for completion before unwinding its stack).
//
- if (ct.ctx.sched.async (
+ if (ct.ctx.sched->async (
start_count,
*task_count,
[a, try_match] (const diag_frame* ds,
@@ -2388,7 +2388,7 @@ namespace build2
target::offset_busy - target::offset_executed,
memory_order_release));
assert (tc == ctx.count_busy ());
- ctx.sched.resume (s.task_count);
+ ctx.sched->resume (s.task_count);
return ts;
}
@@ -2459,7 +2459,7 @@ namespace build2
: s.state;
s.task_count.store (exec, memory_order_release);
- ctx.sched.resume (s.task_count);
+ ctx.sched->resume (s.task_count);
}
else
{
@@ -2470,15 +2470,15 @@ namespace build2
// Pass our diagnostics stack (this is safe since we expect the
// caller to wait for completion before unwinding its diag stack).
//
- if (ctx.sched.async (start_count,
- *task_count,
- [a] (const diag_frame* ds, target& t)
- {
- diag_frame::stack_guard dsg (ds);
- execute_impl (a, t);
- },
- diag_frame::stack (),
- ref (t)))
+ if (ctx.sched->async (start_count,
+ *task_count,
+ [a] (const diag_frame* ds, target& t)
+ {
+ diag_frame::stack_guard dsg (ds);
+ execute_impl (a, t);
+ },
+ diag_frame::stack (),
+ ref (t)))
return target_state::unknown; // Queued.
// Executed synchronously, fall through.
@@ -2527,15 +2527,15 @@ namespace build2
r = execute_impl (a, t);
else
{
- if (ctx.sched.async (start_count,
- *task_count,
- [a] (const diag_frame* ds, target& t)
- {
- diag_frame::stack_guard dsg (ds);
- execute_impl (a, t);
- },
- diag_frame::stack (),
- ref (t)))
+ if (ctx.sched->async (start_count,
+ *task_count,
+ [a] (const diag_frame* ds, target& t)
+ {
+ diag_frame::stack_guard dsg (ds);
+ execute_impl (a, t);
+ },
+ diag_frame::stack (),
+ ref (t)))
return target_state::unknown; // Queued.
// Executed synchronously, fall through.
@@ -2551,7 +2551,7 @@ namespace build2
: s.state;
s.task_count.store (exec, memory_order_release);
- ctx.sched.resume (s.task_count);
+ ctx.sched->resume (s.task_count);
}
}
else
@@ -3096,7 +3096,7 @@ namespace build2
target_state gs (execute_impl (a, g, 0, nullptr));
if (gs == target_state::busy)
- ctx.sched.wait (ctx.count_executed (),
+ ctx.sched->wait (ctx.count_executed (),
g[a].task_count,
scheduler::work_none);
diff --git a/libbuild2/algorithm.ixx b/libbuild2/algorithm.ixx
index b87a535..6029290 100644
--- a/libbuild2/algorithm.ixx
+++ b/libbuild2/algorithm.ixx
@@ -753,7 +753,7 @@ namespace build2
if (r == target_state::busy)
{
- t.ctx.sched.wait (t.ctx.count_executed (),
+ t.ctx.sched->wait (t.ctx.count_executed (),
t[a].task_count,
scheduler::work_none);
@@ -789,7 +789,7 @@ namespace build2
// If the target is still busy, wait for its completion.
//
- ctx.sched.wait (ctx.count_executed (),
+ ctx.sched->wait (ctx.count_executed (),
t[a].task_count,
scheduler::work_none);
@@ -806,7 +806,7 @@ namespace build2
if (r == target_state::busy)
{
- t.ctx.sched.wait (t.ctx.count_executed (),
+ t.ctx.sched->wait (t.ctx.count_executed (),
t[a].task_count,
scheduler::work_none);
diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx
index e76cb7c..7a357d9 100644
--- a/libbuild2/cc/compile-rule.cxx
+++ b/libbuild2/cc/compile-rule.cxx
@@ -3449,7 +3449,7 @@ namespace build2
msvc_sanitize_cl (args);
- psrc = ctx.fcache.create (t.path () + pext, !modules);
+ psrc = ctx.fcache->create (t.path () + pext, !modules);
if (fc)
{
@@ -3601,7 +3601,7 @@ namespace build2
// Preprocessor output.
//
- psrc = ctx.fcache.create (t.path () + pext, !modules);
+ psrc = ctx.fcache->create (t.path () + pext, !modules);
args.push_back ("-o");
args.push_back (psrc.path ().string ().c_str ());
}
@@ -3896,7 +3896,7 @@ namespace build2
if (modules && (ctype != compiler_type::msvc ||
md.type != unit_type::module_intf))
{
- result.first = ctx.fcache.create_existing (t.path () + pext);
+ result.first = ctx.fcache->create_existing (t.path () + pext);
result.second = true;
}
@@ -7521,7 +7521,7 @@ namespace build2
// Compressed preprocessed file extension.
//
- string cpext (t.ctx.fcache.compressed_extension (pext));
+ string cpext (t.ctx.fcache->compressed_extension (pext));
clean_extras extras;
switch (ctype)
diff --git a/libbuild2/cc/link-rule.cxx b/libbuild2/cc/link-rule.cxx
index f860fdc..490e0b4 100644
--- a/libbuild2/cc/link-rule.cxx
+++ b/libbuild2/cc/link-rule.cxx
@@ -3964,7 +3964,7 @@ namespace build2
auto i (find_option_prefix ("-flto", args.rbegin (), args.rend ()));
if (i != args.rend () && strcmp (*i, "-flto=auto") == 0)
{
- jobs_extra = scheduler::alloc_guard (ctx.sched, 0);
+ jobs_extra = scheduler::alloc_guard (*ctx.sched, 0);
jobs_arg = "-flto=" + to_string (1 + jobs_extra.n);
*i = jobs_arg.c_str ();
}
@@ -3983,7 +3983,7 @@ namespace build2
strcmp (*i, "-flto=thin") == 0 &&
!find_option_prefix ("-flto-jobs=", args))
{
- jobs_extra = scheduler::alloc_guard (ctx.sched, 0);
+ jobs_extra = scheduler::alloc_guard (*ctx.sched, 0);
jobs_arg = "-flto-jobs=" + to_string (1 + jobs_extra.n);
args.insert (i.base (), jobs_arg.c_str ()); // After -flto=thin.
}
diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx
index b7429e0..90c4f6c 100644
--- a/libbuild2/context.cxx
+++ b/libbuild2/context.cxx
@@ -86,9 +86,9 @@ namespace build2
optional<context*> mc,
const loaded_modules_lock* ml)
: data_ (new data (*this)),
- sched (s),
- mutexes (ms),
- fcache (fc),
+ sched (&s),
+ mutexes (&ms),
+ fcache (&fc),
match_only (mo),
no_external_modules (nem),
dry_run_option (dr),
@@ -111,6 +111,8 @@ namespace build2
? optional<unique_ptr<context>> (nullptr)
: nullopt)
{
+ // NOTE: see also the bare minimum version below if adding anything here.
+
tracer trace ("context");
l6 ([&]{trace << "initializing build state";});
@@ -673,6 +675,42 @@ namespace build2
}
context::
+ context ()
+ : data_ (new data (*this)),
+ sched (nullptr),
+ mutexes (nullptr),
+ fcache (nullptr),
+ match_only (false),
+ no_external_modules (true),
+ dry_run_option (false),
+ no_diag_buffer (false),
+ keep_going (false),
+ phase_mutex (*this),
+ scopes (data_->scopes),
+ targets (data_->targets),
+ var_pool (data_->var_pool),
+ var_patterns (data_->var_patterns),
+ var_overrides (data_->var_overrides),
+ functions (data_->functions),
+ global_scope (create_global_scope (data_->scopes)),
+ global_target_types (data_->global_target_types),
+ global_override_cache (data_->global_override_cache),
+ global_var_overrides (data_->global_var_overrides),
+ modules_lock (nullptr),
+ module_context (nullptr)
+ {
+ variable_pool& vp (data_->var_pool);
+
+ var_src_root = &vp.insert<dir_path> ("src_root");
+ var_out_root = &vp.insert<dir_path> ("out_root");
+
+ var_project = &vp.insert<project_name> ("project");
+ var_amalgamation = &vp.insert<dir_path> ("amalgamation");
+
+ load_generation = 1;
+ }
+
+ context::
~context ()
{
// Cannot be inline since context::data is undefined.
@@ -812,11 +850,11 @@ namespace build2
{
++contention; // Protected by m_.
- ctx_.sched.deactivate (false /* external */);
+ ctx_.sched->deactivate (false /* external */);
for (; ctx_.phase != n; v->wait (l)) ;
r = !fail_;
l.unlock (); // Important: activate() can block.
- ctx_.sched.activate (false /* external */);
+ ctx_.sched->activate (false /* external */);
}
else
r = !fail_;
@@ -828,9 +866,9 @@ namespace build2
{
if (!lm_.try_lock ())
{
- ctx_.sched.deactivate (false /* external */);
+ ctx_.sched->deactivate (false /* external */);
lm_.lock ();
- ctx_.sched.activate (false /* external */);
+ ctx_.sched->activate (false /* external */);
++contention_load; // Protected by lm_.
}
@@ -880,9 +918,9 @@ namespace build2
// relock().
//
if (o == run_phase::match && n == run_phase::execute)
- ctx_.sched.push_phase ();
+ ctx_.sched->push_phase ();
else if (o == run_phase::execute && n == run_phase::match)
- ctx_.sched.pop_phase ();
+ ctx_.sched->pop_phase ();
if (v != nullptr)
{
@@ -937,9 +975,9 @@ namespace build2
// unlock().
//
if (o == run_phase::match && n == run_phase::execute)
- ctx_.sched.push_phase ();
+ ctx_.sched->push_phase ();
else if (o == run_phase::execute && n == run_phase::match)
- ctx_.sched.pop_phase ();
+ ctx_.sched->pop_phase ();
// Notify others that could be waiting for this phase.
//
@@ -953,11 +991,11 @@ namespace build2
{
++contention; // Protected by m_.
- ctx_.sched.deactivate (false /* external */);
+ ctx_.sched->deactivate (false /* external */);
for (; ctx_.phase != n; v->wait (l)) ;
r = !fail_;
l.unlock (); // Important: activate() can block.
- ctx_.sched.activate (false /* external */);
+ ctx_.sched->activate (false /* external */);
}
}
@@ -972,9 +1010,9 @@ namespace build2
//
s = false;
- ctx_.sched.deactivate (false /* external */);
+ ctx_.sched->deactivate (false /* external */);
lm_.lock ();
- ctx_.sched.activate (false /* external */);
+ ctx_.sched->activate (false /* external */);
++contention_load; // Protected by lm_.
}
diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx
index c040927..35ba11d 100644
--- a/libbuild2/context.hxx
+++ b/libbuild2/context.hxx
@@ -211,9 +211,11 @@ namespace build2
unique_ptr<data> data_;
public:
- scheduler& sched;
- global_mutexes& mutexes;
- file_cache& fcache;
+ // These are only NULL for the "bare minimum" context (see below).
+ //
+ scheduler* sched;
+ global_mutexes* mutexes;
+ file_cache* fcache;
// Match only flag (see --match-only but also dist).
//
@@ -677,7 +679,6 @@ namespace build2
reserves (size_t t, size_t v): targets (t), variables (v) {}
};
- explicit
context (scheduler&,
global_mutexes&,
file_cache&,
@@ -691,6 +692,14 @@ namespace build2
optional<context*> module_context = nullptr,
const loaded_modules_lock* inherited_mudules_lock = nullptr);
+ // Special context with bare minimum of initializations. It is only
+ // guaranteed to be sufficiently initialized to call extract_variable().
+ //
+ // Note that for this purpose you may omit calls to init_diag() and
+ // init().
+ //
+ context ();
+
// Reserve elements in containers to avoid re-allocation/re-hashing. Zero
// values are ignored (that is, the corresponding container reserve()
// function is not called). Can only be called in the load phase.
diff --git a/libbuild2/context.ixx b/libbuild2/context.ixx
index 95c5416..7b2a405 100644
--- a/libbuild2/context.ixx
+++ b/libbuild2/context.ixx
@@ -57,7 +57,7 @@ namespace build2
wait ()
{
phase_unlock u (*ctx, phase, true /* delay */);
- ctx->sched.wait (start_count, *task_count, u);
+ ctx->sched->wait (start_count, *task_count, u);
task_count = nullptr;
}
}
diff --git a/libbuild2/diagnostics.cxx b/libbuild2/diagnostics.cxx
index b31ff82..e164f10 100644
--- a/libbuild2/diagnostics.cxx
+++ b/libbuild2/diagnostics.cxx
@@ -18,11 +18,11 @@ using namespace butl;
namespace build2
{
- // Diagnostics state (verbosity level, progress, etc). Keep disabled until
- // set from options.
+ // Diagnostics state (verbosity level, progress, etc). Keep default/disabled
+ // until set from options.
//
- uint16_t verb = 0;
- bool silent = true;
+ uint16_t verb = 1;
+ bool silent = false;
optional<bool> diag_progress_option;
optional<bool> diag_color_option;
@@ -621,7 +621,7 @@ namespace build2
int diag_buffer::
pipe (context& ctx, bool force)
{
- return (ctx.sched.serial () || ctx.no_diag_buffer) && !force ? 2 : -1;
+ return (ctx.sched->serial () || ctx.no_diag_buffer) && !force ? 2 : -1;
}
void diag_buffer::
@@ -629,7 +629,7 @@ namespace build2
{
assert (state_ == state::closed && args0 != nullptr);
- serial = ctx_.sched.serial ();
+ serial = ctx_.sched->serial ();
nobuf = !serial && ctx_.no_diag_buffer;
if (fd != nullfd)
@@ -653,7 +653,7 @@ namespace build2
{
assert (state_ == state::closed && args0 != nullptr);
- serial = ctx_.sched.serial ();
+ serial = ctx_.sched->serial ();
nobuf = !serial && ctx_.no_diag_buffer;
this->args0 = args0;
state_ = state::eof;
diff --git a/libbuild2/module.cxx b/libbuild2/module.cxx
index 234b469..0928307 100644
--- a/libbuild2/module.cxx
+++ b/libbuild2/module.cxx
@@ -81,9 +81,9 @@ namespace build2
// adding a reasonable margin for future growth.
//
ctx.module_context_storage->reset (
- new context (ctx.sched,
- ctx.mutexes,
- ctx.fcache,
+ new context (*ctx.sched,
+ *ctx.mutexes,
+ *ctx.fcache,
false, /* match_only */
false, /* no_external_modules */
false, /* dry_run */
@@ -144,8 +144,8 @@ namespace build2
// keep it in case things change. Actually, we may need it, if the
// scheduler was started up in a tuned state, like in bpkg).
//
- auto sched_tune (ctx.sched.serial ()
- ? scheduler::tune_guard (ctx.sched, 0)
+ auto sched_tune (ctx.sched->serial ()
+ ? scheduler::tune_guard (*ctx.sched, 0)
: scheduler::tune_guard ());
// Remap verbosity level 0 to 1 unless we were requested to be silent.
@@ -429,7 +429,7 @@ namespace build2
//
auto_thread_env penv (nullptr);
context& ctx (*bs.ctx.module_context);
- scheduler::phase_guard pg (ctx.sched);
+ scheduler::phase_guard pg (*ctx.sched);
// Load the imported project in the module context.
//
diff --git a/libbuild2/operation.cxx b/libbuild2/operation.cxx
index 2e5886c..d84db4f 100644
--- a/libbuild2/operation.cxx
+++ b/libbuild2/operation.cxx
@@ -278,11 +278,11 @@ namespace build2
// through a few hoops to make sure we don't overindulge.
//
md.incr = stderr_term // Scale depending on output type.
- ? (ctx.sched.serial () ? 1 : 5)
+ ? (ctx.sched->serial () ? 1 : 5)
: 100;
md.what = " targets to " + diag_do (ctx, a);
- mg = ctx.sched.monitor (
+ mg = ctx.sched->monitor (
ctx.target_count,
md.incr,
[&md] (size_t c) -> size_t
@@ -571,7 +571,7 @@ namespace build2
switch (ctx.current_inner_oif->concurrency)
{
- case 0: sched_tune = tune_guard (ctx.sched, 1); break; // Run serially.
+ case 0: sched_tune = tune_guard (*ctx.sched, 1); break; // Run serially.
case 1: break; // Run as is.
default: assert (false); // Not supported.
}
@@ -594,7 +594,7 @@ namespace build2
{
what = "% of targets " + diag_did (ctx, a);
- mg = ctx.sched.monitor (
+ mg = ctx.sched->monitor (
ctx.target_count,
init - incr,
[init, incr, &what, &ctx] (size_t c) -> size_t
diff --git a/libbuild2/script/run.cxx b/libbuild2/script/run.cxx
index 1106421..6d73a7e 100644
--- a/libbuild2/script/run.cxx
+++ b/libbuild2/script/run.cxx
@@ -2984,7 +2984,7 @@ namespace build2
// If/when required we could probably support the precise sleep
// mode (e.g., via an option).
//
- env.context.sched.sleep (t);
+ env.context.sched->sleep (t);
}
};
diff --git a/libbuild2/test/rule.cxx b/libbuild2/test/rule.cxx
index 2d02d39..81bf50a 100644
--- a/libbuild2/test/rule.cxx
+++ b/libbuild2/test/rule.cxx
@@ -563,22 +563,22 @@ namespace build2
{
scope_state& r (res.back ());
- if (!ctx.sched.async (ctx.count_busy (),
- t[a].task_count,
- [this] (const diag_frame* ds,
- scope_state& r,
- const target& t,
- const testscript& ts,
- const dir_path& wd)
- {
- diag_frame::stack_guard dsg (ds);
- r = perform_script_impl (t, ts, wd, *this);
- },
- diag_frame::stack (),
- ref (r),
- cref (t),
- cref (ts),
- cref (wd)))
+ if (!ctx.sched->async (ctx.count_busy (),
+ t[a].task_count,
+ [this] (const diag_frame* ds,
+ scope_state& r,
+ const target& t,
+ const testscript& ts,
+ const dir_path& wd)
+ {
+ diag_frame::stack_guard dsg (ds);
+ r = perform_script_impl (t, ts, wd, *this);
+ },
+ diag_frame::stack (),
+ ref (r),
+ cref (t),
+ cref (ts),
+ cref (wd)))
{
// Executed synchronously. If failed and we were not asked to
// keep going, bail out.
diff --git a/libbuild2/test/script/parser.cxx b/libbuild2/test/script/parser.cxx
index 60656a1..b712c21 100644
--- a/libbuild2/test/script/parser.cxx
+++ b/libbuild2/test/script/parser.cxx
@@ -1831,19 +1831,19 @@ namespace build2
// UBSan workaround.
//
const diag_frame* df (diag_frame::stack ());
- if (!ctx->sched.async (task_count,
- [] (const diag_frame* ds,
- scope& s,
- script& scr,
- runner& r)
- {
- diag_frame::stack_guard dsg (ds);
- execute_impl (s, scr, r);
- },
- df,
- ref (*chain),
- ref (*script_),
- ref (*runner_)))
+ if (!ctx->sched->async (task_count,
+ [] (const diag_frame* ds,
+ scope& s,
+ script& scr,
+ runner& r)
+ {
+ diag_frame::stack_guard dsg (ds);
+ execute_impl (s, scr, r);
+ },
+ df,
+ ref (*chain),
+ ref (*script_),
+ ref (*runner_)))
{
// Bail out if the scope has failed and we weren't instructed
// to keep going.
diff --git a/libbuild2/variable.cxx b/libbuild2/variable.cxx
index d55737b..8c52e22 100644
--- a/libbuild2/variable.cxx
+++ b/libbuild2/variable.cxx
@@ -369,8 +369,8 @@ namespace build2
// Typification is kind of like caching so we reuse that mutex shard.
//
shared_mutex& m (
- ctx.mutexes.variable_cache[
- hash<value*> () (&v) % ctx.mutexes.variable_cache_size]);
+ ctx.mutexes->variable_cache[
+ hash<value*> () (&v) % ctx.mutexes->variable_cache_size]);
// Note: v.type is rechecked by typify() under lock.
//
diff --git a/libbuild2/variable.txx b/libbuild2/variable.txx
index 2950ea0..2c1265a 100644
--- a/libbuild2/variable.txx
+++ b/libbuild2/variable.txx
@@ -1019,8 +1019,8 @@ namespace build2
: 0);
shared_mutex& m (
- ctx.mutexes.variable_cache[
- hash<variable_cache*> () (this) % ctx.mutexes.variable_cache_size]);
+ ctx.mutexes->variable_cache[
+ hash<variable_cache*> () (this) % ctx.mutexes->variable_cache_size]);
slock sl (m);
ulock ul (m, defer_lock);