@@ -110,43 +110,76 @@ pub fn decode_error_kind(code: i32) -> ErrorKind {
110
110
}
111
111
}
112
112
113
- // This function makes an effort to sleep at least as long as `duration`.
114
- // Note that in general there is no guarantee about accuracy of time and
115
- // timeouts in SGX model. The enclave runner serving usercalls may lie about
116
- // current time and/or ignore timeout values.
113
+ // This function makes an effort to wait for a non-spurious event at least as
114
+ // long as `duration`. Note that in general there is no guarantee about accuracy
115
+ // of time and timeouts in SGX model. The enclave runner serving usercalls may
116
+ // lie about current time and/or ignore timeout values.
117
117
//
118
- // Once the event is observed, `stop ` will be used to determine whether or not
119
- // we should continue to wait .
118
+ // Once the event is observed, `woken_up ` will be used to determine whether or
119
+ // not the event was spurious .
120
120
//
121
121
// FIXME: note these caveats in documentation of all public types that use this
122
122
// function in their execution path.
123
- pub fn wait_timeout_sgx < F > ( event_mask : u64 , duration : crate :: time:: Duration , stop : F )
123
+ pub fn wait_timeout_sgx < F > ( event_mask : u64 , duration : crate :: time:: Duration , woken_up : F )
124
124
where
125
125
F : Fn ( ) -> bool ,
126
126
{
127
127
use self :: abi:: usercalls;
128
128
use crate :: cmp;
129
129
use crate :: io:: ErrorKind ;
130
- use crate :: time:: Instant ;
131
-
132
- let start = Instant :: now ( ) ;
133
- let mut remaining = duration;
134
- loop {
135
- let timeout = cmp:: min ( ( u64:: MAX - 1 ) as u128 , remaining. as_nanos ( ) ) as u64 ;
130
+ use crate :: time:: { Duration , Instant } ;
131
+
132
+ // Calls the wait usercall and checks the result. Returns true if event was
133
+ // returned, and false if WouldBlock/TimedOut was returned.
134
+ // If duration is None, it will use WAIT_NO.
135
+ fn wait_checked ( event_mask : u64 , duration : Option < Duration > ) -> bool {
136
+ let timeout = duration. map_or ( usercalls:: raw:: WAIT_NO , |duration| {
137
+ cmp:: min ( ( u64:: MAX - 1 ) as u128 , duration. as_nanos ( ) ) as u64
138
+ } ) ;
136
139
match usercalls:: wait ( event_mask, timeout) {
137
140
Ok ( eventset) => {
138
141
if event_mask == 0 {
139
142
rtabort ! ( "expected usercalls::wait() to return Err, found Ok." ) ;
140
143
}
141
144
rtassert ! ( eventset & event_mask == event_mask) ;
142
- if stop ( ) {
143
- return ;
144
- }
145
+ true
145
146
}
146
147
Err ( e) => {
147
- rtassert ! ( e. kind( ) == ErrorKind :: TimedOut || e. kind( ) == ErrorKind :: WouldBlock )
148
+ rtassert ! ( e. kind( ) == ErrorKind :: TimedOut || e. kind( ) == ErrorKind :: WouldBlock ) ;
149
+ false
148
150
}
149
151
}
152
+ }
153
+
154
+ match wait_checked ( event_mask, Some ( duration) ) {
155
+ false => return , // timed out
156
+ true if woken_up ( ) => return , // woken up
157
+ true => { } // spurious event
158
+ }
159
+
160
+ // Drain all cached events.
161
+ // Note that `event_mask != 0` is implied if we get here.
162
+ loop {
163
+ match wait_checked ( event_mask, None ) {
164
+ false => break , // no more cached events
165
+ true if woken_up ( ) => return , // woken up
166
+ true => { } // spurious event
167
+ }
168
+ }
169
+
170
+ // Continue waiting, but take note of time spent waiting so we don't wait
171
+ // forever. We intentionally don't call `Instant::now()` before this point
172
+ // to avoid the cost of the `insecure_time` usercall in case there are no
173
+ // spurious wakeups.
174
+
175
+ let start = Instant :: now ( ) ;
176
+ let mut remaining = duration;
177
+ loop {
178
+ match wait_checked ( event_mask, Some ( remaining) ) {
179
+ false => return , // timed out
180
+ true if woken_up ( ) => return , // woken up
181
+ true => { } // spurious event
182
+ }
150
183
remaining = match duration. checked_sub ( start. elapsed ( ) ) {
151
184
Some ( remaining) => remaining,
152
185
None => break ,
0 commit comments