wallet: Call load handlers without cs_wallet locked #22868

pull promag wants to merge 1 commits into bitcoin:master from promag:2021-09-wallet-load-lock changing 3 files +5 −9
  1. promag commented at 10:18 pm on September 2, 2021: member

    Don’t have cs_wallet locked while calling each context.wallet_load_fns. A load handler can always lock cs_wallet if needed.

    The lock was added in 1c7e25db0c to satisfy TSAN. With 44c430ffac most of the code requiring the lock is in CWallet::AttachChain. A comment is added to warn about wallets_mutex and cs_wallet lock ordering.

  2. DrahtBot added the label Wallet on Sep 2, 2021
  3. promag force-pushed on Sep 2, 2021
  4. promag force-pushed on Sep 2, 2021
  5. promag force-pushed on Sep 2, 2021
  6. promag force-pushed on Sep 3, 2021
  7. DrahtBot commented at 3:21 pm on September 4, 2021: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    No conflicts as of last run.

  8. hebasto commented at 6:55 pm on September 7, 2021: member
    Why this change is safe?
  9. promag commented at 8:31 pm on September 7, 2021: member
    @hebasto what is the concern? The lock can be acquired inside the load handler. This change also avoids recursive locks on cs_wallet.
  10. ryanofsky commented at 8:39 pm on September 8, 2021: member

    what is the concern?

    This does seem probably safe, but it would save reviewers some effort to know when the lock was added, when it stopped being necessary, and the specific reason why it was necessary whenever it was needed (for example whether it was avoiding deadlocks or asserts by acquiring recursive locks in a consistent order, or whether it was avoiding race condition.) This information could go in the PR description.

    One concern might be that one of the wallet_load_fns callbacks could call a wallet method and acquire cs_wallet mutex after context.wallets_mutex, and maybe this would be in inconsistent order.

  11. promag commented at 10:12 pm on September 11, 2021: member

    @ryanofsky

    but it would save reviewers some effort to know when the lock was added, when it stopped being necessary

    My bad for not writing this, I went thru history before making the change, will redo and update this.

    One concern might be that one of the wallet_load_fns callbacks could call a wallet method and acquire cs_wallet mutex after context.wallets_mutex, and maybe this would be in inconsistent order.

    Would be bad to lock one cs_wallet after wallets_mutex? In master that already happens but works because cs_wallet is recursive. Couldn’t find more cases of cs_wallet -> wallets_mutex lock order.

  12. promag commented at 8:49 pm on September 12, 2021: member
    @ryanofsky see https://github.com/bitcoin/bitcoin/pull/11634/files#r227725517 for when the lock was added and @practicalswift submitted a similar change #14560 but @MarcoFalke rejected it.
  13. ryanofsky approved
  14. ryanofsky commented at 3:01 pm on September 24, 2021: member

    Code review ACK 2c87f99411e6529f69af9b299c9cc7f050f5caa7. It seems safe to remove this lock ~because it look like it was only added by accident in #11634 to try to satisfy lock annotations, even though it was never really needed to satisfy lock annotations even according to the thread there https://github.com/bitcoin/bitcoin/pull/11634/files#r227725517~. (EDIT: lock was not added by accident, it was needed but was always broader than it needed to be and it became unnecessary after a recursive lock was added in #20773)

    ⬆️ I think above information would be helpful to add to PR description because otherwise this PR seems like a random change.

    After this PR, I think there are no more cases where cs_wallet and wallets_mutex are locked at the same time so there is no required lock ordering between them. But in the future, GUI code could do arbitrary things in its wallet_load_fns handler, and maybe it will call a wallet function and lock cs_wallet in one. In that case the lock order would be wallets_mutex first then cs_wallet second. It may be good to state some intended lock ordering, maybe adding a code comment to WalletContext::wallets_mutex like “It is unsafe to lock this after locking a CWallet::cs_wallet mutex because this could introduce inconsistent lock ordering and cause deadlocks.”

    One concern might be that one of the wallet_load_fns callbacks could call a wallet method and acquire cs_wallet mutex after context.wallets_mutex, and maybe this would be in inconsistent order.

    Would be bad to lock one cs_wallet after wallets_mutex?

    If there is any thread locking wallets_mutex after cs_wallet then it would be bad, but if not, then it’s fine.

    In master that already happens but works because cs_wallet is recursive. Couldn’t find more cases of cs_wallet -> wallets_mutex lock order.

    I don’t think this matters because recursive locks are no-ops. It a thread locks mutex A, then locks mutex B, then recursively locks mutex A again, then the recursive lock isn’t doing anything, and the lock order is still A before B.

  15. promag commented at 3:08 pm on September 24, 2021: member
    @ryanofsky thanks! You might want to see https://github.com/bitcoin-core/gui/pull/417/commits/c09fd3acb9aee9245a033e9d7251cd29de1d24bb, it needs this change otherwise it deadlocks.
  16. DrahtBot added the label Needs rebase on Sep 30, 2021
  17. ryanofsky commented at 5:05 pm on November 8, 2021: member

    @ryanofsky thanks! You might want to see bitcoin-core/gui@c09fd3a, it needs this change otherwise it deadlocks.

    Thanks! That also looks like a good change. Is there a PR or issue this is all a part of?

  18. promag commented at 5:07 pm on November 8, 2021: member

    @ryanofsky yes, https://github.com/bitcoin-core/gui/pull/417

    Edit: I guess I have to rebase.

  19. promag force-pushed on Nov 8, 2021
  20. promag commented at 10:00 pm on November 8, 2021: member
    Rebased due to trivial conflict with #23123.
  21. DrahtBot removed the label Needs rebase on Nov 8, 2021
  22. ryanofsky approved
  23. ryanofsky commented at 6:33 pm on November 10, 2021: member
    Code review ACK 7850d33f7ff1c2ef7e34248efdbb60e792419d46 with caveats from #22868#pullrequestreview-763184176 that I’m not 100% sure this won’t cause deadlocks now or in the future, but do think this seems safe and is probably a good simplification. Also I think the PR description is lacking essential information like why it is safe to remove the lock and how long it’s been unnecessary.
  24. meshcollider commented at 2:21 am on November 22, 2021: contributor

    Looks correct to me, utACK 7850d33f7ff1c2ef7e34248efdbb60e792419d46

    Agree with Russ though, definitely think the PR description needs updating.

  25. promag force-pushed on Nov 22, 2021
  26. promag commented at 9:38 am on November 22, 2021: member

    But in the future, GUI code could do arbitrary things in its wallet_load_fns handler, and maybe it will call a wallet function and lock cs_wallet in one. In that case the lock order would be wallets_mutex first then cs_wallet second

    This is already the case and it is where the GUI models are filled. @meshcollider @ryanofsky updated OP, added wallets_mutex comment as suggested.

    Also rebased.

  27. wallet: Call load handlers without cs_wallet locked
    Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
    f13a22a631
  28. promag force-pushed on Nov 22, 2021
  29. meshcollider commented at 7:02 am on November 23, 2021: contributor
    re-utACK f13a22a631efe01e1fbae4ae78a4901d14ebda3c
  30. ryanofsky commented at 5:15 am on November 24, 2021: member

    PR description doesn’t seem totally accurate, from #22868#issue-987214408

    Don’t have cs_wallet locked while calling each context.wallet_load_fns. A load handler can always lock cs_wallet if needed.

    The lock was added in 1c7e25d to satisfy TSAN. With 44c430f most of the code requiring the lock is in CWallet::AttachChain. A comment is added to warn about wallets_mutex and cs_wallet lock ordering.

    If my understanding of https://github.com/bitcoin/bitcoin/pull/11634/files#r227725517 is correct, then the lock was not added to satsify TSAN but was added to satisfy clang annotations. I think you could summarize this by saying that this LOCK(cs_wallet) was correctly added in #11634, but it became no longer unnecessary after #20773 when code requiring the lock was moved to the new AttachChain method.

    Also it now seems like the motivation for this change is not just removing an unnecessary lock, but reversing the 1. cs_wallet 2. wallets_mutex lock order so it can now be 1. wallets_mutex 2. cs_wallet, because upcoming GUI PR https://github.com/bitcoin-core/gui/pull/417 needs this

  31. ryanofsky approved
  32. ryanofsky commented at 5:16 am on November 24, 2021: member
    Code review ACK f13a22a631efe01e1fbae4ae78a4901d14ebda3c. Only change since last review is adding a lock order comment
  33. in src/wallet/context.h:38 in f13a22a631
    33@@ -34,6 +34,8 @@ using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wall
    34 struct WalletContext {
    35     interfaces::Chain* chain{nullptr};
    36     ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
    37+    // It is unsafe to lock this after locking a CWallet::cs_wallet mutex because
    38+    // this could introduce inconsistent lock ordering and cause deadlocks.
    


    jonatack commented at 12:34 pm on November 24, 2021:
    Haven’t tried, but would there be any point in using EXCLUDES / LOCKS_EXCLUDED (or REQUIRES(!mutex) with -Wthread-safety-negative) annotations to enforce this?
  34. jonatack commented at 12:35 pm on November 24, 2021: member
    ACK f13a22a631efe01e1fbae4ae78a4901d14ebda3c
  35. meshcollider merged this on Nov 27, 2021
  36. meshcollider closed this on Nov 27, 2021

  37. sidhujag referenced this in commit 73db64cc9d on Nov 27, 2021
  38. promag deleted the branch on Feb 23, 2022
  39. Gemk83 commented at 10:37 pm on February 26, 2022: none
    Ok
  40. DrahtBot locked this on Feb 26, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-11-21 18:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me