Implement a new target.process.follow-fork-mode setting to control
LLDB's behavior on fork. If set to 'parent', the forked child is
detached and parent continues being traced. If set to 'child',
the parent is detached and child becomes traced instead.
Details
Details
Diff Detail
Diff Detail
Event Timeline
Comment Actions
This is it! The fruit of my labor! It feels like it's... kinda small. But I guess this is because all the groundwork has been done well, and now it's just a matter of plugging it in.
Comment Actions
@mgorny Do your changes allow debugging both the parent and child processes after a fork?
Comment Actions
No. This patch supports choosing either the parent or the child but it's a step in that direction. Further work is necessary to support debugging multiple processes simultaneously.
Comment Actions
The new tests here fall for me on macOS:
[4303/4304] Running lldb shell test suite llvm-lit: /Users/thakis/src/llvm-project/lldb/test/Shell/helper/toolchain.py:126: note: using SDKROOT: '/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk' llvm-lit: /Users/thakis/src/llvm-project/llvm/utils/lit/lit/llvm/config.py:436: note: using clang: /Users/thakis/src/llvm-build-project/bin/clang llvm-lit: /Users/thakis/src/llvm-project/llvm/utils/lit/lit/llvm/config.py:436: note: using ld.lld: /Users/thakis/src/llvm-build-project/bin/ld.lld llvm-lit: /Users/thakis/src/llvm-project/llvm/utils/lit/lit/llvm/config.py:436: note: using lld-link: /Users/thakis/src/llvm-build-project/bin/lld-link llvm-lit: /Users/thakis/src/llvm-project/llvm/utils/lit/lit/llvm/config.py:436: note: using ld64.lld: /Users/thakis/src/llvm-build-project/bin/ld64.lld llvm-lit: /Users/thakis/src/llvm-project/llvm/utils/lit/lit/llvm/config.py:436: note: using wasm-ld: /Users/thakis/src/llvm-build-project/bin/wasm-ld llvm-lit: /Users/thakis/src/llvm-project/lldb/test/Shell/lit.cfg.py:98: warning: Could not set a default per-test timeout. Requires the Python psutil module but it could not be found. Try installing it via pip or via your operating system's package manager. FAIL: lldb-shell :: Subprocess/fork-follow-child.test (433 of 437) ******************** TEST 'lldb-shell :: Subprocess/fork-follow-child.test' FAILED ******************** Script: -- : 'RUN: at line 3'; /Users/thakis/src/llvm-build-project/bin/clang --driver-mode=g++ --target=specify-a-target-or-use-a-_host-substitution --target=x86_64-apple-darwin19.6.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/Inputs/fork.cpp -DTEST_FORK=fork -o /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child.test.tmp : 'RUN: at line 4'; /Users/thakis/src/llvm-build-project/bin/lldb --no-lldbinit -S /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init -b -s /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child.test /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child.test.tmp | /Users/thakis/src/llvm-build-project/bin/FileCheck /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child.test -- Exit Code: 1 Command Output (stderr): -- clang-13: warning: argument unused during compilation: '-fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell' [-Wunused-command-line-argument] /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child.test:9:10: error: CHECK: expected string not found in input # CHECK: child exited: 0 ^ <stdin>:26:69: note: scanning from here 0x100003cee <+14>: leaq 0x21b(%rip), %rdi ; "function run in parent\n" ^ <stdin>:27:115: note: possible intended match here Process 39485 launched: '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child.test.tmp' (x86_64) ^ Input file: <stdin> Check file: /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child.test -dump-input=help explains the following input dump. Input was: <<<<<< . . . 21: frame #0: 0x0000000100003ce0 fork-follow-child.test.tmp`parent_func() 22: fork-follow-child.test.tmp`parent_func: 23: -> 0x100003ce0 <+0>: pushq %rbp 24: 0x100003ce1 <+1>: movq %rsp, %rbp 25: 0x100003ce4 <+4>: movl $0x1, 0x434a(%rip) ; _dyld_private + 4 26: 0x100003cee <+14>: leaq 0x21b(%rip), %rdi ; "function run in parent\n" check:9'0 X~~~ error: no match found 27: Process 39485 launched: '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child.test.tmp' (x86_64) check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ check:9'1 ? possible intended match >>>>>> -- ******************** FAIL: lldb-shell :: Subprocess/vfork-follow-child.test (434 of 437) ******************** TEST 'lldb-shell :: Subprocess/vfork-follow-child.test' FAILED ******************** Script: -- : 'RUN: at line 3'; /Users/thakis/src/llvm-build-project/bin/clang --driver-mode=g++ --target=specify-a-target-or-use-a-_host-substitution --target=x86_64-apple-darwin19.6.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/Inputs/fork.cpp -DTEST_FORK=vfork -o /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child.test.tmp : 'RUN: at line 4'; /Users/thakis/src/llvm-build-project/bin/lldb --no-lldbinit -S /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init -b -s /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child.test /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child.test.tmp | /Users/thakis/src/llvm-build-project/bin/FileCheck /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child.test -- Exit Code: 1 Command Output (stderr): -- clang-13: warning: argument unused during compilation: '-fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell' [-Wunused-command-line-argument] /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child.test:9:10: error: CHECK: expected string not found in input # CHECK: child exited: 0 ^ <stdin>:26:69: note: scanning from here 0x100003cee <+14>: leaq 0x21b(%rip), %rdi ; "function run in parent\n" ^ <stdin>:27:116: note: possible intended match here Process 39484 launched: '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child.test.tmp' (x86_64) ^ Input file: <stdin> Check file: /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child.test -dump-input=help explains the following input dump. Input was: <<<<<< . . . 21: frame #0: 0x0000000100003ce0 vfork-follow-child.test.tmp`parent_func() 22: vfork-follow-child.test.tmp`parent_func: 23: -> 0x100003ce0 <+0>: pushq %rbp 24: 0x100003ce1 <+1>: movq %rsp, %rbp 25: 0x100003ce4 <+4>: movl $0x1, 0x434a(%rip) ; _dyld_private + 4 26: 0x100003cee <+14>: leaq 0x21b(%rip), %rdi ; "function run in parent\n" check:9'0 X~~~ error: no match found 27: Process 39484 launched: '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child.test.tmp' (x86_64) check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ check:9'1 ? possible intended match >>>>>> -- ******************** FAIL: lldb-shell :: Subprocess/fork-follow-child-softbp.test (435 of 437) ******************** TEST 'lldb-shell :: Subprocess/fork-follow-child-softbp.test' FAILED ******************** Script: -- : 'RUN: at line 3'; /Users/thakis/src/llvm-build-project/bin/clang --driver-mode=g++ --target=specify-a-target-or-use-a-_host-substitution --target=x86_64-apple-darwin19.6.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/Inputs/fork.cpp -DTEST_FORK=fork -o /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child-softbp.test.tmp : 'RUN: at line 4'; /Users/thakis/src/llvm-build-project/bin/lldb --no-lldbinit -S /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init -b -s /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-softbp.test /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child-softbp.test.tmp | /Users/thakis/src/llvm-build-project/bin/FileCheck /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-softbp.test -- Exit Code: 1 Command Output (stderr): -- clang-13: warning: argument unused during compilation: '-fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell' [-Wunused-command-line-argument] /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-softbp.test:10:15: error: CHECK-NEXT: expected string not found in input # CHECK-NEXT: child_func ^ <stdin>:22:71: note: scanning from here * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 ^ <stdin>:23:43: note: possible intended match here frame #0: 0x0000000100003ce0 fork-follow-child-softbp.test.tmp`parent_func() ^ Input file: <stdin> Check file: /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-softbp.test -dump-input=help explains the following input dump. Input was: <<<<<< . . . 17: Breakpoint 1: where = fork-follow-child-softbp.test.tmp`child_func(void*), address = 0x0000000100003d00 18: (lldb) b parent_func 19: Breakpoint 2: where = fork-follow-child-softbp.test.tmp`parent_func(), address = 0x0000000100003ce0 20: (lldb) process launch 21: Process 39486 stopped 22: * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 next:10'0 X~~~~ error: no match found 23: frame #0: 0x0000000100003ce0 fork-follow-child-softbp.test.tmp`parent_func() next:10'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ next:10'1 ? possible intended match 24: fork-follow-child-softbp.test.tmp`parent_func: next:10'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25: -> 0x100003ce0 <+0>: pushq %rbp next:10'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26: 0x100003ce1 <+1>: movq %rsp, %rbp next:10'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27: 0x100003ce4 <+4>: movl $0x1, 0x434a(%rip) ; _dyld_private + 4 next:10'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28: 0x100003cee <+14>: leaq 0x21b(%rip), %rdi ; "function run in parent\n" next:10'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ . . . >>>>>> -- ******************** FAIL: lldb-shell :: Subprocess/fork-follow-child-wp.test (436 of 437) ******************** TEST 'lldb-shell :: Subprocess/fork-follow-child-wp.test' FAILED ******************** Script: -- : 'RUN: at line 3'; /Users/thakis/src/llvm-build-project/bin/clang --driver-mode=g++ --target=specify-a-target-or-use-a-_host-substitution --target=x86_64-apple-darwin19.6.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell -g /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/Inputs/fork.cpp -DTEST_FORK=fork -o /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child-wp.test.tmp : 'RUN: at line 4'; /Users/thakis/src/llvm-build-project/bin/lldb --no-lldbinit -S /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init -b -s /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-wp.test /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/fork-follow-child-wp.test.tmp | /Users/thakis/src/llvm-build-project/bin/FileCheck /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-wp.test -- Exit Code: 1 Command Output (stderr): -- clang-13: warning: argument unused during compilation: '-fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell' [-Wunused-command-line-argument] error: Process must be launched. /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-wp.test:12:10: error: CHECK: expected string not found in input # CHECK: stop reason = watchpoint ^ <stdin>:29:71: note: scanning from here * thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1 ^ <stdin>:40:4: note: possible intended match here function run in parent ^ Input file: <stdin> Check file: /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/fork-follow-child-wp.test -dump-input=help explains the following input dump. Input was: <<<<<< . . . 24: Watchpoint 1 hit: 25: old value: 0 26: new value: 1 27: Process 39492 resuming 28: Process 39492 stopped 29: * thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1 check:12'0 X~~ error: no match found 30: frame #0: 0x0000000100003cee fork-follow-child-wp.test.tmp`parent_func() at fork.cpp:15:3 check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31: 12 check:12'0 ~~~~~ 32: 13 void parent_func() { check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~~~ 33: 14 g_val = 1; check:12'0 ~~~~~~~~~~~~~~~ 34: -> 15 printf("function run in parent\n"); check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35: ^ check:12'0 ~~~ 36: 16 } check:12'0 ~~~~~~ 37: 17 check:12'0 ~~~~~ 38: 18 int child_func(void *unused) { check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39: (lldb) continue check:12'0 ~~~~~~~~~~~~~~~~ 40: function run in parent check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~ check:12'1 ? possible intended match 41: child exited: 0 check:12'0 ~~~~~~~~~~~~~~~~ 42: Process 39492 resuming check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~ 43: Process 39492 exited with status = 0 (0x00000000) check:12'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 44: (lldb) continue check:12'0 ~~~~~~~~~~~~~~~~ >>>>>> -- ******************** FAIL: lldb-shell :: Subprocess/vfork-follow-child-softbp.test (437 of 437) ******************** TEST 'lldb-shell :: Subprocess/vfork-follow-child-softbp.test' FAILED ******************** Script: -- : 'RUN: at line 3'; /Users/thakis/src/llvm-build-project/bin/clang --driver-mode=g++ --target=specify-a-target-or-use-a-_host-substitution --target=x86_64-apple-darwin19.6.0 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk -fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/Inputs/fork.cpp -DTEST_FORK=vfork -o /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child-softbp.test.tmp : 'RUN: at line 4'; /Users/thakis/src/llvm-build-project/bin/lldb --no-lldbinit -S /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init -b -s /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child-softbp.test /Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child-softbp.test.tmp | /Users/thakis/src/llvm-build-project/bin/FileCheck /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child-softbp.test -- Exit Code: 1 Command Output (stderr): -- clang-13: warning: argument unused during compilation: '-fmodules-cache-path=/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-clang/lldb-shell' [-Wunused-command-line-argument] /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child-softbp.test:9:10: error: CHECK: expected string not found in input # CHECK: function run in parent ^ <stdin>:1:1: note: scanning from here (lldb) command source -s 0 '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init' ^ <stdin>:6:8: note: possible intended match here (lldb) settings set interpreter.echo-comment-commands false ^ Input file: <stdin> Check file: /Users/thakis/src/llvm-project/lldb/test/Shell/Subprocess/vfork-follow-child-softbp.test -dump-input=help explains the following input dump. Input was: <<<<<< 1: (lldb) command source -s 0 '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init' check:9'0 X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: no match found 2: Executing commands in '/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/lit-lldb-init'. check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3: (lldb) # LLDB init file for the LIT tests. check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4: (lldb) settings set symbols.enable-external-lookup false check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5: (lldb) settings set plugin.process.gdb-remote.packet-timeout 60 check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6: (lldb) settings set interpreter.echo-comment-commands false check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ check:9'1 ? possible intended match 7: (lldb) settings set symbols.clang-modules-cache-path "/Users/thakis/src/llvm-build-project/lldb-test-build.noindex/module-cache-lldb" check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8: (lldb) settings set target.auto-apply-fixits false check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9: (lldb) settings set target.inherit-tcc true check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10: (lldb) settings set target.detach-on-error false check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11: (lldb) target create "/Users/thakis/src/llvm-build-project/tools/lldb/test/Shell/Subprocess/Output/vfork-follow-child-softbp.test.tmp" check:9'0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ . . . >>>>>> -- ******************** ******************** Failed Tests (5): lldb-shell :: Subprocess/fork-follow-child-softbp.test lldb-shell :: Subprocess/fork-follow-child-wp.test lldb-shell :: Subprocess/fork-follow-child.test lldb-shell :: Subprocess/vfork-follow-child-softbp.test lldb-shell :: Subprocess/vfork-follow-child.test
Comment Actions
I'm sorry about looking into it this late. I've just marked them all unsupported on Darwin.
Should we lock the WatchpointList while iterating over it? If so I think that class could benefit from an Iterable (like D105914) that will lock during iteration, which would also simplify this code a bit.