Merge pull request #394 from smoltcp-rs/async
Async/await waker support.
This commit is contained in:
commit
1d5a329155
|
@ -34,7 +34,7 @@ jobs:
|
||||||
- std ethernet proto-ipv6 socket-icmp socket-tcp
|
- std ethernet proto-ipv6 socket-icmp socket-tcp
|
||||||
|
|
||||||
# Test features chosen to be as aggressive as possible.
|
# Test features chosen to be as aggressive as possible.
|
||||||
- std ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp
|
- std ethernet proto-ipv4 proto-ipv6 socket-raw socket-udp socket-tcp socket-icmp async
|
||||||
|
|
||||||
include:
|
include:
|
||||||
# Test alloc feature which requires nightly.
|
# Test alloc feature which requires nightly.
|
||||||
|
@ -66,7 +66,7 @@ jobs:
|
||||||
|
|
||||||
features:
|
features:
|
||||||
# These feature sets cannot run tests, so we only check they build.
|
# These feature sets cannot run tests, so we only check they build.
|
||||||
- ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp
|
- ethernet proto-ipv6 proto-ipv6 proto-igmp proto-dhcpv4 socket-raw socket-udp socket-tcp socket-icmp async
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
|
@ -42,12 +42,14 @@ ethernet = []
|
||||||
"socket-udp" = []
|
"socket-udp" = []
|
||||||
"socket-tcp" = []
|
"socket-tcp" = []
|
||||||
"socket-icmp" = []
|
"socket-icmp" = []
|
||||||
|
"async" = []
|
||||||
default = [
|
default = [
|
||||||
"std", "log", # needed for `cargo test --no-default-features --features default` :/
|
"std", "log", # needed for `cargo test --no-default-features --features default` :/
|
||||||
"ethernet",
|
"ethernet",
|
||||||
"phy-raw_socket", "phy-tap_interface",
|
"phy-raw_socket", "phy-tap_interface",
|
||||||
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6",
|
"proto-ipv4", "proto-igmp", "proto-dhcpv4", "proto-ipv6",
|
||||||
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp"
|
"socket-raw", "socket-icmp", "socket-udp", "socket-tcp",
|
||||||
|
"async"
|
||||||
]
|
]
|
||||||
|
|
||||||
# experimental; do not use; no guarantees provided that this feature will be kept
|
# experimental; do not use; no guarantees provided that this feature will be kept
|
||||||
|
|
|
@ -5,6 +5,10 @@ use phy::{ChecksumCapabilities, DeviceCapabilities};
|
||||||
use socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
use socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
||||||
use storage::{PacketBuffer, PacketMetadata};
|
use storage::{PacketBuffer, PacketMetadata};
|
||||||
use wire::{IpAddress, IpEndpoint, IpProtocol, IpRepr};
|
use wire::{IpAddress, IpEndpoint, IpProtocol, IpRepr};
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use socket::WakerRegistration;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
use wire::{Ipv4Address, Ipv4Repr, Icmpv4Packet, Icmpv4Repr};
|
use wire::{Ipv4Address, Ipv4Repr, Icmpv4Packet, Icmpv4Repr};
|
||||||
|
@ -61,7 +65,11 @@ pub struct IcmpSocket<'a, 'b: 'a> {
|
||||||
/// The endpoint this socket is communicating with
|
/// The endpoint this socket is communicating with
|
||||||
endpoint: Endpoint,
|
endpoint: Endpoint,
|
||||||
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
||||||
hop_limit: Option<u8>
|
hop_limit: Option<u8>,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> IcmpSocket<'a, 'b> {
|
impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
|
@ -73,10 +81,49 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
rx_buffer: rx_buffer,
|
rx_buffer: rx_buffer,
|
||||||
tx_buffer: tx_buffer,
|
tx_buffer: tx_buffer,
|
||||||
endpoint: Endpoint::default(),
|
endpoint: Endpoint::default(),
|
||||||
hop_limit: None
|
hop_limit: None,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration::new(),
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a waker for receive operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `recv` method calls, such as receiving data, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_recv_waker(&mut self, waker: &Waker) {
|
||||||
|
self.rx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker for send operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `send` method calls, such as space becoming available in the transmit
|
||||||
|
/// buffer, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_send_waker(&mut self, waker: &Waker) {
|
||||||
|
self.tx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the socket handle.
|
/// Return the socket handle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn handle(&self) -> SocketHandle {
|
pub fn handle(&self) -> SocketHandle {
|
||||||
|
@ -174,6 +221,13 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
if self.is_open() { return Err(Error::Illegal) }
|
if self.is_open() { return Err(Error::Illegal) }
|
||||||
|
|
||||||
self.endpoint = endpoint;
|
self.endpoint = endpoint;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
{
|
||||||
|
self.rx_waker.wake();
|
||||||
|
self.tx_waker.wake();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,6 +393,10 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
self.meta.handle, icmp_repr.buffer_len(), packet_buf.len());
|
self.meta.handle, icmp_repr.buffer_len(), packet_buf.len());
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.rx_waker.wake();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,7 +438,12 @@ impl<'a, 'b> IcmpSocket<'a, 'b> {
|
||||||
},
|
},
|
||||||
_ => Err(Error::Unaddressable)
|
_ => Err(Error::Unaddressable)
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.tx_waker.wake();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_at(&self) -> PollAt {
|
pub(crate) fn poll_at(&self) -> PollAt {
|
||||||
|
|
|
@ -26,7 +26,12 @@ mod tcp;
|
||||||
mod set;
|
mod set;
|
||||||
mod ref_;
|
mod ref_;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
mod waker;
|
||||||
|
|
||||||
pub(crate) use self::meta::Meta as SocketMeta;
|
pub(crate) use self::meta::Meta as SocketMeta;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub(crate) use self::waker::WakerRegistration;
|
||||||
|
|
||||||
#[cfg(feature = "socket-raw")]
|
#[cfg(feature = "socket-raw")]
|
||||||
pub use self::raw::{RawPacketMetadata,
|
pub use self::raw::{RawPacketMetadata,
|
||||||
|
|
|
@ -9,6 +9,10 @@ use wire::{IpVersion, IpRepr, IpProtocol};
|
||||||
use wire::{Ipv4Repr, Ipv4Packet};
|
use wire::{Ipv4Repr, Ipv4Packet};
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
use wire::{Ipv6Repr, Ipv6Packet};
|
use wire::{Ipv6Repr, Ipv6Packet};
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use socket::WakerRegistration;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
/// A UDP packet metadata.
|
/// A UDP packet metadata.
|
||||||
pub type RawPacketMetadata = PacketMetadata<()>;
|
pub type RawPacketMetadata = PacketMetadata<()>;
|
||||||
|
@ -27,6 +31,10 @@ pub struct RawSocket<'a, 'b: 'a> {
|
||||||
ip_protocol: IpProtocol,
|
ip_protocol: IpProtocol,
|
||||||
rx_buffer: RawSocketBuffer<'a, 'b>,
|
rx_buffer: RawSocketBuffer<'a, 'b>,
|
||||||
tx_buffer: RawSocketBuffer<'a, 'b>,
|
tx_buffer: RawSocketBuffer<'a, 'b>,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> RawSocket<'a, 'b> {
|
impl<'a, 'b> RawSocket<'a, 'b> {
|
||||||
|
@ -41,9 +49,48 @@ impl<'a, 'b> RawSocket<'a, 'b> {
|
||||||
ip_protocol,
|
ip_protocol,
|
||||||
rx_buffer,
|
rx_buffer,
|
||||||
tx_buffer,
|
tx_buffer,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration::new(),
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a waker for receive operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `recv` method calls, such as receiving data, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_recv_waker(&mut self, waker: &Waker) {
|
||||||
|
self.rx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker for send operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `send` method calls, such as space becoming available in the transmit
|
||||||
|
/// buffer, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_send_waker(&mut self, waker: &Waker) {
|
||||||
|
self.tx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the socket handle.
|
/// Return the socket handle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn handle(&self) -> SocketHandle {
|
pub fn handle(&self) -> SocketHandle {
|
||||||
|
@ -171,6 +218,10 @@ impl<'a, 'b> RawSocket<'a, 'b> {
|
||||||
net_trace!("{}:{}:{}: receiving {} octets",
|
net_trace!("{}:{}:{}: receiving {} octets",
|
||||||
self.meta.handle, self.ip_version, self.ip_protocol,
|
self.meta.handle, self.ip_version, self.ip_protocol,
|
||||||
packet_buf.len());
|
packet_buf.len());
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.rx_waker.wake();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +279,12 @@ impl<'a, 'b> RawSocket<'a, 'b> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.tx_waker.wake();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_at(&self) -> PollAt {
|
pub(crate) fn poll_at(&self) -> PollAt {
|
||||||
|
|
|
@ -10,6 +10,10 @@ use time::{Duration, Instant};
|
||||||
use socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
use socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
||||||
use storage::{Assembler, RingBuffer};
|
use storage::{Assembler, RingBuffer};
|
||||||
use wire::{IpProtocol, IpRepr, IpAddress, IpEndpoint, TcpSeqNumber, TcpRepr, TcpControl};
|
use wire::{IpProtocol, IpRepr, IpAddress, IpEndpoint, TcpSeqNumber, TcpRepr, TcpControl};
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use socket::WakerRegistration;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
/// A TCP socket ring buffer.
|
/// A TCP socket ring buffer.
|
||||||
pub type SocketBuffer<'a> = RingBuffer<'a, u8>;
|
pub type SocketBuffer<'a> = RingBuffer<'a, u8>;
|
||||||
|
@ -248,6 +252,12 @@ pub struct TcpSocket<'a> {
|
||||||
/// The number of packets recived directly after
|
/// The number of packets recived directly after
|
||||||
/// each other which have the same ACK number.
|
/// each other which have the same ACK number.
|
||||||
local_rx_dup_acks: u8,
|
local_rx_dup_acks: u8,
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_MSS: usize = 536;
|
const DEFAULT_MSS: usize = 536;
|
||||||
|
@ -298,9 +308,49 @@ impl<'a> TcpSocket<'a> {
|
||||||
local_rx_last_ack: None,
|
local_rx_last_ack: None,
|
||||||
local_rx_last_seq: None,
|
local_rx_last_seq: None,
|
||||||
local_rx_dup_acks: 0,
|
local_rx_dup_acks: 0,
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration::new(),
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a waker for receive operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `recv` method calls, such as receiving data, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_recv_waker(&mut self, waker: &Waker) {
|
||||||
|
self.rx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker for send operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `send` method calls, such as space becoming available in the transmit
|
||||||
|
/// buffer, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_send_waker(&mut self, waker: &Waker) {
|
||||||
|
self.tx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the socket handle.
|
/// Return the socket handle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn handle(&self) -> SocketHandle {
|
pub fn handle(&self) -> SocketHandle {
|
||||||
|
@ -438,6 +488,12 @@ impl<'a> TcpSocket<'a> {
|
||||||
self.remote_win_shift = rx_cap_log2.saturating_sub(16) as u8;
|
self.remote_win_shift = rx_cap_log2.saturating_sub(16) as u8;
|
||||||
self.remote_mss = DEFAULT_MSS;
|
self.remote_mss = DEFAULT_MSS;
|
||||||
self.remote_last_ts = None;
|
self.remote_last_ts = None;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
{
|
||||||
|
self.rx_waker.wake();
|
||||||
|
self.tx_waker.wake();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start listening on the given endpoint.
|
/// Start listening on the given endpoint.
|
||||||
|
@ -825,7 +881,17 @@ impl<'a> TcpSocket<'a> {
|
||||||
self.state, state);
|
self.state, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.state = state
|
|
||||||
|
self.state = state;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
{
|
||||||
|
// Wake all tasks waiting. Even if we haven't received/sent data, this
|
||||||
|
// is needed because return values of functions may change depending on the state.
|
||||||
|
// For example, a pending read has to fail with an error if the socket is closed.
|
||||||
|
self.rx_waker.wake();
|
||||||
|
self.tx_waker.wake();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reply(ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
|
pub(crate) fn reply(ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
|
||||||
|
@ -1283,6 +1349,10 @@ impl<'a> TcpSocket<'a> {
|
||||||
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
||||||
ack_len, self.tx_buffer.len() - ack_len);
|
ack_len, self.tx_buffer.len() - ack_len);
|
||||||
self.tx_buffer.dequeue_allocated(ack_len);
|
self.tx_buffer.dequeue_allocated(ack_len);
|
||||||
|
|
||||||
|
// There's new room available in tx_buffer, wake the waiting task if any.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.tx_waker.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ack_number) = repr.ack_number {
|
if let Some(ack_number) = repr.ack_number {
|
||||||
|
@ -1367,6 +1437,10 @@ impl<'a> TcpSocket<'a> {
|
||||||
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
self.meta.handle, self.local_endpoint, self.remote_endpoint,
|
||||||
contig_len, self.rx_buffer.len() + contig_len);
|
contig_len, self.rx_buffer.len() + contig_len);
|
||||||
self.rx_buffer.enqueue_unallocated(contig_len);
|
self.rx_buffer.enqueue_unallocated(contig_len);
|
||||||
|
|
||||||
|
// There's new data in rx_buffer, notify waiting task if any.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.rx_waker.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.assembler.is_empty() {
|
if !self.assembler.is_empty() {
|
||||||
|
|
|
@ -4,6 +4,10 @@ use {Error, Result};
|
||||||
use socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
use socket::{Socket, SocketMeta, SocketHandle, PollAt};
|
||||||
use storage::{PacketBuffer, PacketMetadata};
|
use storage::{PacketBuffer, PacketMetadata};
|
||||||
use wire::{IpProtocol, IpRepr, IpEndpoint, UdpRepr};
|
use wire::{IpProtocol, IpRepr, IpEndpoint, UdpRepr};
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use socket::WakerRegistration;
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
/// A UDP packet metadata.
|
/// A UDP packet metadata.
|
||||||
pub type UdpPacketMetadata = PacketMetadata<IpEndpoint>;
|
pub type UdpPacketMetadata = PacketMetadata<IpEndpoint>;
|
||||||
|
@ -22,7 +26,11 @@ pub struct UdpSocket<'a, 'b: 'a> {
|
||||||
rx_buffer: UdpSocketBuffer<'a, 'b>,
|
rx_buffer: UdpSocketBuffer<'a, 'b>,
|
||||||
tx_buffer: UdpSocketBuffer<'a, 'b>,
|
tx_buffer: UdpSocketBuffer<'a, 'b>,
|
||||||
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
/// The time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets.
|
||||||
hop_limit: Option<u8>
|
hop_limit: Option<u8>,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> UdpSocket<'a, 'b> {
|
impl<'a, 'b> UdpSocket<'a, 'b> {
|
||||||
|
@ -34,10 +42,49 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
||||||
endpoint: IpEndpoint::default(),
|
endpoint: IpEndpoint::default(),
|
||||||
rx_buffer: rx_buffer,
|
rx_buffer: rx_buffer,
|
||||||
tx_buffer: tx_buffer,
|
tx_buffer: tx_buffer,
|
||||||
hop_limit: None
|
hop_limit: None,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
rx_waker: WakerRegistration::new(),
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
tx_waker: WakerRegistration::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a waker for receive operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `recv` method calls, such as receiving data, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `recv` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_recv_waker(&mut self, waker: &Waker) {
|
||||||
|
self.rx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker for send operations.
|
||||||
|
///
|
||||||
|
/// The waker is woken on state changes that might affect the return value
|
||||||
|
/// of `send` method calls, such as space becoming available in the transmit
|
||||||
|
/// buffer, or the socket closing.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
///
|
||||||
|
/// - Only one waker can be registered at a time. If another waker was previously registered,
|
||||||
|
/// it is overwritten and will no longer be woken.
|
||||||
|
/// - The Waker is woken only once. Once woken, you must register it again to receive more wakes.
|
||||||
|
/// - "Spurious wakes" are allowed: a wake doesn't guarantee the result of `send` has
|
||||||
|
/// necessarily changed.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
pub fn register_send_waker(&mut self, waker: &Waker) {
|
||||||
|
self.tx_waker.register(waker)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the socket handle.
|
/// Return the socket handle.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn handle(&self) -> SocketHandle {
|
pub fn handle(&self) -> SocketHandle {
|
||||||
|
@ -89,6 +136,13 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
||||||
if self.is_open() { return Err(Error::Illegal) }
|
if self.is_open() { return Err(Error::Illegal) }
|
||||||
|
|
||||||
self.endpoint = endpoint;
|
self.endpoint = endpoint;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
{
|
||||||
|
self.rx_waker.wake();
|
||||||
|
self.tx_waker.wake();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,6 +288,10 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
||||||
net_trace!("{}:{}:{}: receiving {} octets",
|
net_trace!("{}:{}:{}: receiving {} octets",
|
||||||
self.meta.handle, self.endpoint,
|
self.meta.handle, self.endpoint,
|
||||||
endpoint, size);
|
endpoint, size);
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.rx_waker.wake();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +319,12 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
|
||||||
hop_limit: hop_limit,
|
hop_limit: hop_limit,
|
||||||
};
|
};
|
||||||
emit((ip_repr, repr))
|
emit((ip_repr, repr))
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
self.tx_waker.wake();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_at(&self) -> PollAt {
|
pub(crate) fn poll_at(&self) -> PollAt {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use core::task::Waker;
|
||||||
|
|
||||||
|
/// Utility struct to register and wake a waker.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WakerRegistration {
|
||||||
|
waker: Option<Waker>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WakerRegistration {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self { waker: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a waker. Overwrites the previous waker, if any.
|
||||||
|
pub fn register(&mut self, w: &Waker) {
|
||||||
|
match self.waker {
|
||||||
|
// Optimization: If both the old and new Wakers wake the same task, we can simply
|
||||||
|
// keep the old waker, skipping the clone. (In most executor implementations,
|
||||||
|
// cloning a waker is somewhat expensive, comparable to cloning an Arc).
|
||||||
|
Some(ref w2) if (w2.will_wake(w)) => {}
|
||||||
|
// In all other cases
|
||||||
|
// - we have no waker registered
|
||||||
|
// - we have a waker registered but it's for a different task.
|
||||||
|
// then clone the new waker and store it
|
||||||
|
_ => self.waker = Some(w.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the registered waker, if any.
|
||||||
|
pub fn wake(&mut self) {
|
||||||
|
self.waker.take().map(|w| w.wake());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue