9
9
//! tasks run on the same worker do not need Send. It is just important that write operations on
10
10
//! the RefCell do not `.await` or a panic is likely.
11
11
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 } ,
20
17
} ;
18
+ use embassy_time:: Timer ;
19
+ use zephyr:: { printkln, sync:: Arc } ;
21
20
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 ) ;
23
30
24
31
/// Number of iterations of each philospher.
25
32
///
@@ -28,56 +35,27 @@ use crate::{get_random_delay, Stats, NUM_PHIL};
28
35
/// there are two waits, so typically, each "eat" will take about a second.
29
36
const EAT_COUNT : usize = 10 ;
30
37
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 ) {
41
40
// 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 ( ) ) ) ;
65
42
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 ( ) ;
69
52
}
70
53
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 ( ) ;
74
56
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) ;
81
59
}
82
60
83
61
/// Simulate a single philospher.
@@ -86,28 +64,35 @@ async fn local_phil() -> Stats {
86
64
/// likely deadlock.
87
65
///
88
66
/// 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
+ ) {
90
73
for i in 0 ..EAT_COUNT {
91
74
// Acquire the forks.
92
75
// printkln!("Child {n} take left fork");
93
- forks[ 0 ] . take_async ( Forever ) . await . unwrap ( ) ;
76
+ forks[ 0 ] . acquire ( 1 ) . await . unwrap ( ) . disarm ( ) ;
94
77
// printkln!("Child {n} take right fork");
95
- forks[ 1 ] . take_async ( Forever ) . await . unwrap ( ) ;
78
+ forks[ 1 ] . acquire ( 1 ) . await . unwrap ( ) . disarm ( ) ;
96
79
97
80
// printkln!("Child {n} eating");
98
81
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) ;
101
84
102
85
// Release the forks.
103
86
// printkln!("Child {n} giving up forks");
104
- forks[ 1 ] . give ( ) ;
105
- forks[ 0 ] . give ( ) ;
87
+ forks[ 1 ] . release ( 1 ) ;
88
+ forks[ 0 ] . release ( 1 ) ;
106
89
107
90
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) ;
110
93
111
94
printkln ! ( "Philospher {n} finished eating time {i}" ) ;
112
95
}
96
+
97
+ DONE_SEM . release ( 1 ) ;
113
98
}
0 commit comments