2 Commits
Author SHA1 Message Date
Garrett D'Amore effecfb659 Reduce the timeout to 2 seconds, and close the client handle.
We can safely close the client handle, because the server side
is not closed, and thsi keeps our hold on the pipe instance.
2018-07-18 12:07:29 -07:00
Garrett D'Amore ecd994be06 fixes #67 DialPipe problem with multiple calls / waiting for busy pipe
This changes a few things to try to ensure that we never wind up with
a result of ERROR_FILE_NOT_FOUND, due to a race between closing the
last pipe instance and opening the next.

First we keep an "open" client instance (unused) while the listener
is open, so that we are guaranteed to always have an active pipe
instance.  This means attempts to open while no other instances exist
result in ERROR_PIPE_BUSY instead of ERROR_FILE_NOT_FOUND.

Second we have changed the loop for dialing to eliminate a race condition
that is more or less inherent in WaitNamedPipe when synchronizing with
CreateFile.  The real timeout needs to be some larger value than the
WaitNamedPipe timeout, and furthermore WaitNamedPipe is not very nice
with the Go runtime, since it is a blocking system call.  Instead we
just put the goroutine to sleep for 10 milliseconds, and keep retrying
the CreateFile until the maximum timeout is reached.  If no timeout is
specified we assume a reasonable and large default of 5 seconds, which is
similar to a TCP connection timeout.

This isn't perfect, as a client attempting to connect to an extremely
busy pipe server can be starved out by other clients coming in while
it is in that brief sleep, but this potential race was already present
with WaitNamedPipe.  The numerous retries (by default 500 retries!)
mean its pretty unlikely to occur, and if a single client hits the
race once, it has an excellent chance of getting in the next cycle.

(A real "fix" that is completely race free and fair would require
changes in the underlying Named Pipe implementation, or some other
kind of external coordination.)
2018-06-24 11:39:09 -07:00