Skip to content

Rework scheduler locking - #197

Merged
daniel5151 merged 1 commit into
daniel5151:dev/0.8from
jonathanzetier:rework-scheduler-lock
May 9, 2026
Merged

daniel5151 merged 1 commit into
daniel5151:dev/0.8from
jonathanzetier:rework-scheduler-lock

Conversation

@jonathanzetier

Copy link
Copy Markdown

Description

This lays down some groundwork for v0.8, where the primary new feature will be multiprocess support, which will be similar to multithreaded support.

As discussed on the multiprocess github support issue, there's a simpler way to support the scheduler locking behavior that we plan to use for multiprocess targets, and since we're breaking the API anyways with v0.8, it's a decent time to implement it for multithreaded targets as well.

While I was in the area, I fixed some typos I noticed when I had copied most of these during local development of multiprocess-extensions.

This PR does NOT do anything about the proposed changes in this comment regarding the order in which we parse resume actions laid out here: #124 (comment).

API Stability

  • This PR does not require a breaking API change

This is part of the initial transition to v0.8. Justification for breaking the API is provided here: #124 (comment)

Another quick API breakage that might make sense to throw in this PR too is changing the name of is_thread_alive to check_thread_alive (available for bikeshedding), which removes the need for the #[allow(clippy::wrong_self_convention)].

Checklist

  • Documentation
    • Ensured any public-facing rustdoc formatting looks good (via cargo doc)
    • [N/A] (if appropriate) Added feature to "Debugging Features" in README.md
  • Validation
    • Included output of running examples/armv4t with RUST_LOG=trace + any relevant GDB output under the "Validation" section below
    • Included output of running ./example_no_std/check_size.sh before/after changes under the "Validation" section below
  • If implementing a new protocol extension IDET
    • [N/A] Included a basic sample implementation in examples/armv4t
    • [N/A] IDET can be optimized out (confirmed via ./example_no_std/check_size.sh)
    • [N/A] OR implementation requires introducing non-optional binary bloat (please elaborate under "Description")
  • If upstreaming an Arch implementation
    • [N/A] I have tested this code in my project, and to the best of my knowledge, it is working as intended.

Validation

I tested a lot of different scenarios in armv4t for both dev/0.8 and this PR. I'm taking a "ask forgiveness, not permission" here approach for the logs; there's a lot of logs to generate (which also means a lot of logs for you to sift through), so for now I'll list all the scenarios I tested, and I can post logs on request (or test alternative scenarios).

  • scheduler-lock off, continue from thread 1
  • scheduler-lock off, continue from thread 2
  • scheduler-lock off, nexti 10 from thread 1
  • scheduler-lock off, nexti 80 from thread 2 (which led to the discovery of Remove / Rename synthetic DoneStep stop reason #196)
  • scheduler-lock on, continue from thread 1 (program hangs; I needed to ctrl+C, switch to thread 2, continue, ctrl+C, switch to thread 1, continue, which makes sense given the behavior of scheduler-lock and the example binary)
  • scheduler-lock on, continue from thread 2 (program hangs; ctrl+C'ing and switching between threads doesn't actually seem to ever resolve. When I have more time I'd like dig into the example binary to figure out why that might be and if there's a deeper underlying bug, but this is the behavior exhibited by dev/0.8, so for the purposes of this PR I stopped investigating there)
  • scheduler-lock on, nexti 10 from thread 1
  • scheduler-lock on, nexti 80 from thread 2

Let me know if you would like logs for any (...or all) of these, or if there are any situations I didn't consider.

Before/After `./example_no_std/check_size.sh` output

Before

File  .text    Size          Crate Name
2.5%  68.8% 10.4KiB      [Unknown] main
0.2%   6.3%    975B        gdbstub gdbstub::stub::state_machine::GdbStubStateMachineInner<gdbstub::stub::state_machine::state::Running,T,C>::report_stop
0.1%   2.4%    372B        gdbstub gdbstub::protocol::commands::breakpoint::BasicBreakpoint::from_slice
0.1%   1.9%    295B        gdbstub <gdbstub::protocol::common::thread_id::ThreadId as core::convert::TryFrom<&[u8]>>::try_from
0.1%   1.8%    275B        gdbstub gdbstub::protocol::common::hex::decode_hex_buf
0.1%   1.4%    222B        gdbstub gdbstub::stub::core_impl::resume::<impl gdbstub::stub::core_impl::GdbStubImpl<T,C>>::write_stop_common
0.1%   1.4%    221B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write
0.0%   1.3%    204B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_specific_thread_id
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    132B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.8%    131B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.8%    122B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::inner_write
0.0%   0.7%    110B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.7%    109B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    107B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    106B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_addrs
0.0%   0.7%    104B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_hex
0.0%   0.7%    102B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::flush
0.0%   0.6%     93B           core <core::iter::adapters::skip::Skip<I> as core::iter::traits::iterator::Iterator>::next
0.0%   0.6%     92B        gdbstub <gdbstub::protocol::common::thread_id::IdKind as core::convert::TryFrom<&[u8]>>::try_from
0.0%   0.6%     87B           core <core::slice::iter::SplitMut<T,P> as core::iter::traits::iterator::Iterator>::next
0.0%   0.4%     67B   gdbstub_arch <gdbstub_arch::arm::reg::arm_core::ArmCoreRegs as gdbstub::arch::Registers>::gdb_deserialize
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_addrs
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::resume
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::set_resume_action_continue
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::clear_resume_actions
0.0%   0.3%     44B  gdbstub_nostd gdbstub_nostd::print_str::print_str
0.0%   0.2%     38B      [Unknown] _start
0.0%   0.0%      6B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::breakpoints::SwBreakpoint>::add_sw_breakpoint
3.6% 100.0% 15.1KiB                .text section size, the file size is 420.9KiB
target/release/gdbstub-nostd  :
section               size    addr
.interp                 28     680
.note.ABI-tag           32     708
.note.gnu.build-id      36     740
.dynsym                384     776
.gnu.version            32    1160
.gnu.version_r          64    1192
.gnu.hash               28    1256
.dynstr                215    1284
.rela.dyn              432    1504
.rela.plt               24    1936
.rodata               1005    1968
.eh_frame_hdr          268    2976
.eh_frame             1328    3248
.text                15495    8672
.init                   27   24168
.fini                   13   24196
.plt                    32   24224
.fini_array              8   28352
.init_array              8   28360
.dynamic               432   28368
.got                   120   28800
.got.plt                32   28920
.relro_padding        3816   28952
.tm_clone_table          0   33048
.data                    8   33048
.bss                     1   33056
.comment               184       0
Total                24052

After

File  .text    Size          Crate Name
2.5%  68.5% 10.3KiB      [Unknown] main
0.2%   6.3%    975B        gdbstub gdbstub::stub::state_machine::GdbStubStateMachineInner<gdbstub::stub::state_machine::state::Running,T,C>::report_stop
0.1%   2.4%    372B        gdbstub gdbstub::protocol::commands::breakpoint::BasicBreakpoint::from_slice
0.1%   1.9%    295B        gdbstub <gdbstub::protocol::common::thread_id::ThreadId as core::convert::TryFrom<&[u8]>>::try_from
0.1%   1.8%    275B        gdbstub gdbstub::protocol::common::hex::decode_hex_buf
0.1%   1.4%    222B        gdbstub gdbstub::stub::core_impl::resume::<impl gdbstub::stub::core_impl::GdbStubImpl<T,C>>::write_stop_common
0.1%   1.4%    221B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write
0.0%   1.3%    204B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_specific_thread_id
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    143B           core core::iter::traits::iterator::Iterator::nth
0.0%   0.9%    132B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.9%    131B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.8%    122B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::inner_write
0.0%   0.7%    110B        gdbstub gdbstub::protocol::common::hex::decode_hex
0.0%   0.7%    109B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    107B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_num
0.0%   0.7%    106B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_addrs
0.0%   0.7%    104B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::write_hex
0.0%   0.7%    102B        gdbstub gdbstub::protocol::response_writer::ResponseWriter<C>::flush
0.0%   0.6%     93B           core <core::iter::adapters::skip::Skip<I> as core::iter::traits::iterator::Iterator>::next
0.0%   0.6%     92B        gdbstub <gdbstub::protocol::common::thread_id::IdKind as core::convert::TryFrom<&[u8]>>::try_from
0.0%   0.6%     87B           core <core::slice::iter::SplitMut<T,P> as core::iter::traits::iterator::Iterator>::next
0.0%   0.4%     67B   gdbstub_arch <gdbstub_arch::arm::reg::arm_core::ArmCoreRegs as gdbstub::arch::Registers>::gdb_deserialize
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::read_registers
0.0%   0.4%     65B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadBase>::write_addrs
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::resume
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::set_resume_action_continue
0.0%   0.3%     50B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::base::multithread::MultiThreadResume>::clear_resume_actions
0.0%   0.3%     44B  gdbstub_nostd gdbstub_nostd::print_str::print_str
0.0%   0.2%     38B      [Unknown] _start
0.0%   0.0%      6B gdbstub_nostd? <gdbstub_nostd::gdb::DummyTarget as gdbstub::target::ext::breakpoints::SwBreakpoint>::add_sw_breakpoint
3.6% 100.0% 15.0KiB                .text section size, the file size is 418.3KiB
target/release/gdbstub-nostd  :
section               size    addr
.interp                 28     680
.note.ABI-tag           32     708
.note.gnu.build-id      36     740
.dynsym                384     776
.gnu.version            32    1160
.gnu.version_r          64    1192
.gnu.hash               28    1256
.dynstr                215    1284
.rela.dyn              432    1504
.rela.plt               24    1936
.rodata                989    1968
.eh_frame_hdr          268    2960
.eh_frame             1328    3232
.text                15357    8656
.init                   27   24016
.fini                   13   24044
.plt                    32   24064
.fini_array              8   28192
.init_array              8   28200
.dynamic               432   28208
.got                   120   28640
.got.plt                32   28760
.relro_padding        3976   28792
.tm_clone_table          0   32888
.data                    8   32888
.bss                     1   32896
.comment               184       0
Total                24058

@daniel5151 daniel5151 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent first PR! A few minor comments, but at first blush - I don't see anything wrong with this approach.

And yeah, no worries about providing the big mess of logs. There are a lot of scenarios, and aside from trusting that you're validating the changes as you work on them, I'm sure I'll also spend some time poking around with the examples as we progress further along in 0.8's development

Comment thread src/target/ext/base/multithread.rs
Comment thread src/target/ext/base/multithread.rs
Comment thread examples/armv4t_multicore/gdb.rs Outdated
Comment thread src/target/ext/base/multithread.rs
@jonathanzetier

Copy link
Copy Markdown
Author

Sounds good! Typically with PRs after feedback, I amend my commit and force push, though I'm not sure how well GitHub handles this (most of my experience is with GitLab, which handles this...decently enough). I know this is a controversial practice though; do you have any strong feelings about this? I'm comfortable enough just pushing new commits if that's what you prefer.

@daniel5151

Copy link
Copy Markdown
Owner

The PR is gonna get squash-merge'd, so you can feel free to iterate on it however you like!

@jonathanzetier
jonathanzetier force-pushed the rework-scheduler-lock branch from 9e4cf4f to 0c0e6ff Compare May 8, 2026 03:46
@jonathanzetier

Copy link
Copy Markdown
Author

After incorporating the changes to vCont, the binary size of the example_nostd went down a bit. The .text section dropped a few hundred bytes, nothing to sneeze at (something like 2%), but that seemed to drop the size enough that there didn't need to be as much bytes in the relro padding section, which drops the size another 3000 bytes!

section               size    addr
.interp                 28     680
.note.ABI-tag           32     708
.note.gnu.build-id      36     740
.dynsym                384     776
.gnu.version            32    1160
.gnu.version_r          64    1192
.gnu.hash               28    1256
.dynstr                215    1284
.rela.dyn              432    1504
.rela.plt               24    1936
.rodata               1005    1968
.eh_frame_hdr          268    2976
.eh_frame             1328    3248
.text                15495    8672
.init                   27   24168
.fini                   13   24196
.plt                    32   24224
.fini_array              8   28352
.init_array              8   28360
.dynamic               432   28368
.got                   120   28800
.got.plt                32   28920
.relro_padding        3816   28952
.tm_clone_table          0   33048
.data                    8   33048
.bss                     1   33056
.comment               184       0
Total                24052

@jonathanzetier
jonathanzetier force-pushed the rework-scheduler-lock branch 2 times, most recently from ff70565 to d78fe5c Compare May 8, 2026 14:25
Comment thread src/protocol/commands/_vCont.rs Outdated
// "Specifying no actions is an error."
b"" => None,
b"?" => Some(vCont::Query),
_ => Some(vCont::Actions(Actions::new_from_buf(body))),

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the following formulation will let you avoid the unnecessary empty-body handling in the iterator:

Suggested change
_ => Some(vCont::Actions(Actions::new_from_buf(body))),
[b';', rest @ ..] => Some(vCont::Actions(Actions::new_from_buf(rest))),
_ => None,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about doing that at first too, but the protocol specifies that the leading semicolon is part of the action, so I figured keeping the semicolon in there is a more pure representation of the actions, and doesn't carry around the cognitive baggage of having to remember "this datatype has the full contents of every action *except the first one, which is missing the leading semicolon".

That being said, it's small enough and you could just as easily make the case that removing the leading semicolon cleans up the loop, and it's just shifting the cognitive baggage between the code versus datastructures, and it becomes a matter of preference.

Just wanted to offer an alternative viewpoint; I'll plan to implement the suggestion, unless you say otherwise!

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think it's totally fine treating individual packet parser modules (i.e: _vCont.rs, etc...) as single "cognitive domains". And even though the iterator data structure does end up being used outside the module, external consumers don't need to care about how the parser works (i.e: whether it was front-loaded vs. deferred, etc...).

Comment thread src/stub/core_impl/resume.rs Outdated
Comment on lines +94 to +95
// ourselves with: 1 action, or 2 actions where the second is a
// continue action (which occurs when XXX?) that we ignore.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the behavior I observed in the past was that GDB would send over a packet along the lines of vCont;s:foo,c, even in single-threaded scenarios.

Comment thread src/target/ext/base/multithread.rs
Comment thread src/target/ext/base/multithread.rs Outdated
/// and end (exclusive) addresses, or another stop condition is met
/// (e.g: a breakpoint it hit).
///
/// If no thread is specified, step all threads, if supported.

@daniel5151 daniel5151 May 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know I just said that we should apply this transform to all functions... but now that I see this change in the context of range stepping, I wonder if this is actually the right call?

Sure, at a protocol level, this would be valid... but I wonder if it's actually possible (in practice) to configure GDB / LLDB to send over a range-step action as the fallback for all threads? Heck, same thought applies to single-step as a fallback action, and the reverse-step/continue actions as well.

Maybe for v0, we should leave all actions except for set_resume_action_continue as taking a specific tid, and adding some error-handling inside gdbstub to warn the user if the GDB client tries to use a non-continue fallback action (and, in turn - to open an issue on github reporting how they managed to get into that situation)?

At that point, assuming someone does stumble across a valid debugging scenario with a non-continue default resume actions... it shouldn't be too hard to add new (backwards-compatible) set_resume_action_{step,reange_step}_as_fallback IDETs to allow hooking into that functionality.

The benefit is that in the common case where a client + target do not support fallback actions aside from continue, the implementation of set_resume_action_* foo methods don't need to include error handling for None thread IDs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, that's why I left it off of the step resume actions in the first iteration, but figured it probably wasn't too much to ask of targets to complain about not being able to handle it.

The error message for PacketUnexpected (the original error returned in this case) seems to accomplish this, saying it's something we don't expect to happen, and a request to file an issue, so I'm planning to just revert these changes, unless you'd prefer a more specific error variant

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PacketUnexpected is the "cop out" error message when past me was too lazy to add in a proper error message with more context, hah.

I'm fine using it here for expediency (and wouldn't block the PR on it), but if you want to add a proper error message with some more context, that might be better.

Error paths as a whole need more love, but that's a larger work stream in and of itself #112

@jonathanzetier
jonathanzetier force-pushed the rework-scheduler-lock branch from d78fe5c to 0949523 Compare May 9, 2026 03:06
@jonathanzetier

jonathanzetier commented May 9, 2026 •

Copy link
Copy Markdown
Author

In my last comment regarding the cargo bloat result, I seem to have accidentally copied the "before" size. After the requested changes, the cargo bloat result is still significantly smaller (again due to the smaller relro_padding section). Here's what it is now (which is closer to what my last comment above was, if I had actually copied the correct size)

section               size    addr
.interp                 28     680
.note.ABI-tag           32     708
.note.gnu.build-id      36     740
.dynsym                384     776
.gnu.version            32    1160
.gnu.version_r          64    1192
.gnu.hash               28    1256
.dynstr                215    1284
.rela.dyn              432    1504
.rela.plt               24    1936
.rodata                973    1968
.eh_frame_hdr          260    2944
.eh_frame             1312    3208
.text                15008    8624
.init                   27   23632
.fini                   13   23660
.plt                    32   23680
.fini_array              8   27808
.init_array              8   27816
.dynamic               432   27824
.got                   120   28256
.got.plt                32   28376
.relro_padding         264   28408
.tm_clone_table          0   32504
.data                    8   32504
.bss                     1   32512
.comment               184       0
Total                19957

@daniel5151 daniel5151 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 small nits, but otherwise LGTM!

Comment thread examples/armv4t_multicore/emu.rs Outdated
Comment on lines +207 to +213
if self.exec_mode.is_empty() {
// This should never happen (gdbstub will always ensure at least one
// `set_resume_action_XXX` method is called), but in case it does, we explicitly
// log it and return the closest event that represents this.
eprintln!("Running while all threads are stopped; this should never happen! Treating as 0 steps");
return RunEvent::Event(Event::DoneStep, CpuId::Cpu);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, I really think this entire block should just be omitted.

The docs and gdbstub implementation make it clear that the contract forbids calling this method without having called set_resume_action_*, so we shouldn't nudge end users to hedge against bugs in gdbstub.

If you want to leave this in purely in the example code, then swap it out with:

Suggested change
if self.exec_mode.is_empty() {
// This should never happen (gdbstub will always ensure at least one
// `set_resume_action_XXX` method is called), but in case it does, we explicitly
// log it and return the closest event that represents this.
eprintln!("Running while all threads are stopped; this should never happen! Treating as 0 steps");
return RunEvent::Event(Event::DoneStep, CpuId::Cpu);
}
assert!(!self.exec_mode.is_empty(), "gdbstub violated resume() contract (called prior to calling `set_resume_action_XXX` at least once");

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops! For some reason I thought you only meant the block in the resume() function, not this one. I just removed the block entirely.

Comment thread src/protocol/commands/_vCont.rs Outdated
b"?" => Some(vCont::Query),
_ => Some(vCont::Actions(Actions::new_from_buf(body))),
[b';', rest @ ..] => Some(vCont::Actions(Actions::new_from_buf(rest))),
// Anything that doesn't start with a semicolon is malformed

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nix the comment (the ? case is literally 2 lines up lol)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it again, the empty case also doesn't need to exist, so I took that out too

This lays down some groundwork for v0.8, where the primary new feature
will be multiprocess support, which will be similar to multithreaded
support.

As discussed on the multiprocess github support issue, there's
a simpler way to support the scheduler locking behavior that we plan to
use for multiprocess targets, and since we're breaking the API anyways
with v0.8, it's a decent time to implement it for multithreaded targets
as well.
@jonathanzetier
jonathanzetier force-pushed the rework-scheduler-lock branch from 0949523 to 2acb95f Compare May 9, 2026 21:50

@daniel5151 daniel5151 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! :shipit:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants