#34775 kernel: allow only one global logging connection

ReviewabilityReviewsAgreementSize
#34775 stickies-v kernel: allow only one global logging connectionReady0Mild132 + 96 tests
  • Prevent logging deadlocks when consumer callbacks trigger logging during garbage collection or finalization
  • Restrict kernel logging to one connection handle to match the process-wide singleton reality
  • Ready for review
  • Concept support because single connections are simpler and pragmatic for consumers (sedited)
  • Approach approval without detailed reasoning (w0xlt)
  • Answered objection: premature API restriction is hard to reverse and lacks benefit (ryanofsky)
  • 132 lines added or modified outside tests
  • 96 lines added or modified in tests
  • 112 lines removed in total
  • 5 files, 4 commits
Kernel (libbitcoinkernel)#1 of 18
P1 · bug fix
  • P1 after comparing with the other PRs here (assessed alone as P2): Raised to P1 and moved up five places: a deadlock risk when consumer callbacks log is a reliability defect exactly at the kernel boundary, and the single-connection decision also gates the per-context logging series.
  • P2 because it fixes potential deadlocks at the kernel boundary when consumer callbacks invoke logging
  • It eliminates thread serialization on user callbacks and aligns the public API with singleton behavior
Reviewability: ReadyStalePaused
Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets
Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs.
Size: lines added or modified outside tests, then in tests; greener = smaller.

Goal

Restricts libbitcoinkernel to a single process-wide logging connection, moves log level configuration onto the connection handle, and invokes logging callbacks without holding the logger mutex. Creating a second concurrent connection now fails, and logging callbacks can be invoked concurrently across threads.

Problem: The underlying KernelLogger is a process-wide singleton, but the API permitted multiple connection handles, misleading consumers into expecting independent loggers. In addition, holding the logger mutex while invoking the consumer callback serialized all logging threads on user code and risked deadlocks if the callback thread triggered any logging (such as during garbage collector finalization).

Evidence of importance:

  • Description notes that multiple handles 'give the false impression of independent loggers.'
  • Commit 921329000f notes that holding the lock 'serializes all logging threads on user code, and deadlocks if anything on the callback's thread logs, e.g. a garbage collector running finalizers that destroy kernel objects.'

Scope: Modifies the public libbitcoinkernel C API by renaming btck_logging_connection_create to btck_global_logging_connection_create, replacing btck_logging_set_min_level with btck_logging_connection_set_min_level, and requiring logging callbacks to be thread-safe.

Risk of a mistake: medium (other). Synchronization or concurrency bugs in the kernel logging interface could cause deadlocks, race conditions, or crashes in applications consuming libbitcoinkernel.

Changed since the previous assessment: Now invokes logging callbacks without holding the logger mutex, using an atomic in-flight counter to wait for running callbacks on connection destruction, and updates consumers like bitcoin-chainstate to format log output without interleaving concurrent lines.

Reviewability

Ready

Nothing known that would invalidate a review now.

Waiting on (from the thread read):

  • reviewer: review of the updated approach and deadlock-free callback invocation 2026-10-19

Agreement

Mild

objection that needs a change was answered, no reply from the objector (ryanofsky: Prematurely restricts the kernel logging API in a way difficult to reverse without notable simplification)

Thread notes: The author updated the PR to invoke the logging callback without holding the logger mutex to avoid deadlocks from GC finalizers, restructured the commits, and marked the PR ready for review.

Objections, suggestions, and questions:

ReviewerTypeHarm, request, or questionStatusMust beAuthor repliedQuote
purpleKarrot (member)suggestion, interfaceDrop local user_data in favor of a simple function pointeranswered · author replied that user_data avoids forcing users to use globals for stateansweredyes2026-03-09: 'Since the log function is global, there is no need for local user data. It can be a simple function pointer, even in the C++ wrapper.'
Status from: 2026-03-09: stickies-v: 'Forcing the user to use globals if they need state seems unnecessary, when using `user_data` is I think a well-establish'
ryanofsky (member)objection, approachPrematurely restricts the kernel logging API in a way difficult to reverse without notable simplificationanswered · author force-pushed to keep btck_LoggingConnection handles while enforcing a single active connection to avoid caller restructuringchangedyes2026-03-09: 'I think it would be a mistake to limit functionality of the logging/debuging/tracing API prematurely, in a way that seems difficult to reverse and does not seem to provide a noticeable simplification'
Status from: 2026-10-05: stickies-v: 'I believe this new approach addresses your concern about callers having to restructure if logging is contextualized late'
sedited (member)question, maintenanceDoes the pointer have to be a raw pointer?answered · author explained that a raw pointer avoids running consumer code from static destructors during process teardownansweredyes2026-06-11: 'Does this have to be a raw pointer?'
Status from: 2026-09-16: stickies-v: 'I think so, to avoid running consumer code from static destructors.'
sedited (member)objection, correctnessGlobal logging callback leaks state across unit tests if not resetfixed · fix pushed · author pushed an RAII Logger class wrapper preventing state leakage across testschangedyes2026-06-11: 'Even though this function is scoped to this test, it now enables logging for all the the other unit tests too. Maybe add another call to set the callback to null at the end of the test?'
Status from: 2026-09-17: stickies-v: 'The `Logger` class should offer all required functionality, in a way that is much harder to abuse. Thank you both for yo'
sedited (member)suggestion, interfaceRename to logging_reset_callback and remove the argumentanswered · author agreed in concept but noted it was rendered obsolete by the new Logger wrapper designansweredyes2026-06-11: 'How about calling this `logging_reset_callback` and removing the argument?'
Status from: 2026-09-17: stickies-v: 'I agree, but this is no longer relevant in the latest version as per https://github.com/bitcoin/bitcoin/pull/34775#discu'
w0xlt (contributor)objection, correctnessTests installing global callback leak state unless explicitly clearedfixed · fix pushed · author adopted RAII wrapper approach to prevent test state leakagechangedyes2026-07-16: 'any test that installs the global logging callback now needs to clear it before returning to prevent state leakage into later tests.'
Status from: 2026-09-17: stickies-v: 'The `Logger` class should offer all required functionality, in a way that is much harder to abuse.'
w0xlt (contributor)suggestion, interfaceRetain RAII in the C++ wrapper while exposing a single global logging callbackfixed · fix pushed · author implemented an RAII Logger class in the C++ wrapperansweredyes2026-07-16: 'I think the C++ wrapper could retain RAII while still exposing a single global logging callback.'
Status from: 2026-09-17: stickies-v: 'address @w0xlt's suggestion to have an RAII `Logger` in the C++ wrapper instead of free functions'

Support:

  • sedited (member) (Concept ACK, 2026-03-09) [read]: Not having separate connections seems simpler, clients can multiplex themselves, and it is pragmatic
  • w0xlt (contributor) (Approach ACK, 2026-06-24): (no reason given) [not substantive]

Participants:

  • purpleKarrot (member, neutral, 1 statements 2026-03-09 to 2026-03-09): suggested dropping user_data in favor of a plain function pointer
  • ryanofsky (member, objection, 2 statements 2026-03-09 to 2026-09-25): objected that limiting logging API to a global callback is premature, hard to reverse, and disrupts callers
  • sedited (member, support, 6 statements 2026-03-09 to 2026-08-27): Concept ACK; raised concern about test state leakage and asked about raw pointer
  • w0xlt (contributor, support, 3 statements 2026-06-24 to 2026-07-16): Approach ACK; noted test callback leakage and suggested RAII wrapper

Files

114 lines under test/bench/ci.

  • src/kernel/bitcoinkernel.cpp +87/-62
  • src/test/kernel/test_kernel.cpp +96/-18
  • src/kernel/bitcoinkernel.h +27/-22
  • src/kernel/bitcoinkernel_wrapper.h +9/-6
  • src/bitcoin-chainstate.cpp +9/-4

Card

The short text the ranking pass compares across PRs.

Restricts libbitcoinkernel to allow only one active logging connection per process, and executes logging callbacks without holding the logger mutex. Previously, multiple connection handles gave consumers the false impression of independent loggers, while holding the mutex serialized all logging threads and risked deadlocks if consumer callbacks triggered kernel logging. Attempting to create a second connection now fails, log level configuration is moved to the connection handle, and callbacks must be thread-safe as they can run concurrently.

Data

dossier JSON · extract JSON · model ledger, generated 2026-10-21T01:17, confidence high, input hash a88dc2b35b64ce72
thread read through 2026-10-19 (20 statements), head 921329000f
labels: Validation

Categories

Kernel (libbitcoinkernel)

P1 · bug fix (assessed alone as P2; Raised to P1 and moved up five places: a deadlock risk when consumer callbacks log is a reliability defect exactly at the kernel boundary, and the single-connection decision also gates the per-context logging series.)

Fixes a potential deadlock at the kernel boundary by releasing the logger mutex before invoking consumer callbacks, and aligns the API with the underlying singleton logger. As noted in commit 921329000f, holding the lock 'serializes all logging threads on user code, and deadlocks if anything on the callback's thread logs, e.g. a garbage collector running finalizers that destroy kernel objects.'

Membership: Modifies the libbitcoinkernel C/C++ API headers and implementations (`src/kernel/bitcoinkernel.h`, `src/kernel/bitcoinkernel.cpp`), kernel tests, and the `bitcoin-chainstate` example.

Factors: security/stability 2, bug 1, performance 1, user value 1, leverage 1