diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2023-05-26 07:22:40 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2023-05-29 10:21:12 +0200 |
commit | ab91d32c1b23ea92b988d5618db2938a8c5dc63f (patch) | |
tree | fc02b89ae71aa3bcad127149718a7a4e7480f0b7 /libbuild2/adhoc-rule-regex-pattern.cxx | |
parent | 56d79a62e64180f639dad02f0887fef5d57bb096 (diff) |
Avoid group linkup deadlocks for dynamic and pattern-static members
Diffstat (limited to 'libbuild2/adhoc-rule-regex-pattern.cxx')
-rw-r--r-- | libbuild2/adhoc-rule-regex-pattern.cxx | 36 |
1 files changed, 23 insertions, 13 deletions
diff --git a/libbuild2/adhoc-rule-regex-pattern.cxx b/libbuild2/adhoc-rule-regex-pattern.cxx index 0f2ecc3..c4b4cab 100644 --- a/libbuild2/adhoc-rule-regex-pattern.cxx +++ b/libbuild2/adhoc-rule-regex-pattern.cxx @@ -400,21 +400,31 @@ namespace build2 if (find (ms.begin (), ms.end (), &t) != ms.end ()) continue; - // We can only update the group under lock. + // Check if we already belong to this group. Note that this not a + // mere optimization since we may be in the member->group->member + // chain and trying to lock the member the second time would + // deadlock (this can be triggered, for example, by dist, which sort + // of depends on such members directly @@ maybe this should be fixed + // there?). // - target_lock tl (lock (a, t)); - - if (!tl) - fail << "group " << *g << " member " << t << " is already matched" << - info << "static group members specified by pattern rules cannot " - << "be used as prerequisites directly, only via group"; - - if (t.group == nullptr) - tl.target->group = g; - else if (t.group != g) + if (t.group != g) // Note: atomic. { - fail << "group " << *g << " member " << t - << " is already member of group " << *t.group; + // We can only update the group under lock. + // + target_lock tl (lock (a, t)); + + if (!tl) + fail << "group " << *g << " member " << t << " is already matched" << + info << "static group members specified by pattern rules cannot " + << "be used as prerequisites directly, only via group"; + + if (t.group == nullptr) + tl.target->group = g; + else if (t.group != g) + { + fail << "group " << *g << " member " << t + << " is already member of group " << *t.group; + } } } |