@@ -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,66 @@ 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
+ 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
+ anonsocket_write( & self_ref, ptr, len, & dest, this)
175
+ }
176
+ ) ,
177
+ ) ;
178
+ }
207
179
} else {
180
+ // There is space to write!
208
181
let mut writebuf = writebuf. borrow_mut ( ) ;
209
182
// Remember this clock so `read` can synchronize with us.
210
183
ecx. release_clock ( |clock| {
@@ -229,25 +202,26 @@ fn anonsocket_write<'tcx>(
229
202
ecx. unblock_thread ( thread_id, BlockReason :: UnnamedSocket ) ?;
230
203
}
231
204
232
- return ecx. return_write_success ( actual_write_size, & dest) ;
205
+ return ecx. return_write_success ( actual_write_size, dest) ;
233
206
}
234
207
interp_ok ( ( ) )
235
208
}
236
209
237
210
/// Read from AnonSocket and return the number of bytes read.
238
211
fn anonsocket_read < ' tcx > (
239
- weak_self_ref : WeakFileDescriptionRef ,
212
+ self_ref : & FileDescriptionRef ,
240
213
len : usize ,
241
214
ptr : Pointer ,
242
- dest : MPlaceTy < ' tcx > ,
215
+ dest : & MPlaceTy < ' tcx > ,
243
216
ecx : & mut MiriInterpCx < ' tcx > ,
244
217
) -> 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
218
let self_anonsocket = self_ref. downcast :: < AnonSocket > ( ) . unwrap ( ) ;
250
219
220
+ // Always succeed on read size 0.
221
+ if len == 0 {
222
+ return ecx. return_read_success ( ptr, & [ ] , 0 , dest) ;
223
+ }
224
+
251
225
let Some ( readbuf) = & self_anonsocket. readbuf else {
252
226
// FIXME: This should return EBADF, but there's no nice way to do that as there's no
253
227
// corresponding ErrorKind variant.
@@ -258,10 +232,19 @@ fn anonsocket_read<'tcx>(
258
232
if self_anonsocket. peer_fd ( ) . upgrade ( ) . is_none ( ) {
259
233
// Socketpair with no peer and empty buffer.
260
234
// 0 bytes successfully read indicates end-of-file.
261
- return ecx. return_read_success ( ptr, & [ ] , 0 , & dest) ;
235
+ return ecx. return_read_success ( ptr, & [ ] , 0 , dest) ;
236
+ } else if self_anonsocket. is_nonblock {
237
+ // Non-blocking socketpair with writer and empty buffer.
238
+ // https://linux.die.net/man/2/read
239
+ // EAGAIN or EWOULDBLOCK can be returned for socket,
240
+ // POSIX.1-2001 allows either error to be returned for this case.
241
+ // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
242
+ return ecx. set_last_error_and_return ( ErrorKind :: WouldBlock , dest) ;
262
243
} else {
263
244
// Blocking socketpair with writer and empty buffer.
264
- let weak_self_ref = weak_self_ref. clone ( ) ;
245
+ // Block the current thread; only keep a weak ref for this.
246
+ let weak_self_ref = self_ref. downgrade ( ) ;
247
+ let dest = dest. clone ( ) ;
265
248
self_anonsocket. blocked_read_tid . borrow_mut ( ) . push ( ecx. active_thread ( ) ) ;
266
249
ecx. block_thread (
267
250
BlockReason :: UnnamedSocket ,
@@ -274,12 +257,17 @@ fn anonsocket_read<'tcx>(
274
257
dest: MPlaceTy <' tcx>,
275
258
}
276
259
@unblock = |this| {
277
- anonsocket_read( weak_self_ref, len, ptr, dest, this)
260
+ let Some ( self_ref) = weak_self_ref. upgrade( ) else {
261
+ // FIXME: We should raise a deadlock error if the self_ref upgrade failed.
262
+ throw_unsup_format!( "This will be a deadlock error in future" )
263
+ } ;
264
+ anonsocket_read( & self_ref, len, ptr, & dest, this)
278
265
}
279
266
) ,
280
267
) ;
281
268
}
282
269
} else {
270
+ // There's data to be read!
283
271
let mut bytes = vec ! [ 0 ; len] ;
284
272
let mut readbuf = readbuf. borrow_mut ( ) ;
285
273
// Synchronize with all previous writes to this buffer.
@@ -313,7 +301,7 @@ fn anonsocket_read<'tcx>(
313
301
}
314
302
} ;
315
303
316
- return ecx. return_read_success ( ptr, & bytes, actual_read_size, & dest) ;
304
+ return ecx. return_read_success ( ptr, & bytes, actual_read_size, dest) ;
317
305
}
318
306
interp_ok ( ( ) )
319
307
}
0 commit comments