Worker thread shares same name with event loop thread creating confusion when inspecting in GDB #248

issue Eunovo opened this issue on March 10, 2026
  1. Eunovo commented at 12:32 PM on March 10, 2026: contributor

    In the image obtained from running bitcoin-core's interface_ipc_mining test below, there are two "b-capnp-loop" threads: only one (Thread ID 11) is the actual worker thread calling createNewBlock().

    <img width="694" height="529" alt="Image" src="https://github.com/user-attachments/assets/27d7c5bc-dd05-4569-99c4-fb70183200fc" />

    This creates confusion for the developer trying to find the right thread to inspect.

    I took a quick stab at this and tried to set the name of the newly created thread in ProxyServer<ThreadMap>::makeThread, but it didn't seem to work.

    You can reproduce with this diff applied to bitcoin-core and using GDB to inspect the running threads.

    diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h
    index f4c42e204a..bbef70196b 100644
    --- a/src/interfaces/mining.h
    +++ b/src/interfaces/mining.h
    @@ -139,6 +139,13 @@ public:
          */
         virtual void interrupt() = 0;
     
    +    /**
    +     * Sets the debug mining flag.
    +     *
    +     * [@param](/bitcoin-core-multiprocess/contributor/param/)[in] debug_mining whether to enable debug mining mode
    +     */
    +    virtual void setDebugMining(bool debug_mining) = 0;
    +
         /**
          * Checks if a given block is valid.
          *
    diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp
    index 64cad4d49f..38a1758f61 100644
    --- a/src/ipc/capnp/mining.capnp
    +++ b/src/ipc/capnp/mining.capnp
    @@ -25,6 +25,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") {
         createNewBlock [@4](/bitcoin-core-multiprocess/contributor/4/) (context :Proxy.Context, options: BlockCreateOptions, cooldown: Bool = true) -> (result: BlockTemplate);
         checkBlock [@5](/bitcoin-core-multiprocess/contributor/5/) (context :Proxy.Context, block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool);
         interrupt [@6](/bitcoin-core-multiprocess/contributor/6/) () -> ();
    +    setDebugMining [@7](/bitcoin-core-multiprocess/contributor/7/) (debugMining: Bool) -> ();
     }
     
     interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
    diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
    index 84fd5bb794..e83e7ea003 100644
    --- a/src/node/interfaces.cpp
    +++ b/src/node/interfaces.cpp
    @@ -959,6 +959,9 @@ public:
     
         std::unique_ptr<BlockTemplate> createNewBlock(const BlockCreateOptions& options, bool cooldown) override
         {
    +        if (m_debug_mining) {
    +            while (true) {} //DEBUG
    +        }
             // Reject too-small values instead of clamping so callers don't silently
             // end up mining with different options than requested. This matches the
             // behavior of the `-blockreservedweight` startup option, which rejects
    @@ -999,6 +1002,11 @@ public:
             InterruptWait(notifications(), m_interrupt_mining);
         }
     
    +    void setDebugMining(bool debug_mining) override
    +    {
    +        m_debug_mining = debug_mining;
    +    }
    +
         bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) override
         {
             LOCK(chainman().GetMutex());
    @@ -1013,6 +1021,7 @@ public:
         KernelNotifications& notifications() { return *Assert(m_node.notifications); }
         // Treat as if guarded by notifications().m_tip_block_mutex
         bool m_interrupt_mining{false};
    +    bool m_debug_mining{false};
         NodeContext& m_node;
     };
     } // namespace
    diff --git a/test/functional/test_framework/ipc_util.py b/test/functional/test_framework/ipc_util.py
    index 11497463eb..1469294b63 100644
    --- a/test/functional/test_framework/ipc_util.py
    +++ b/test/functional/test_framework/ipc_util.py
    @@ -108,6 +108,8 @@ async def make_capnp_init_ctx(self):
     
     async def mining_create_block_template(mining, stack, ctx, opts):
         """Call mining.createNewBlock() and return template, then call template.destroy() when stack exits."""
    +    await mining.setDebugMining(True)  # Block createNewBlock() infinitely
    +    import pdb; pdb.set_trace()
         response = await mining.createNewBlock(ctx, opts)
         if not response._has("result"):
             return None
    
    
  2. ryanofsky commented at 1:39 AM on March 12, 2026: collaborator

    I took a quick stab at this and tried to set the name of the newly created thread in ProxyServer<ThreadMap>::makeThread, but it didn't seem to work.

    That's surprising. But one problem might be that the thread name passed passed to the OS is too long. I believe the name passed includes the exe name + thread name from the calling process. Might make sense to split it up or add truncation if that is the problem

  3. Eunovo commented at 10:54 AM on March 12, 2026: contributor

    I believe the name passed includes the exe name + thread name from the calling process. Might make sense to split it up or add truncation if that is the problem

    I had the same thought, and I believe I tried shorter names as well, but the name of the worker thread remained unchanged. I can double-check this later to confirm.

Contributors

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/libmultiprocess. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-20 17:30 UTC

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