@@ -69,17 +69,24 @@ pub struct EpollReadyEvents {
69
69
/// Stream socket peer closed connection, or shut down writing
70
70
/// half of connection.
71
71
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 ,
72
78
}
73
79
74
80
impl EpollReadyEvents {
75
81
pub fn new ( ) -> Self {
76
- EpollReadyEvents { epollin : false , epollout : false , epollrdhup : false }
82
+ EpollReadyEvents { epollin : false , epollout : false , epollrdhup : false , epollhup : false }
77
83
}
78
84
79
85
pub fn get_event_bitmask < ' tcx > ( & self , ecx : & MiriInterpCx < ' tcx > ) -> u32 {
80
86
let epollin = ecx. eval_libc_u32 ( "EPOLLIN" ) ;
81
87
let epollout = ecx. eval_libc_u32 ( "EPOLLOUT" ) ;
82
88
let epollrdhup = ecx. eval_libc_u32 ( "EPOLLRDHUP" ) ;
89
+ let epollhup = ecx. eval_libc_u32 ( "EPOLLHUP" ) ;
83
90
84
91
let mut bitmask = 0 ;
85
92
if self . epollin {
@@ -91,6 +98,9 @@ impl EpollReadyEvents {
91
98
if self . epollrdhup {
92
99
bitmask |= epollrdhup;
93
100
}
101
+ if self . epollhup {
102
+ bitmask |= epollhup;
103
+ }
94
104
bitmask
95
105
}
96
106
}
@@ -217,6 +227,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
217
227
let epollout = this. eval_libc_u32 ( "EPOLLOUT" ) ;
218
228
let epollrdhup = this. eval_libc_u32 ( "EPOLLRDHUP" ) ;
219
229
let epollet = this. eval_libc_u32 ( "EPOLLET" ) ;
230
+ let epollhup = this. eval_libc_u32 ( "EPOLLHUP" ) ;
220
231
221
232
// Fail on unsupported operations.
222
233
if op & epoll_ctl_add != epoll_ctl_add
@@ -244,11 +255,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
244
255
245
256
if op == epoll_ctl_add || op == epoll_ctl_mod {
246
257
// 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 ( ) ?;
248
259
let data = this. read_scalar ( & this. project_field ( & event, 1 ) ?) ?. to_u64 ( ) ?;
249
260
250
261
// Unset the flag we support to discover if any unsupported flags are used.
251
262
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
+
252
268
if events & epollet != epollet {
253
269
// We only support edge-triggered notification for now.
254
270
throw_unsup_format ! ( "epoll_ctl: epollet flag must be included." ) ;
@@ -264,6 +280,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
264
280
if flags & epollrdhup == epollrdhup {
265
281
flags &= !epollrdhup;
266
282
}
283
+ if flags & epollhup == epollhup {
284
+ flags &= !epollhup;
285
+ }
267
286
if flags != 0 {
268
287
throw_unsup_format ! (
269
288
"epoll_ctl: encountered unknown unsupported flags {:#x}" ,
0 commit comments