@@ -96,26 +96,7 @@ impl FileDescription for AnonSocket {
96
96
dest : & MPlaceTy < ' tcx > ,
97
97
ecx : & mut MiriInterpCx < ' tcx > ,
98
98
) -> InterpResult < ' tcx > {
99
- // Always succeed on read size 0.
100
- if len == 0 {
101
- return ecx. return_read_success ( ptr, & [ ] , 0 , dest) ;
102
- }
103
-
104
- let Some ( readbuf) = & self . readbuf else {
105
- // FIXME: This should return EBADF, but there's no nice way to do that as there's no
106
- // corresponding ErrorKind variant.
107
- throw_unsup_format ! ( "reading from the write end of a pipe" ) ;
108
- } ;
109
-
110
- if readbuf. borrow ( ) . buf . is_empty ( ) && self . is_nonblock {
111
- // Non-blocking socketpair with writer and empty buffer.
112
- // https://linux.die.net/man/2/read
113
- // EAGAIN or EWOULDBLOCK can be returned for socket,
114
- // POSIX.1-2001 allows either error to be returned for this case.
115
- // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
116
- return ecx. set_last_error_and_return ( ErrorKind :: WouldBlock , dest) ;
117
- }
118
- anonsocket_read ( self_ref. downgrade ( ) , len, ptr, dest. clone ( ) , ecx)
99
+ anonsocket_read ( self_ref, len, ptr, dest, ecx)
119
100
}
120
101
121
102
fn write < ' tcx > (
@@ -127,31 +108,7 @@ impl FileDescription for AnonSocket {
127
108
dest : & MPlaceTy < ' tcx > ,
128
109
ecx : & mut MiriInterpCx < ' tcx > ,
129
110
) -> InterpResult < ' tcx > {
130
- // Always succeed on write size 0.
131
- // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
132
- if len == 0 {
133
- return ecx. return_write_success ( 0 , dest) ;
134
- }
135
-
136
- // We are writing to our peer's readbuf.
137
- let Some ( peer_fd) = self . peer_fd ( ) . upgrade ( ) else {
138
- // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
139
- // closed.
140
- return ecx. set_last_error_and_return ( ErrorKind :: BrokenPipe , dest) ;
141
- } ;
142
-
143
- let Some ( writebuf) = & peer_fd. downcast :: < AnonSocket > ( ) . unwrap ( ) . readbuf else {
144
- // FIXME: This should return EBADF, but there's no nice way to do that as there's no
145
- // corresponding ErrorKind variant.
146
- throw_unsup_format ! ( "writing to the reading end of a pipe" ) ;
147
- } ;
148
- let available_space =
149
- MAX_SOCKETPAIR_BUFFER_CAPACITY . strict_sub ( writebuf. borrow ( ) . buf . len ( ) ) ;
150
- if available_space == 0 && self . is_nonblock {
151
- // Non-blocking socketpair with a full buffer.
152
- return ecx. set_last_error_and_return ( ErrorKind :: WouldBlock , dest) ;
153
- }
154
- anonsocket_write ( self_ref. downgrade ( ) , ptr, len, dest. clone ( ) , ecx)
111
+ anonsocket_write ( self_ref, ptr, len, dest, ecx)
155
112
}
156
113
157
114
fn as_unix ( & self ) -> & dyn UnixFileDescription {
@@ -161,50 +118,65 @@ impl FileDescription for AnonSocket {
161
118
162
119
/// Write to AnonSocket based on the space available and return the written byte size.
163
120
fn anonsocket_write < ' tcx > (
164
- weak_self_ref : WeakFileDescriptionRef ,
121
+ self_ref : & FileDescriptionRef ,
165
122
ptr : Pointer ,
166
123
len : usize ,
167
- dest : MPlaceTy < ' tcx > ,
124
+ dest : & MPlaceTy < ' tcx > ,
168
125
ecx : & mut MiriInterpCx < ' tcx > ,
169
126
) -> InterpResult < ' tcx > {
170
- let Some ( self_ref) = weak_self_ref. upgrade ( ) else {
171
- // FIXME: We should raise a deadlock error if the self_ref upgrade failed.
172
- throw_unsup_format ! ( "This will be a deadlock error in future" )
173
- } ;
174
127
let self_anonsocket = self_ref. downcast :: < AnonSocket > ( ) . unwrap ( ) ;
128
+
129
+ // Always succeed on write size 0.
130
+ // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
131
+ if len == 0 {
132
+ return ecx. return_write_success ( 0 , dest) ;
133
+ }
134
+
135
+ // We are writing to our peer's readbuf.
175
136
let Some ( peer_fd) = self_anonsocket. peer_fd ( ) . upgrade ( ) else {
176
137
// If the upgrade from Weak to Rc fails, it indicates that all read ends have been
177
- // closed.
178
- return ecx. set_last_error_and_return ( ErrorKind :: BrokenPipe , & dest) ;
138
+ // closed. It is an error to write even if there would be space.
139
+ return ecx. set_last_error_and_return ( ErrorKind :: BrokenPipe , dest) ;
179
140
} ;
141
+
180
142
let Some ( writebuf) = & peer_fd. downcast :: < AnonSocket > ( ) . unwrap ( ) . readbuf else {
181
- // FIXME: This should return EBADF, but there's no nice way to do that as there's no
182
- // corresponding ErrorKind variant.
183
- throw_unsup_format ! ( "writing to the reading end of a pipe" )
143
+ // Writing to the read end of a pipe.
144
+ return ecx. set_last_error_and_return ( IoError :: LibcError ( "EBADF" ) , dest) ;
184
145
} ;
185
146
147
+ // Let's see if we can write.
186
148
let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY . strict_sub ( writebuf. borrow ( ) . buf . len ( ) ) ;
187
-
188
149
if available_space == 0 {
189
- // Blocking socketpair with a full buffer.
190
- let dest = dest. clone ( ) ;
191
- self_anonsocket. blocked_write_tid . borrow_mut ( ) . push ( ecx. active_thread ( ) ) ;
192
- ecx. block_thread (
193
- BlockReason :: UnnamedSocket ,
194
- None ,
195
- callback ! (
196
- @capture<' tcx> {
197
- weak_self_ref: WeakFileDescriptionRef ,
198
- ptr: Pointer ,
199
- len: usize ,
200
- dest: MPlaceTy <' tcx>,
201
- }
202
- @unblock = |this| {
203
- anonsocket_write( weak_self_ref, ptr, len, dest, this)
204
- }
205
- ) ,
206
- ) ;
150
+ if self_anonsocket. is_nonblock {
151
+ // Non-blocking socketpair with a full buffer.
152
+ return ecx. set_last_error_and_return ( ErrorKind :: WouldBlock , dest) ;
153
+ } else {
154
+ // Blocking socketpair with a full buffer.
155
+ // Block the current thread; only keep a weak ref for this.
156
+ let weak_self_ref = self_ref. downgrade ( ) ;
157
+ let dest = dest. clone ( ) ;
158
+ self_anonsocket. blocked_write_tid . borrow_mut ( ) . push ( ecx. active_thread ( ) ) ;
159
+ ecx. block_thread (
160
+ BlockReason :: UnnamedSocket ,
161
+ None ,
162
+ callback ! (
163
+ @capture<' tcx> {
164
+ weak_self_ref: WeakFileDescriptionRef ,
165
+ ptr: Pointer ,
166
+ len: usize ,
167
+ dest: MPlaceTy <' tcx>,
168
+ }
169
+ @unblock = |this| {
170
+ // If we got unblocked, then our peer successfully upgraded its weak
171
+ // ref to us. That means we can also upgrade our weak ref.
172
+ let self_ref = weak_self_ref. upgrade( ) . unwrap( ) ;
173
+ anonsocket_write( & self_ref, ptr, len, & dest, this)
174
+ }
175
+ ) ,
176
+ ) ;
177
+ }
207
178
} else {
179
+ // There is space to write!
208
180
let mut writebuf = writebuf. borrow_mut ( ) ;
209
181
// Remember this clock so `read` can synchronize with us.
210
182
ecx. release_clock ( |clock| {
@@ -229,25 +201,26 @@ fn anonsocket_write<'tcx>(
229
201
ecx. unblock_thread ( thread_id, BlockReason :: UnnamedSocket ) ?;
230
202
}
231
203
232
- return ecx. return_write_success ( actual_write_size, & dest) ;
204
+ return ecx. return_write_success ( actual_write_size, dest) ;
233
205
}
234
206
interp_ok ( ( ) )
235
207
}
236
208
237
209
/// Read from AnonSocket and return the number of bytes read.
238
210
fn anonsocket_read < ' tcx > (
239
- weak_self_ref : WeakFileDescriptionRef ,
211
+ self_ref : & FileDescriptionRef ,
240
212
len : usize ,
241
213
ptr : Pointer ,
242
- dest : MPlaceTy < ' tcx > ,
214
+ dest : & MPlaceTy < ' tcx > ,
243
215
ecx : & mut MiriInterpCx < ' tcx > ,
244
216
) -> InterpResult < ' tcx > {
245
- let Some ( self_ref) = weak_self_ref. upgrade ( ) else {
246
- // FIXME: We should raise a deadlock error if the self_ref upgrade failed.
247
- throw_unsup_format ! ( "This will be a deadlock error in future" )
248
- } ;
249
217
let self_anonsocket = self_ref. downcast :: < AnonSocket > ( ) . unwrap ( ) ;
250
218
219
+ // Always succeed on read size 0.
220
+ if len == 0 {
221
+ return ecx. return_read_success ( ptr, & [ ] , 0 , dest) ;
222
+ }
223
+
251
224
let Some ( readbuf) = & self_anonsocket. readbuf else {
252
225
// FIXME: This should return EBADF, but there's no nice way to do that as there's no
253
226
// corresponding ErrorKind variant.
@@ -258,10 +231,19 @@ fn anonsocket_read<'tcx>(
258
231
if self_anonsocket. peer_fd ( ) . upgrade ( ) . is_none ( ) {
259
232
// Socketpair with no peer and empty buffer.
260
233
// 0 bytes successfully read indicates end-of-file.
261
- return ecx. return_read_success ( ptr, & [ ] , 0 , & dest) ;
234
+ return ecx. return_read_success ( ptr, & [ ] , 0 , dest) ;
235
+ } else if self_anonsocket. is_nonblock {
236
+ // Non-blocking socketpair with writer and empty buffer.
237
+ // https://linux.die.net/man/2/read
238
+ // EAGAIN or EWOULDBLOCK can be returned for socket,
239
+ // POSIX.1-2001 allows either error to be returned for this case.
240
+ // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
241
+ return ecx. set_last_error_and_return ( ErrorKind :: WouldBlock , dest) ;
262
242
} else {
263
243
// Blocking socketpair with writer and empty buffer.
264
- let weak_self_ref = weak_self_ref. clone ( ) ;
244
+ // Block the current thread; only keep a weak ref for this.
245
+ let weak_self_ref = self_ref. downgrade ( ) ;
246
+ let dest = dest. clone ( ) ;
265
247
self_anonsocket. blocked_read_tid . borrow_mut ( ) . push ( ecx. active_thread ( ) ) ;
266
248
ecx. block_thread (
267
249
BlockReason :: UnnamedSocket ,
@@ -274,12 +256,16 @@ fn anonsocket_read<'tcx>(
274
256
dest: MPlaceTy <' tcx>,
275
257
}
276
258
@unblock = |this| {
277
- anonsocket_read( weak_self_ref, len, ptr, dest, this)
259
+ // If we got unblocked, then our peer successfully upgraded its weak
260
+ // ref to us. That means we can also upgrade our weak ref.
261
+ let self_ref = weak_self_ref. upgrade( ) . unwrap( ) ;
262
+ anonsocket_read( & self_ref, len, ptr, & dest, this)
278
263
}
279
264
) ,
280
265
) ;
281
266
}
282
267
} else {
268
+ // There's data to be read!
283
269
let mut bytes = vec ! [ 0 ; len] ;
284
270
let mut readbuf = readbuf. borrow_mut ( ) ;
285
271
// Synchronize with all previous writes to this buffer.
@@ -313,7 +299,7 @@ fn anonsocket_read<'tcx>(
313
299
}
314
300
} ;
315
301
316
- return ecx. return_read_success ( ptr, & bytes, actual_read_size, & dest) ;
302
+ return ecx. return_read_success ( ptr, & bytes, actual_read_size, dest) ;
317
303
}
318
304
interp_ok ( ( ) )
319
305
}
0 commit comments