aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/algorithm.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/algorithm.ixx')
-rw-r--r--libbuild2/algorithm.ixx311
1 files changed, 262 insertions, 49 deletions
diff --git a/libbuild2/algorithm.ixx b/libbuild2/algorithm.ixx
index 24d9e5b..9f1b70f 100644
--- a/libbuild2/algorithm.ixx
+++ b/libbuild2/algorithm.ixx
@@ -45,6 +45,39 @@ namespace build2
k.proj, {&tt, k.tk.dir, k.tk.out, k.tk.name, k.tk.ext}, k.scope});
}
+ inline const target*
+ search_exsiting (context& ctx,
+ const target_type& tt,
+ const prerequisite_key& k)
+ {
+ return search_existing (
+ ctx,
+ prerequisite_key {
+ k.proj, {&tt, k.tk.dir, k.tk.out, k.tk.name, k.tk.ext}, k.scope});
+ }
+
+ inline const target&
+ search_new (context& ctx,
+ const target_type& tt,
+ const prerequisite_key& k)
+ {
+ return search_new (
+ ctx,
+ prerequisite_key {
+ k.proj, {&tt, k.tk.dir, k.tk.out, k.tk.name, k.tk.ext}, k.scope});
+ }
+
+ inline pair<target&, ulock>
+ search_new_locked (context& ctx,
+ const target_type& tt,
+ const prerequisite_key& k)
+ {
+ return search_new_locked (
+ ctx,
+ prerequisite_key {
+ k.proj, {&tt, k.tk.dir, k.tk.out, k.tk.name, k.tk.ext}, k.scope});
+ }
+
inline const target&
search (const target& t,
const target_type& type,
@@ -110,6 +143,48 @@ namespace build2
scope});
}
+ inline const target&
+ search_new (context& ctx,
+ const target_type& type,
+ const dir_path& dir,
+ const dir_path& out,
+ const string& name,
+ const string* ext,
+ const scope* scope)
+ {
+ return search_new (
+ ctx,
+ prerequisite_key {
+ nullopt,
+ {
+ &type,
+ &dir, &out, &name,
+ ext != nullptr ? optional<string> (*ext) : nullopt
+ },
+ scope});
+ }
+
+ inline pair<target&, ulock>
+ search_new_locked (context& ctx,
+ const target_type& type,
+ const dir_path& dir,
+ const dir_path& out,
+ const string& name,
+ const string* ext,
+ const scope* scope)
+ {
+ return search_new_locked (
+ ctx,
+ prerequisite_key {
+ nullopt,
+ {
+ &type,
+ &dir, &out, &name,
+ ext != nullptr ? optional<string> (*ext) : nullopt
+ },
+ scope});
+ }
+
template <typename T>
inline const T&
search (const target& t,
@@ -123,6 +198,21 @@ namespace build2
t, T::static_type, dir, out, name, ext, scope).template as<T> ();
}
+ template <typename T>
+ inline const T*
+ search_existing (context& ctx,
+ const dir_path& dir,
+ const dir_path& out,
+ const string& name,
+ const string* ext,
+ const scope* scope)
+ {
+ const target* r (
+ search_existing (
+ ctx, T::static_type, dir, out, name, ext, scope));
+ return r != nullptr ? &r->template as<T> () : nullptr;
+ }
+
LIBBUILD2_SYMEXPORT target_lock
lock_impl (action, const target&, optional<scheduler::work_queue>);
@@ -130,8 +220,8 @@ namespace build2
unlock_impl (action, target&, size_t);
inline target_lock::
- target_lock (action_type a, target_type* t, size_t o)
- : action (a), target (t), offset (o)
+ target_lock (action_type a, target_type* t, size_t o, bool f)
+ : action (a), target (t), offset (o), first (f)
{
if (target != nullptr)
prev = stack (this);
@@ -143,7 +233,8 @@ namespace build2
if (target != nullptr && prev != this)
{
const target_lock* cur (stack (prev));
- assert (cur == this);
+ if (cur != this) // NDEBUG
+ assert (cur == this);
prev = this;
}
}
@@ -158,7 +249,8 @@ namespace build2
if (prev != this)
{
const target_lock* cur (stack (prev));
- assert (cur == this);
+ if (cur != this) // NDEBUG
+ assert (cur == this);
}
target = nullptr;
@@ -168,14 +260,15 @@ namespace build2
inline auto target_lock::
release () -> data
{
- data r {action, target, offset};
+ data r {action, target, offset, first};
if (target != nullptr)
{
if (prev != this)
{
const target_lock* cur (stack (prev));
- assert (cur == this);
+ if (cur != this) // NDEBUG
+ assert (cur == this);
}
target = nullptr;
@@ -191,7 +284,7 @@ namespace build2
}
inline target_lock::
- target_lock (target_lock&& x)
+ target_lock (target_lock&& x) noexcept
: action (x.action), target (x.target), offset (x.offset)
{
if (target != nullptr)
@@ -199,7 +292,8 @@ namespace build2
if (x.prev != &x)
{
const target_lock* cur (stack (this));
- assert (cur == &x);
+ if (cur != &x) // NDEBUG
+ assert (cur == &x);
prev = x.prev;
}
else
@@ -210,7 +304,7 @@ namespace build2
}
inline target_lock& target_lock::
- operator= (target_lock&& x)
+ operator= (target_lock&& x) noexcept
{
if (this != &x)
{
@@ -225,7 +319,8 @@ namespace build2
if (x.prev != &x)
{
const target_lock* cur (stack (this));
- assert (cur == &x);
+ if (cur != &x) // NDEBUG
+ assert (cur == &x);
prev = x.prev;
}
else
@@ -297,48 +392,66 @@ namespace build2
}
LIBBUILD2_SYMEXPORT const rule_match*
- match_rule (action, target&, const rule* skip, bool try_match = false);
+ match_rule (action, target&,
+ const rule* skip,
+ bool try_match = false,
+ match_extra* = nullptr);
LIBBUILD2_SYMEXPORT recipe
apply_impl (action, target&, const rule_match&);
LIBBUILD2_SYMEXPORT pair<bool, target_state>
- match (action, const target&, size_t, atomic_count*, bool try_match = false);
+ match_impl (action, const target&,
+ size_t, atomic_count*,
+ bool try_match = false);
inline void
- match_inc_dependens (action a, const target& t)
+ match_inc_dependents (action a, const target& t)
{
t.ctx.dependency_count.fetch_add (1, memory_order_relaxed);
t[a].dependents.fetch_add (1, memory_order_release);
}
inline target_state
- match (action a, const target& t, bool fail)
+ match_sync (action a, const target& t, bool fail)
{
assert (t.ctx.phase == run_phase::match);
- target_state r (match (a, t, 0, nullptr).second);
+ target_state r (match_impl (a, t, 0, nullptr).second);
if (r != target_state::failed)
- match_inc_dependens (a, t);
+ match_inc_dependents (a, t);
else if (fail)
throw failed ();
return r;
}
+ inline target_state
+ match_direct_sync (action a, const target& t, bool fail)
+ {
+ assert (t.ctx.phase == run_phase::match);
+
+ target_state r (match_impl (a, t, 0, nullptr).second);
+
+ if (r == target_state::failed && fail)
+ throw failed ();
+
+ return r;
+ }
+
inline pair<bool, target_state>
- try_match (action a, const target& t, bool fail)
+ try_match_sync (action a, const target& t, bool fail)
{
assert (t.ctx.phase == run_phase::match);
pair<bool, target_state> r (
- match (a, t, 0, nullptr, true /* try_match */));
+ match_impl (a, t, 0, nullptr, true /* try_match */));
if (r.first)
{
if (r.second != target_state::failed)
- match_inc_dependens (a, t);
+ match_inc_dependents (a, t);
else if (fail)
throw failed ();
}
@@ -347,11 +460,11 @@ namespace build2
}
inline pair<bool, target_state>
- match (action a, const target& t, unmatch um)
+ match_sync (action a, const target& t, unmatch um)
{
assert (t.ctx.phase == run_phase::match);
- target_state s (match (a, t, 0, nullptr).second);
+ target_state s (match_impl (a, t, 0, nullptr).second);
if (s == target_state::failed)
throw failed ();
@@ -385,7 +498,7 @@ namespace build2
}
}
- match_inc_dependens (a, t);
+ match_inc_dependents (a, t);
return make_pair (false, s);;
}
@@ -397,23 +510,49 @@ namespace build2
context& ctx (t.ctx);
assert (ctx.phase == run_phase::match);
- target_state r (match (a, t, sc, &tc).second);
+ target_state r (match_impl (a, t, sc, &tc).second);
- if (fail && !ctx.keep_going && r == target_state::failed)
+ if (r == target_state::failed && fail && !ctx.keep_going)
throw failed ();
return r;
}
+ inline target_state
+ match_complete (action a, const target& t, bool fail)
+ {
+ return match_sync (a, t, fail);
+ }
+
+ inline pair<bool, target_state>
+ match_complete (action a, const target& t, unmatch um)
+ {
+ return match_sync (a, t, um);
+ }
+
// Clear rule match-specific target data.
//
inline void
clear_target (action a, target& t)
{
- t[a].vars.clear ();
+ target::opstate& s (t.state[a]);
+ s.recipe = nullptr;
+ s.recipe_keep = false;
+ s.resolve_counted = false;
+ s.vars.clear ();
t.prerequisite_targets[a].clear ();
- if (a.inner ())
- t.clear_data ();
+ }
+
+ LIBBUILD2_SYMEXPORT void
+ set_rule_trace (target_lock&, const rule_match*);
+
+ inline void
+ set_rule (target_lock& l, const rule_match* r)
+ {
+ if (l.target->ctx.trace_match == nullptr)
+ (*l.target)[l.action].rule = r;
+ else
+ set_rule_trace (l, r);
}
inline void
@@ -423,6 +562,7 @@ namespace build2
target::opstate& s (t[l.action]);
s.recipe = move (r);
+ s.recipe_group_action = false;
// If this is a noop recipe, then mark the target unchanged to allow for
// some optimizations.
@@ -448,9 +588,11 @@ namespace build2
// likely. The alternative (trying to "merge" the count keeping track of
// whether inner and/or outer is noop) gets hairy rather quickly.
//
- if (l.action.inner ())
+ if (f != nullptr && *f == &group_action)
+ s.recipe_group_action = true;
+ else
{
- if (f == nullptr || *f != &group_action)
+ if (l.action.inner ())
t.ctx.target_count.fetch_add (1, memory_order_relaxed);
}
}
@@ -464,7 +606,7 @@ namespace build2
l.target->ctx.phase == run_phase::match);
clear_target (l.action, *l.target);
- (*l.target)[l.action].rule = nullptr; // No rule.
+ set_rule (l, nullptr); // No rule.
set_recipe (l, move (r));
l.offset = target::offset_applied;
}
@@ -477,7 +619,7 @@ namespace build2
l.target->ctx.phase == run_phase::match);
clear_target (l.action, *l.target);
- (*l.target)[l.action].rule = &r;
+ set_rule (l, &r);
l.offset = target::offset_matched;
}
@@ -499,18 +641,18 @@ namespace build2
// In a sense this is like any other dependency.
//
assert (a.outer ());
- return match (a.inner_action (), t);
+ return match_sync (a.inner_action (), t);
}
inline pair<bool, target_state>
match_inner (action a, const target& t, unmatch um)
{
assert (a.outer ());
- return match (a.inner_action (), t, um);
+ return match_sync (a.inner_action (), t, um);
}
LIBBUILD2_SYMEXPORT void
- resolve_group_impl (action, const target&, target_lock);
+ resolve_group_impl (action, const target&, target_lock&&);
inline const target*
resolve_group (action a, const target& t)
@@ -544,7 +686,7 @@ namespace build2
inline void
inject (action a, target& t, const target& p)
{
- match (a, p);
+ match_sync (a, p);
t.prerequisite_targets[a].emplace_back (&p);
}
@@ -608,23 +750,26 @@ namespace build2
}
LIBBUILD2_SYMEXPORT target_state
- execute (action, const target&, size_t, atomic_count*);
+ execute_impl (action, const target&, size_t, atomic_count*);
inline target_state
- execute (action a, const target& t)
+ execute_sync (action a, const target& t, bool fail)
{
- return execute (a, t, 0, nullptr);
- }
+ target_state r (execute_impl (a, t, 0, nullptr));
- inline target_state
- execute_wait (action a, const target& t)
- {
- if (execute (a, t) == target_state::busy)
- t.ctx.sched.wait (t.ctx.count_executed (),
+ if (r == target_state::busy)
+ {
+ t.ctx.sched->wait (t.ctx.count_executed (),
t[a].task_count,
scheduler::work_none);
- return t.executed_state (a);
+ r = t.executed_state (a, false);
+ }
+
+ if (r == target_state::failed && fail)
+ throw failed ();
+
+ return r;
}
inline target_state
@@ -632,9 +777,62 @@ namespace build2
size_t sc, atomic_count& tc,
bool fail)
{
- target_state r (execute (a, t, sc, &tc));
+ target_state r (execute_impl (a, t, sc, &tc));
+
+ if (r == target_state::failed && fail && !t.ctx.keep_going)
+ throw failed ();
+
+ return r;
+ }
+
+ inline target_state
+ execute_complete (action a, const target& t)
+ {
+ // Note: standard operation execute() sidesteps this and calls
+ // executed_state() directly.
+
+ context& ctx (t.ctx);
+
+ // If the target is still busy, wait for its completion.
+ //
+ ctx.sched->wait (ctx.count_executed (),
+ t[a].task_count,
+ scheduler::work_none);
+
+ return t.executed_state (a);
+ }
+
+ LIBBUILD2_SYMEXPORT target_state
+ execute_direct_impl (action, const target&, size_t, atomic_count*);
+
+ inline target_state
+ execute_direct_sync (action a, const target& t, bool fail)
+ {
+ target_state r (execute_direct_impl (a, t, 0, nullptr));
+
+ if (r == target_state::busy)
+ {
+ t.ctx.sched->wait (t.ctx.count_executed (),
+ t[a].task_count,
+ scheduler::work_none);
+
+ r = t.executed_state (a, false);
+ }
+
+ if (r == target_state::failed && fail)
+ throw failed ();
+
+ return r;
+ }
+
+ inline target_state
+ execute_direct_async (action a, const target& t,
+ size_t sc, atomic_count& tc,
+ bool fail)
+ {
+ target_state r (execute_direct_impl (a, t, sc, &tc));
- if (fail && !t.ctx.keep_going && r == target_state::failed)
+ if (r == target_state::failed && fail && !t.ctx.keep_going)
throw failed ();
return r;
@@ -650,7 +848,7 @@ namespace build2
execute_inner (action a, const target& t)
{
assert (a.outer ());
- return execute_wait (a.inner_action (), t);
+ return execute_sync (a.inner_action (), t);
}
inline target_state
@@ -726,6 +924,12 @@ namespace build2
const timestamp&, const execute_filter&,
size_t);
+ LIBBUILD2_SYMEXPORT pair<optional<target_state>, const target*>
+ reverse_execute_prerequisites (const target_type*,
+ action, const target&,
+ const timestamp&, const execute_filter&,
+ size_t);
+
inline optional<target_state>
execute_prerequisites (action a, const target& t,
const timestamp& mt, const execute_filter& ef,
@@ -734,6 +938,14 @@ namespace build2
return execute_prerequisites (nullptr, a, t, mt, ef, n).first;
}
+ inline optional<target_state>
+ reverse_execute_prerequisites (action a, const target& t,
+ const timestamp& mt, const execute_filter& ef,
+ size_t n)
+ {
+ return reverse_execute_prerequisites (nullptr, a, t, mt, ef, n).first;
+ }
+
template <typename T>
inline pair<optional<target_state>, const T&>
execute_prerequisites (action a, const target& t,
@@ -767,8 +979,9 @@ namespace build2
p.first, static_cast<const T&> (p.second));
}
+ template <typename T>
inline target_state
- execute_members (action a, const target& t, const target* ts[], size_t n)
+ execute_members (action a, const target& t, T ts[], size_t n)
{
return t.ctx.current_mode == execution_mode::first
? straight_execute_members (a, t, ts, n, 0)