diff options
Diffstat (limited to 'examples/std/src/tuntap.rs')
| -rw-r--r-- | examples/std/src/tuntap.rs | 113 |
1 files changed, 58 insertions, 55 deletions
diff --git a/examples/std/src/tuntap.rs b/examples/std/src/tuntap.rs index a0cace7f7..bb3e194cc 100644 --- a/examples/std/src/tuntap.rs +++ b/examples/std/src/tuntap.rs | |||
| @@ -1,8 +1,10 @@ | |||
| 1 | use std::io; | 1 | use std::io; |
| 2 | use std::io::{Read, Write}; | 2 | use std::io::{Read, Write}; |
| 3 | use std::os::unix::io::{AsRawFd, RawFd}; | 3 | use std::os::unix::io::{AsRawFd, RawFd}; |
| 4 | use std::task::Context; | ||
| 4 | 5 | ||
| 5 | use async_io::Async; | 6 | use async_io::Async; |
| 7 | use embassy_net::device::{self, Device, DeviceCapabilities, LinkState}; | ||
| 6 | use log::*; | 8 | use log::*; |
| 7 | 9 | ||
| 8 | pub const SIOCGIFMTU: libc::c_ulong = 0x8921; | 10 | pub const SIOCGIFMTU: libc::c_ulong = 0x8921; |
| @@ -125,54 +127,35 @@ impl io::Write for TunTap { | |||
| 125 | 127 | ||
| 126 | pub struct TunTapDevice { | 128 | pub struct TunTapDevice { |
| 127 | device: Async<TunTap>, | 129 | device: Async<TunTap>, |
| 128 | waker: Option<Waker>, | ||
| 129 | } | 130 | } |
| 130 | 131 | ||
| 131 | impl TunTapDevice { | 132 | impl TunTapDevice { |
| 132 | pub fn new(name: &str) -> io::Result<TunTapDevice> { | 133 | pub fn new(name: &str) -> io::Result<TunTapDevice> { |
| 133 | Ok(Self { | 134 | Ok(Self { |
| 134 | device: Async::new(TunTap::new(name)?)?, | 135 | device: Async::new(TunTap::new(name)?)?, |
| 135 | waker: None, | ||
| 136 | }) | 136 | }) |
| 137 | } | 137 | } |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | use core::task::Waker; | ||
| 141 | use std::task::Context; | ||
| 142 | |||
| 143 | use embassy_net::{Device, DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf}; | ||
| 144 | |||
| 145 | impl Device for TunTapDevice { | 140 | impl Device for TunTapDevice { |
| 146 | fn is_transmit_ready(&mut self) -> bool { | 141 | type RxToken<'a> = RxToken where Self: 'a; |
| 147 | true | 142 | type TxToken<'a> = TxToken<'a> where Self: 'a; |
| 148 | } | ||
| 149 | 143 | ||
| 150 | fn transmit(&mut self, pkt: PacketBuf) { | 144 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { |
| 151 | // todo handle WouldBlock | 145 | let mut buf = vec![0; self.device.get_ref().mtu]; |
| 152 | match self.device.get_mut().write(&pkt) { | ||
| 153 | Ok(_) => {} | ||
| 154 | Err(e) if e.kind() == io::ErrorKind::WouldBlock => { | ||
| 155 | info!("transmit WouldBlock"); | ||
| 156 | } | ||
| 157 | Err(e) => panic!("transmit error: {:?}", e), | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | fn receive(&mut self) -> Option<PacketBuf> { | ||
| 162 | let mut pkt = PacketBox::new(Packet::new()).unwrap(); | ||
| 163 | loop { | 146 | loop { |
| 164 | match self.device.get_mut().read(&mut pkt[..]) { | 147 | match self.device.get_mut().read(&mut buf) { |
| 165 | Ok(n) => { | 148 | Ok(n) => { |
| 166 | return Some(pkt.slice(0..n)); | 149 | buf.truncate(n); |
| 150 | return Some(( | ||
| 151 | RxToken { buffer: buf }, | ||
| 152 | TxToken { | ||
| 153 | device: &mut self.device, | ||
| 154 | }, | ||
| 155 | )); | ||
| 167 | } | 156 | } |
| 168 | Err(e) if e.kind() == io::ErrorKind::WouldBlock => { | 157 | Err(e) if e.kind() == io::ErrorKind::WouldBlock => { |
| 169 | let ready = if let Some(w) = self.waker.as_ref() { | 158 | if !self.device.poll_readable(cx).is_ready() { |
| 170 | let mut cx = Context::from_waker(w); | ||
| 171 | self.device.poll_readable(&mut cx).is_ready() | ||
| 172 | } else { | ||
| 173 | false | ||
| 174 | }; | ||
| 175 | if !ready { | ||
| 176 | return None; | 159 | return None; |
| 177 | } | 160 | } |
| 178 | } | 161 | } |
| @@ -181,28 +164,10 @@ impl Device for TunTapDevice { | |||
| 181 | } | 164 | } |
| 182 | } | 165 | } |
| 183 | 166 | ||
| 184 | fn register_waker(&mut self, w: &Waker) { | 167 | fn transmit(&mut self, _cx: &mut Context) -> Option<Self::TxToken<'_>> { |
| 185 | match self.waker { | 168 | Some(TxToken { |
| 186 | // Optimization: If both the old and new Wakers wake the same task, we can simply | 169 | device: &mut self.device, |
| 187 | // keep the old waker, skipping the clone. (In most executor implementations, | 170 | }) |
| 188 | // cloning a waker is somewhat expensive, comparable to cloning an Arc). | ||
| 189 | Some(ref w2) if (w2.will_wake(w)) => {} | ||
| 190 | _ => { | ||
| 191 | // clone the new waker and store it | ||
| 192 | if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) { | ||
| 193 | // We had a waker registered for another task. Wake it, so the other task can | ||
| 194 | // reregister itself if it's still interested. | ||
| 195 | // | ||
| 196 | // If two tasks are waiting on the same thing concurrently, this will cause them | ||
| 197 | // to wake each other in a loop fighting over this WakerRegistration. This wastes | ||
| 198 | // CPU but things will still work. | ||
| 199 | // | ||
| 200 | // If the user wants to have two tasks waiting on the same thing they should use | ||
| 201 | // a more appropriate primitive that can store multiple wakers. | ||
| 202 | old_waker.wake() | ||
| 203 | } | ||
| 204 | } | ||
| 205 | } | ||
| 206 | } | 171 | } |
| 207 | 172 | ||
| 208 | fn capabilities(&self) -> DeviceCapabilities { | 173 | fn capabilities(&self) -> DeviceCapabilities { |
| @@ -211,7 +176,7 @@ impl Device for TunTapDevice { | |||
| 211 | caps | 176 | caps |
| 212 | } | 177 | } |
| 213 | 178 | ||
| 214 | fn link_state(&mut self) -> LinkState { | 179 | fn link_state(&mut self, _cx: &mut Context) -> LinkState { |
| 215 | LinkState::Up | 180 | LinkState::Up |
| 216 | } | 181 | } |
| 217 | 182 | ||
| @@ -219,3 +184,41 @@ impl Device for TunTapDevice { | |||
| 219 | [0x02, 0x03, 0x04, 0x05, 0x06, 0x07] | 184 | [0x02, 0x03, 0x04, 0x05, 0x06, 0x07] |
| 220 | } | 185 | } |
| 221 | } | 186 | } |
| 187 | |||
| 188 | #[doc(hidden)] | ||
| 189 | pub struct RxToken { | ||
| 190 | buffer: Vec<u8>, | ||
| 191 | } | ||
| 192 | |||
| 193 | impl device::RxToken for RxToken { | ||
| 194 | fn consume<R, F>(mut self, f: F) -> R | ||
| 195 | where | ||
| 196 | F: FnOnce(&mut [u8]) -> R, | ||
| 197 | { | ||
| 198 | f(&mut self.buffer) | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | #[doc(hidden)] | ||
| 203 | pub struct TxToken<'a> { | ||
| 204 | device: &'a mut Async<TunTap>, | ||
| 205 | } | ||
| 206 | |||
| 207 | impl<'a> device::TxToken for TxToken<'a> { | ||
| 208 | fn consume<R, F>(self, len: usize, f: F) -> R | ||
| 209 | where | ||
| 210 | F: FnOnce(&mut [u8]) -> R, | ||
| 211 | { | ||
| 212 | let mut buffer = vec![0; len]; | ||
| 213 | let result = f(&mut buffer); | ||
| 214 | |||
| 215 | // todo handle WouldBlock with async | ||
| 216 | match self.device.get_mut().write(&buffer) { | ||
| 217 | Ok(_) => {} | ||
| 218 | Err(e) if e.kind() == io::ErrorKind::WouldBlock => info!("transmit WouldBlock"), | ||
| 219 | Err(e) => panic!("transmit error: {:?}", e), | ||
| 220 | } | ||
| 221 | |||
| 222 | result | ||
| 223 | } | ||
| 224 | } | ||
