Cygwin: new class fhandler_pipe_fifo

This is a parent of fhandler_pipe and fhandler_fifo for code that is
common between the two classes.  Currently it just contains
max_atomic_write and raw_write().  The latter is identical to what
used to be fhandler_pipe::raw_write().
This commit is contained in:
Ken Brown 2021-09-03 19:41:52 -04:00 committed by Corinna Vinschen
parent eb50f82677
commit 085fc12948
3 changed files with 26 additions and 106 deletions

View File

@ -1168,12 +1168,24 @@ class fhandler_socket_unix : public fhandler_socket
#endif /* __WITH_AF_UNIX */
class fhandler_pipe: public fhandler_base
/* A parent of fhandler_pipe and fhandler_fifo. */
class fhandler_pipe_fifo: public fhandler_base
{
protected:
size_t max_atomic_write;
public:
fhandler_pipe_fifo ();
ssize_t __reg3 raw_write (const void *ptr, size_t len);
};
class fhandler_pipe: public fhandler_pipe_fifo
{
private:
HANDLE read_mtx;
pid_t popen_pid;
size_t max_atomic_write;
void set_pipe_non_blocking (bool nonblocking);
public:
fhandler_pipe ();
@ -1193,7 +1205,6 @@ public:
int dup (fhandler_base *child, int);
int close ();
void __reg3 raw_read (void *ptr, size_t& len);
ssize_t __reg3 raw_write (const void *ptr, size_t len);
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, intptr_t);
int __reg2 fstat (struct stat *buf);
@ -1319,7 +1330,7 @@ public:
{ InterlockedExchange (&_sh_fc_handler_updated, val); }
};
class fhandler_fifo: public fhandler_base
class fhandler_fifo: public fhandler_pipe_fifo
{
/* Handles to named events shared by all fhandlers for a given FIFO. */
HANDLE read_ready; /* A reader is open; OK for a writer to open. */
@ -1342,7 +1353,6 @@ class fhandler_fifo: public fhandler_base
int nhandlers; /* Number of elements in the array. */
af_unix_spinlock_t _fifo_client_lock;
bool reader, writer, duplexer;
size_t max_atomic_write;
fifo_reader_id_t me;
HANDLE shmem_handle;
@ -1447,7 +1457,6 @@ public:
bool isfifo () const { return true; }
void set_close_on_exec (bool val);
void __reg3 raw_read (void *ptr, size_t& ulen);
ssize_t __reg3 raw_write (const void *ptr, size_t ulen);
void fixup_after_fork (HANDLE);
void fixup_after_exec ();
int __reg2 fstat (struct stat *buf);

View File

@ -128,13 +128,12 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
static NO_COPY fifo_reader_id_t null_fr_id = { .winpid = 0, .fh = NULL };
fhandler_fifo::fhandler_fifo ():
fhandler_base (),
fhandler_pipe_fifo (),
read_ready (NULL), write_ready (NULL), writer_opening (NULL),
owner_needed_evt (NULL), owner_found_evt (NULL), update_needed_evt (NULL),
cancel_evt (NULL), thr_sync_evt (NULL), pipe_name_buf (NULL),
fc_handler (NULL), shandlers (0), nhandlers (0),
reader (false), writer (false), duplexer (false),
max_atomic_write (DEFAULT_PIPEBUFSIZE),
me (null_fr_id), shmem_handle (NULL), shmem (NULL),
shared_fc_hdl (NULL), shared_fc_handler (NULL)
{
@ -1138,99 +1137,6 @@ fhandler_fifo::wait (HANDLE h)
}
}
ssize_t __reg3
fhandler_fifo::raw_write (const void *ptr, size_t len)
{
ssize_t ret = -1;
size_t nbytes = 0;
ULONG chunk;
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK io;
HANDLE evt = NULL;
if (!len)
return 0;
if (len <= max_atomic_write)
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)))
{
__seterrno ();
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;
ULONG len1;
DWORD waitret = WAIT_OBJECT_0;
if (left > chunk)
len1 = chunk;
else
len1 = (ULONG) left;
nbytes_now = 0;
status = NtWriteFile (get_handle (), evt, NULL, NULL, &io,
(PVOID) ptr, len1, NULL, NULL);
if (evt && status == STATUS_PENDING)
{
waitret = cygwait (evt);
if (waitret == WAIT_OBJECT_0)
status = io.Status;
}
if (waitret == WAIT_CANCELED)
status = STATUS_THREAD_CANCELED;
else if (waitret == WAIT_SIGNALED)
status = STATUS_THREAD_SIGNALED;
else if (isclosed ()) /* A signal handler might have closed the fd. */
{
if (waitret == WAIT_OBJECT_0)
set_errno (EBADF);
else
__seterrno ();
}
else if (NT_SUCCESS (status))
{
nbytes_now = io.Information;
/* NtWriteFile returns success with # of bytes written == 0
if writing on a non-blocking pipe fails because the pipe
buffer doesn't have sufficient space. */
if (nbytes_now == 0)
set_errno (EAGAIN);
ptr = ((char *) ptr) + chunk;
nbytes += nbytes_now;
}
else if (STATUS_PIPE_IS_CLOSED (status))
{
set_errno (EPIPE);
raise (SIGPIPE);
}
else
__seterrno_from_nt_status (status);
if (nbytes_now == 0)
len = 0; /* Terminate loop. */
if (nbytes > 0)
ret = nbytes;
}
if (evt)
NtClose (evt);
if (status == STATUS_THREAD_SIGNALED && ret < 0)
set_errno (EINTR);
else if (status == STATUS_THREAD_CANCELED)
pthread::static_cancel_self ();
return ret;
}
/* Called from raw_read and select.cc:peek_fifo. */
int
fhandler_fifo::take_ownership (DWORD timeout)

View File

@ -28,10 +28,15 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */
|| _s == STATUS_PIPE_BROKEN \
|| _s == STATUS_PIPE_EMPTY; })
fhandler_pipe::fhandler_pipe ()
: fhandler_base (), popen_pid (0)
fhandler_pipe_fifo::fhandler_pipe_fifo ()
: fhandler_base (), max_atomic_write (DEFAULT_PIPEBUFSIZE)
{
}
fhandler_pipe::fhandler_pipe ()
: fhandler_pipe_fifo (), popen_pid (0)
{
max_atomic_write = DEFAULT_PIPEBUFSIZE;
need_fork_fixup (true);
}
@ -340,7 +345,7 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
}
ssize_t __reg3
fhandler_pipe::raw_write (const void *ptr, size_t len)
fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
{
size_t nbytes = 0;
ULONG chunk;
@ -358,7 +363,7 @@ fhandler_pipe::raw_write (const void *ptr, size_t len)
else
chunk = max_atomic_write;
/* Create a wait event if the pipe is in blocking mode. */
/* Create a wait event if the pipe or fifo is in blocking mode. */
if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
{
__seterrno ();