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:
parent
eb50f82677
commit
085fc12948
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ();
|
||||
|
|
Loading…
Reference in New Issue