aboutsummaryrefslogtreecommitdiff
path: root/build2/algorithm.hxx
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/algorithm.hxx
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/algorithm.hxx')
-rw-r--r--build2/algorithm.hxx87
1 files changed, 65 insertions, 22 deletions
diff --git a/build2/algorithm.hxx b/build2/algorithm.hxx
index ff70b21..8978eba 100644
--- a/build2/algorithm.hxx
+++ b/build2/algorithm.hxx
@@ -102,33 +102,39 @@ namespace build2
const scope&,
const dir_path& out = dir_path ());
- // Target match lock: a non-const target reference as well as the
- // target::offset_* state that has already been "achieved".
+ // Target match lock: a non-const target reference and the target::offset_*
+ // state that has already been "achieved". Note that target::task_count
+ // itself is set to busy for the duration or the lock.
//
struct target_lock
{
+ using action_type = build2::action;
using target_type = build2::target;
+ action_type action;
target_type* target = nullptr;
- size_t offset = 0;
+ size_t offset = 0;
explicit operator bool () const {return target != nullptr;}
- void unlock ();
- target_type* release ();
+ void
+ unlock ();
target_lock () = default;
-
target_lock (target_lock&&);
target_lock& operator= (target_lock&&);
- // Implementation details.
- //
target_lock (const target_lock&) = delete;
target_lock& operator= (const target_lock&) = delete;
- target_lock (target_type* t, size_t o): target (t), offset (o) {}
+ // Implementation details.
+ //
~target_lock ();
+ target_lock (action_type a, target_type* t, size_t o)
+ : action (a), target (t), offset (o) {}
+
+ target_type*
+ release () {auto r (target); target = nullptr; return r;}
};
// If the target is already applied (for this action ) or executed, then no
@@ -222,13 +228,23 @@ namespace build2
// Match a "delegate rule" from withing another rules' apply() function
// avoiding recursive matches (thus the third argument). Unless try_match is
- // true, fail if not rule is found. Otherwise return empty recipe. Note that
- // unlike match(), this function does not increment the dependents
- // count. See also the companion execute_delegate().
+ // true, fail if no rule is found. Otherwise return empty recipe. Note that
+ // unlike match(), this function does not increment the dependents count and
+ // the two rules must coordinate who is using the target's data pad and/or
+ // prerequisite_targets. See also the companion execute_delegate().
//
recipe
match_delegate (action, target&, const rule&, bool try_match = false);
+ // Match a rule for the inner operation from withing the outer rule's
+ // apply() function. See also the companion execute_inner().
+ //
+ target_state
+ match_inner (action, const target&);
+
+ bool
+ match_inner (action, const target&, unmatch);
+
// The standard prerequisite search and match implementations. They call
// search() and then match() for each prerequisite in a loop omitting out of
// project prerequisites for the clean operation. If this target is a member
@@ -259,7 +275,7 @@ namespace build2
//
template <typename T>
void
- match_members (action, target&, T[], size_t);
+ match_members (action, target&, T const*, size_t);
template <size_t N>
inline void
@@ -269,7 +285,10 @@ namespace build2
}
inline void
- match_members (action a, target& t, prerequisite_targets& ts, size_t start)
+ match_members (action a,
+ target& t,
+ prerequisite_targets& ts,
+ size_t start = 0)
{
match_members (a, t, ts.data () + start, ts.size () - start);
}
@@ -279,6 +298,13 @@ namespace build2
// member's list might still not be available (e.g., if some wildcard/
// fallback rule matched).
//
+ // If the action is is for an outer operation, then it is changed to inner
+ // which means the members are always resolved by the inner (e.g., update)
+ // rule. This feels right since this is the rule that will normally do the
+ // work (e.g., update) and therefore knows what it will produce (and if we
+ // don't do this, then the group resolution will be racy since we will use
+ // two different task_count instances for synchronization).
+ //
group_view
resolve_group_members (action, const target&);
@@ -307,6 +333,12 @@ namespace build2
target_state
execute (action, const target&);
+ // As above but wait for completion if the target is busy and translate
+ // target_state::failed to the failed exception.
+ //
+ target_state
+ execute_wait (action, const target&);
+
// As above but start asynchronous execution. Return target_state::unknown
// if the asynchrounous execution has been started and target_state::busy if
// the target has already been busy.
@@ -328,6 +360,18 @@ namespace build2
target_state
execute_delegate (const recipe&, action, const target&);
+ // Execute the inner operation matched with match_inner(). Note that the
+ // returned target state is for the inner operation. The appropriate usage
+ // is to call this function from the outer operation's recipe and to factor
+ // the obtained state into the one returned (similar to how we do it for
+ // prerequisites).
+ //
+ // Note: waits for the completion if the target is busy and translates
+ // target_state::failed to the failed exception.
+ //
+ target_state
+ execute_inner (action, const target&);
+
// A special version of the above that should be used for "direct" and "now"
// execution, that is, side-stepping the normal target-prerequisite
// relationship (so no dependents count is decremented) and execution order
@@ -344,30 +388,29 @@ namespace build2
// for their completion. Return target_state::changed if any of them were
// changed and target_state::unchanged otherwise. If a prerequisite's
// execution is postponed, then set its pointer in prerequisite_targets to
- // NULL (since its state cannot be queried MT-safely).
- //
- // Note that this function can be used as a recipe.
+ // NULL (since its state cannot be queried MT-safely). If count is not 0,
+ // then only the first count prerequisites are executed.
//
target_state
- straight_execute_prerequisites (action, const target&);
+ straight_execute_prerequisites (action, const target&, size_t count = 0);
// As above but iterates over the prerequisites in reverse.
//
target_state
- reverse_execute_prerequisites (action, const target&);
+ reverse_execute_prerequisites (action, const target&, size_t count = 0);
// Call straight or reverse depending on the current mode.
//
target_state
- execute_prerequisites (action, const target&);
+ execute_prerequisites (action, const target&, size_t count = 0);
// A version of the above that also determines whether the action needs to
// be executed on the target based on the passed timestamp and filter.
//
// The filter is passed each prerequisite target and is expected to signal
// which ones should be used for timestamp comparison. If the filter is
- // NULL, then all the prerequisites are used. If the count is not 0, then
- // only the first count prerequisites are executed.
+ // NULL, then all the prerequisites are used. If count is not 0, then only
+ // the first count prerequisites are executed.
//
// Note that the return value is an optional target state. If the target
// needs updating, then the value absent. Otherwise it is the state that