@@ -69,17 +69,24 @@ pub struct EpollReadyEvents {
6969 /// Stream socket peer closed connection, or shut down writing
7070 /// half of connection.
7171 pub epollrdhup : bool ,
72+ /// For stream socket, this event merely indicates that the peer
73+ /// closed its end of the channel.
74+ /// Unlike epollrdhup, this should only be set when the stream is fully closed.
75+ /// epollrdhup also gets set when only the write half is closed, which is possible
76+ /// via `shutdown(_, SHUT_WR)`.
77+ pub epollhup : bool ,
7278}
7379
7480impl EpollReadyEvents {
7581 pub fn new ( ) -> Self {
76- EpollReadyEvents { epollin : false , epollout : false , epollrdhup : false }
82+ EpollReadyEvents { epollin : false , epollout : false , epollrdhup : false , epollhup : false }
7783 }
7884
7985 pub fn get_event_bitmask < ' tcx > ( & self , ecx : & MiriInterpCx < ' tcx > ) -> u32 {
8086 let epollin = ecx. eval_libc_u32 ( "EPOLLIN" ) ;
8187 let epollout = ecx. eval_libc_u32 ( "EPOLLOUT" ) ;
8288 let epollrdhup = ecx. eval_libc_u32 ( "EPOLLRDHUP" ) ;
89+ let epollhup = ecx. eval_libc_u32 ( "EPOLLHUP" ) ;
8390
8491 let mut bitmask = 0 ;
8592 if self . epollin {
@@ -91,6 +98,9 @@ impl EpollReadyEvents {
9198 if self . epollrdhup {
9299 bitmask |= epollrdhup;
93100 }
101+ if self . epollhup {
102+ bitmask |= epollhup;
103+ }
94104 bitmask
95105 }
96106}
@@ -217,6 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
217227 let epollout = this. eval_libc_u32 ( "EPOLLOUT" ) ;
218228 let epollrdhup = this. eval_libc_u32 ( "EPOLLRDHUP" ) ;
219229 let epollet = this. eval_libc_u32 ( "EPOLLET" ) ;
230+ let epollhup = this. eval_libc_u32 ( "EPOLLHUP" ) ;
220231
221232 // Fail on unsupported operations.
222233 if op & epoll_ctl_add != epoll_ctl_add
@@ -244,11 +255,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
244255
245256 if op == epoll_ctl_add || op == epoll_ctl_mod {
246257 // Read event bitmask and data from epoll_event passed by caller.
247- let events = this. read_scalar ( & this. project_field ( & event, 0 ) ?) ?. to_u32 ( ) ?;
258+ let mut events = this. read_scalar ( & this. project_field ( & event, 0 ) ?) ?. to_u32 ( ) ?;
248259 let data = this. read_scalar ( & this. project_field ( & event, 1 ) ?) ?. to_u64 ( ) ?;
249260
250261 // Unset the flag we support to discover if any unsupported flags are used.
251262 let mut flags = events;
263+ // epoll_wait(2) will always wait for epollhup; it is not
264+ // necessary to set it in events when calling epoll_ctl().
265+ // So we will always set this event type.
266+ events |= epollhup;
267+
252268 if events & epollet != epollet {
253269 // We only support edge-triggered notification for now.
254270 throw_unsup_format ! ( "epoll_ctl: epollet flag must be included." ) ;
@@ -264,6 +280,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
264280 if flags & epollrdhup == epollrdhup {
265281 flags &= !epollrdhup;
266282 }
283+ if flags & epollhup == epollhup {
284+ flags &= !epollhup;
285+ }
267286 if flags != 0 {
268287 throw_unsup_format ! (
269288 "epoll_ctl: encountered unknown unsupported flags {:#x}" ,
0 commit comments