@@ -331,24 +331,6 @@ impl SubmitResult {
331
331
}
332
332
}
333
333
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
-
352
334
/// A simple action that just does something with its data.
353
335
///
354
336
/// 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> {
394
376
/// inter-thread sharing mechanisms are needed.
395
377
///
396
378
/// 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) } ;
403
384
404
- // SAFETY: Initializes above zero-initialized struct.
385
+ // SAFETY: Initializes the above zero-initialized struct.
405
386
unsafe {
406
- k_work_init ( this. work . get ( ) , Some ( Self :: handler) ) ;
387
+ k_work_init ( this. get_work ( ) , Some ( P :: handler) ) ;
407
388
}
408
389
409
390
this
@@ -413,89 +394,117 @@ impl<T: SimpleAction + Send> Work<T> {
413
394
///
414
395
/// This can return several possible `Ok` results. See the docs on [`SubmitResult`] for an
415
396
/// 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
+ {
417
401
// We "leak" the arc, so that when the handler runs, it can be safely turned back into an
418
402
// Arc, and the drop on the arc will then run.
419
- let work = this. work . get ( ) ;
403
+ let work = this. get_work ( ) ;
420
404
421
405
// SAFETY: C the code does not perform moves on the data, and the `from_raw` below puts it
422
406
// 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
+ }
425
410
426
411
// SAFETY: The Pin ensures this will not move. Our implementation of drop ensures that the
427
412
// work item is no longer queued when the data is dropped.
428
413
let result = SubmitResult :: to_result ( unsafe { k_work_submit ( work) } ) ;
429
414
430
- Self :: check_drop ( work, & result) ;
415
+ P :: check_drop ( work, & result) ;
431
416
432
417
result
433
418
}
434
419
435
420
/// Submit this work to a specified work queue.
436
421
///
437
422
/// 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 ( ) ;
443
428
444
429
// "leak" the arc to give to C. We'll reconstruct it in the handler.
445
430
// SAFETY: The C code does not perform moves on the data, and the `from_raw` below puts it
446
431
// 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
+ }
449
435
450
436
// SAFETY: The Pin ensures this will not move. Our implementation of drop ensures that the
451
437
// work item is no longer queued when the data is dropped.
452
438
let result =
453
439
SubmitResult :: to_result ( unsafe { k_work_submit_to_queue ( queue. item . get ( ) , work) } ) ;
454
440
455
- Self :: check_drop ( work, & result) ;
441
+ P :: check_drop ( work, & result) ;
456
442
457
443
result
458
444
}
459
445
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
+ }
466
451
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 ;
470
457
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
+ } )
472
483
}
473
484
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 ( )
482
487
}
483
- */
484
488
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 {
487
490
// SAFETY: This fixes the pointer back to the beginning of Self. This also assumes the
488
491
// pointer is valid.
489
492
let ptr = ptr
490
493
. cast :: < u8 > ( )
491
- . sub ( mem:: offset_of!( Self , work) )
492
- . cast :: < Self > ( ) ;
494
+ . sub ( mem:: offset_of!( Work < T > , work) )
495
+ . cast :: < Work < T > > ( ) ;
493
496
let this = Arc :: from_raw ( ptr) ;
494
497
Pin :: new_unchecked ( this)
495
498
}
496
499
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 > ) {
499
508
if matches ! ( result, Ok ( SubmitResult :: AlreadySubmitted ) | Err ( _) ) {
500
509
// SAFETY: If the above submit indicates that it was already running, the work will not
501
510
// 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> {
507
516
}
508
517
}
509
518
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 ( ) ;
513
530
}
514
531
}
515
532
0 commit comments