aboutsummaryrefslogtreecommitdiff
path: root/build2/algorithm.ixx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-02-16 16:24:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-02-16 16:40:45 +0200
commit6293ede7a742866a713050737cc2b43d51161b6f (patch)
treef259845f47c2e03432bdd98b4b665e1a3de85d55 /build2/algorithm.ixx
parentad9cb7fec5cc74697322620909e0ff1ba9ecb61b (diff)
Add support for detecting dependency cycles
Diffstat (limited to 'build2/algorithm.ixx')
-rw-r--r--build2/algorithm.ixx66
1 files changed, 63 insertions, 3 deletions
diff --git a/build2/algorithm.ixx b/build2/algorithm.ixx
index 9b1df35..7572548 100644
--- a/build2/algorithm.ixx
+++ b/build2/algorithm.ixx
@@ -131,16 +131,45 @@ namespace build2
void
unlock_impl (action, target&, size_t);
+ inline target_lock::
+ target_lock (action_type a, target_type* t, size_t o)
+ : action (a), target (t), offset (o)
+ {
+ if (target != nullptr)
+ {
+ prev = stack;
+ stack = this;
+ }
+ }
+
inline void target_lock::
unlock ()
{
if (target != nullptr)
{
unlock_impl (action, *target, offset);
+
+ assert (stack == this);
+ stack = prev;
target = nullptr;
}
}
+ inline auto target_lock::
+ release () -> data
+ {
+ data r {action, target, offset};
+
+ if (target != nullptr)
+ {
+ assert (stack == this);
+ stack = prev;
+ target = nullptr;
+ }
+
+ return r;
+ }
+
inline target_lock::
~target_lock ()
{
@@ -151,7 +180,14 @@ namespace build2
target_lock (target_lock&& x)
: action (x.action), target (x.target), offset (x.offset)
{
- x.target = nullptr;
+ if (target != nullptr)
+ {
+ assert (stack == &x);
+ prev = x.prev;
+ stack = this;
+
+ x.target = nullptr;
+ }
}
inline target_lock& target_lock::
@@ -159,15 +195,39 @@ namespace build2
{
if (this != &x)
{
- unlock ();
+ assert (target == nullptr);
+
action = x.action;
target = x.target;
offset = x.offset;
- x.target = nullptr;
+
+ if (target != nullptr)
+ {
+ assert (stack == &x);
+ prev = x.prev;
+ stack = this;
+
+ x.target = nullptr;
+ }
}
+
return *this;
}
+ inline const target_lock*
+ dependency_cycle (action a, const target& t)
+ {
+ const target_lock* l (target_lock::stack);
+
+ for (; l != nullptr; l = l->prev)
+ {
+ if (l->action == a && l->target == &t)
+ break;
+ }
+
+ return l;
+ }
+
inline target_lock
lock (action a, const target& t)
{