aboutsummaryrefslogtreecommitdiff
path: root/build2/target.ixx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-01-20 13:46:11 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-02-03 14:35:45 +0200
commit934f2a9a90c5cad3cdc8a66b50c17827a3ddbcee (patch)
treef35f106e5369e98350327c79080c571195234c0b /build2/target.ixx
parent280f4a5bf787587227ca193cd59c6bd74091db70 (diff)
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.
Diffstat (limited to 'build2/target.ixx')
-rw-r--r--build2/target.ixx104
1 files changed, 39 insertions, 65 deletions
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<bool, target_state> 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<recipe_function*> ())
+ if (recipe_function* const* f = s.recipe.target<recipe_function*> ())
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<bool, target_state> r (state (a));
+ pair<bool, target_state> r (matched_state_impl (a));
if (fail && (!r.first || r.second == target_state::failed))
throw failed ();
@@ -102,9 +124,9 @@ namespace build2
}
inline pair<bool, target_state> target::
- try_matched_state (action_type a, bool fail) const
+ try_matched_state (action a, bool fail) const
{
- pair<bool, target_state> r (state (a));
+ pair<bool, target_state> 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<recipe_function*> ());
-
- 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