Commit Graph

128 Commits

Author SHA1 Message Date
Ken Brown 16e7c10578 Cygwin: FIFO: introduce a new type, fifo_reader_id_t
This uniquely identifies an fhandler_fifo open for reading in any
process.

Add a new data member 'me' of this type, which is set in open, dup,
fork, and exec.
2020-05-08 06:32:00 -04:00
Ken Brown 365818a4a5 Cygwin: FIFO: keep track of the number of readers
Add data and methods to the shared memory that keep track of the
number of open readers.

Increment this number in open, dup, fork, and exec.  Decrement it in
close.  Reset read_ready if there are no readers left.
2020-05-08 06:32:00 -04:00
Ken Brown 878eb22462 Cygwin: FIFO: add shared memory
Even though we currently allow a FIFO to be opened for reading only
once, we can still have more than one reader open because of dup and
fork.  Add a named shared memory section accessible to all readers of
a given FIFO.  In future commits we will add information needed by all
readers to this section

Add a class fifo_shmem_t that lets us access this information.

Add a method create_shmem that is called when a reader opens, and add
a method reopen_shmem that is called by dup, fork, and exec.  (Each
new reader needs its own view of the shared memory.)
2020-05-08 06:32:00 -04:00
Ken Brown 71726ba70b Cygwin: FIFO: use a cygthread instead of a homemade thread
This will simplify future work.

Rename the thread from "listen_client_thread" to "fifo_reader_thread"
because it will be used for more than just listening.

Remove the fixup_before stuff, which won't be needed after future
changes to fixup_after_fork and fixup_after_exec.
2020-05-08 06:32:00 -04:00
Ken Brown 9ee8fdf2b3 Cygwin: FIFO: make opening a writer more robust
- Make read_ready a manual-reset event.

- Signal read_ready in open instead of in the listen_client_thread.

- Don't reset read_ready when the listen_client thread terminates;
  instead do it in close().

- Rearrange open and change its error handling.

- Add a wait_open_pipe method that waits for a pipe instance to be
  available and then calls open_pipe.  Use it when opening a writer if
  we can't connect immediately.  This can happen if the system is
  heavily loaded and/or if many writers are trying to open
  simultaneously.
2020-05-08 06:32:00 -04:00
Ken Brown 301454f132 Cygwin: FIFO: fix hit_eof
According to Posix, a FIFO open for reading is at EOF if it is empty
and there are no writers open.

The only way to test this is to poll the fifo_client_handlers as in
raw_read and select.cc:peek_fifo.  The current hit_eof instead relies
on the value of nconnected, which can be out of date.  On the one
hand, it doesn't take into account writers that were connected but
have since closed.  On the other hand, it doesn't take into account
writers that are in the process of opening but haven't yet connected.

Fix this by introducing a maybe_eof method that tentatively assumes
EOF if there are no connected writers after polling.  Then check for
writers currently opening (via a new 'writer_opening' event), and wait
for the fifo_reader_thread to record any new connection that was made
while we were polling.

To handle the needs of peek_fifo, replace the get_fc_handle method
by a get_fc_handler method, and add a fifo_client_handler::get_state
method.

Remove the is_connected method, which was used only in peek_fifo and
is no longer needed.

Remove the nconnected data member, which was used only for the flawed
hit_eof.

Add some comments about events to fhandler.h.
2020-05-08 06:32:00 -04:00
Ken Brown 13c65c43c2 Cygwin: FIFO: dup/fork/exec: make sure child starts unlocked
There can be deadlocks if the child starts with its fifo_client_lock
in the locked state.
2020-05-08 06:32:00 -04:00
Ken Brown 624fda1e96 Cygwin: FIFO: honor the flags argument in dup
Also improve the error handling.
2020-05-08 06:32:00 -04:00
Ken Brown 25e8727368 Cygwin: FIFO: remove the arm method
There's no reason to check for errors when we set read_ready or
write_ready.  We don't do that for other events.
2020-05-08 06:32:00 -04:00
Ken Brown 9b2afd78ce Cygwin: FIFO: simplify the listen_client_thread code
Always return 0; no one is doing anything with the return value
anyway.

Remove the return value from stop_listen_client.

Make the connection event auto-reset, so that we don't have to reset
it later.

Simplify the process of connecting a bogus client when thread
termination is signaled.

Make some failures fatal.

Remove the unnecessary extra check for thread termination near the end
of listen_client_thread.
2020-05-08 06:32:00 -04:00
Ken Brown 32dbc3d215 Cygwin: FIFO: change the fifo_client_connect_state enum
Make the values correspond to the possible return values of
fifo_client_handler::pipe_state().

When cleaning up the fc_handler list in listen_client_thread(), don't
delete handlers in the fc_closing state.  I think the pipe might still
have input to be read in that case.

Set the state to fc_closing later in the same function if a connection
is made and the status returned by NtFsControlFile is
STATUS_PIPE_CLOSING.

In raw_read, don't error out if NtReadFile returns an unexpected
status; just set the state of that handler to fc_error.  One writer in
a bad state doesn't justify giving up on reading.
2020-05-08 06:32:00 -04:00
Ken Brown ce23e97640 Cygwin: FIFO: simplify the fifo_client_handler structure
Replace the 'fhandler_base *' member by a HANDLE to the server side of
the Windows named pipe instance.  Make the corresponding
simplifications throughout.
2020-05-08 06:32:00 -04:00
Ken Brown d05124dc6b Cygwin: FIFO: minor change - use NtClose
Replace CloseHandle by NtClose since all handles are created by NT
functions.
2020-05-08 06:32:00 -04:00
Ken Brown 279f230620 Cygwin: fhandler_fifo.cc: add commentary 2020-02-01 16:36:31 -05:00
Ken Brown 13d75fce48 Cygwin: FIFO: fstatvfs: use our handle if O_PATH is set
If O_PATH is set, then the fhandler_fifo object has a handle that can
be used for getting the statvfs information.  Use it by calling
fhandler_base::fstatvfs_by_handle.  Before this change,
fhandler_disk_file::fstatfvs was called on a new fhandler_disk_file
object, which would then have to be opened.
2020-01-28 14:05:13 -05:00
Ken Brown 7d68ffadd3 Cygwin: FIFO: tweak fcntl and dup when O_PATH is set
fhandler_fifo::fcntl and fhandler_fifo::dup now call the corresponding
fhandler_base methods if the FIFO was opened with the O_PATH flag.
2020-01-24 11:24:18 +01:00
Ken Brown 5fb3790422 Cygwin: re-implement fhandler_fifo::open with O_PATH
If the O_PATH flag is set, fhandler_fifo::open now simply calls
fhandler_base::open_fs.

The previous attempt to handle O_PATH in commit aa55d22c, "Cygwin:
honor the O_PATH flag when opening a FIFO", fixed a hang but otherwise
didn't do anything useful.
2020-01-24 11:24:18 +01:00
Ken Brown 3bc79b275e Cygwin: FIFO: use FILE_PIPE_REJECT_REMOTE_CLIENTS flag
Add that flag to the pipe type argument when creating the Windows
named pipe.  And add a definition of that flag to ntdll.h (copied from
/usr/include/w32api/ddk/ntifs.h).
2019-12-21 17:53:52 -05:00
Ken Brown aa55d22cb5 Cygwin: honor the O_PATH flag when opening a FIFO
Previously fhandler_fifo::open would treat the FIFO as a reader and
would block, waiting for a writer.
2019-06-27 07:46:14 -04:00
Ken Brown 09e2ec87ef Cygwin: FIFO: fix a thinko in raw_write
Remove a line that has no effect.
2019-06-25 18:45:34 -04:00
Ken Brown d54edfdf81 Cygwin: FIFO: minor cleanup
Don't use a label with the same name as a variable.

Also fix indentation in fhandler.h.
2019-06-23 10:16:34 -04:00
Ken Brown 2357091617 Cygwin: FIFO: slightly change the use of write_ready
Make it a manual reset event.  It's only used once to allow a reader
to open, and there's no reason to ever reset it.  Defensively set it
when a client connection is recorded, even though it should be set by
the writer that connected.
2019-06-23 10:16:34 -04:00
Ken Brown 6e7e82fee7 Cygwin: FIFO: remove fifo_client_handler::connect_evt
It's not needed.  Instead just create and use an event in
fhandler_fifo::listen_client_thread.
2019-06-23 10:16:34 -04:00
Ken Brown 5b2696cb83 Cygwin: FIFO: simplify raw_read
Call NtReadFile directly instead of calling fhandler_base::raw_read.
In addition to being simpler, this gives us access to the return value
from NtReadFile.
2019-06-23 10:16:33 -04:00
Ken Brown 5bd5e3dc6c Cygwin: FIFO: improve termination of the listen_client thread
Add a method fifo_client_handler::pipe_state that queries Windows for
the state of a pipe instance.  Use this to help terminate the
listen_client thread cleanly.

If the last client handler is useless, delete it instead of declaring
it invalid.
2019-06-23 10:16:33 -04:00
Ken Brown d1b36ea949 Cygwin: FIFO: avoid deadlock when closing
fhandler_fifo::close could be called from a signal handler or another
thread at a time when another function is holding the fifo_client
lock.  This could prevent the listen_client thread from acting on the
thread termination event.  Avoid a deadlock by calling
fifo_client_unlock at the beginning of fhandler_fifo::close.
2019-06-23 10:16:33 -04:00
Ken Brown 281d3bf060 Cygwin: FIFO: clean up locks
Make sure to use the fifo_client lock when (and only when) it is
needed.
2019-06-23 10:16:33 -04:00
Ken Brown a9b6d32882 Cygwin: FIFO: add some error checking
Change the return type of fhandler_fifo::delete_client_handler from
void to int so that we can report errors.
2019-06-23 10:16:33 -04:00
Ken Brown 724c18ff7e Cygwin: FIFO: fix signal handling in raw_read and raw_write
cygwait wasn't being called correctly.

Also do some minor cleanup in raw_read and raw_write.
2019-06-23 10:16:33 -04:00
Ken Brown d79aa0f593 Cygwin: FIFO: respect the O_CLOEXEC flag
Set the inheritance of the Windows pipe handles according to the
O_CLOEXEC flag.  Previously the pipe was always created and opened
with OBJ_INHERIT.
2019-05-28 15:50:05 -04:00
Ken Brown e91bc190ff Cygwin: FIFO: code simplifications.
There's no longer a need to consider the connect_evt after fork/exec.
After stopping the listen_client thread, all client handlers should be
in the fc_connected or fc_invalid states, so their connect_evt members
won't be used again.

Also remove code in fhandler_fifo::dup that just repeats things
already done in stop_listen_client.
2019-05-09 14:41:29 -04:00
Ken Brown 0771fc7031 Cygwin: FIFO: make read_ready an auto-reset event
There's no point in allowing a writer to attempt to open until we've
created a pipe instance.
2019-05-09 14:41:29 -04:00
Ken Brown 102571f85d Cygwin: FIFO: improve the check for the listen_client thread
Add a method fhandler_fifo::check_listen_client_thread that checks
whether the thread is running.  Use it in raw_read instead of just
testing the handle listen_client_thr.
2019-05-09 14:41:29 -04:00
Ken Brown 7ad80b3c23 Cygwin: FIFO: set client handler flags more accurately
Reflect the fact that client handlers are only used for reading and
that, after connection, they are always nonblocking.
2019-05-09 14:41:29 -04:00
Ken Brown c12053a793 Cygwin: FIFO: don't leave a pending listen request
On exit from the listen_client thread, make sure there's no pending
FSCTL_PIPE_LISTEN request.  Otherwise we might get a client connection
after restarting the thread, and we won't have a handle for
communicating with that client.

Remove the retry loop in the case of STATUS_PIPE_LISTENING; that case
shouldn't occur.

Remove the now-unused fc_connecting value from
fifo_client_connect_state.
2019-05-09 14:41:29 -04:00
Ken Brown 816c6da53a Cygwin: FIFO: add a HANDLE parameter to open_pipe
It's now up to the caller to pass a handle to open_pipe and, if
desired, to call set_handle on return.

This will be useful for a future commit, in which we will open a
client connection without setting an io_handle.
2019-05-09 14:41:29 -04:00
Ken Brown 00b2e56d31 Cygwin: FIFO: re-implement duplexers
When opening a duplexer, open a client connection to the first client
handler.  Previously we gave the duplexer a bogus write handle, which
was just a duplicate of the first client handler's handle.  This meant
that we had a pipe server with no clients connected, and all I/O
attempts failed with STATUS_PIPE_LISTENING.

Extend the last fcntl change to duplexers.

Remove a now unused fifo_client_handler constructor, as well as the
long unusued method fifo_client_handler::connect.

Don't create the pipe in duplex mode; the server handle will only be
used for reading.
2019-05-09 14:41:29 -04:00
Ken Brown f3d1fe2ff8 Cygwin: FIFO: add 'record_connection' method
Future commits will have to re-use the code for recording a client
connection.  For convenience, factor out this code into a new method.
2019-05-09 14:41:29 -04:00
Ken Brown 1372021a2d Cygwin: FIFO: remove incorrect duplexer code
raw_read had some code that was based on an incorrect implementation
of duplexers.
2019-05-09 14:41:28 -04:00
Ken Brown 440559c40a Cygwin: FIFO: synchronize the blocking mode of a writer's pipe
The blocking mode of the Windows pipe underlying a writer is set to
match that of the writer itself when the latter is opened.  Define
fhandler_fifo::fcntl to keep the pipe and the writer in sync if the
blocking mode is changed via fcntl.
2019-04-26 07:45:37 -04:00
Ken Brown 9957a7895b Cygwin: FIFO: restart listen_client thread after fork/exec
This allows writers to connect immediately.  Previously the lct wasn't
restarted until the reader attempted to read.
2019-04-22 07:55:58 -04:00
Ken Brown 4443100b53 Cygwin: FIFO: stop the listen_client thread before fork/exec
Add methods need_fixup_before, init_fixup_before, and
fixup_before_fork_exec to accomplish this.  Stopping the thread makes
sure that the client handler lists of the parent and child remain in
sync while the forking/execing is in progress.
2019-04-20 14:31:07 -04:00
Ken Brown 252cd0ce2b Cygwin: FIFO: close connect_evt handles as soon as possible
Keeping them open too long can cause an attempt to close them twice
after a fork or exec.
2019-04-20 14:31:07 -04:00
Ken Brown 24c56e5a2c Cygwin: FIFO: avoid WFMO error in listen_client_thread
Don't set lct_termination_evt to NULL too early in
fhandler_fifo::stop_listen_client.  Doing so leads to an "Invalid
Handle" error in WFMO.
2019-04-20 14:31:07 -04:00
Ken Brown ef269531a9 Cygwin: FIFO: duplicate the i/o handle when opening a duplexer
Don't use the same i/o handle for the first client handler as is used
for the fhandler itself; this can lead to a later attempt to close the
same handle twice.  Instead use a duplicate.
2019-04-20 14:31:07 -04:00
Ken Brown 4ecea14a58 Cygwin: FIFO: stop the listen_client thread on an opening error
Don't just close the thread handle.
2019-04-20 14:31:07 -04:00
Ken Brown 230c5df2df Cygwin: FIFO: avoid hang after exec
Define fhandler:fifo::fixup_after_exec, which sets listen_client_thr
and lct_termination_evt to NULL.  This forces the listen_client thread
to restart on the first attempt to read after an exec.  Previously the
exec'd process could hang in fhandler_fifo::raw_read.
2019-04-18 19:34:07 +02:00
Ken Brown 2b4cf7622e Cygwin: FIFO: fix and simplify listen_client_thread
Remove fifo_client_handler::connect and move its code into
listen_client_thread.  That way we can check the return status when a
client handler's connect_evt is signaled.  Previously we incorrectly
assumed there was a successful connection.

Also simplify listen_client_thread in the following ways:

- Replace fhandler_fifo::disconnect_and_reconnect by a new
  delete_client_handler method.  Now we just delete invalid client
  handlers rather than trying to re-use them.

- Try to maintain a client handler list that consists of connected
  client handlers and exactly one that is listening for a connection.
  This allows us to call WaitForMultipleObjects with only two wait
  objects.

- Remove 'dummy_evt' from the fifo_client_handler struct; it is no
  longer needed.

- On exit from listen_client_thread, delete the "extra" (listening)
  client handler.  Otherwise there could be a connection that doesn't
  get recorded in the client handler list.  This could happen when a
  file descriptor is being duplicated.
2019-04-16 12:54:43 +02:00
Ken Brown bb46627871 Cygwin: FIFO: improve raw_write
Don't set the write end of the pipe to non-blocking mode if the FIFO
is opened in blocking mode.

In fhandler_fifo::raw_write in blocking mode, wait for the write to
complete rather than returning -1 with EAGAIN.

If the amount to write is large, write in smaller chunks (of size
determined by a new data member max_atomic_write), as in
fhandler_base_overlapped.

For convenience, add two new NTSTATUS codes, STATUS_THREAD_SIGNALED
and STATUS_THREAD_CANCELED, to ntdll.h.
2019-04-16 12:54:43 +02:00
Ken Brown a7d08b3ecd Cygwin: FIFO: start the listen_client thread when duping a reader
Otherwise it doesn't get started until the dup'd fd tries to read,
which delays client connections.
2019-04-16 12:54:43 +02:00