@@ -96,26 +96,7 @@ impl FileDescription for AnonSocket {
9696 dest : & MPlaceTy < ' tcx > ,
9797 ecx : & mut MiriInterpCx < ' tcx > ,
9898 ) -> 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)
119100 }
120101
121102 fn write < ' tcx > (
@@ -127,31 +108,7 @@ impl FileDescription for AnonSocket {
127108 dest : & MPlaceTy < ' tcx > ,
128109 ecx : & mut MiriInterpCx < ' tcx > ,
129110 ) -> 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)
155112 }
156113
157114 fn as_unix ( & self ) -> & dyn UnixFileDescription {
@@ -161,50 +118,66 @@ impl FileDescription for AnonSocket {
161118
162119/// Write to AnonSocket based on the space available and return the written byte size.
163120fn anonsocket_write < ' tcx > (
164- weak_self_ref : WeakFileDescriptionRef ,
121+ self_ref : & FileDescriptionRef ,
165122 ptr : Pointer ,
166123 len : usize ,
167- dest : MPlaceTy < ' tcx > ,
124+ dest : & MPlaceTy < ' tcx > ,
168125 ecx : & mut MiriInterpCx < ' tcx > ,
169126) -> 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- } ;
174127 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.
175136 let Some ( peer_fd) = self_anonsocket. peer_fd ( ) . upgrade ( ) else {
176137 // 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) ;
179140 } ;
141+
180142 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) ;
184145 } ;
185146
147+ // Let's see if we can write.
186148 let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY . strict_sub ( writebuf. borrow ( ) . buf . len ( ) ) ;
187-
188149 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+ }
207179 } else {
180+ // There is space to write!
208181 let mut writebuf = writebuf. borrow_mut ( ) ;
209182 // Remember this clock so `read` can synchronize with us.
210183 ecx. release_clock ( |clock| {
@@ -229,25 +202,26 @@ fn anonsocket_write<'tcx>(
229202 ecx. unblock_thread ( thread_id, BlockReason :: UnnamedSocket ) ?;
230203 }
231204
232- return ecx. return_write_success ( actual_write_size, & dest) ;
205+ return ecx. return_write_success ( actual_write_size, dest) ;
233206 }
234207 interp_ok ( ( ) )
235208}
236209
237210/// Read from AnonSocket and return the number of bytes read.
238211fn anonsocket_read < ' tcx > (
239- weak_self_ref : WeakFileDescriptionRef ,
212+ self_ref : & FileDescriptionRef ,
240213 len : usize ,
241214 ptr : Pointer ,
242- dest : MPlaceTy < ' tcx > ,
215+ dest : & MPlaceTy < ' tcx > ,
243216 ecx : & mut MiriInterpCx < ' tcx > ,
244217) -> 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- } ;
249218 let self_anonsocket = self_ref. downcast :: < AnonSocket > ( ) . unwrap ( ) ;
250219
220+ // Always succeed on read size 0.
221+ if len == 0 {
222+ return ecx. return_read_success ( ptr, & [ ] , 0 , dest) ;
223+ }
224+
251225 let Some ( readbuf) = & self_anonsocket. readbuf else {
252226 // FIXME: This should return EBADF, but there's no nice way to do that as there's no
253227 // corresponding ErrorKind variant.
@@ -258,10 +232,19 @@ fn anonsocket_read<'tcx>(
258232 if self_anonsocket. peer_fd ( ) . upgrade ( ) . is_none ( ) {
259233 // Socketpair with no peer and empty buffer.
260234 // 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) ;
262243 } else {
263244 // 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 ( ) ;
265248 self_anonsocket. blocked_read_tid . borrow_mut ( ) . push ( ecx. active_thread ( ) ) ;
266249 ecx. block_thread (
267250 BlockReason :: UnnamedSocket ,
@@ -274,12 +257,17 @@ fn anonsocket_read<'tcx>(
274257 dest: MPlaceTy <' tcx>,
275258 }
276259 @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)
278265 }
279266 ) ,
280267 ) ;
281268 }
282269 } else {
270+ // There's data to be read!
283271 let mut bytes = vec ! [ 0 ; len] ;
284272 let mut readbuf = readbuf. borrow_mut ( ) ;
285273 // Synchronize with all previous writes to this buffer.
@@ -313,7 +301,7 @@ fn anonsocket_read<'tcx>(
313301 }
314302 } ;
315303
316- return ecx. return_read_success ( ptr, & bytes, actual_read_size, & dest) ;
304+ return ecx. return_read_success ( ptr, & bytes, actual_read_size, dest) ;
317305 }
318306 interp_ok ( ( ) )
319307}
0 commit comments