@@ -331,24 +331,6 @@ impl SubmitResult {
331331 }
332332}
333333
334- /*
335- pub trait Queueable: Send + Sync {
336- fn as_ptr(&self) -> *const ();
337- }
338-
339- impl<T: Send + Sync> Queueable for Arc<T> {
340- fn as_ptr(&self) -> *const () {
341- todo!()
342- }
343- }
344-
345- impl<T: Send + Sync> Queueable for &'static T {
346- fn as_ptr(&self) -> *const () {
347- todo!()
348- }
349- }
350- */
351-
352334/// A simple action that just does something with its data.
353335///
354336/// This is similar to a Future, except there is no concept of it completing. It manages its
@@ -394,16 +376,15 @@ impl<T: SimpleAction + Send> Work<T> {
394376 /// inter-thread sharing mechanisms are needed.
395377 ///
396378 /// TODO: Can we come up with a way to allow sharing on the same worker using Rc instead of Arc?
397- pub fn new ( action : T ) -> Pin < Arc < Self > > {
398- let this = Arc :: pin ( Self {
399- // SAFETY: will be initialized below, after this is pinned.
400- work : unsafe { mem:: zeroed ( ) } ,
401- action,
402- } ) ;
379+ pub fn new < P > ( action : T ) -> P
380+ where
381+ P : SubmittablePointer < T > ,
382+ {
383+ let this: P = unsafe { SubmittablePointer :: new_ptr ( action) } ;
403384
404- // SAFETY: Initializes above zero-initialized struct.
385+ // SAFETY: Initializes the above zero-initialized struct.
405386 unsafe {
406- k_work_init ( this. work . get ( ) , Some ( Self :: handler) ) ;
387+ k_work_init ( this. get_work ( ) , Some ( P :: handler) ) ;
407388 }
408389
409390 this
@@ -413,89 +394,117 @@ impl<T: SimpleAction + Send> Work<T> {
413394 ///
414395 /// This can return several possible `Ok` results. See the docs on [`SubmitResult`] for an
415396 /// explanation of them.
416- pub fn submit ( this : Pin < Arc < Self > > ) -> crate :: Result < SubmitResult > {
397+ pub fn submit < P > ( this : P ) -> crate :: Result < SubmitResult >
398+ where
399+ P : SubmittablePointer < T > ,
400+ {
417401 // We "leak" the arc, so that when the handler runs, it can be safely turned back into an
418402 // Arc, and the drop on the arc will then run.
419- let work = this. work . get ( ) ;
403+ let work = this. get_work ( ) ;
420404
421405 // SAFETY: C the code does not perform moves on the data, and the `from_raw` below puts it
422406 // back into a Pin when it reconstructs the Arc.
423- let this = unsafe { Pin :: into_inner_unchecked ( this) } ;
424- let _ = Arc :: into_raw ( this. clone ( ) ) ;
407+ unsafe {
408+ P :: into_raw ( this) ;
409+ }
425410
426411 // SAFETY: The Pin ensures this will not move. Our implementation of drop ensures that the
427412 // work item is no longer queued when the data is dropped.
428413 let result = SubmitResult :: to_result ( unsafe { k_work_submit ( work) } ) ;
429414
430- Self :: check_drop ( work, & result) ;
415+ P :: check_drop ( work, & result) ;
431416
432417 result
433418 }
434419
435420 /// Submit this work to a specified work queue.
436421 ///
437422 /// TODO: Change when we have better wrappers for work queues.
438- pub fn submit_to_queue (
439- this : Pin < Arc < Self > > ,
440- queue : & ' static WorkQueue ,
441- ) -> crate :: Result < SubmitResult > {
442- let work = this. work . get ( ) ;
423+ pub fn submit_to_queue < P > ( this : P , queue : & ' static WorkQueue ) -> crate :: Result < SubmitResult >
424+ where
425+ P : SubmittablePointer < T > ,
426+ {
427+ let work = this. get_work ( ) ;
443428
444429 // "leak" the arc to give to C. We'll reconstruct it in the handler.
445430 // SAFETY: The C code does not perform moves on the data, and the `from_raw` below puts it
446431 // back into a Pin when it reconstructs the Arc.
447- let this = unsafe { Pin :: into_inner_unchecked ( this) } ;
448- let _ = Arc :: into_raw ( this) ;
432+ unsafe {
433+ P :: into_raw ( this) ;
434+ }
449435
450436 // SAFETY: The Pin ensures this will not move. Our implementation of drop ensures that the
451437 // work item is no longer queued when the data is dropped.
452438 let result =
453439 SubmitResult :: to_result ( unsafe { k_work_submit_to_queue ( queue. item . get ( ) , work) } ) ;
454440
455- Self :: check_drop ( work, & result) ;
441+ P :: check_drop ( work, & result) ;
456442
457443 result
458444 }
459445
460- /// Callback, through C, but bound by a specific type.
461- extern "C" fn handler ( work : * mut k_work ) {
462- // We want to avoid needing a `repr(C)` on our struct, so the `k_work` pointer is not
463- // necessarily at the beginning of the struct.
464- // SAFETY: Converts raw pointer to work back into the box.
465- let this = unsafe { Self :: from_raw ( work) } ;
446+ /// Access the inner action.
447+ pub fn action ( & self ) -> & T {
448+ & self . action
449+ }
450+ }
466451
467- // Access the action within, still pinned.
468- // SAFETY: It is safe to keep the pin on the interior.
469- let action = unsafe { this. as_ref ( ) . map_unchecked ( |p| & p. action ) } ;
452+ /// Capture the kinds of pointers that are safe to submit to work queues.
453+ pub trait SubmittablePointer < T > {
454+ /// Create a new version of a pointer for this particular type. The pointer should be pinned
455+ /// after this call, and can then be initialized and used by C code.
456+ unsafe fn new_ptr ( action : T ) -> Self ;
470457
471- action. act ( ) ;
458+ /// Given a raw pointer to the work_q burried within, recover the Self pointer containing our
459+ /// data.
460+ unsafe fn from_raw ( ptr : * const k_work ) -> Self ;
461+
462+ /// Given our Self, indicate that this reference is now owned by the C code. For something like
463+ /// Arc, this should leak a reference, and is the opposite of from_raw.
464+ unsafe fn into_raw ( self ) ;
465+
466+ /// Determine from the submitted work if this work has been enqueued, and if not, cause a "drop"
467+ /// to happen on the Self pointer type.
468+ fn check_drop ( work : * const k_work , result : & crate :: Result < SubmitResult > ) ;
469+
470+ /// Get the inner work pointer.
471+ fn get_work ( & self ) -> * mut k_work ;
472+
473+ /// The low-level handler for this specific type.
474+ extern "C" fn handler ( work : * mut k_work ) ;
475+ }
476+
477+ impl < T : SimpleAction + Send > SubmittablePointer < T > for Pin < Arc < Work < T > > > {
478+ unsafe fn new_ptr ( action : T ) -> Self {
479+ Arc :: pin ( Work {
480+ work : unsafe { mem:: zeroed ( ) } ,
481+ action,
482+ } )
472483 }
473484
474- /*
475- /// Consume this Arc, returning the internal pointer. Needs to have a complementary `from_raw`
476- /// called to avoid leaking the item.
477- fn into_raw(this: Pin<Arc<Self>>) -> *const Self {
478- // SAFETY: This removes the Pin guarantee, but is given as a raw pointer to C, which doesn't
479- // generally use move.
480- let this = unsafe { Pin::into_inner_unchecked(this) };
481- Arc::into_raw(this)
485+ fn get_work ( & self ) -> * mut k_work {
486+ self . work . get ( )
482487 }
483- */
484488
485- /// Given a pointer to the work_q burried within, recover the Pinned Box containing our data.
486- unsafe fn from_raw ( ptr : * const k_work ) -> Pin < Arc < Self > > {
489+ unsafe fn from_raw ( ptr : * const k_work ) -> Self {
487490 // SAFETY: This fixes the pointer back to the beginning of Self. This also assumes the
488491 // pointer is valid.
489492 let ptr = ptr
490493 . cast :: < u8 > ( )
491- . sub ( mem:: offset_of!( Self , work) )
492- . cast :: < Self > ( ) ;
494+ . sub ( mem:: offset_of!( Work < T > , work) )
495+ . cast :: < Work < T > > ( ) ;
493496 let this = Arc :: from_raw ( ptr) ;
494497 Pin :: new_unchecked ( this)
495498 }
496499
497- /// Determine if this work was submitted, and cause a drop of the Arc to happen if it was not.
498- pub fn check_drop ( work : * const k_work , result : & crate :: Result < SubmitResult > ) {
500+ unsafe fn into_raw ( self ) {
501+ // SAFETY: The C code does not perform moves on the data, and the `from_raw` that gets back
502+ // our Arc puts it back into the pin when it reconstructs the Arc.
503+ let this = unsafe { Pin :: into_inner_unchecked ( self ) } ;
504+ let _ = Arc :: into_raw ( this. clone ( ) ) ;
505+ }
506+
507+ fn check_drop ( work : * const k_work , result : & crate :: Result < SubmitResult > ) {
499508 if matches ! ( result, Ok ( SubmitResult :: AlreadySubmitted ) | Err ( _) ) {
500509 // SAFETY: If the above submit indicates that it was already running, the work will not
501510 // be submitted (no additional handle will be called). "un leak" the work so that it
@@ -507,9 +516,17 @@ impl<T: SimpleAction + Send> Work<T> {
507516 }
508517 }
509518
510- /// Access the inner action.
511- pub fn action ( & self ) -> & T {
512- & self . action
519+ extern "C" fn handler ( work : * mut k_work ) {
520+ // We want to avoid needing a `repr(C)` on our struct, so the `k_work` pointer is not
521+ // necessarily at the beginning of the struct.
522+ // SAFETY: Converts raw pointer to work back into the box.
523+ let this = unsafe { Self :: from_raw ( work) } ;
524+
525+ // Access the action within, still pinned.
526+ // SAFETY: It is safe to keep the pin on the interior.
527+ let action = unsafe { this. as_ref ( ) . map_unchecked ( |p| & p. action ) } ;
528+
529+ action. act ( ) ;
513530 }
514531}
515532
0 commit comments