@@ -7,6 +7,8 @@ use socketpair::SocketPair;
7
7
8
8
use shims:: unix:: fs:: EvalContextExt as _;
9
9
10
+ use std:: cell:: Cell ;
11
+
10
12
pub mod epoll;
11
13
pub mod event;
12
14
pub mod socketpair;
@@ -101,6 +103,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
101
103
}
102
104
}
103
105
106
+ /// The `epoll_wait()` system call waits for events on the `Epoll`
107
+ /// instance referred to by the file descriptor `epfd`. The buffer
108
+ /// pointed to by `events` is used to return information from the ready
109
+ /// list about file descriptors in the interest list that have some
110
+ /// events available. Up to `maxevents` are returned by `epoll_wait()`.
111
+ /// The `maxevents` argument must be greater than zero.
112
+
113
+ /// The `timeout` argument specifies the number of milliseconds that
114
+ /// `epoll_wait()` will block. Time is measured against the
115
+ /// CLOCK_MONOTONIC clock.
116
+
117
+ /// A call to `epoll_wait()` will block until either:
118
+ /// • a file descriptor delivers an event;
119
+ /// • the call is interrupted by a signal handler; or
120
+ /// • the timeout expires.
121
+
122
+ /// Note that the timeout interval will be rounded up to the system
123
+ /// clock granularity, and kernel scheduling delays mean that the
124
+ /// blocking interval may overrun by a small amount. Specifying a
125
+ /// timeout of -1 causes `epoll_wait()` to block indefinitely, while
126
+ /// specifying a timeout equal to zero cause `epoll_wait()` to return
127
+ /// immediately, even if no events are available.
128
+ ///
129
+ /// On success, `epoll_wait()` returns the number of file descriptors
130
+ /// ready for the requested I/O, or zero if no file descriptor became
131
+ /// ready during the requested timeout milliseconds. On failure,
132
+ /// `epoll_wait()` returns -1 and errno is set to indicate the error.
133
+ ///
134
+ /// <https://man7.org/linux/man-pages/man2/epoll_wait.2.html>
135
+ fn epoll_wait (
136
+ & mut self ,
137
+ epfd : & OpTy < ' tcx , Provenance > ,
138
+ events : & OpTy < ' tcx , Provenance > ,
139
+ maxevents : & OpTy < ' tcx , Provenance > ,
140
+ timeout : & OpTy < ' tcx , Provenance > ,
141
+ ) -> InterpResult < ' tcx , Scalar < Provenance > > {
142
+ let this = self . eval_context_mut ( ) ;
143
+
144
+ let epfd = this. read_scalar ( epfd) ?. to_i32 ( ) ?;
145
+ let _events = this. read_scalar ( events) ?. to_pointer ( this) ?;
146
+ let _maxevents = this. read_scalar ( maxevents) ?. to_i32 ( ) ?;
147
+ let _timeout = this. read_scalar ( timeout) ?. to_i32 ( ) ?;
148
+
149
+ let numevents = 0 ;
150
+ if let Some ( epfd) = this. machine . file_handler . handles . get_mut ( & epfd) {
151
+ let _epfd = epfd. as_epoll_handle ( ) ?;
152
+
153
+ // FIXME return number of events ready when scheme for marking events ready exists
154
+ Ok ( Scalar :: from_i32 ( numevents) )
155
+ } else {
156
+ Ok ( Scalar :: from_i32 ( this. handle_not_found ( ) ?) )
157
+ }
158
+ }
159
+
104
160
/// This function creates an `Event` that is used as an event wait/notify mechanism by
105
161
/// user-space applications, and by the kernel to notify user-space applications of events.
106
162
/// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized
@@ -142,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
142
198
}
143
199
144
200
let fh = & mut this. machine . file_handler ;
145
- let fd = fh. insert_fd ( Box :: new ( Event { val } ) ) ;
201
+ let fd = fh. insert_fd ( Box :: new ( Event { val : Cell :: new ( val . into ( ) ) } ) ) ;
146
202
Ok ( Scalar :: from_i32 ( fd) )
147
203
}
148
204
0 commit comments