Skip to content

Commit f6e8d61

Browse files
xuchang-vivoclaude
andcommitted
net: remove spin::Once from LinkRegistry, simplify to Mutex
LinkRegistry was using spin::Once<spin::Mutex<Vec<...>>> but the Once layer is unnecessary — the registry is initialized empty at static construction and only modified during single-threaded init. All access methods are simplified to direct self.devices.lock(). This also eliminates the batch-init pattern: devices are now pushed one at a time via LINK_REGISTRY.push(), matching the per-device registration pattern in iface_list::register(). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent 1b20e95 commit f6e8d61

12 files changed

Lines changed: 93 additions & 83 deletions

File tree

kernel/src/net/iface_list.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,28 @@
2222
use alloc::{sync::Arc, vec::Vec};
2323
use spin::RwLock;
2424

25-
use crate::net::smoltcp::iface::NetIface;
25+
use crate::net::{
26+
link::{LinkLayer, LINK_REGISTRY},
27+
smoltcp::iface::NetIface,
28+
};
2629

2730
/// Global list of network interfaces.
2831
static NET_IFACE_LIST: RwLock<Vec<Arc<NetIface>>> = RwLock::new(Vec::new());
2932

3033
/// Default interface (the last registered non-loopback interface, or loopback).
3134
static DEFAULT_IFACE: RwLock<Option<Arc<NetIface>>> = RwLock::new(None);
3235

33-
/// Register a NetIface into the global list.
36+
/// Register a NetIface and its corresponding LinkLayer into the global registries.
37+
///
38+
/// This is the **single entry point** for all interface+link registration.
39+
/// Both `NET_IFACE_LIST` and `LINK_REGISTRY` are updated atomically (per call).
40+
/// The caller *must* already have populated `LINK_REGISTRY` via `LINK_REGISTRY.init()`
41+
/// before calling this function for the first time.
3442
///
3543
/// If `set_default` is true, this interface becomes the default.
36-
/// (The driver should call this once per interface during boot.)
37-
pub fn register(iface: Arc<NetIface>, set_default: bool) {
44+
pub fn register(iface: Arc<NetIface>, link: Arc<spin::RwLock<dyn LinkLayer>>, set_default: bool) {
3845
NET_IFACE_LIST.write().push(iface.clone());
46+
LINK_REGISTRY.push(link);
3947
if set_default {
4048
DEFAULT_IFACE.write().replace(iface);
4149
}
@@ -69,4 +77,4 @@ pub fn len() -> usize {
6977
/// Check whether the list is empty.
7078
pub fn is_empty() -> bool {
7179
NET_IFACE_LIST.read().is_empty()
72-
}
80+
}

kernel/src/net/link/loopback.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ use smoltcp::{
2525
wire::{HardwareAddress, IpAddress, IpCidr},
2626
};
2727

28-
use crate::net::link::{HwAddr, LinkKind, LinkLayer, Medium};
29-
use crate::net::smoltcp::link::SmoltcpDevice;
28+
use crate::net::{
29+
link::{HwAddr, LinkKind, LinkLayer, Medium},
30+
smoltcp::link::SmoltcpDevice,
31+
};
3032

3133
/// Loopback link-layer device.
3234
pub struct LoopbackLink {
@@ -126,4 +128,4 @@ impl SmoltcpDevice for LoopbackLink {
126128
fn poll_smoltcp(&mut self, timestamp: Instant, iface: &mut Interface, sockets: &mut SocketSet) {
127129
iface.poll(timestamp, &mut self.inner, sockets);
128130
}
129-
}
131+
}

kernel/src/net/link/mod.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ use spin;
4848

4949
pub(crate) use self::{link_kind::LinkKind, medium::Medium};
5050

51-
use crate::net::iface::{InterfaceFlags, NetIfaceControl, NetIfaceError, NetIfaceResult};
52-
use crate::net::link::{ethernet_ops::EthernetOps, wifi_ops::WifiOps};
51+
use crate::net::{
52+
iface::{InterfaceFlags, NetIfaceControl, NetIfaceError, NetIfaceResult},
53+
link::{ethernet_ops::EthernetOps, wifi_ops::WifiOps},
54+
};
5355

5456
/// A hardware address (MAC or similar).
5557
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -133,44 +135,43 @@ impl dyn LinkLayer {
133135

134136
/// Global registry of link-layer devices.
135137
///
136-
/// # Safety
137-
///
138-
/// All devices must be registered during `net::init()`, before the network
139-
/// thread starts. After that, the registry is immutable — no further `register()`
140-
/// calls are allowed. This eliminates locking overhead for reads.
141-
///
142-
/// `init()` panics if called more than once.
138+
/// All devices are registered during `net::init()` (single-threaded, before the
139+
/// network thread starts). After that, the registry is logically immutable —
140+
/// no further `push()` calls are made, so `Mutex` contention is zero at runtime.
143141
pub(crate) struct LinkRegistry {
144-
devices: spin::Once<Vec<Arc<spin::RwLock<dyn LinkLayer>>>>,
142+
devices: spin::Mutex<Vec<Arc<spin::RwLock<dyn LinkLayer>>>>,
145143
}
146144

147145
impl LinkRegistry {
148146
pub const fn new() -> Self {
149147
LinkRegistry {
150-
devices: spin::Once::new(),
148+
devices: spin::Mutex::new(Vec::new()),
151149
}
152150
}
153151

154-
/// Initialize the registry with all devices. Must be called exactly once
155-
/// during `net::init()` before the network thread starts.
156-
pub fn init(&self, devices: Vec<Arc<spin::RwLock<dyn LinkLayer>>>) {
157-
self.devices.call_once(|| devices);
152+
/// Push a single device into the registry during init.
153+
pub fn push(&self, device: Arc<spin::RwLock<dyn LinkLayer>>) {
154+
self.devices.lock().push(device);
158155
}
159156

160157
pub fn get(&self, index: usize) -> Option<Arc<spin::RwLock<dyn LinkLayer>>> {
161-
self.devices.get()?.get(index).cloned()
158+
self.devices.lock().get(index).cloned()
162159
}
163160

164161
pub fn iter(&self) -> Vec<Arc<spin::RwLock<dyn LinkLayer>>> {
165-
self.devices.get().cloned().unwrap_or_default()
162+
self.devices.lock().clone()
166163
}
167164

168165
pub fn len(&self) -> usize {
169-
self.devices.get().map_or(0, Vec::len)
166+
self.devices.lock().len()
170167
}
171168

172169
pub fn find_by_name(&self, name: &str) -> Option<Arc<spin::RwLock<dyn LinkLayer>>> {
173-
self.devices.get()?.iter().find(|d| d.read().name() == name).cloned()
170+
self.devices
171+
.lock()
172+
.iter()
173+
.find(|dev| dev.read().name() == name)
174+
.cloned()
174175
}
175176
}
176177

@@ -205,4 +206,3 @@ pub(crate) fn handle_control(cmd: NetIfaceControl) -> Result<NetIfaceResult, Net
205206
_ => Err(NetIfaceError::NotSupported),
206207
}
207208
}
208-

kernel/src/net/link/virtio.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ use smoltcp::{
2727

2828
use crate::{
2929
devices::net::virtio_net_device::{VirtIONetDevice, VirtIONetRxToken, VirtIONetTxToken},
30-
net::link::{HwAddr, LinkKind, LinkLayer, Medium},
31-
net::smoltcp::link::SmoltcpDevice,
30+
net::{
31+
link::{HwAddr, LinkKind, LinkLayer, Medium},
32+
smoltcp::link::SmoltcpDevice,
33+
},
3234
};
3335

3436
/// VirtIO link-layer device.
@@ -142,4 +144,4 @@ impl SmoltcpDevice for VirtioLink {
142144
fn poll_smoltcp(&mut self, timestamp: Instant, iface: &mut Interface, sockets: &mut SocketSet) {
143145
iface.poll(timestamp, &mut self.inner, sockets);
144146
}
145-
}
147+
}

kernel/src/net/smoltcp/iface/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
//! (which IS dyn-compatible) for both control operations and smoltcp
2929
//! poll dispatch.
3030
31-
pub(crate) use crate::net::iface::control::{InterfaceFlags, NetIfaceControl, NetIfaceError, NetIfaceResult};
31+
pub(crate) use crate::net::iface::control::{
32+
InterfaceFlags, NetIfaceControl, NetIfaceError, NetIfaceResult,
33+
};
3234
use alloc::{rc::Rc, string::String, sync::Arc, vec::Vec};
3335
use core::cell::RefCell;
3436
use smoltcp::{
@@ -38,9 +40,11 @@ use smoltcp::{
3840
};
3941
use spin::RwLock;
4042

41-
use crate::net::link::{HwAddr, Medium};
42-
use crate::net::smoltcp::link::SmoltcpDevice;
43-
use crate::net::socket::socket_err::SocketError;
43+
use crate::net::{
44+
link::{HwAddr, Medium},
45+
smoltcp::link::SmoltcpDevice,
46+
socket::socket_err::SocketError,
47+
};
4448

4549
/// L3 network interface.
4650
///
@@ -253,4 +257,4 @@ impl core::fmt::Display for NetIface {
253257
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
254258
write!(f, "NetIface({})", self.name)
255259
}
256-
}
260+
}

kernel/src/net/smoltcp/link/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ use crate::net::link::LinkLayer;
3030
/// (GATs on `RxToken`/`TxToken`).
3131
pub trait SmoltcpDevice: LinkLayer + 'static {
3232
/// Create a smoltcp Interface and SocketSet for this device.
33-
fn create_smoltcp_iface(&mut self) -> (smoltcp::iface::Interface, smoltcp::iface::SocketSet<'static>);
33+
fn create_smoltcp_iface(
34+
&mut self,
35+
) -> (
36+
smoltcp::iface::Interface,
37+
smoltcp::iface::SocketSet<'static>,
38+
);
3439

3540
/// Poll the smoltcp Interface using this device's concrete Device impl.
3641
fn poll_smoltcp(
@@ -46,4 +51,4 @@ impl dyn SmoltcpDevice {
4651
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
4752
(self as &dyn Any).downcast_ref::<T>()
4853
}
49-
}
54+
}

kernel/src/net/smoltcp/mod.rs

Lines changed: 29 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,18 @@ pub(crate) mod iface;
2525
pub(crate) mod link;
2626
pub(crate) mod socket;
2727

28-
use alloc::rc::Rc;
29-
use alloc::sync::Arc;
30-
use alloc::string::ToString;
31-
use alloc::vec::Vec;
28+
use alloc::{rc::Rc, string::ToString, sync::Arc, vec::Vec};
3229
use core::cell::RefCell;
3330
use smoltcp::wire::IpAddress;
3431
use spin;
3532

36-
use crate::net::iface_list;
37-
use crate::net::link::LinkLayer;
38-
use crate::net::link::LINK_REGISTRY;
39-
use crate::net::smoltcp::iface::NetIface;
40-
use crate::net::socket::PosixSocket;
41-
use crate::net::SocketFd;
42-
use crate::net::smoltcp::link::SmoltcpDevice;
33+
use crate::net::{
34+
iface_list,
35+
link::LinkLayer,
36+
smoltcp::{iface::NetIface, link::SmoltcpDevice},
37+
socket::PosixSocket,
38+
SocketFd,
39+
};
4340

4441
/// Entry in the device registration list: (name, set_default, Arc<dyn SmoltcpDevice>).
4542
pub(crate) type DeviceEntry = (&'static str, bool, Arc<spin::RwLock<dyn SmoltcpDevice>>);
@@ -51,25 +48,18 @@ pub(crate) type DeviceEntry = (&'static str, bool, Arc<spin::RwLock<dyn SmoltcpD
5148
/// Each entry is `(device, name, set_default)`. Returns the created
5249
/// `NetIface` instances in registration order.
5350
pub(crate) fn init_devices(devices: &[DeviceEntry]) -> Vec<Arc<NetIface>> {
54-
let link_devices: Vec<Arc<spin::RwLock<dyn LinkLayer>>> =
55-
devices.iter().map(|(_, _, link)| link.clone() as Arc<spin::RwLock<dyn LinkLayer>>).collect();
56-
LINK_REGISTRY.init(link_devices);
57-
5851
let mut ifaces = Vec::new();
59-
for (i, (name, set_default, _)) in devices.iter().enumerate() {
60-
let link = devices[i].2.clone();
61-
let iface = Arc::new(NetIface::new(name.to_string(), link, i));
62-
iface_list::register(iface.clone(), *set_default);
52+
for (i, (name, set_default, link)) in devices.iter().enumerate() {
53+
let iface = Arc::new(NetIface::new(name.to_string(), link.clone(), i));
54+
let link_layer: Arc<spin::RwLock<dyn LinkLayer>> = link.clone();
55+
iface_list::register(iface.clone(), link_layer, *set_default);
6356
ifaces.push(iface);
6457
}
6558
ifaces
6659
}
6760

6861
/// Bind a socket to the default NetIface.
69-
pub(crate) fn bind_default_interface(
70-
socket_fd: SocketFd,
71-
socket: Rc<RefCell<dyn PosixSocket>>,
72-
) {
62+
pub(crate) fn bind_default_interface(socket_fd: SocketFd, socket: Rc<RefCell<dyn PosixSocket>>) {
7363
if let Some(interface) = iface_list::default() {
7464
let mut socket = socket.borrow_mut();
7565
socket.bind_interface(interface.clone());
@@ -86,21 +76,20 @@ pub(crate) fn bind_interface_by_addr(
8676
socket: Rc<RefCell<dyn PosixSocket>>,
8777
binding_addr: IpAddress,
8878
) {
89-
iface_list::find(|iface| iface.contains_addr(binding_addr))
90-
.map_or_else(
91-
|| {
92-
if let Some(interface) = iface_list::default() {
93-
let mut socket = socket.borrow_mut();
94-
socket.bind_interface(interface.clone());
95-
log::debug!("Socket Fd={} binding to {}", socket_fd, interface);
96-
} else {
97-
log::error!("Socket Fd={} binding fail, find no interface", socket_fd);
98-
}
99-
},
100-
|iface| {
79+
iface_list::find(|iface| iface.contains_addr(binding_addr)).map_or_else(
80+
|| {
81+
if let Some(interface) = iface_list::default() {
10182
let mut socket = socket.borrow_mut();
102-
socket.bind_interface(iface.clone());
103-
log::debug!("Socket Fd={} binding to {}", socket_fd, iface);
104-
},
105-
)
106-
}
83+
socket.bind_interface(interface.clone());
84+
log::debug!("Socket Fd={} binding to {}", socket_fd, interface);
85+
} else {
86+
log::error!("Socket Fd={} binding fail, find no interface", socket_fd);
87+
}
88+
},
89+
|iface| {
90+
let mut socket = socket.borrow_mut();
91+
socket.bind_interface(iface.clone());
92+
log::debug!("Socket Fd={} binding to {}", socket_fd, iface);
93+
},
94+
)
95+
}

kernel/src/net/smoltcp/socket/icmp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,4 +366,4 @@ impl PosixSocket for IcmpSocket {
366366
fn is_shutdown(&self) -> bool {
367367
self.is_shutdown.get()
368368
}
369-
}
369+
}

kernel/src/net/smoltcp/socket/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
pub(crate) mod icmp;
1818
pub(crate) mod socket_err;
1919
pub(crate) mod tcp;
20-
pub(crate) mod udp;
20+
pub(crate) mod udp;

kernel/src/net/smoltcp/socket/socket_err.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,4 @@ impl From<smoltcp::socket::icmp::RecvError> for SocketError {
7474
fn from(err: smoltcp::socket::icmp::RecvError) -> Self {
7575
Self::SmoltcpIcmpRecvError(err)
7676
}
77-
}
77+
}

0 commit comments

Comments
 (0)