feat(arty_executor): migrate executor from ox-sdk - #647
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
✅ Version increments look sufficient
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #647 +/- ##
=========================================
Coverage 100.0% 100.0%
=========================================
Files 473 484 +11
Lines 45493 46552 +1059
=========================================
+ Hits 45493 46552 +1059
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 30 changed files in this pull request and generated no new comments.
Suppressed comments (13)
crates/arty_executor/src/wake.rs:125
- Comment typo: "x84" should be "x86" (the fence is a no-op on x86, not an "x84" architecture).
// This does nothing on x84 but on weaker memory models, the visibility of
// writes to arbitrary locations may be delayed without this fence.
crates/arty_executor/src/wake.rs:232
- Spelling: "ocasional" -> "occasional".
#[cfg_attr(test, mutants::skip)] // It's well tested, but causes ocasional test timeouts
crates/arty_executor/src/wake.rs:260
- Repository coverage convention: unit-test modules inside library code should be excluded from coverage with
#[cfg_attr(coverage_nightly, coverage(off))](see e.g.crates/tick/src/error.rs:103-105). This avoids test-only lines impacting the 100% coverage gate.
#[cfg(test)]
mod tests {
crates/arty_executor/src/task.rs:300
- Repository coverage convention: unit-test modules inside library code should be excluded from coverage with
#[cfg_attr(coverage_nightly, coverage(off))](see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/executor.rs:153
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/executor_core.rs:767
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/join_handle.rs:51
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/task_ref.rs:108
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/task_set.rs:50
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/ptr_hash.rs:50
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake_diagnostic.rs:165
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/builder.rs:86
- Repository coverage convention: add
#[cfg_attr(coverage_nightly, coverage(off))]above#[cfg(test)] mod testsso test-only lines don't affect coverage gating (see e.g.crates/tick/src/error.rs:103-105).
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake_diagnostic.rs:106
RawWakerVTable::wakeis the consuming variant; forwarding it toinner.wake_by_ref()can miss optimizations or semantics of the underlying waker's consumingwake(). Prefer calling the consumingwake()on the inner waker and then droppingDiagnosticWakerto unregister the backtrace.
let waker = unwrap_diagnostic_waker(ptr);
waker.inner.wake_by_ref();
// This consumes the waker!
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 30 changed files in this pull request and generated no new comments.
Suppressed comments (10)
crates/arty_executor/src/executor_core.rs:369
- Comment has a duplicated word ("on the the thread").
// SAFETY: The task is alive (we own it and just created it) and we are on the the thread
crates/arty_executor/src/executor_core.rs:392
- Comment has a duplicated word ("on the the thread").
// SAFETY: The task is alive (we own it and just created it) and we are on the the thread
crates/arty_executor/src/executor_core.rs:449
- Comment has a duplicated word ("on the the thread").
// SAFETY: The task is alive (we own it and just created it) and we are on the the thread
crates/arty_executor/src/executor_core.rs:542
- Comment has a duplicated word ("on the the thread").
// SAFETY: The task is alive (we own it and just created it) and we are on the the thread
crates/arty_executor/src/executor_core.rs:651
- Comment has a duplicated word ("on the the thread").
// SAFETY: The task is alive (we own it and just created it) and we are on the the thread
crates/arty_executor/src/task.rs:283
- Doc comment has a duplicated word ("the the").
/// Initializes the the task, providing it the wake signal that it needs to enable polling
crates/arty_executor/src/executor.rs:91
- Doc comment has a duplicated word ("with with").
/// Creates a new handle to the set of tasks registered with with the executor. You can use
crates/arty_executor/src/wake.rs:124
- Typo in architecture name: "x84" should be "x86".
// This does nothing on x84 but on weaker memory models, the visibility of
crates/arty_executor/src/wake.rs:232
- Spelling typo in comment: "ocasional" should be "occasional".
#[cfg_attr(test, mutants::skip)] // It's well tested, but causes ocasional test timeouts
crates/arty_executor/src/executor_core.rs:239
- Comment has a duplicated word ("on the the thread").
This issue also appears in the following locations of the same file:
- line 369
- line 392
- line 449
- line 542
- line 651
// SAFETY: The task is alive (we own it and just created it) and we are on the the thread
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 30 changed files in this pull request and generated no new comments.
Suppressed comments (16)
crates/arty_executor/src/executor_core.rs:767
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module to keep the crate’s coverage gate stable.
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake.rs:260
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; other crates in this repo add#[cfg_attr(coverage_nightly, coverage(off))]immediately above test modules to avoid counting test harness lines toward the 100% coverage requirement.
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake_diagnostic.rs:165
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module so test-only lines don't count toward the 100% coverage requirement.
#[cfg(test)]
mod tests {
crates/arty_executor/src/task.rs:300
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module to avoid coverage failures due to test-only lines being counted.
#[cfg(test)]
mod tests {
crates/arty_executor/src/executor.rs:153
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module so coverage doesn't count test harness code.
#[cfg(test)]
mod tests {
crates/arty_executor/src/join_handle.rs:51
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module to avoid counting test code toward coverage.
#[cfg(test)]
mod tests {
crates/arty_executor/src/task_set.rs:50
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module to prevent test-only lines from impacting coverage.
#[cfg(test)]
mod tests {
crates/arty_executor/src/task_ref.rs:108
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module so test-only lines don’t count toward coverage.
#[cfg(test)]
mod tests {
crates/arty_executor/src/ptr_hash.rs:50
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module to keep coverage accounting consistent with the rest of the workspace.
#[cfg(test)]
mod tests {
crates/arty_executor/src/builder.rs:86
- The
#[cfg(test)] mod testsmodule should be excluded from thecoverage_nightlycoverage gate; add#[cfg_attr(coverage_nightly, coverage(off))]above the module to avoid coverage-gate failures from test-only code.
#[cfg(test)]
mod tests {
crates/arty_executor/src/task.rs:284
- Duplicate word in trait docs: "Initializes the the task".
/// Initializes the the task, providing it the wake signal that it needs to enable polling
///
crates/arty_executor/src/wake.rs:232
- Typo in comment: "ocasional" should be "occasional".
#[cfg_attr(test, mutants::skip)] // It's well tested, but causes ocasional test timeouts
crates/arty_executor/src/wake.rs:125
- Typo in comment: this should refer to x86 (or x86_64), not "x84".
// This does nothing on x84 but on weaker memory models, the visibility of
// writes to arbitrary locations may be delayed without this fence.
crates/arty_executor/src/executor.rs:92
- Duplicate word in doc comment: "with with".
/// Creates a new handle to the set of tasks registered with with the executor. You can use
/// this to register additional tasks.
crates/arty_executor/src/executor_core.rs:74
- Grammar in field docs: "try report" should be "try to report".
This issue also appears on line 766 of the same file.
/// threads). New tasks can no longer be scheduled in this mode (a panic will occur). If the
/// deadline is reached without a successful shutdown, we terminate the process and try report
/// the underlying reasons.
crates/arty_executor/src/ptr_hash.rs:43
PointerHasher::writecurrently panics unless the input slice is exactly 8 bytes.Hasherimplementors may receive 4-byte inputs on 32-bit platforms (e.g., viawrite_usize’s default implementation), and the panic would make this type unexpectedly non-portable.
fn write(&mut self, bytes: &[u8]) {
let input_raw = u64::from_ne_bytes(
bytes
.try_into()
.expect("PointerHasher only supports 64-bit input data, so the slice must be exactly 8 bytes long."),
);
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated no new comments.
Suppressed comments (6)
crates/arty_executor/src/wake.rs:232
- Spelling typo in comment: "ocasional" -> "occasional".
#[cfg_attr(test, mutants::skip)] // It's well tested, but causes ocasional test timeouts
crates/arty_executor/src/wake.rs:125
- Typo in comment: "x84" should be "x86" (the usual reference is to x86/x86_64 memory model).
This issue also appears on line 232 of the same file.
// This does nothing on x84 but on weaker memory models, the visibility of
// writes to arbitrary locations may be delayed without this fence.
crates/arty_executor/src/task.rs:283
- Doc comment has a duplicated word: "the the".
/// Initializes the the task, providing it the wake signal that it needs to enable polling
crates/arty_executor/src/lib.rs:16
- The generated README currently links
JoinHandletohttps://crates.io/crates/JoinHandle(a non-existent crate). Using an explicit intra-doc link target here should make doc2readme resolve it to the localcrate::JoinHandleinstead.
//! Application logic may encounter [`JoinHandle`]s but otherwise has no direct interaction
//! with the executor.
crates/arty_executor/src/executor.rs:91
- Doc comment has a duplicated word: "with with".
/// Creates a new handle to the set of tasks registered with with the executor. You can use
.spelling:801
- Duplicate entry:
wakeralready exists earlier in this file (line ~620). Keeping duplicates can make future dictionary maintenance noisier.
waker
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated no new comments.
Suppressed comments (13)
crates/arty_executor/src/ptr_hash.rs:50
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake.rs:232
- Typo in comment: "ocasional" should be "occasional".
#[cfg_attr(test, mutants::skip)] // It's well tested, but causes ocasional test timeouts
crates/arty_executor/src/ptr_hash.rs:43
- PointerHasher::write() panics unless the input slice is exactly 8 bytes, but pointer hashing may feed 4-byte usize values on 32-bit targets. Supporting both 4- and 8-byte inputs (or overriding write_usize) avoids a cross-target panic.
This issue also appears on line 49 of the same file.
fn write(&mut self, bytes: &[u8]) {
let input_raw = u64::from_ne_bytes(
bytes
.try_into()
.expect("PointerHasher only supports 64-bit input data, so the slice must be exactly 8 bytes long."),
crates/arty_executor/src/task_set.rs:50
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake.rs:124
- Typo in architecture name: this comment likely meant x86 (or x86_64), not "x84".
// This does nothing on x84 but on weaker memory models, the visibility of
crates/arty_executor/src/executor.rs:153
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/builder.rs:86
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake.rs:260
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/task.rs:300
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/wake_diagnostic.rs:165
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/executor_core.rs:767
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/join_handle.rs:51
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
crates/arty_executor/src/task_ref.rs:108
- Test modules should be excluded from coverage accounting to avoid tripping the workspace 100% coverage gate (repo convention is #[cfg_attr(coverage_nightly, coverage(off))] above #[cfg(test)] mod tests).
#[cfg(test)]
mod tests {
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated no new comments.
Suppressed comments (5)
crates/arty_executor/src/wake.rs:150
- The safety contract is inverted: the wake signal must not be dropped until
is_inert()returns true (i.e., is inert). As written, it says "until ... signalsfalse", which is the opposite of the intended meaning.
/// After calling this, the owner of the wake signal must query `is_inert()` for permission
/// to drop the object. Until `is_inert()` signals `false`, the wake signal must not be dropped.
.spelling:801
.spellingcontainswakertwice (already present earlier). Duplicate entries can cause unnecessary churn and may break tooling that expects unique dictionary words.
dereferencing
enqueue
enqueued
multithreaded
waker
crates/arty_executor/src/wake.rs:124
- Typo in the architecture name: "x84" should be "x86" (or similar) in this comment.
// This does nothing on x84 but on weaker memory models, the visibility of
crates/arty_executor/src/wake.rs:232
- Spelling typo in this comment: "ocasional" -> "occasional".
#[cfg_attr(test, mutants::skip)] // It's well tested, but causes ocasional test timeouts
crates/arty_executor/src/ptr_hash.rs:43
PointerHasher::writepanics unless the input slice is exactly 8 bytes, butHashcommonly feedsHasher::writewithusize-sized bytes (4 bytes on 32-bit targets) viawrite_usize. That makes this hasher architecture-dependent and can panic at runtime on 32-bit targets when hashing pointers.
fn write(&mut self, bytes: &[u8]) {
let input_raw = u64::from_ne_bytes(
bytes
.try_into()
.expect("PointerHasher only supports 64-bit input data, so the slice must be exactly 8 bytes long."),
);
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4026d9f7-fe1c-4acd-ac16-e84204180086
|
review this PR |
martintmk
left a comment
There was a problem hiding this comment.
[Copilot speaking]
Shutdown progress and timeout validation still violate the public lifecycle contract, and a completed future's destructor can escape the executor's panic trap and leave executor-owned state inconsistent. Verdict: changes requested.
| // We want to be immediately called again because we may have more work to do. | ||
| CYCLE_OUTCOME_CONTINUE.with(Event::observe_once); | ||
| CycleOutcome::Continue | ||
| } else { |
There was a problem hiding this comment.
This returns Suspend while shutdown is still waiting on completed tasks or result resources, but releasing those resources does not wake owner_waker; verified: a live JoinHandle makes the first shutdown cycle suspend, and dropping it provides no signal to cycle again. Return Continue while shutdown_deadline is set, or wake the owner whenever a shutdown-blocking resource is released.
| state_reentrant.shutdown_deadline = Some( | ||
| shutdown_start_time | ||
| .checked_add(self.shared.shutdown_timeout) | ||
| .expect("impossible for shutdown timeout to be so high we cross the end of the universe"), |
There was a problem hiding this comment.
shutdown_timeout() accepts every Duration, but verified: Duration::MAX panics here when shutdown begins. Reject unrepresentable timeouts in the builder, treat them as no deadline, or document and test this panic instead of claiming caller-controlled input is impossible.
| task::Poll::Ready(result) => { | ||
| // We need to send the result through the result transmitter. This also drops | ||
| // any state still held by the state machine, as it cannot be polled any more. | ||
| let tx = maybe_payload |
There was a problem hiding this comment.
Taking and dropping the completed future here, and dropping it in abort(), runs arbitrary user Drop code outside the panic trap; verified: a future that returns Ready and panics in Drop unwinds from execute_cycle(). Include payload destruction in the trap and route it to on_unhandled_task_panic so executor-owned queues cannot be left inconsistent.
| /// # Resource management | ||
| /// | ||
| /// Join handles must be dropped before the executor they came from shuts down or the executor | ||
| /// shutdown will result in a timeout and panic. You can think of it as there existing an imaginary |
There was a problem hiding this comment.
Non-blocking: consumers cannot select the test-only Panic timeout behavior; the production path aborts the process. Document process termination rather than a panic, because this cannot be caught or unwound.
| // times. That is fine - it is up to the receiver of the notifications to deal | ||
| // with spurious notifications (which may arrive anyway through other means). | ||
| awakened_set.push_back(self.task_ref); | ||
| self.parent_waker.wake_by_ref(); |
There was a problem hiding this comment.
Non-blocking: parent_waker is arbitrary external code and is invoked while the awakened-queue mutex remains held, widening the window in which concurrent wakes fall back to the O(n) scan. Drop awakened_set after the push and before calling wake_by_ref().
| #[library_benchmark] | ||
| #[bench::async_round_trip(setup = make_executor_only)] | ||
| fn spawn_and_complete(mut state: State) -> State { | ||
| let mut join_handle = Box::pin(state.tasks.add(async move {})); |
There was a problem hiding this comment.
Non-blocking: this heap allocation is inside the measured Callgrind region, while the paired Criterion benchmark stack-pins the handle. Use pin! and let the handle drop in the measured body so the two benchmarks measure the same operation.
Summary
oxidizer_executorfrom the O365 Coreox-sdkrepository at commit47aaa9f9fc60e95de9b0c3aeb7742e7cd883f9cearty_executorValidation
arty_executorall-feature/all-target tests: 39 passed