Skip to content

Commit b8d92ed

Browse files
committed
zephyr: sync: channel: Wrap channel implementation with "flavor"
Taken from crossbeam channel, instead of directly storing the queue into the Receiver and Sender, instead wrap this in a enum, which will allow us to have different kinds of implementations. This is done via enum rather than traits as it would otherwise have to be dynamic, and a small dynamic decision is generally faster than the vtable that would result from using `dyn`. Signed-off-by: David Brown <[email protected]>
1 parent ce42e4b commit b8d92ed

File tree

1 file changed

+86
-38
lines changed

1 file changed

+86
-38
lines changed

zephyr/src/sync/channel.rs

Lines changed: 86 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,16 @@ mod counter;
3636
pub fn unbounded_from<T>(queue: Queue) -> (Sender<T>, Receiver<T>) {
3737
let (s, r) = counter::new(queue);
3838
let s = Sender {
39-
queue: s,
40-
_phantom: PhantomData,
39+
flavor: SenderFlavor::Unbounded {
40+
queue: s,
41+
_phantom: PhantomData,
42+
}
4143
};
4244
let r = Receiver {
43-
queue: r,
44-
_phantom: PhantomData,
45+
flavor: ReceiverFlavor::Unbounded {
46+
queue: r,
47+
_phantom: PhantomData,
48+
}
4549
};
4650
(s, r)
4751
}
@@ -81,8 +85,7 @@ impl<T> Message<T> {
8185

8286
/// The sending side of a channel.
8387
pub struct Sender<T> {
84-
queue: counter::Sender<Queue>,
85-
_phantom: PhantomData<T>,
88+
flavor: SenderFlavor<T>,
8689
}
8790

8891
unsafe impl<T: Send> Send for Sender<T> {}
@@ -92,45 +95,67 @@ impl<T> Sender<T> {
9295
/// Sends a message over the given channel. This will perform an alloc of the message, which
9396
/// will have an accompanied free on the recipient side.
9497
pub fn send(&self, msg: T) -> Result<(), SendError<T>> {
95-
let msg = Box::new(Message::new(msg));
96-
let msg = Box::into_raw(msg);
97-
unsafe {
98-
self.queue.send(msg as *mut c_void);
98+
match &self.flavor {
99+
SenderFlavor::Unbounded { queue, .. } => {
100+
let msg = Box::new(Message::new(msg));
101+
let msg = Box::into_raw(msg);
102+
unsafe {
103+
queue.send(msg as *mut c_void);
104+
}
105+
}
99106
}
100107
Ok(())
101108
}
102109
}
103110

104111
impl<T> Drop for Sender<T> {
105112
fn drop(&mut self) {
106-
unsafe {
107-
self.queue.release(|_| {
108-
crate::printkln!("Release");
109-
true
110-
})
113+
match &self.flavor {
114+
SenderFlavor::Unbounded { queue, .. } => {
115+
unsafe {
116+
queue.release(|_| {
117+
crate::printkln!("Release");
118+
true
119+
})
120+
}
121+
}
111122
}
112123
}
113124
}
114125

115126
impl<T> Clone for Sender<T> {
116127
fn clone(&self) -> Self {
117-
Sender {
118-
queue: self.queue.acquire(),
119-
_phantom: PhantomData,
120-
}
128+
let flavor = match &self.flavor {
129+
SenderFlavor::Unbounded { queue, .. } => {
130+
SenderFlavor::Unbounded {
131+
queue: queue.acquire(),
132+
_phantom: PhantomData,
133+
}
134+
}
135+
};
136+
137+
Sender { flavor }
138+
}
139+
}
140+
141+
/// The "flavor" of a sender. This maps to the type of channel.
142+
enum SenderFlavor<T> {
143+
/// An unbounded queue. Messages are allocated with Box, and sent directly.
144+
Unbounded {
145+
queue: counter::Sender<Queue>,
146+
_phantom: PhantomData<T>,
121147
}
122148
}
123149

124150
impl<T: fmt::Debug> fmt::Debug for Sender<T> {
125151
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126-
write!(f, "Sender {:?}", *self.queue)
152+
write!(f, "Sender")
127153
}
128154
}
129155

130156
/// The receiving side of a channel.
131157
pub struct Receiver<T> {
132-
queue: counter::Receiver<Queue>,
133-
_phantom: PhantomData<T>,
158+
flavor: ReceiverFlavor<T>,
134159
}
135160

136161
unsafe impl<T: Send> Send for Receiver<T> {}
@@ -144,38 +169,61 @@ impl<T> Receiver<T> {
144169
/// operation can proceed. If the channel is empty and becomes disconnected, this call will
145170
/// wake up and return an error.
146171
pub fn recv(&self) -> Result<T, RecvError> {
147-
let msg = unsafe {
148-
self.queue.recv()
149-
};
150-
let msg = msg as *mut Message<T>;
151-
let msg = unsafe { Box::from_raw(msg) };
152-
Ok(msg.data)
172+
match &self.flavor {
173+
ReceiverFlavor::Unbounded { queue, .. } => {
174+
let msg = unsafe {
175+
queue.recv()
176+
};
177+
let msg = msg as *mut Message<T>;
178+
let msg = unsafe { Box::from_raw(msg) };
179+
Ok(msg.data)
180+
}
181+
}
153182
}
154183
}
155184

156185
impl<T> Drop for Receiver<T> {
157186
fn drop(&mut self) {
158-
unsafe {
159-
self.queue.release(|_| {
160-
crate::printkln!("Release");
161-
true
162-
})
187+
match &self.flavor {
188+
ReceiverFlavor::Unbounded { queue, .. } => {
189+
unsafe {
190+
queue.release(|_| {
191+
crate::printkln!("Release");
192+
true
193+
})
194+
}
195+
}
163196
}
164197
}
165198
}
166199

167200
impl<T> Clone for Receiver<T> {
168201
fn clone(&self) -> Self {
169-
Receiver {
170-
queue: self.queue.acquire(),
171-
_phantom: PhantomData,
172-
}
202+
let flavor = match &self.flavor {
203+
ReceiverFlavor::Unbounded { queue, .. } => {
204+
ReceiverFlavor::Unbounded {
205+
queue: queue.acquire(),
206+
_phantom: PhantomData,
207+
}
208+
}
209+
};
210+
211+
Receiver { flavor }
173212
}
174213
}
175214

176215
impl<T> fmt::Debug for Receiver<T> {
177216
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178-
write!(f, "Sender {:?}", *self.queue)
217+
write!(f, "Sender")
218+
}
219+
}
220+
221+
/// The "flavor" of a receiver. This maps to the type of the channel.
222+
enum ReceiverFlavor<T> {
223+
/// An unbounded queue. Messages were allocated with Box, and will be freed upon receipt.
224+
Unbounded {
225+
queue: counter::Receiver<Queue>,
226+
_phantom: PhantomData<T>,
179227
}
180228
}
181229

0 commit comments

Comments
 (0)