Skip to content

Commit 75570fd

Browse files
committed
zephyr: work: Fix lifetimes of submitted work
Using the return code from submitting work, distinguish the cases where work is actually submitted vs those where the work was not submitted (either "already submitted" or an error). If it was not submitted, turn the value back into an Arc, so that it can be properly dropped. Signed-off-by: David Brown <[email protected]>
1 parent edf102c commit 75570fd

File tree

1 file changed

+25
-3
lines changed

1 file changed

+25
-3
lines changed

zephyr/src/work.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,11 +526,15 @@ impl<T: SimpleAction + Send> Work<T> {
526526
// SAFETY: C the code does not perform moves on the data, and the `from_raw` below puts it
527527
// back into a Pin when it reconstructs the Arc.
528528
let this = unsafe { Pin::into_inner_unchecked(this) };
529-
let _ = Arc::into_raw(this);
529+
let _ = Arc::into_raw(this.clone());
530530

531531
// SAFETY: The Pin ensures this will not move. Our implementation of drop ensures that the
532532
// work item is no longer queued when the data is dropped.
533-
SubmitResult::to_result(unsafe { k_work_submit(work) })
533+
let result = SubmitResult::to_result(unsafe { k_work_submit(work) });
534+
535+
Self::check_drop(work, &result);
536+
537+
result
534538
}
535539

536540
/// Submit this work to a specified work queue.
@@ -550,7 +554,11 @@ impl<T: SimpleAction + Send> Work<T> {
550554

551555
// SAFETY: The Pin ensures this will not move. Our implementation of drop ensures that the
552556
// work item is no longer queued when the data is dropped.
553-
SubmitResult::to_result(unsafe { k_work_submit_to_queue(queue.item.get(), work) })
557+
let result = SubmitResult::to_result(unsafe { k_work_submit_to_queue(queue.item.get(), work) });
558+
559+
Self::check_drop(work, &result);
560+
561+
result
554562
}
555563

556564
/// Callback, through C, but bound by a specific type.
@@ -590,6 +598,20 @@ impl<T: SimpleAction + Send> Work<T> {
590598
Pin::new_unchecked(this)
591599
}
592600

601+
/// Determine if this work was submitted, and cause a drop of the Arc to happen if it was not.
602+
pub fn check_drop(work: *const k_work, result: &crate::Result<SubmitResult>) {
603+
if matches!(result, Ok(SubmitResult::AlreadySubmitted) | Err(_)) {
604+
// SAFETY: If the above submit indicates that it was already running, the work will not
605+
// be submitted (no additional handle will be called). "un leak" the work so that it
606+
// will be dropped. Also, any error indicates that the work did not enqueue.
607+
unsafe {
608+
let this = Self::from_raw(work);
609+
drop(this);
610+
}
611+
}
612+
613+
}
614+
593615
/// Access the inner action.
594616
pub fn action(&self) -> &T {
595617
&self.action

0 commit comments

Comments
 (0)