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.
This commit is contained in:
parent
a7d08b3ecd
commit
bb46627871
|
@ -1273,6 +1273,7 @@ class fhandler_fifo: public fhandler_base
|
||||||
int nhandlers, nconnected;
|
int nhandlers, nconnected;
|
||||||
af_unix_spinlock_t _fifo_client_lock;
|
af_unix_spinlock_t _fifo_client_lock;
|
||||||
bool reader, writer, duplexer;
|
bool reader, writer, duplexer;
|
||||||
|
size_t max_atomic_write;
|
||||||
bool __reg2 wait (HANDLE);
|
bool __reg2 wait (HANDLE);
|
||||||
NTSTATUS npfs_handle (HANDLE &);
|
NTSTATUS npfs_handle (HANDLE &);
|
||||||
HANDLE create_pipe_instance (bool);
|
HANDLE create_pipe_instance (bool);
|
||||||
|
|
|
@ -39,7 +39,8 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
|
||||||
fhandler_fifo::fhandler_fifo ():
|
fhandler_fifo::fhandler_fifo ():
|
||||||
fhandler_base (), read_ready (NULL), write_ready (NULL),
|
fhandler_base (), read_ready (NULL), write_ready (NULL),
|
||||||
listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
|
listen_client_thr (NULL), lct_termination_evt (NULL), nhandlers (0),
|
||||||
nconnected (0), reader (false), writer (false), duplexer (false)
|
nconnected (0), reader (false), writer (false), duplexer (false),
|
||||||
|
max_atomic_write (DEFAULT_PIPEBUFSIZE)
|
||||||
{
|
{
|
||||||
pipe_name_buf[0] = L'\0';
|
pipe_name_buf[0] = L'\0';
|
||||||
need_fork_fixup (true);
|
need_fork_fixup (true);
|
||||||
|
@ -559,7 +560,7 @@ fhandler_fifo::open (int flags, mode_t)
|
||||||
NTSTATUS status = open_pipe ();
|
NTSTATUS status = open_pipe ();
|
||||||
if (NT_SUCCESS (status))
|
if (NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
set_pipe_non_blocking (get_handle (), true);
|
set_pipe_non_blocking (get_handle (), flags & O_NONBLOCK);
|
||||||
if (!arm (write_ready))
|
if (!arm (write_ready))
|
||||||
res = error_set_errno;
|
res = error_set_errno;
|
||||||
else
|
else
|
||||||
|
@ -661,20 +662,65 @@ ssize_t __reg3
|
||||||
fhandler_fifo::raw_write (const void *ptr, size_t len)
|
fhandler_fifo::raw_write (const void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t ret = -1;
|
ssize_t ret = -1;
|
||||||
NTSTATUS status;
|
size_t nbytes = 0, chunk;
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
|
HANDLE evt = NULL;
|
||||||
|
|
||||||
status = NtWriteFile (get_handle (), NULL, NULL, NULL, &io,
|
if (len <= max_atomic_write)
|
||||||
(PVOID) ptr, len, NULL, NULL);
|
chunk = len;
|
||||||
|
else if (is_nonblocking ())
|
||||||
|
chunk = len = max_atomic_write;
|
||||||
|
else
|
||||||
|
chunk = max_atomic_write;
|
||||||
|
|
||||||
|
/* Create a wait event if the FIFO is in blocking mode. */
|
||||||
|
if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Write in chunks, accumulating a total. If there's an error, just
|
||||||
|
return the accumulated total unless the first write fails, in
|
||||||
|
which case return -1. */
|
||||||
|
while (nbytes < len)
|
||||||
|
{
|
||||||
|
ULONG_PTR nbytes_now = 0;
|
||||||
|
size_t left = len - nbytes;
|
||||||
|
size_t len1;
|
||||||
|
if (left > chunk)
|
||||||
|
len1 = chunk;
|
||||||
|
else
|
||||||
|
len1 = left;
|
||||||
|
nbytes_now = 0;
|
||||||
|
status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
|
||||||
|
(PVOID) ptr, len1, NULL, NULL);
|
||||||
|
if (evt && status == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
DWORD waitret = cygwait (evt, cw_infinite, cw_cancel | cw_sig_eintr);
|
||||||
|
switch (waitret)
|
||||||
|
{
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
status = io.Status;
|
||||||
|
break;
|
||||||
|
case WAIT_SIGNALED:
|
||||||
|
status = STATUS_THREAD_SIGNALED;
|
||||||
|
break;
|
||||||
|
case WAIT_CANCELED:
|
||||||
|
status = STATUS_THREAD_CANCELED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (NT_SUCCESS (status))
|
if (NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
/* NtWriteFile returns success with # of bytes written == 0 in
|
nbytes_now = io.Information;
|
||||||
case writing on a non-blocking pipe fails if the pipe buffer
|
/* NtWriteFile returns success with # of bytes written == 0
|
||||||
is full. */
|
if writing on a non-blocking pipe fails because the pipe
|
||||||
if (io.Information == 0)
|
buffer doesn't have sufficient space. */
|
||||||
|
if (nbytes_now == 0)
|
||||||
set_errno (EAGAIN);
|
set_errno (EAGAIN);
|
||||||
else
|
ptr = ((char *) ptr) + chunk;
|
||||||
ret = io.Information;
|
nbytes += nbytes_now;
|
||||||
}
|
}
|
||||||
else if (STATUS_PIPE_IS_CLOSED (status))
|
else if (STATUS_PIPE_IS_CLOSED (status))
|
||||||
{
|
{
|
||||||
|
@ -683,6 +729,17 @@ fhandler_fifo::raw_write (const void *ptr, size_t len)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
|
if (nbytes_now == 0)
|
||||||
|
len = 0; /* Terminate loop. */
|
||||||
|
if (nbytes > 0)
|
||||||
|
ret = nbytes;
|
||||||
|
}
|
||||||
|
if (evt)
|
||||||
|
CloseHandle (evt);
|
||||||
|
if (status == STATUS_THREAD_SIGNALED && !_my_tls.call_signal_handler ())
|
||||||
|
set_errno (EINTR);
|
||||||
|
else if (status == STATUS_THREAD_CANCELED)
|
||||||
|
pthread::static_cancel_self ();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
extern GUID __cygwin_socket_guid;
|
extern GUID __cygwin_socket_guid;
|
||||||
#define CYGWIN_SOCKET_GUID (&__cygwin_socket_guid)
|
#define CYGWIN_SOCKET_GUID (&__cygwin_socket_guid)
|
||||||
|
|
||||||
/* custom status code: */
|
/* Custom Cygwin-only status codes. */
|
||||||
|
#define STATUS_THREAD_SIGNALED ((NTSTATUS)0xe0000001)
|
||||||
|
#define STATUS_THREAD_CANCELED ((NTSTATUS)0xe0000002)
|
||||||
#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269)
|
#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269)
|
||||||
|
|
||||||
/* Simplify checking for a transactional error code. */
|
/* Simplify checking for a transactional error code. */
|
||||||
|
|
Loading…
Reference in New Issue