99//! tasks run on the same worker do not need Send. It is just important that write operations on
1010//! the RefCell do not `.await` or a panic is likely.
1111
12- use core:: cell:: RefCell ;
13-
14- use alloc:: { rc:: Rc , vec:: Vec } ;
15- use zephyr:: {
16- kio:: { sleep, spawn_local} ,
17- printkln,
18- sys:: sync:: Semaphore ,
19- time:: Forever ,
12+ use embassy_executor:: Spawner ;
13+ use embassy_sync:: {
14+ blocking_mutex:: raw:: CriticalSectionRawMutex ,
15+ mutex:: Mutex ,
16+ semaphore:: { FairSemaphore , Semaphore } ,
2017} ;
18+ use embassy_time:: Timer ;
19+ use zephyr:: { printkln, sync:: Arc } ;
2120
22- use crate :: { get_random_delay, Stats , NUM_PHIL } ;
21+ use crate :: { get_random_delay, ResultSignal , Stats , NUM_PHIL } ;
22+
23+ type ESemaphore = FairSemaphore < CriticalSectionRawMutex , NUM_PHIL > ;
24+
25+ /// The semaphores for the forks.
26+ static FORKS : [ ESemaphore ; NUM_PHIL ] = [ const { ESemaphore :: new ( 1 ) } ; NUM_PHIL ] ;
27+
28+ /// The semaphore to wait for them all to finish.
29+ static DONE_SEM : ESemaphore = ESemaphore :: new ( 0 ) ;
2330
2431/// Number of iterations of each philospher.
2532///
@@ -28,56 +35,27 @@ use crate::{get_random_delay, Stats, NUM_PHIL};
2835/// there are two waits, so typically, each "eat" will take about a second.
2936const EAT_COUNT : usize = 10 ;
3037
31- pub async fn phil ( ) -> Stats {
32- // It is a little tricky to be able to use local workers. We have to have this nested thread
33- // that waits. This is because the Future from `local_phil()` does not implement Send, since it
34- // waits for the philosophers, which are not Send. However, this outer async function does not
35- // hold onto any data that is not send, and therefore will be Send. Fortunately, this extra
36- // Future is very lightweight.
37- spawn_local ( local_phil ( ) , c"phil_wrap" ) . join_async ( ) . await
38- }
39-
40- async fn local_phil ( ) -> Stats {
38+ #[ embassy_executor:: task]
39+ pub async fn phil ( spawner : Spawner , stats_sig : & ' static ResultSignal ) {
4140 // Our overall stats.
42- let stats = Rc :: new ( RefCell :: new ( Stats :: default ( ) ) ) ;
43-
44- // One fork for each philospher.
45- let forks: Vec < _ > = ( 0 ..NUM_PHIL )
46- . map ( |_| Rc :: new ( Semaphore :: new ( 1 , 1 ) ) )
47- . collect ( ) ;
48-
49- // Create all of the philosphers
50- let phils: Vec < _ > = ( 0 ..NUM_PHIL )
51- . map ( |i| {
52- // Determine the two forks. The forks are paired with each philosopher taking the fork of
53- // their number, and the next on, module the size of the ring. However, for the last case,
54- // we need to swap the forks used, it is necessary to obey a strict ordering of the locks to
55- // avoid deadlocks.
56- let forks = if i == NUM_PHIL - 1 {
57- [ forks[ 0 ] . clone ( ) , forks[ i] . clone ( ) ]
58- } else {
59- [ forks[ i] . clone ( ) , forks[ i + 1 ] . clone ( ) ]
60- } ;
61-
62- spawn_local ( one_phil ( forks, i, stats. clone ( ) ) , c"phil" )
63- } )
64- . collect ( ) ;
41+ let stats = Arc :: new ( Mutex :: new ( Stats :: default ( ) ) ) ;
6542
66- // Wait for them all to finish.
67- for p in phils {
68- p. join_async ( ) . await ;
43+ // Spawn off each philosopher.
44+ for i in 0 ..NUM_PHIL {
45+ let forks = if i == NUM_PHIL - 1 {
46+ [ & FORKS [ 0 ] , & FORKS [ i] ]
47+ } else {
48+ [ & FORKS [ i] , & FORKS [ i + 1 ] ]
49+ } ;
50+
51+ spawner. spawn ( one_phil ( forks, i, stats. clone ( ) ) ) . unwrap ( ) ;
6952 }
7053
71- // Leak the stats as a test.
72- // Uncomment this to test that the expect below does truly detect a missed drop.
73- // let _ = Rc::into_raw(stats.clone());
54+ // Wait for them all to finish.
55+ DONE_SEM . acquire ( NUM_PHIL ) . await . unwrap ( ) ;
7456
75- // At this point, all of the philosphers should have dropped their stats ref, and we should be
76- // able to turn stats back into it's value.
77- // This tests that completed work does drop the future.
78- Rc :: into_inner ( stats)
79- . expect ( "Failure: a philospher didn't drop it's future" )
80- . into_inner ( )
57+ // Send the stats back.
58+ stats_sig. signal ( stats) ;
8159}
8260
8361/// Simulate a single philospher.
@@ -86,28 +64,35 @@ async fn local_phil() -> Stats {
8664/// likely deadlock.
8765///
8866/// This will run for EAT_COUNT times, and then return.
89- async fn one_phil ( forks : [ Rc < Semaphore > ; 2 ] , n : usize , stats : Rc < RefCell < Stats > > ) {
67+ #[ embassy_executor:: task( pool_size = NUM_PHIL ) ]
68+ async fn one_phil (
69+ forks : [ & ' static ESemaphore ; 2 ] ,
70+ n : usize ,
71+ stats : Arc < Mutex < CriticalSectionRawMutex , Stats > > ,
72+ ) {
9073 for i in 0 ..EAT_COUNT {
9174 // Acquire the forks.
9275 // printkln!("Child {n} take left fork");
93- forks[ 0 ] . take_async ( Forever ) . await . unwrap ( ) ;
76+ forks[ 0 ] . acquire ( 1 ) . await . unwrap ( ) . disarm ( ) ;
9477 // printkln!("Child {n} take right fork");
95- forks[ 1 ] . take_async ( Forever ) . await . unwrap ( ) ;
78+ forks[ 1 ] . acquire ( 1 ) . await . unwrap ( ) . disarm ( ) ;
9679
9780 // printkln!("Child {n} eating");
9881 let delay = get_random_delay ( n, 25 ) ;
99- sleep ( delay) . await ;
100- stats. borrow_mut ( ) . record_eat ( n, delay) ;
82+ Timer :: after ( delay) . await ;
83+ stats. lock ( ) . await . record_eat ( n, delay) ;
10184
10285 // Release the forks.
10386 // printkln!("Child {n} giving up forks");
104- forks[ 1 ] . give ( ) ;
105- forks[ 0 ] . give ( ) ;
87+ forks[ 1 ] . release ( 1 ) ;
88+ forks[ 0 ] . release ( 1 ) ;
10689
10790 let delay = get_random_delay ( n, 25 ) ;
108- sleep ( delay) . await ;
109- stats. borrow_mut ( ) . record_think ( n, delay) ;
91+ Timer :: after ( delay) . await ;
92+ stats. lock ( ) . await . record_think ( n, delay) ;
11093
11194 printkln ! ( "Philospher {n} finished eating time {i}" ) ;
11295 }
96+
97+ DONE_SEM . release ( 1 ) ;
11398}
0 commit comments