对于 inet socket
,不需要引用计数来维护 SocketInode
,raw udp完全不需要,而 tcp accept的新 “socket
” 会有额外的 SocketInode
;即使有dup等,其inode的open-close也应由外部统一维护而非内部进行引用计数。
对于 unix socket
,观察到其确实有对同一socket多次open的行为(其引用计数会>1)。然而,
- 其open-close的维护仍然由外部统一维护,并不会出错
- 根据以下,也不存在资源泄露的问题,包括其自身close行为不做任何事。
因此我提议移除 SocketInode
多余的引用计数设计
将 SocketInode
相关代码段简化为以下部分,运行正常:
/// # Socket在文件系统中的inode封装
#[derive(Debug)]
pub struct SocketInode(SpinLock<Box<dyn Socket>>);
impl SocketInode {
pub fn new(socket: Box<dyn Socket>) -> Arc<Self> {
Arc::new(Self(SpinLock::new(socket)))
}
#[inline]
pub fn inner(&self) -> SpinLockGuard<Box<dyn Socket>> {
self.0.lock()
}
pub unsafe fn inner_no_preempt(&self) -> SpinLockGuard<Box<dyn Socket>> {
self.0.lock_no_preempt()
}
}
impl IndexNode for SocketInode {
fn open(
&self,
_data: SpinLockGuard<FilePrivateData>,
_mode: &FileMode,
) -> Result<(), SystemError> {
Ok(())
}
fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<(), SystemError> {
let mut socket = self.0.lock_irqsave();
if socket.metadata().socket_type == SocketType::Unix {
return Ok(());
}
if let Some(Endpoint::Ip(Some(ip))) = socket.endpoint() {
PORT_MANAGER.unbind_port(socket.metadata().socket_type, ip.port);
}
socket.clear_epoll()?;
HANDLE_MAP
.write_irqsave()
.remove(&socket.socket_handle())
.unwrap();
socket.close();
Ok(())
}
// 剩下的内容省略
此处是抛砖引玉,我希望尽可能多地知道socket各方面设计的原因()
这个我熟,是我设计的
当时是为了在fork产生的多进程环境下确保所有进程都close了这个inode再关闭socket
你可以在github里翻翻我的pr(直接看文件历史可能找不到,我移动过这部分文件