diff options
Diffstat (limited to 'libbuild2/target.ixx')
-rw-r--r-- | libbuild2/target.ixx | 70 |
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, |