From 934f2a9a90c5cad3cdc8a66b50c17827a3ddbcee Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 20 Jan 2018 13:46:11 +0200 Subject: Get rid of action rule override semantics Instead we now have two more or less separate match states for outer and inner parts of an action. --- build2/target.ixx | 104 ++++++++++++++++++++---------------------------------- 1 file changed, 39 insertions(+), 65 deletions(-) (limited to 'build2/target.ixx') diff --git a/build2/target.ixx b/build2/target.ixx index 6225aef..16dbf61 100644 --- a/build2/target.ixx +++ b/build2/target.ixx @@ -62,26 +62,48 @@ namespace build2 } } + inline pair target:: + matched_state_impl (action a) const + { + assert (phase == run_phase::match); + + const opstate& s (state[a]); + size_t o (s.task_count.load (memory_order_relaxed) - // Synchronized. + target::count_base ()); + + if (o == target::offset_tried) + return make_pair (false, target_state::unknown); + else + { + // Normally applied but can also be already executed. + // + assert (o == target::offset_applied || o == target::offset_executed); + return make_pair (true, (group_state (a) ? group->state[a] : s).state); + } + } + inline target_state target:: - state () const + executed_state_impl (action a) const { assert (phase == run_phase::execute); - return group_state () ? group->state_ : state_; + return (group_state (a) ? group->state : state)[a].state; } inline bool target:: - group_state () const + group_state (action a) const { // We go an extra step and short-circuit to the target state even if the // raw state is not group provided the recipe is group_recipe and the // state is not failed. + // + const opstate& s (state[a]); - if (state_ == target_state::group) + if (s.state == target_state::group) return true; - if (state_ != target_state::failed && group != nullptr) + if (s.state != target_state::failed && group != nullptr) { - if (recipe_function* const* f = recipe_.target ()) + if (recipe_function* const* f = s.recipe.target ()) return *f == &group_action; } @@ -89,11 +111,11 @@ namespace build2 } inline target_state target:: - matched_state (action_type a, bool fail) const + matched_state (action a, bool fail) const { // Note that the target could be being asynchronously re-matched. // - pair r (state (a)); + pair r (matched_state_impl (a)); if (fail && (!r.first || r.second == target_state::failed)) throw failed (); @@ -102,9 +124,9 @@ namespace build2 } inline pair target:: - try_matched_state (action_type a, bool fail) const + try_matched_state (action a, bool fail) const { - pair r (state (a)); + pair r (matched_state_impl (a)); if (fail && r.first && r.second == target_state::failed) throw failed (); @@ -113,22 +135,9 @@ namespace build2 } inline target_state target:: - executed_state (bool fail) const - { - target_state r (state ()); - - if (fail && r == target_state::failed) - throw failed (); - - return r; - } - - inline target_state target:: - serial_state (bool fail) const + executed_state (action a, bool fail) const { - //assert (sched.serial ()); - - target_state r (group_state () ? group->state_ : state_); + target_state r (executed_state_impl (a)); if (fail && r == target_state::failed) throw failed (); @@ -136,44 +145,6 @@ namespace build2 return r; } - extern atomic_count target_count; // context.hxx - - inline void target:: - recipe (recipe_type r) - { - recipe_ = move (r); - - // Do not clear the failed target state in case of an override (and we - // should never see the failed state from the previous operation since we - // should abort the execution in this case). - // - if (state_ != target_state::failed) - { - state_ = target_state::unknown; - - // If this is a noop recipe, then mark the target unchanged to allow for - // some optimizations. - // - recipe_function** f (recipe_.target ()); - - if (f != nullptr && *f == &noop_action) - state_ = target_state::unchanged; - else - { - // This gets tricky when we start considering overrides (which can - // only happen for noop recipes), direct execution, etc. So here seems - // like the best place to do this. - // - // We also ignore the group recipe since it is used for ad hoc - // groups (which are not executed). Plus, group action means real - // recipe is in the group so this also feels right conceptually. - // - if (f == nullptr || *f != &group_action) - target_count.fetch_add (1, memory_order_relaxed); - } - } - } - // mark()/unmark() // @@ -323,7 +294,8 @@ namespace build2 inline timestamp mtime_target:: load_mtime (const path& p) const { - assert (phase == run_phase::execute && !group_state ()); + assert (phase == run_phase::execute && + !group_state (action () /* inner */)); duration::rep r (mtime_.load (memory_order_consume)); if (r == timestamp_unknown_rep) @@ -349,7 +321,9 @@ namespace build2 // much we can do here except detect the case where the target was // changed on this run. // - return mt < mp || (mt == mp && state () == target_state::changed); + return mt < mp || (mt == mp && + executed_state_impl (action () /* inner */) == + target_state::changed); } // path_target -- cgit v1.1