aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/target.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/target.ixx')
-rw-r--r--libbuild2/target.ixx70
1 files changed, 54 insertions, 16 deletions
diff --git a/libbuild2/target.ixx b/libbuild2/target.ixx
index 5432f7c..39b81e7 100644
--- a/libbuild2/target.ixx
+++ b/libbuild2/target.ixx
@@ -136,10 +136,13 @@ namespace build2
// match_extra
//
inline void match_extra::
- init (bool f)
+ reinit (bool f)
{
clear_data ();
fallback = f;
+ cur_options = all_options;
+ new_options = 0;
+ posthoc_prerequisite_targets = nullptr;
}
inline void match_extra::
@@ -235,17 +238,30 @@ namespace build2
}
inline bool target::
- matched (action a) const
+ matched (action a, memory_order mo) const
{
assert (ctx.phase == run_phase::match ||
ctx.phase == run_phase::execute);
const opstate& s (state[a]);
- size_t c (s.task_count.load (memory_order_relaxed) - ctx.count_base ());
+ size_t c (s.task_count.load (mo));
+ size_t b (ctx.count_base ()); // Note: cannot do (c - b)!
if (ctx.phase == run_phase::match)
{
- return c == offset_applied;
+ // While it will normally be applied, it could also be already executed
+ // or being relocked to reapply match options (see lock_impl() for
+ // background).
+ //
+ // Note that we can't just do >= offset_applied since offset_busy can
+ // also mean it is being matched.
+ //
+ // See also matched_state_impl(), mtime() for similar logic.
+ //
+ return (c == (b + offset_applied) ||
+ c == (b + offset_executed) ||
+ (c >= (b + offset_busy) &&
+ s.match_extra.cur_options_.load (memory_order_relaxed) != 0));
}
else
{
@@ -253,13 +269,10 @@ namespace build2
// least offset_matched since it must have been "achieved" before the
// phase switch.
//
- return c >= offset_matched;
+ return c >= (b + offset_matched);
}
}
- LIBBUILD2_SYMEXPORT target_state
- group_action (action, const target&); // <libbuild2/algorithm.hxx>
-
inline bool target::
group_state (action a) const
{
@@ -273,6 +286,19 @@ namespace build2
// @@ Hm, I wonder why not just return s.recipe_group_action now that we
// cache it.
//
+
+ // This special hack allows us to do things like query an ad hoc member's
+ // state or mtime without matching/executing the member, only the group.
+ // Requiring matching/executing the member would be too burdensome and
+ // this feels harmless (ad hoc membership cannot be changed during the
+ // execute phase).
+ //
+ // Note: this test must come first since the member may not be matched and
+ // thus its state uninitialized.
+ //
+ if (ctx.phase == run_phase::execute && adhoc_group_member ())
+ return true;
+
const opstate& s (state[a]);
if (s.state == target_state::group)
@@ -293,17 +319,22 @@ namespace build2
// Note: already synchronized.
//
- size_t o (s.task_count.load (memory_order_relaxed) - ctx.count_base ());
+ size_t c (s.task_count.load (memory_order_relaxed));
+ size_t b (ctx.count_base ()); // Note: cannot do (c - b)!
- if (o == offset_tried)
+ if (c == (b + offset_tried))
return make_pair (false, target_state::unknown);
else
{
- // Normally applied but can also be already executed. Note that in the
- // latter case we are guaranteed to be synchronized since we are in the
- // match phase.
+ // The same semantics as in target::matched(). Note that in the executed
+ // case we are guaranteed to be synchronized since we are in the match
+ // phase.
//
- assert (o == offset_applied || o == offset_executed);
+ assert (c == (b + offset_applied) ||
+ c == (b + offset_executed) ||
+ (c >= (b + offset_busy) &&
+ s.match_extra.cur_options_.load (memory_order_relaxed) != 0));
+
return make_pair (true, (group_state (a) ? group->state[a] : s).state);
}
}
@@ -715,8 +746,13 @@ namespace build2
inline timestamp mtime_target::
load_mtime (const path& p) const
{
- assert (ctx.phase == run_phase::execute &&
- !group_state (action () /* inner */));
+ // We can only enforce "not group state" during the execute phase. During
+ // match (e.g., the target is being matched), we will just have to pay
+ // attention.
+ //
+ assert (ctx.phase == run_phase::match ||
+ (ctx.phase == run_phase::execute &&
+ !group_state (action () /* inner */)));
duration::rep r (mtime_.load (memory_order_consume));
if (r == timestamp_unknown_rep)
@@ -733,6 +769,8 @@ namespace build2
inline bool mtime_target::
newer (timestamp mt, target_state s) const
{
+ assert (s != target_state::unknown); // Should be executed.
+
timestamp mp (mtime ());
// What do we do if timestamps are equal? This can happen, for example,