Skip to content

Commit fe587e1

Browse files
authored
Merge pull request #103 from dscho/fix-ssh-hang-revolutions
Fix SSH hang (next attempt)
2 parents cb9b2d0 + 2f6e584 commit fe587e1

File tree

3 files changed

+61
-51
lines changed

3 files changed

+61
-51
lines changed

winsup/cygwin/fhandler/pipe.cc

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -491,24 +491,29 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
491491
FilePipeLocalInformation);
492492
if (NT_SUCCESS (status))
493493
{
494-
if (fpli.WriteQuotaAvailable != 0)
494+
if (fpli.WriteQuotaAvailable == fpli.InboundQuota)
495495
avail = fpli.WriteQuotaAvailable;
496-
else /* WriteQuotaAvailable == 0 */
496+
else /* WriteQuotaAvailable != InboundQuota */
497497
{ /* Refer to the comment in select.cc: pipe_data_available(). */
498498
/* NtSetInformationFile() in set_pipe_non_blocking(true) seems
499499
to fail with STATUS_PIPE_BUSY if the pipe is not empty.
500-
In this case, the pipe is really full if WriteQuotaAvailable
501-
is zero. Otherwise, the pipe is empty. */
500+
In this case, WriteQuotaAvailable indicates real pipe space.
501+
Otherwise, the pipe is empty. */
502502
status = fh->set_pipe_non_blocking (true);
503503
if (NT_SUCCESS (status))
504504
/* Pipe should be empty because reader is waiting for data. */
505505
/* Restore the pipe mode to blocking. */
506506
fh->set_pipe_non_blocking (false);
507507
else if (status == STATUS_PIPE_BUSY)
508508
{
509-
/* Full */
510-
set_errno (EAGAIN);
511-
goto err;
509+
if (fpli.WriteQuotaAvailable == 0)
510+
{
511+
/* Full */
512+
set_errno (EAGAIN);
513+
goto err;
514+
}
515+
avail = fpli.WriteQuotaAvailable;
516+
status = STATUS_SUCCESS;
512517
}
513518
}
514519
}
@@ -561,7 +566,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
561566
ULONG len1;
562567
DWORD waitret = WAIT_OBJECT_0;
563568

564-
if (left > chunk && !real_non_blocking_mode)
569+
if (left > chunk && !is_nonblocking ())
565570
len1 = chunk;
566571
else
567572
len1 = (ULONG) left;
@@ -650,22 +655,21 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
650655
if (io.Information > 0 || len <= PIPE_BUF || short_write_once)
651656
break;
652657
/* Independent of being blocking or non-blocking, if we're here,
653-
the pipe has less space than requested. If the pipe is a
654-
non-Cygwin pipe, just try the old strategy of trying a half
655-
write. If the pipe has at
658+
the pipe has less space than requested. If the pipe has at
656659
least PIPE_BUF bytes available, try to write all matching
657660
PIPE_BUF sized blocks. If it's less than PIPE_BUF, try
658661
the next less power of 2 bytes. This is not really the Linux
659662
strategy because Linux is filling the pages of a pipe buffer
660663
in a very implementation-defined way we can't emulate, but it
661664
resembles it closely enough to get useful results. */
662665
avail = pipe_data_available (-1, this, get_handle (), PDA_WRITE);
663-
if (avail < 1) /* error or pipe closed */
666+
if (avail == PDA_UNKNOWN && real_non_blocking_mode)
667+
avail = len1;
668+
else if (avail == 0 || !PDA_NOERROR (avail))
669+
/* error or pipe closed */
664670
break;
665671
if (avail > len1) /* somebody read from the pipe */
666672
avail = len1;
667-
if (avail == 1) /* 1 byte left or non-Cygwin pipe */
668-
len1 >>= 1;
669673
else if (avail >= PIPE_BUF)
670674
len1 = avail & ~(PIPE_BUF - 1);
671675
else

winsup/cygwin/local_includes/select.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,5 +143,8 @@ ssize_t pipe_data_available (int, fhandler_base *, HANDLE, int);
143143

144144
#define PDA_READ 0x00
145145
#define PDA_WRITE 0x01
146+
#define PDA_ERROR -1
147+
#define PDA_UNKNOWN -2
148+
#define PDA_NOERROR(x) (x >= 0)
146149

147150
#endif /* _SELECT_H_ */

winsup/cygwin/select.cc

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
601601
if (mode == PDA_READ
602602
&& PeekNamedPipe (h, NULL, 0, NULL, &nbytes_in_pipe, NULL))
603603
return nbytes_in_pipe;
604-
return -1;
604+
return PDA_ERROR;
605605
}
606606

607607
IO_STATUS_BLOCK iosb = {{0}, 0};
@@ -618,46 +618,49 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
618618
access on the write end. */
619619
select_printf ("fd %d, %s, NtQueryInformationFile failed, status %y",
620620
fd, fh->get_name (), status);
621-
return (mode == PDA_WRITE) ? 1 : -1;
621+
return (mode == PDA_WRITE) ? PDA_UNKNOWN : PDA_ERROR;
622622
}
623623
if (mode == PDA_WRITE)
624624
{
625625
/* If there is anything available in the pipe buffer then signal
626-
that. This means that a pipe could still block since you could
627-
be trying to write more to the pipe than is available in the
628-
buffer but that is the hazard of select().
629-
630-
Note that WriteQuotaAvailable is unreliable.
631-
632-
Usually WriteQuotaAvailable on the write side reflects the space
633-
available in the inbound buffer on the read side. However, if a
634-
pipe read is currently pending, WriteQuotaAvailable on the write side
635-
is decremented by the number of bytes the read side is requesting.
636-
So it's possible (even likely) that WriteQuotaAvailable is 0, even
637-
if the inbound buffer on the read side is not full. This can lead to
638-
a deadlock situation: The reader is waiting for data, but select
639-
on the writer side assumes that no space is available in the read
640-
side inbound buffer.
641-
642-
Consequentially, there are two possibilities when WriteQuotaAvailable
643-
is 0. One is that the buffer is really full. The other is that the
644-
reader is currently trying to read the pipe and it is pending.
645-
In the latter case, the fact that the reader cannot read the data
646-
immediately means that the pipe is empty. In the former case,
647-
NtSetInformationFile() in set_pipe_non_blocking(true) will fail
648-
with STATUS_PIPE_BUSY, while it succeeds in the latter case.
649-
Therefore, we can distinguish these cases by calling set_pipe_non_
650-
blocking(true). If it returns success, the pipe is empty, so we
651-
return the pipe buffer size. Otherwise, we return 0. */
652-
if (fh->get_device () == FH_PIPEW && fpli.WriteQuotaAvailable == 0)
626+
that. This means that a pipe could still block since you could
627+
be trying to write more to the pipe than is available in the
628+
buffer but that is the hazard of select().
629+
630+
Note that WriteQuotaAvailable is unreliable.
631+
632+
Usually WriteQuotaAvailable on the write side reflects the space
633+
available in the inbound buffer on the read side. However, if a
634+
pipe read is currently pending, WriteQuotaAvailable on the write side
635+
is decremented by the number of bytes the read side is requesting.
636+
So it's possible (even likely) that WriteQuotaAvailable is less than
637+
actual space available in the pipe, even if the inbound buffer is
638+
empty. This can lead to a deadlock situation: The reader is waiting
639+
for data, but select on the writer side assumes that no space is
640+
available in the read side inbound buffer.
641+
642+
Consequentially, there are two possibilities when WriteQuotaAvailable
643+
is less than pipe size. One is that the buffer is really not empty.
644+
The other is that the reader is currently trying to read the pipe
645+
and it is pending.
646+
In the latter case, the fact that the reader cannot read the data
647+
immediately means that the pipe is empty. In the former case,
648+
NtSetInformationFile() in set_pipe_non_blocking(true) will fail
649+
with STATUS_PIPE_BUSY, while it succeeds in the latter case.
650+
Therefore, we can distinguish these cases by calling set_pipe_non_
651+
blocking(true). If it returns success, the pipe is empty, so we
652+
return the pipe buffer size. Otherwise, we return the value of
653+
WriteQuotaAvailable as is. */
654+
if (fh->get_device () == FH_PIPEW
655+
&& fpli.WriteQuotaAvailable < fpli.InboundQuota)
653656
{
654657
NTSTATUS status =
655658
((fhandler_pipe *) fh)->set_pipe_non_blocking (true);
656659
if (status == STATUS_PIPE_BUSY)
657-
return 0; /* Full */
660+
return fpli.WriteQuotaAvailable; /* Not empty */
658661
else if (!NT_SUCCESS (status))
659662
/* We cannot know actual write pipe space. */
660-
return 1;
663+
return PDA_UNKNOWN;
661664
/* Restore pipe mode to blocking mode */
662665
((fhandler_pipe *) fh)->set_pipe_non_blocking (false);
663666
/* Empty */
@@ -681,7 +684,7 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int mode)
681684
return fpli.ReadDataAvailable;
682685
}
683686
if (fpli.NamedPipeState & FILE_PIPE_CLOSING_STATE)
684-
return -1;
687+
return PDA_ERROR;
685688
return 0;
686689
}
687690

@@ -731,7 +734,7 @@ peek_pipe (select_record *s, bool from_select)
731734
if (n == 0 && fh->get_echo_handle ())
732735
n = pipe_data_available (s->fd, fh, fh->get_echo_handle (), PDA_READ);
733736

734-
if (n < 0)
737+
if (n == PDA_ERROR)
735738
{
736739
select_printf ("read: %s, n %d", fh->get_name (), n);
737740
if (s->except_selected)
@@ -772,8 +775,8 @@ peek_pipe (select_record *s, bool from_select)
772775
}
773776
ssize_t n = pipe_data_available (s->fd, fh, h, PDA_WRITE);
774777
select_printf ("write: %s, n %d", fh->get_name (), n);
775-
gotone += s->write_ready = (n > 0);
776-
if (n < 0 && s->except_selected)
778+
gotone += s->write_ready = (n > 0 || n == PDA_UNKNOWN);
779+
if (n == PDA_ERROR && s->except_selected)
777780
gotone += s->except_ready = true;
778781
}
779782
return gotone;
@@ -986,7 +989,7 @@ peek_fifo (select_record *s, bool from_select)
986989
ssize_t n = pipe_data_available (s->fd, fh, fh->get_handle (), PDA_WRITE);
987990
select_printf ("write: %s, n %d", fh->get_name (), n);
988991
gotone += s->write_ready = (n > 0);
989-
if (n < 0 && s->except_selected)
992+
if (n == PDA_ERROR && s->except_selected)
990993
gotone += s->except_ready = true;
991994
}
992995
return gotone;
@@ -1412,7 +1415,7 @@ peek_pty_slave (select_record *s, bool from_select)
14121415
ssize_t n = pipe_data_available (s->fd, fh, h, PDA_WRITE);
14131416
select_printf ("write: %s, n %d", fh->get_name (), n);
14141417
gotone += s->write_ready = (n > 0);
1415-
if (n < 0 && s->except_selected)
1418+
if (n == PDA_ERROR && s->except_selected)
14161419
gotone += s->except_ready = true;
14171420
}
14181421
return gotone;

0 commit comments

Comments
 (0)