NtQueryInformationFile hangs if it's called on the read side handle of
a pipe while another thread or process is performing a blocking read.
Avoid select potentially hanging by calling NtQueryInformationFile
only on the write side of the pipe and using PeekNamedPipe otherwise.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- In pipe_data_available() in select.cc, PeekNamedPipe() call is
not needed if WriteQuotaAvailable is non-zero because we already
know the write pipe has a space. Therefore, with this patch,
PeekNamedPipe() is called only when WriteQuotaAvailable is zero.
This makes select() on pipe faster a bit.
- Usually WriteQuotaAvailable retrieved by NtQueryInformationFile()
on the write side reflects the space available in the inbound buffer
on the read side. However, if a pipe read is currently pending,
WriteQuotaAvailable on the write side is decremented by the number
of bytes the read side is requesting. So it's possible (even likely)
that WriteQuotaAvailable is 0, even if the inbound buffer on the
read side is not full. This can lead to a deadlock situation:
The reader is waiting for data, but select on the writer side
assumes that no space is available in the read side inbound buffer.
Currently, to avoid this stuation, read() does not request larger
block than pipe size - 1. However, this mechanism does not take
effect if the reader side is non-cygwin app.
The only reliable information is available on the read side, so
fetch info from the read side via the pipe-specific query handle
(query_hdl) introduced.
If the query_hdl (read handle) is kept in write side, writer can
not detect closure of read pipe. Therefore, raw_write() counts
write handle and query_hdl. If they are equal, only the pairs of
write handle and query_hdl are alive. In this case, raw_write()
returns EPIPE and raises SIGPIPE.
- Nonblocking pipes (PIPE_NOWAIT) are not well handled by non-Cygwin
tools, so convert pipe handles to PIPE_WAIT handles when spawning
a non-Cygwin process.
Given we return 1 already if WriteQuotaAvailable is > 0, the condition
for tiny pipes is never true. Fix the comments.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
FILE_PIPE_LOCAL_INFORMATION::WriteQuotaAvailable is unreliable.
Usually WriteQuotaAvailable on the write side reflects the space
available in the inbound buffer on the read side. However, if a
pipe read is currently pending, WriteQuotaAvailable on the write side
is decremented by the number of bytes the read side is requesting.
So it's possible (even likely) that WriteQuotaAvailable is 0, even
if the inbound buffer on the read side is not full. This can lead to
a deadlock situation: The reader is waiting for data, but select
on the writer side assumes that no space is available in the read
side inbound buffer.
This patch implements a workaround by never trying to read more than
half the buffer size blocking if the read buffer is empty. This first
cut tries to take the number of open readers into account by reducing
the amount of requested bytes accordingly.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
An FD_CLOSE event sets a socket descriptor ready for writing.
This is incorrect if the FD_CLOSE is a result of shutdown(SHUT_RD).
Only set the socket descriptor ready for writing if the FD_CLOSE
is indicating an connection abort or reset error condition.
This requires to tweak fhandler_socket_wsock::evaluate_events.
FD_CLOSE in conjunction with FD_ACCEPT/FD_CONNECT special cases
a shutdown condition by setting an error code. This is correct
for accept/connect, but not for select. In this case, make sure
to return with an error code only if FD_CLOSE indicates a
connection error.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
So far select wrongly sets the descriptor as ready for exception
when a shutdown occurs. This is entirely non-standard. Only set
this bit on an out-of-band event.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- Currently, functions/variables regarding the handles for cygwin
apps are with "_cyg", and those of handles for non-cygwin apps
are without "_cyg", such as get_handle_cyg() and get_handle().
This patch renames these to the names without "_nat" and with
"_nat" respectively, such as get_handle() and get_handle_nat().
- If ENABLE_LINE_INPUT is set, Ctrl-S is handled by Windows if the
OS is Windows 7. This conflicts with Ctrl-S handling in cygwin
console code. This patch unsets ENABLE_LINE_INPUT flag in cygwin
and set it when native app is executed.
- After commit bb428520, there has been the disadvantage:
7) Pseudo console cannot be activated if it is already activated for
another process on same pty.
This patch clears this disadvantage.
- After commit bb428520, there has been the disadvantage:
2) The apps which use console API cannot be debugged with gdb. This
is because pseudo console is not activated since gdb uses
CreateProcess() rather than exec(). Even with this limitation,
attaching gdb to native app, in which pseudo console is already
activated, works.
This patch clears this disadvantage.
- After the commit 72770148, script command exits occasionally with
the error "Bad file descriptor" if it is started in console on Win7
and non-cygwin process is executed. This patch fixes the issue.
- If application changes the console mode, mode management introduced
by commit 10d8c278 will be corrupted. For example, stdout of jansi
v2.0.1 or later is piped to less, jansi resets the xterm mode flag
ENABLE_VIRTUAL_TERMINA_PROCESSING when jansi is terminated. This
causes garbled output in less because less needs this flag enabled.
This patch fixes the issue.
- In this implementation, pseudo console is created for each native
console app. Advantages and disadvantages of this implementation
over the previous implementation are as follows.
Advantages:
1) No performance degradation in pty output for cygwin process.
https://cygwin.com/pipermail/cygwin/2020-February/243858.html
2) Free from the problem caused by difference of behaviour of control
sequences between real terminal and pseudo console.
https://cygwin.com/pipermail/cygwin/2019-December/243281.htmlhttps://cygwin.com/pipermail/cygwin/2020-February/243855.html
3) Free from the problem in cgdb and emacs gud.
https://cygwin.com/pipermail/cygwin/2020-January/243601.htmlhttps://cygwin.com/pipermail/cygwin/2020-March/244146.html
4) Redrawing screen on executing native console apps is not necessary.
5) cygwin-console-helper is not necessary for the pseudo console
support.
6) The codes for pseudo console support are much simpler than that
of the previous one.
Disadvantages:
1) The cygwin program which calls console API directly does not work.
2) The apps which use console API cannot be debugged with gdb. This
is because pseudo console is not activated since gdb uses
CreateProcess() rather than exec(). Even with this limitation,
attaching gdb to native apps, in which pseudo console is already
activated, works.
3) Typeahead key inputs are discarded while native console app is
executed. Simirally, typeahead key inputs while cygwin app is
executed are not inherited to native console app.
4) Code page cannot be changed by chcp.com. Acctually, chcp works
itself and changes code page of its own pseudo console. However,
since pseudo console is recreated for another process, it cannot
inherit the code page.
5) system_printf() does not work after stderr is closed. (Same with
cygwin 3.0.7)
6) Startup time of native console apps is about 3 times slower than
previous implemenation.
7) Pseudo console cannot be activated if it is already activated for
another process on same pty.
This patch has been inspired by the Linux kernel patch
294f69e662d1 compiler_attributes.h: Add 'fallthrough' pseudo keyword for switch/case use
written by Joe Perches <joe AT perches DOT com> based on an idea from
Dan Carpenter <dan DOT carpenter AT oracle DOT com>. The following text
is from the original log message:
Reserve the pseudo keyword 'fallthrough' for the ability to convert the
various case block /* fallthrough */ style comments to appear to be an
actual reserved word with the same gcc case block missing fallthrough
warning capability.
All switch/case blocks now should end in one of:
break;
fallthrough;
goto <label>;
return [expression];
continue;
In C mode, GCC supports the __fallthrough__ attribute since 7.1,
the same time the warning and the comment parsing were introduced.
Cygwin-only: add an explicit -Wimplicit-fallthrough=5 to the build
flags.
The fifo_reader thread function and the function select.cc:peek_fifo()
can both change the state of a fifo_client_handler. These changes are
made under fifo_client_lock, so there is no race, but the changes can
still be incompatible.
Add code to make sure that only one of these functions can change the
state from its initial fc_listening state. Whichever function does
this calls the fhandler_fifo::record_connection method, which is now
public so that peek_fifo can call it.
Slightly modify that method to make it suitable for being called by
peek_fifo.
Make a few other small changes to the fifo_reader thread function to
change how it deals with the STATUS_PIPE_CLOSING value that can
(rarely) be returned by NtFsControlFile.
Add commentary to fhandler_fifo.cc to explain fifo_client connect
states and where they can be changed.
Don't try to read from fifo_client_handlers that are in the fc_closing
state. Experiments have shown that this always yields
STATUS_PIPE_BROKEN, so it just wastes a Windows system call.
Re-order the values in enum fifo_client_connect_state to reflect the
new status of fc_closing.
Rename the existing set_state() to query_and_set_state() to reflect
what it really does. (It queries the O/S for the pipe state.) Add a
new set_state() method, which is a standard setter, and a
corresponding getter get_state().
fhandler_fifo::take_ownership() is called from select.cc::peek_fifo
and fhandler_fifo::raw_read and could potentially block indefinitely
if something goes wrong. This is always undesirable in peek_fifo, and
it is undesirable in a nonblocking read. Fix this by adding a timeout
parameter to take_ownership.
Arbitrarily use a 1 ms timeout in peek_fifo and a 10 ms timeout in
raw_read. These numbers may have to be tweaked based on experience.
Replace the call to cygwait in take_ownership by a call to WFSO.
There's no need to allow interruption now that we have a timeout.
Use cygwait in take_ownership to allow interruption while waiting to
become owner. Return the cygwait return value or a suitable value to
indicate an error.
raw_read now checks the return value and acts accordingly.
There are currently three functions that call NtQueryInformationFile
to determine the state of a pipe instance. Do this only once, in a
new fifo_client_handler::set_state () function, and call that when
state information is needed.
Remove the fifo_client_handler methods pipe_state and get_state, which
are no longer needed.
Make fhandler_fifo::get_fc_handler return a reference, for use in
select.cc:peek_fifo.
Make other small changes to ensure that this commit doesn't change any
decisions based on the state of a fifo_client_handler.
The tricky part is interpreting FILE_PIPE_CLOSING_STATE, which we
translate to fc_closing. Our current interpretation, which is not
changing as a result of this commit, is that the writer at the other
end of the pipe instance is viewed as still connected from the point
of view of raw_read and determining EOF.
But it is not viewed as still connected if we are deciding whether to
unblock a new reader that is trying to open.
Add a take_ownership method, used by raw_read and select.cc:peek_fifo.
It wakes up all fifo_reader_threads and allows the caller to become
owner. The work is done by the fifo_reader_threads.
For synchronization we introduce several new fhandler_fifo data
members and methods:
- update_needed_evt signals the current owner to stop listening for
writer connections and update its fc_handler list.
- shared_fc_handler() gets and sets the status of the fc_handler
update process.
- get_pending_owner() and set_pending_owner() get and set the reader
that is requesting ownership.
Finally, a new 'reading_lock' prevents two readers from trying to take
ownership simultaneously.
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.
Sharing the OVERLAPPED struct and event object in there between
read and select calls in the fhandler might have been a nice
optimization way back when, but it is a dangerous, not thread-safe
approach. Fix this by creating per-fhandler, per-call OVERLAPPED
structs and event objects on demand.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- make sure event object is reset
- set read_ready to true if WaitCommEvent returns success
- improve debugging
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Get rid of WaitCommEvent and using overlapped_armed to share the
same overlapped operation between read and select. Rather, make
sure to cancel the overlapped IO before leaving any of these functions.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- Don't use ev member for ClearCommError and WaitCommEvent.
Both returned values are different (error value vs. event
code). The values are not used elsewhere so it doesn't make
sense to store them in the object.
- Drop local variable ready which is used inconsequentially.
- Since WFSO already waits 10 ms, don't wait again if no char
is in the inbound queue.
- Avoid else if chains.
- Only print one line of debug output on error.
- Drop overlapped_armed < 0 check. This value is only set in
fhandler_serial::raw_read if VTIME > 0, and even then it's only
set to be immediately reset to 0 before calling ReadFile. So
overlapped_armed is never actually < 0 when calling select.
- Fix a screwed up statement order.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- If two cygwin programs are executed simultaneousley with pipes
in cmd.exe, xterm compatible mode is accidentally disabled by
the process which ends first. After that, escape sequences are
not handled correctly in the other app. This is the problem 2
reported in https://cygwin.com/ml/cygwin/2020-02/msg00116.html.
This patch fixes the issue. This patch also fixes the problem 3.
For these issues, the timing of setting and unsetting xterm
compatible mode is changed. For read, xterm compatible mode is
enabled only within read() or select() functions. For write, it
is enabled every time write() is called, and restored on close().
- PTY has a problem that the key input, which is typed during
windows native app is running, disappear when it returns to shell.
(Problem 3 in https://cygwin.com/ml/cygwin/2020-02/msg00007.html)
This is beacuse pty has two input pipes, one is for cygwin apps
and the other one is for native windows apps. The key input during
windows native program is running is sent to the second input pipe
while cygwin shell reads input from the first input pipe.
This patch realize transfering input data between these two pipes.
- Debug codes used in the early stage of pseudo console support are
removed. (Regarding ALWAYS_USE_PCON and USE_API_HOOK) Along with
this, the codes related to this change are organized.
- The slowing down issue of X11 forwarding using ssh -Y, reported
in https://www.cygwin.com/ml/cygwin/2019-12/msg00295.html,
is due to the change of select() code for pty in the commit
915fcd0ae8. cygthread::detach()
takes at most about 10msec because Sleep() is used in the thread.
For this issue, this patch uses cygwait() instead of Sleep() and
introduces an event to abort the wait. For not only pty, but pipe
and fifo also have the same problem potentially, so this patch
applies same strategy to them as well.
- Previously, input and output pipes were switched together between
the traditional pty and the pseudo console. However, for example,
if stdin is redirected to another device, it is better to leave
input pipe traditional pty side even for non-cygwin program. This
patch realizes such behaviour.
- When the I/O pipe is switched to the pseudo console side, the
behaviour of Ctrl-C was unstable. This rarely happens, however,
for example, shell sometimes crashes by Ctrl-C in that situation.
Furthermore, Ctrl-C was ignored if output of non-cygwin program
is redirected to pipe. This patch fixes these issues.
- select() did not work correctly when both read and except are
polled simultaneously for the same fd and the r/w pipe is switched
to pseudo console side. This patch fixes this isseu.
- Support pseudo console in PTY. Pseudo console is a new feature
in Windows 10 1809, which provides console APIs on virtual
terminal. With this patch, native console applications can work
in PTYs such as mintty, ssh, gnu screen or tmux.
Rather than waiting for signalfd_select_wait in a thread, which is racy,
create a global event "my_pendingsigs_evt" which is set and reset by
wait_sig depending only on the fact if blocked signals are pending or not.
This in turn allows to WFMO on this event in select as soon as signalfds
are present in the read descriptor set. Select's peek and verify
will then check if one of the present signalfds is affected.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>