1
1
//! An embassy executor tailored for Zephyr
2
2
3
- use core:: { marker:: PhantomData , sync :: atomic :: Ordering } ;
3
+ use core:: marker:: PhantomData ;
4
4
5
5
use embassy_executor:: { raw, Spawner } ;
6
- use zephyr_sys:: { k_current_get, k_thread_resume, k_thread_suspend, k_tid_t} ;
7
-
8
- use crate :: sync:: atomic:: AtomicBool ;
6
+ use crate :: sys:: sync:: Semaphore ;
7
+ use crate :: time:: Forever ;
9
8
10
9
/// Zephyr-thread based executor.
11
10
pub struct Executor {
12
11
inner : Option < raw:: Executor > ,
13
- id : k_tid_t ,
14
- pend : AtomicBool ,
12
+ poll_needed : Semaphore ,
15
13
not_send : PhantomData < * mut ( ) > ,
16
14
}
17
15
18
16
impl Executor {
19
17
/// Create a new Executor.
20
18
pub fn new ( ) -> Self {
21
- let id = unsafe { k_current_get ( ) } ;
22
-
23
19
Self {
24
20
inner : None ,
25
- pend : AtomicBool :: new ( false ) ,
26
- id,
21
+ poll_needed : Semaphore :: new ( 0 , 1 ) . unwrap ( ) ,
27
22
not_send : PhantomData ,
28
23
}
29
24
}
@@ -36,16 +31,13 @@ impl Executor {
36
31
init ( inner. spawner ( ) ) ;
37
32
38
33
loop {
34
+ let _ = self . poll_needed . take ( Forever ) ;
39
35
unsafe {
40
36
// The raw executor's poll only runs things that were queued _before_ this poll
41
37
// itself is actually run. This means, specifically, that if the polled execution
42
38
// causes this, or other threads to enqueue, this will return without running them.
43
- // `__pender` _will_ be called, but it isn't "sticky" like `wfe/sev` are. To
44
- // simulate this, we will use the 'pend' atomic to count
39
+ // `__pender` _will_ be called, so the next time around the semaphore will be taken.
45
40
inner. poll ( ) ;
46
- if !self . pend . swap ( false , Ordering :: SeqCst ) {
47
- k_thread_suspend ( k_current_get ( ) ) ;
48
- }
49
41
}
50
42
}
51
43
}
@@ -60,21 +52,7 @@ impl Default for Executor {
60
52
#[ export_name = "__pender" ]
61
53
fn __pender ( context : * mut ( ) ) {
62
54
unsafe {
63
- let myself = k_current_get ( ) ;
64
-
65
55
let this = context as * const Executor ;
66
- let other = ( * this) . id ;
67
-
68
- // The atomic is our equivalent to causing an event (wfe) or pending an IRQ. We need to do
69
- // this before waking the other thread in case that thread runs early. This is needed for
70
- // both the case of another thread, to prevent a race between the `inner.poll()` above, and
71
- // new items being added to the queue, as well as running entirely locally, also to prevent
72
- // the same race.
73
- ( * this) . pend . store ( true , Ordering :: SeqCst ) ;
74
-
75
- // If the other is a different thread, resume it.
76
- if other != myself {
77
- k_thread_resume ( other) ;
78
- }
56
+ ( * this) . poll_needed . give ( ) ;
79
57
}
80
58
}
0 commit comments