Cygwin: pipe: Adopt FILE_SYNCHRONOUS_IO_NONALERT flag for read pipe.

- With this patch, FILE_SYNCHRONOUS_IO_NONALERT flag is applied to
  the read pipe so that native C# programs work with cygwin pipe.
  To handle signals in reading pipe with this flag set, the read
  pipe itself is always set to nonblocking mode and simulates the
  blocking behaviour in raw_read().

- Default to byte mode rather than message mode in order to make
  C# programs work with cygwin pipe.

Addresses: https://cygwin.com/pipermail/cygwin/2021-March/247987.html
This commit is contained in:
Takashi Yano 2021-11-10 21:47:09 +09:00
parent f3d719c694
commit 9e4d308cd5
2 changed files with 28 additions and 46 deletions

View File

@ -90,7 +90,10 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id)
set_ino (uniq_id);
set_unique_id (uniq_id | !!(mode & GENERIC_WRITE));
if (opened_properly)
set_pipe_non_blocking (is_nonblocking ());
/* Set read pipe always nonblocking to allow signal handling
even with FILE_SYNCHRONOUS_IO_NONALERT. */
set_pipe_non_blocking (get_device () == FH_PIPER ?
true : is_nonblocking ());
return 1;
}
@ -264,9 +267,9 @@ fhandler_pipe::release_select_sem (const char *from)
if (get_dev () == FH_PIPER) /* Number of select() and writer */
n_release = get_obj_handle_count (select_sem)
- get_obj_handle_count (read_mtx);
else /* Number of select() call */
else /* Number of select() call and reader */
n_release = get_obj_handle_count (select_sem)
- get_obj_handle_count (hdl_cnt_mtx);
- get_obj_handle_count (get_handle ());
debug_printf("%s(%s) release %d", from,
get_dev () == FH_PIPER ? "PIPER" : "PIPEW", n_release);
if (n_release)
@ -279,7 +282,6 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
size_t nbytes = 0;
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK io;
HANDLE evt;
if (!len)
return;
@ -307,60 +309,27 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
len = (size_t) -1;
return;
}
if (!(evt = CreateEvent (NULL, false, false, NULL)))
{
__seterrno ();
len = (size_t) -1;
ReleaseMutex (read_mtx);
return;
}
while (nbytes < len)
{
ULONG_PTR nbytes_now = 0;
ULONG len1 = (ULONG) (len - nbytes);
waitret = WAIT_OBJECT_0;
ResetEvent (evt);
FILE_PIPE_LOCAL_INFORMATION fpli;
status = NtQueryInformationFile (get_handle (), &io,
&fpli, sizeof (fpli),
FilePipeLocalInformation);
if (NT_SUCCESS (status))
{
if (fpli.ReadDataAvailable == 0 && nbytes != 0)
break;
if (fpli.ReadDataAvailable == 0 && nbytes != 0)
break;
}
else if (nbytes != 0)
break;
status = NtReadFile (get_handle (), evt, NULL, NULL, &io, ptr,
status = NtReadFile (get_handle (), NULL, NULL, NULL, &io, ptr,
len1, NULL, NULL);
if (status == STATUS_PENDING)
{
waitret = cygwait (evt, INFINITE, cw_cancel | cw_sig);
/* If io.Status is STATUS_CANCELLED after CancelIo, IO has actually
been cancelled and io.Information contains the number of bytes
processed so far.
Otherwise IO has been finished regulary and io.Status contains
valid success or error information. */
CancelIo (get_handle ());
if (waitret == WAIT_SIGNALED && io.Status != STATUS_CANCELLED)
waitret = WAIT_OBJECT_0;
if (waitret == WAIT_CANCELED)
status = STATUS_THREAD_CANCELED;
else if (waitret == WAIT_SIGNALED)
status = STATUS_THREAD_SIGNALED;
else
status = io.Status;
}
if (isclosed ()) /* A signal handler might have closed the fd. */
{
if (waitret == WAIT_OBJECT_0)
set_errno (EBADF);
else
__seterrno ();
set_errno (EBADF);
nbytes = (size_t) -1;
}
else if (NT_SUCCESS (status)
@ -393,7 +362,16 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
nbytes = (size_t) -1;
break;
}
fallthrough;
waitret = cygwait (select_sem, 1);
if (waitret == WAIT_CANCELED)
pthread::static_cancel_self ();
else if (waitret == WAIT_SIGNALED)
{
set_errno (EINTR);
nbytes = (size_t) -1;
break;
}
continue;
default:
__seterrno_from_nt_status (status);
nbytes = (size_t) -1;
@ -406,7 +384,6 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
break;
}
ReleaseMutex (read_mtx);
CloseHandle (evt);
if (status == STATUS_THREAD_SIGNALED && nbytes == 0)
{
set_errno (EINTR);
@ -990,9 +967,12 @@ nt_create (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE &r, HANDLE &w,
npfsh, sa_ptr->lpSecurityDescriptor);
timeout.QuadPart = -500000;
/* Set FILE_SYNCHRONOUS_IO_NONALERT flag so that native
C# programs work with cygwin pipe. */
status = NtCreateNamedPipeFile (&r, access, &attr, &io,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE, 0, pipe_type,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT, pipe_type,
FILE_PIPE_BYTE_STREAM_MODE,
0, 1, psize, psize, &timeout);
@ -1104,7 +1084,9 @@ fhandler_pipe::fcntl (int cmd, intptr_t arg)
const bool was_nonblocking = is_nonblocking ();
int res = fhandler_base::fcntl (cmd, arg);
const bool now_nonblocking = is_nonblocking ();
if (now_nonblocking != was_nonblocking)
/* Do not set blocking mode for read pipe to allow signal handling
even with FILE_SYNCHRONOUS_IO_NONALERT. */
if (now_nonblocking != was_nonblocking && get_device () != FH_PIPER)
set_pipe_non_blocking (now_nonblocking);
return res;
}

View File

@ -69,7 +69,7 @@ int NO_COPY dynamically_loaded;
/* Some CYGWIN environment variable variables. */
bool allow_glob = true;
bool ignore_case_with_glob;
bool pipe_byte;
bool pipe_byte = true; /* Default to byte mode so that C# programs work. */
bool reset_com;
bool wincmdln;
winsym_t allow_winsymlinks = WSYM_default;