@@ -26,11 +26,13 @@ use system_error::SystemError;
2626
2727use super :: { fs:: EPollInode , EPollCtlOption , EPollEvent , EPollEventType , EPollItem } ;
2828
29- /// epoll 就绪状态,由独立的 irqsave SpinLock 保护。
29+ /// Epoll ready state protected by a dedicated irqsave spin lock.
3030///
31- /// 对标 Linux 6.6 中由 `ep->lock`(rwlock_t)保护的 `rdllist` + `ovflist` + `wq`。
32- /// 回调路径(`wakeup_epoll`,等价于 Linux `ep_poll_callback`)仅获取此 SpinLock,
33- /// 不碰外层 Mutex,因此完全 hardirq-safe。
31+ /// This corresponds to Linux 6.6's `ep->lock`, which protects `rdllist`,
32+ /// `ovflist`, and the wait queue. The callback path does not acquire the outer
33+ /// sleeping mutex. The source registration snapshot still allocates and scans
34+ /// entries in hardirq context; that existing latency concern is separate from
35+ /// this lock-discipline guarantee.
3436pub ( crate ) struct ReadyState {
3537 /// 就绪列表(正常路径)
3638 ready_list : LinkedList < Arc < EPollItem > > ,
@@ -46,6 +48,21 @@ pub(crate) struct ReadyState {
4648 epoll_wq : WaitQueue ,
4749}
4850
51+ #[ derive( Clone , Copy , Debug , Eq , Ord , PartialEq , PartialOrd ) ]
52+ pub ( crate ) struct EPollKey {
53+ open_file_id : usize ,
54+ fd : i32 ,
55+ }
56+
57+ impl EPollKey {
58+ pub ( super ) fn new ( file : & File , fd : i32 ) -> Self {
59+ Self {
60+ open_file_id : file. open_file_id ( ) ,
61+ fd,
62+ }
63+ }
64+ }
65+
4966impl Debug for ReadyState {
5067 fn fmt ( & self , f : & mut core:: fmt:: Formatter < ' _ > ) -> core:: fmt:: Result {
5168 f. debug_struct ( "ReadyState" )
@@ -69,11 +86,11 @@ impl Debug for ReadyState {
6986#[ derive( Debug ) ]
7087pub struct EventPoll {
7188 /// 维护所有添加进来的socket的红黑树(由外层 Mutex 保护)
72- ep_items : RBTree < i32 , Arc < EPollItem > > ,
89+ ep_items : RBTree < EPollKey , Arc < EPollItem > > ,
7390 /// 就绪状态(由内层 irqsave SpinLock 保护)
7491 ready_state : Arc < SpinLock < ReadyState > > ,
7592 /// 监听本 epollfd 的 epitems(用于支持 epoll 嵌套:epollfd 被加入另一个 epoll)
76- pub ( super ) poll_epitems : Arc < LockedEPItemLinkedList > ,
93+ pub ( super ) poll_epitems : Arc < EPollItemList > ,
7794 self_ref : Option < Weak < Mutex < EventPoll > > > ,
7895}
7996
@@ -90,25 +107,23 @@ impl EventPoll {
90107 ovflist : None ,
91108 epoll_wq : WaitQueue :: default ( ) ,
92109 } ) ) ,
93- poll_epitems : Arc :: new ( LockedEPItemLinkedList :: default ( ) ) ,
110+ poll_epitems : Arc :: new ( EPollItemList :: default ( ) ) ,
94111 self_ref : None ,
95112 }
96113 }
97114
98115 /// 关闭epoll时,执行的逻辑
99116 pub ( super ) fn close ( & mut self ) -> Result < ( ) , SystemError > {
100- let fds: Vec < i32 > = self . ep_items . keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
101- // 清理红黑树里面的epitems
102- for fd in fds {
103- let fdtable = ProcessManager :: current_pcb ( ) . basic ( ) . try_fd_table ( ) . clone ( ) ;
104- let file = fdtable. and_then ( |fdtable| fdtable. read ( ) . get_file_by_fd ( fd) ) ;
105-
106- if let Some ( file) = file {
107- let epitm = self . ep_items . get ( & fd) . unwrap ( ) ;
108- // 尝试移除epitem,忽略错误(对于普通文件,我们没有添加epitem,所以会失败)
109- let _ = file. remove_epitem ( epitm) ;
117+ let keys: Vec < EPollKey > = self . ep_items . keys ( ) . copied ( ) . collect ( ) ;
118+ for key in keys {
119+ let Some ( epitem) = self . ep_items . get ( & key) . cloned ( ) else {
120+ continue ;
121+ } ;
122+ if let Some ( file) = epitem. file ( ) . upgrade ( ) {
123+ let _ = file. remove_epitem ( & epitem) ;
110124 }
111- self . ep_items . remove ( & fd) ;
125+ Self :: deactivate_and_remove_ready ( self , & epitem) ;
126+ self . ep_items . remove ( & key) ;
112127 }
113128
114129 Ok ( ( ) )
@@ -252,7 +267,8 @@ impl EventPoll {
252267 }
253268 } ;
254269
255- let ep_item = epoll_guard. ep_items . get ( & dstfd) . cloned ( ) ;
270+ let key = EPollKey :: new ( & dst_file, dstfd) ;
271+ let ep_item = epoll_guard. ep_items . get ( & key) . cloned ( ) ;
256272 let notify_nested = match op {
257273 EPollCtlOption :: Add => {
258274 // 如果已经存在,则返回错误
@@ -265,16 +281,16 @@ impl EventPoll {
265281 Arc :: downgrade ( & epoll_data. epoll . 0 ) ,
266282 Arc :: downgrade ( & epoll_guard. ready_state ) ,
267283 Arc :: downgrade ( & epoll_guard. poll_epitems ) ,
284+ key,
268285 epds,
269- dstfd,
270286 Arc :: downgrade ( & dst_file) ,
271287 ) ) ;
272288 Self :: ep_insert ( & mut epoll_guard, dst_file, epitem) ?
273289 }
274290 EPollCtlOption :: Del => match ep_item {
275291 Some ( ref ep_item) => {
276292 // 删除
277- Self :: ep_remove ( & mut epoll_guard, dstfd , Some ( dst_file) , ep_item) ?;
293+ Self :: ep_remove ( & mut epoll_guard, key , Some ( dst_file) , ep_item) ?;
278294 false
279295 }
280296 None => {
@@ -700,13 +716,13 @@ impl EventPoll {
700716 return Err ( SystemError :: ENOSYS ) ;
701717 }
702718
703- epoll_guard. ep_items . insert ( epitem. fd , epitem. clone ( ) ) ;
719+ epoll_guard. ep_items . insert ( epitem. key ( ) , epitem. clone ( ) ) ;
704720
705721 // 先将 epitem 添加到目标文件的 epoll_items 中,这样之后的 notify/wakeup_epoll
706722 // 才能找到并唤醒这个 epitem。
707723 if let Err ( e) = dst_file. add_epitem ( epitem. clone ( ) ) {
708724 // 如果添加失败,需要清理 ep_items 中已插入的项
709- epoll_guard. ep_items . remove ( & epitem. fd ) ;
725+ epoll_guard. ep_items . remove ( & epitem. key ( ) ) ;
710726 return Err ( e) ;
711727 }
712728
@@ -726,18 +742,16 @@ impl EventPoll {
726742 Ok ( notify_nested)
727743 }
728744
729- pub fn ep_remove (
745+ fn ep_remove (
730746 epoll : & mut MutexGuard < EventPoll > ,
731- fd : i32 ,
747+ key : EPollKey ,
732748 dst_file : Option < Arc < File > > ,
733749 epitem : & Arc < EPollItem > ,
734750 ) -> Result < ( ) , SystemError > {
751+ let removed = epoll. ep_items . remove ( & key) . ok_or ( SystemError :: ENOENT ) ?;
752+ Self :: deactivate_and_remove_ready ( epoll, & removed) ;
735753 if let Some ( dst_file) = dst_file {
736- dst_file. remove_epitem ( epitem) ?;
737- }
738-
739- if let Some ( removed) = epoll. ep_items . remove ( & fd) {
740- Self :: remove_ready_item ( epoll, & removed) ;
754+ let _ = dst_file. remove_epitem ( epitem) ;
741755 }
742756
743757 Ok ( ( ) )
@@ -752,20 +766,21 @@ impl EventPoll {
752766 return ;
753767 } ;
754768 let mut epoll = epoll. lock ( ) ;
755- let fd = epitem. fd ( ) ;
756- let Some ( current) = epoll. ep_items . get ( & fd ) . cloned ( ) else {
769+ let key = epitem. key ( ) ;
770+ let Some ( current) = epoll. ep_items . get ( & key ) . cloned ( ) else {
757771 return ;
758772 } ;
759773 if !Arc :: ptr_eq ( & current, epitem) {
760774 return ;
761775 }
762776
763- epoll. ep_items . remove ( & fd ) ;
764- Self :: remove_ready_item ( & mut epoll, & current) ;
777+ epoll. ep_items . remove ( & key ) ;
778+ Self :: deactivate_and_remove_ready ( & epoll, & current) ;
765779 }
766780
767- fn remove_ready_item ( epoll : & mut MutexGuard < EventPoll > , epitem : & Arc < EPollItem > ) {
781+ fn deactivate_and_remove_ready ( epoll : & EventPoll , epitem : & Arc < EPollItem > ) {
768782 let mut rs = epoll. ready_state . lock_irqsave ( ) ;
783+ epitem. deactivate ( ) ;
769784 rs. ready_list . retain ( |item| !Arc :: ptr_eq ( item, epitem) ) ;
770785 if let Some ( ovflist) = rs. ovflist . as_mut ( ) {
771786 ovflist. retain ( |item| !Arc :: ptr_eq ( item, epitem) ) ;
@@ -859,23 +874,19 @@ impl EventPoll {
859874 Ok ( ( ) )
860875 }
861876
862- /// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可
863- ///
864- /// 对标 Linux `ep_poll_callback()`。仅获取内层 SpinLock(irqsave),
865- /// **不获取外层 Mutex**,因此完全 hardirq-safe。
877+ /// Processes notifications from files that support epoll.
866878 ///
867- /// 回调路径通过 `EPollItem::ready_state()` 直接访问 `ReadyState`,
868- /// 绕过 `Mutex<EventPoll>`。
879+ /// Like Linux `ep_poll_callback()`, this path never acquires the outer
880+ /// sleeping `Mutex<EventPoll>`. Registration and ready-state locks use
881+ /// irqsave discipline. The registration snapshot's existing allocation and
882+ /// O(N) scan remain a separately documented hardirq latency risk.
869883 pub fn wakeup_epoll (
870- epitems : & LockedEPItemLinkedList ,
884+ epitems : & EPollItemList ,
871885 pollflags : EPollEventType ,
872886 ) -> Result < ( ) , SystemError > {
873887 // 在 epitems 锁下复制一份快照,然后释放锁,再逐个处理。
874888 // 避免持有 epitems 锁时再去获取其他锁导致 ABBA 死锁。
875- let epitems_snapshot: Vec < Arc < EPollItem > > = {
876- let epitems_guard = epitems. lock_irqsave ( ) ;
877- epitems_guard. iter ( ) . cloned ( ) . collect ( )
878- } ;
889+ let epitems_snapshot = epitems. snapshot ( ) ;
879890
880891 for epitem in epitems_snapshot. iter ( ) {
881892 // 通过 EPollItem 的 ready_state Weak 直接访问 ReadyState — 不需要 Mutex
@@ -907,6 +918,9 @@ impl EventPoll {
907918 {
908919 // 仅获取 SpinLock(irqsave)— hardirq-safe
909920 let mut rs = rs_arc. lock_irqsave ( ) ;
921+ if !epitem. is_active ( ) {
922+ continue ;
923+ }
910924
911925 if let Some ( ref mut ovflist) = rs. ovflist {
912926 // 扫描进行中 — 推入溢出列表
@@ -941,16 +955,45 @@ impl EventPoll {
941955 }
942956}
943957
944- /// LockedEPItemLinkedList — 使用 irqsave SpinLock 保护的 epitem 链表。
958+ /// An IRQ-safe list of epoll registrations attached to a pollable source.
945959///
946- /// 从 Mutex 改为 SpinLock 使得 `wakeup_epoll` 中的快照操作在 hardirq
947- /// 上下文中也是安全的。链表操作(push_back、retain、snapshot clone)
948- /// 临界区都很短,适合 SpinLock。
949- pub type LockedEPItemLinkedList = SpinLock < LinkedList < Arc < EPollItem > > > ;
960+ /// The inner lock is deliberately private: wakeups can run in hardirq context,
961+ /// so task-context registration updates must use the same irqsave discipline.
962+ #[ derive( Debug ) ]
963+ pub struct EPollItemList {
964+ items : SpinLock < LinkedList < Arc < EPollItem > > > ,
965+ }
966+
967+ impl EPollItemList {
968+ pub fn add ( & self , epitem : Arc < EPollItem > ) {
969+ self . items . lock_irqsave ( ) . push_back ( epitem) ;
970+ }
971+
972+ pub fn remove ( & self , epitem : & Arc < EPollItem > ) -> Result < ( ) , SystemError > {
973+ let mut items = self . items . lock_irqsave ( ) ;
974+ let old_len = items. len ( ) ;
975+ items. retain ( |item| !Arc :: ptr_eq ( item, epitem) ) ;
976+ if items. len ( ) != old_len {
977+ Ok ( ( ) )
978+ } else {
979+ Err ( SystemError :: ENOENT )
980+ }
981+ }
950982
951- impl Default for LockedEPItemLinkedList {
983+ fn snapshot ( & self ) -> Vec < Arc < EPollItem > > {
984+ self . items . lock_irqsave ( ) . iter ( ) . cloned ( ) . collect ( )
985+ }
986+
987+ pub fn take_all ( & self ) -> LinkedList < Arc < EPollItem > > {
988+ core:: mem:: take ( & mut * self . items . lock_irqsave ( ) )
989+ }
990+ }
991+
992+ impl Default for EPollItemList {
952993 fn default ( ) -> Self {
953- SpinLock :: new ( LinkedList :: new ( ) )
994+ Self {
995+ items : SpinLock :: new ( LinkedList :: new ( ) ) ,
996+ }
954997 }
955998}
956999
0 commit comments