Skip to content

Commit 9d0d6e1

Browse files
tyan0dscho
authored andcommitted
Cygwin: pipe: Restore blocking mode of read pipe on close()/raw_read()
If a cygwin app is executed from a non-cygwin app and the cygwin app exits, the read pipe remains in the non-blocking mode because of the commit fc691d0. Due to this behaviour, the non-cygwin app cannot read the pipe correctly after that. Similarly, if a non-cygwin app is executed from a cygwin app and the non-cygwin app exits, the read pipe remains in the blocking mode. With this patch, the blocking mode of the read pipe is stored into a variable was_blocking_read_pipe on set_pipe_non_blocking() when the cygwin app starts and restored on close(). In addition, the pipe mode is set to non-blocking mode in raw_read() if the mode is blocking mode by referring the variable is_blocking_read_pipe as well. is_blocking_read_pipe is a member of fhandler_pipe class and is set by set_pipe_non_blocking(), so if other process sets the pipe mode to blocking mode, the current process cannot know the pipe is blocking mode. Therefore, is_blocking_read_pipe is also set on the signal __SIGNONCYGCHLD, which is sent to the process group when non-cygwin app is started. Backported-from: c7fe29f (Cygwin: pipe: Restore blocking mode of read pipe on close()/raw_read(), 2024-09-06) Addresses: git-for-windows/git#5115 Fixes: fc691d0 ("Cygwin: pipe: Make sure to set read pipe non-blocking for cygwin apps."); Reported-by: isaacag, Johannes Schindelin <[email protected]> Reviewed-by: Corinna Vinschen <[email protected]>, Ken Brown <[email protected]> Signed-off-by: Takashi Yano <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 8854bb4 commit 9d0d6e1

File tree

3 files changed

+45
-8
lines changed

3 files changed

+45
-8
lines changed

winsup/cygwin/fhandler/pipe.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,16 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking)
5454
NTSTATUS status;
5555
IO_STATUS_BLOCK io;
5656
FILE_PIPE_INFORMATION fpi;
57+
bool was_blocking_read_pipe_new = was_blocking_read_pipe;
58+
59+
if (get_device () == FH_PIPER && nonblocking && !was_blocking_read_pipe)
60+
{
61+
status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi,
62+
FilePipeInformation);
63+
if (NT_SUCCESS (status))
64+
was_blocking_read_pipe_new =
65+
(fpi.CompletionMode == FILE_PIPE_QUEUE_OPERATION);
66+
}
5767

5868
fpi.ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
5969
fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION
@@ -62,6 +72,11 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking)
6272
FilePipeInformation);
6373
if (!NT_SUCCESS (status))
6474
debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status);
75+
else
76+
{
77+
was_blocking_read_pipe = was_blocking_read_pipe_new;
78+
is_blocking_read_pipe = !nonblocking;
79+
}
6580
}
6681

6782
int
@@ -95,6 +110,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id)
95110
even with FILE_SYNCHRONOUS_IO_NONALERT. */
96111
set_pipe_non_blocking (get_device () == FH_PIPER ?
97112
true : is_nonblocking ());
113+
was_blocking_read_pipe = false;
114+
98115
return 1;
99116
}
100117

@@ -289,6 +306,9 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
289306
if (!len)
290307
return;
291308

309+
if (is_blocking_read_pipe)
310+
set_pipe_non_blocking (true);
311+
292312
DWORD timeout = is_nonblocking () ? 0 : INFINITE;
293313
DWORD waitret = cygwait (read_mtx, timeout);
294314
switch (waitret)
@@ -721,6 +741,8 @@ fhandler_pipe::close ()
721741
CloseHandle (query_hdl);
722742
if (query_hdl_close_req_evt)
723743
CloseHandle (query_hdl_close_req_evt);
744+
if (was_blocking_read_pipe)
745+
set_pipe_non_blocking (false);
724746
int ret = fhandler_base::close ();
725747
ReleaseMutex (hdl_cnt_mtx);
726748
CloseHandle (hdl_cnt_mtx);
@@ -1377,6 +1399,7 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout,
13771399
{
13781400
fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
13791401
pipe->set_pipe_non_blocking (false);
1402+
need_send_noncygchld_sig = true;
13801403
}
13811404

13821405
/* If multiple writers including non-cygwin app exist, the non-cygwin
@@ -1402,3 +1425,21 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout,
14021425
t->kill_pgrp (__SIGNONCYGCHLD);
14031426
}
14041427
}
1428+
1429+
void
1430+
fhandler_pipe::sigproc_worker (void)
1431+
{
1432+
cygheap_fdenum cfd (false);
1433+
while (cfd.next () >= 0)
1434+
if (cfd->get_dev () == FH_PIPEW)
1435+
{
1436+
fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
1437+
if (pipe->need_close_query_hdl ())
1438+
pipe->close_query_handle ();
1439+
}
1440+
else if (cfd->get_dev () == FH_PIPER)
1441+
{
1442+
fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
1443+
pipe->is_blocking_read_pipe = true;
1444+
}
1445+
}

winsup/cygwin/local_includes/fhandler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,8 @@ class fhandler_pipe: public fhandler_pipe_fifo
11971197
private:
11981198
HANDLE read_mtx;
11991199
pid_t popen_pid;
1200+
bool was_blocking_read_pipe;
1201+
bool is_blocking_read_pipe;
12001202
HANDLE query_hdl;
12011203
HANDLE hdl_cnt_mtx;
12021204
HANDLE query_hdl_proc;
@@ -1287,6 +1289,7 @@ class fhandler_pipe: public fhandler_pipe_fifo
12871289
}
12881290
static void spawn_worker (int fileno_stdin, int fileno_stdout,
12891291
int fileno_stderr);
1292+
static void sigproc_worker (void);
12901293
};
12911294

12921295
#define CYGWIN_FIFO_PIPE_NAME_LEN 47

winsup/cygwin/sigproc.cc

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,14 +1475,7 @@ wait_sig (VOID *)
14751475
}
14761476
break;
14771477
case __SIGNONCYGCHLD:
1478-
cygheap_fdenum cfd (false);
1479-
while (cfd.next () >= 0)
1480-
if (cfd->get_dev () == FH_PIPEW)
1481-
{
1482-
fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd;
1483-
if (pipe->need_close_query_hdl ())
1484-
pipe->close_query_handle ();
1485-
}
1478+
fhandler_pipe::sigproc_worker ();
14861479
break;
14871480
}
14881481
if (clearwait && !have_execed)

0 commit comments

Comments
 (0)