@@ -24,9 +24,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
24
24
/// `obj`: a pointer to the futex object (can be a lot of things, mostly *AtomicU32)
25
25
/// `op`: the futex operation to run
26
26
/// `val`: the current value of the object as a `c_long` (for wait/wake)
27
- /// `uaddr`: pointer to optional parameter (mostly timeouts)
28
- /// `uaddr2`: pointer to optional parameter (mostly timeouts)
27
+ /// `uaddr`: `op`-specific optional parameter, pointer-sized integer or pointer to an `op`-specific struct
28
+ /// `uaddr2`: `op`-specific optional parameter, pointer-sized integer or pointer to an `op`-specific struct
29
29
/// `dest`: the place this syscall returns to, 0 for success, -1 for failure
30
+ ///
31
+ /// # Note
32
+ /// Curently only the WAIT and WAKE operations are implemented.
30
33
fn _umtx_op (
31
34
& mut self ,
32
35
obj : & OpTy < ' tcx > ,
@@ -83,7 +86,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
83
86
84
87
// From the manual:
85
88
// The timeout is specified by passing either the address of `struct timespec`, or its
86
- // extended variant, `struct _umtx_time`, as the `uaddr2` argument of _umtx_op().
89
+ // extended variant, `struct _umtx_time`, as the `uaddr2` argument of _umtx_op().
87
90
// They are distinguished by the `uaddr` value, which must be equal
88
91
// to the size of the structure pointed to by `uaddr2`, casted to uintptr_t.
89
92
let timeout = if this. ptr_is_null ( uaddr2) ? {
@@ -113,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
113
116
// RealTime clock can't be used in isolation mode.
114
117
this. check_no_isolation ( "`_umtx_op` with `timespec` timeout" ) ?;
115
118
116
- // `uaddr2` points to a `struct timespec`
119
+ // `uaddr2` points to a `struct timespec`.
117
120
let timespec = this. ptr_to_mplace ( uaddr2, timespec_layout) ;
118
121
let duration = match this. read_timespec ( & timespec) ? {
119
122
Some ( duration) => duration,
@@ -123,9 +126,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
123
126
}
124
127
} ;
125
128
126
- // From the FreeBSD source code:
127
- // In the function `umtx_copyin_umtx_time` in kern_umtx.c,
128
- // _clock_id is set to CLOCK_REALTIME when using a `timespec` timeout.
129
+ // FreeBSD does not seem to document which clock is used when the timeout
130
+ // is passed as a `struct timespec*`. Based on discussions online and the source
131
+ // code (umtx_copyin_umtx_time() in kern_umtx.c), it seems to default to CLOCK_REALTIME,
132
+ // so that's what we also do.
133
+ // Discussion in golang: https://github.com/golang/go/issues/17168#issuecomment-250235271
129
134
Some ( ( TimeoutClock :: RealTime , TimeoutAnchor :: Relative , duration) )
130
135
} else {
131
136
return this. set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
@@ -144,7 +149,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
144
149
|ecx, unblock: UnblockKind | match unblock {
145
150
UnblockKind :: Ready => {
146
151
// From the manual:
147
- // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP
152
+ // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP
148
153
// sub-requests of the UMTX_OP_SHM request, will return zero.
149
154
ecx. write_int( 0 , & dest)
150
155
}
@@ -191,8 +196,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
191
196
) ?;
192
197
193
198
// From the manual:
194
- // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP
195
- // sub-requests of the UMTX_OP_SHM request, will return zero.
199
+ // If successful, all requests, except UMTX_SHM_CREAT and UMTX_SHM_LOOKUP
200
+ // sub-requests of the UMTX_OP_SHM request, will return zero.
196
201
this. write_int ( 0 , dest) ?;
197
202
interp_ok ( ( ) )
198
203
}
0 commit comments