aboutsummaryrefslogtreecommitdiff
path: root/build2/target.cxx
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.cxx
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.cxx')
-rw-r--r--build2/target.cxx98
1 files changed, 7 insertions, 91 deletions
diff --git a/build2/target.cxx b/build2/target.cxx
index a5316ce..201bd15 100644
--- a/build2/target.cxx
+++ b/build2/target.cxx
@@ -92,7 +92,7 @@ namespace build2
}
group_view target::
- group_members (action_type) const
+ group_members (action) const
{
assert (false); // Not a group or doesn't expose its members.
return group_view {nullptr, 0};
@@ -117,83 +117,6 @@ namespace build2
return *r;
}
- pair<bool, target_state> target::
- state (action_type a) const
- {
- assert (phase == run_phase::match);
-
- // The tricky aspect here is that we my be re-matching the target for
- // another (overriding action). Since it is only valid to call this
- // function after the target has been matched (for this action), we assume
- // that if the target is busy, then it is being overriden (note that it
- // cannot be being executed since we are in the match phase).
- //
- // But that's not the end of it: in case of a re-match the task count
- // might have been reset to, say, applied. The only way to know for sure
- // that there isn't another match "underneath" is to compare actions. But
- // that can only be done safely if we lock the target. At least we will be
- // quick (and we don't need to wait since if it's busy, we know it is a
- // re-match). This logic is similar to lock_impl().
- //
- size_t b (target::count_base ());
- size_t e (task_count.load (memory_order_acquire));
-
- size_t exec (b + target::offset_executed);
- size_t lock (b + target::offset_locked);
- size_t busy (b + target::offset_busy);
-
- for (;;)
- {
- for (; e == lock; e = task_count.load (memory_order_acquire))
- this_thread::yield ();
-
- if (e >= busy) // Override in progress.
- return make_pair (true, target_state::unchanged);
-
- // Unlike lock_impl(), we are only called after being matched for this
- // action so if we see executed, then it means executed for this action
- // (or noop).
- //
- if (e == exec)
- return make_pair (true, group_state () ? group->state_ : state_);
-
- // Try to grab the spin-lock.
- //
- if (task_count.compare_exchange_strong (
- e,
- lock,
- memory_order_acq_rel, // Synchronize on success.
- memory_order_acquire)) // Synchronize on failure.
- {
- break;
- }
-
- // Task count changed, try again.
- }
-
- // We have the spin-lock. Quickly get the matched action and unlock.
- //
- action_type ma (action);
- bool mf (state_ == target_state::failed);
- task_count.store (e, memory_order_release);
-
- if (ma > a) // Overriden.
- return make_pair (true, // Override may have failed but we had the rule.
- mf ? target_state::failed: target_state::unchanged);
-
- // Otherwise we should have a matched target.
- //
- assert (ma == a);
-
- if (e == b + target::offset_tried)
- return make_pair (false, target_state::unknown);
- else
- {
- assert (e == b + target::offset_applied || e == exec);
- return make_pair (true, group_state () ? group->state_ : state_);
- }
- }
-
pair<lookup, size_t> target::
find_original (const variable& var, bool target_only) const
{
@@ -519,26 +442,19 @@ namespace build2
case run_phase::load: break;
case run_phase::match:
{
- // Similar logic to state(action) except here we don't distinguish
- // between original/overridden actions (an overridable action is by
- // definition a noop and should never need to query the mtime).
- //
- size_t c (task_count.load (memory_order_acquire)); // For group_state()
-
- // Wait out the spin lock to get the meaningful count.
+ // Similar logic to matched_state_impl().
//
- for (size_t lock (target::count_locked ());
- c == lock;
- c = task_count.load (memory_order_acquire))
- this_thread::yield ();
+ const opstate& s (state[action () /* inner */]);
+ size_t o (s.task_count.load (memory_order_relaxed) - // Synchronized.
+ target::count_base ());
- if (c != target::count_applied () && c != target::count_executed ())
+ if (o != target::offset_applied && o != target::offset_executed)
break;
}
// Fall through.
case run_phase::execute:
{
- if (group_state ())
+ if (group_state (action () /* inner */))
t = &group->as<mtime_target> ();
break;