This addresses #12842 by offering fallback implementations for functions that aren't available.
In this case, as Windows XP simply doesn't support symbolic links at all, the fallbacks simply return an error code indicating that the function hasn't been implemented. This should allow programs written in Rust to run under XP while still offering full support for symbolic links under newer versions of Windows with the same binary, but due to LLVM using stderror_s(), which isn't available in msvcrt.dll in XP, rustc itself will not.
The fallback implementation is as follows:
Calling the function instead calls to a mutable function pointer. This in and of itself would not constitute a performance hit because DLL calls are implemented in a similar manner (see Import Address Table). The function pointer initially points to a thunk which tries to get the address of the associated function and write it back to the function pointer. If it fails to find the function, it instead writes the address to a fallback. As this operation is idempotent, reading and writing the pointer simply needs to be atomic. Subsequent calls to the function should be as fast as any other DLL call, as the pointer will then point directly to either the correct function or a fallback.
This commit has an implementation of the previous commit's timeout interface for
I/O objects on unix platforms. For implementation details, see the large comment
at the end of libnative/io/net.rs which talks about the general strategy taken.
Thankfully, all of these implementations can share code because they're
performing all the same operations.
This commit does not implement timeouts for named pipes on windows, only tcp/udp
objects on windows (which are quite similar to their unix equivalents).
Two new methods were added to TcpStream and UnixStream:
fn close_read(&mut self) -> IoResult<()>;
fn close_write(&mut self) -> IoResult<()>;
These two methods map to shutdown()'s behavior (the system call on unix),
closing the reading or writing half of a duplex stream. These methods are
primarily added to allow waking up a pending read in another task. By closing
the reading half of a connection, all pending readers will be woken up and will
return with EndOfFile. The close_write() method was added for symmetry with
close_read(), and I imagine that it will be quite useful at some point.
Implementation-wise, librustuv got the short end of the stick this time. The
native versions just delegate to the shutdown() syscall (easy). The uv versions
can leverage uv_shutdown() for tcp/unix streams, but only for closing the
writing half. Closing the reading half is done through some careful dancing to
wake up a pending reader.
As usual, windows likes to be different from unix. The windows implementation
uses shutdown() for sockets, but shutdown() is not available for named pipes.
Instead, CancelIoEx was used with same fancy synchronization to make sure
everyone knows what's up.
cc #11165
This adds support for connecting to a unix socket with a timeout (a named pipe
on windows), and accepting a connection with a timeout. The goal is to bring
unix pipes/named sockets back in line with TCP support for timeouts.
Similarly to the TCP sockets, all methods are marked #[experimental] due to
uncertainty about the type of the timeout argument.
This internally involved a good bit of refactoring to share as much code as
possible between TCP servers and pipe servers, but the core implementation did
not change drastically as part of this commit.
cc #13523
This adds experimental support for timeouts when accepting sockets through
`TcpAcceptor::accept`. This does not add a separate `accept_timeout` function,
but rather it adds a `set_timeout` function instead. This second function is
intended to be used as a hard deadline after which all accepts will never block
and fail immediately.
This idea was derived from Go's SetDeadline() methods. We do not currently have
a robust time abstraction in the standard library, so I opted to have the
argument be a relative time in millseconds into the future. I believe a more
appropriate argument type is an absolute time, but this concept does not exist
yet (this is also why the function is marked #[experimental]).
The native support is built on select(), similarly to connect_timeout(), and the
green support is based on channel select and a timer.
cc #13523
This adds a `TcpStream::connect_timeout` function in order to assist opening
connections with a timeout (cc #13523). There isn't really much design space for
this specific operation (unlike timing out normal blocking reads/writes), so I
am fairly confident that this is the correct interface for this function.
The function is marked #[experimental] because it takes a u64 timeout argument,
and the u64 type is likely to change in the future.