[newlib-cygwin] Cygwin: fhandler_pipe: add raw_read and raw_write
Corinna Vinschen
corinna@sourceware.org
Tue Sep 14 15:04:43 GMT 2021
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=4b25687ea3ee2fc6c79e2df999a2fa86fcd39e67
commit 4b25687ea3ee2fc6c79e2df999a2fa86fcd39e67
Author: Ken Brown <kbrown@cornell.edu>
Date: Sat May 25 13:03:08 2019 -0400
Cygwin: fhandler_pipe: add raw_read and raw_write
Diff:
---
winsup/cygwin/fhandler.h | 2 +
winsup/cygwin/fhandler_pipe.cc | 200 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 202 insertions(+)
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index c612a3684..12618db58 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -1257,6 +1257,8 @@ public:
char *get_proc_fd_name (char *buf);
int open (int flags, mode_t mode = 0);
int dup (fhandler_base *child, int);
+ 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 __reg2 fstat (struct stat *buf);
int __reg2 fstatvfs (struct statvfs *buf);
diff --git a/winsup/cygwin/fhandler_pipe.cc b/winsup/cygwin/fhandler_pipe.cc
index 65ef70c25..61ab29187 100644
--- a/winsup/cygwin/fhandler_pipe.cc
+++ b/winsup/cygwin/fhandler_pipe.cc
@@ -20,6 +20,14 @@ details. */
#include "pinfo.h"
#include "shared_info.h"
+/* This is only to be used for writing. When reading,
+STATUS_PIPE_EMPTY simply means there's no data to be read. */
+#define STATUS_PIPE_IS_CLOSED(status) \
+ ({ NTSTATUS _s = (status); \
+ _s == STATUS_PIPE_CLOSING \
+ || _s == STATUS_PIPE_BROKEN \
+ || _s == STATUS_PIPE_EMPTY; })
+
fhandler_pipe::fhandler_pipe ()
: fhandler_base (), popen_pid (0)
{
@@ -184,6 +192,198 @@ fhandler_pipe::get_proc_fd_name (char *buf)
return buf;
}
+void __reg3
+fhandler_pipe::raw_read (void *ptr, size_t& len)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK io;
+ HANDLE evt = NULL;
+ DWORD waitret = WAIT_OBJECT_0;
+ bool keep_looping = false;
+ size_t orig_len = len;
+
+ if (!len)
+ return;
+
+ /* Create a wait event if we're in blocking mode. */
+ if (!is_nonblocking () && !(evt = CreateEvent (NULL, false, false, NULL)))
+ {
+ __seterrno ();
+ len = (size_t) -1;
+ return;
+ }
+
+ do
+ {
+ len = orig_len;
+ keep_looping = false;
+ if (evt)
+ ResetEvent (evt);
+ status = NtReadFile (get_handle (), evt, NULL, NULL, &io, ptr,
+ len, 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 ();
+ len = (size_t) -1;
+ }
+ else if (NT_SUCCESS (status))
+ {
+ len = io.Information;
+ if (len == 0)
+ keep_looping = true;
+ }
+ else
+ {
+ /* Some errors are not really errors. Detect such cases here. */
+ switch (status)
+ {
+ case STATUS_END_OF_FILE:
+ case STATUS_PIPE_BROKEN:
+ /* This is really EOF. */
+ len = 0;
+ break;
+ case STATUS_MORE_ENTRIES:
+ case STATUS_BUFFER_OVERFLOW:
+ /* `io.Information' is supposedly valid. */
+ len = io.Information;
+ if (len == 0)
+ keep_looping = true;
+ break;
+ case STATUS_PIPE_LISTENING:
+ case STATUS_PIPE_EMPTY:
+ if (is_nonblocking ())
+ {
+ set_errno (EAGAIN);
+ len = (size_t) -1;
+ break;
+ }
+ fallthrough;
+ default:
+ __seterrno_from_nt_status (status);
+ len = (size_t) -1;
+ break;
+ }
+ }
+ } while (keep_looping);
+ if (evt)
+ CloseHandle (evt);
+ if (status == STATUS_THREAD_SIGNALED)
+ {
+ set_errno (EINTR);
+ len = (size_t) -1;
+ }
+ else if (status == STATUS_THREAD_CANCELED)
+ pthread::static_cancel_self ();
+}
+
+ssize_t __reg3
+fhandler_pipe::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 pipe 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 ();
+ len = (size_t) -1;
+ }
+ 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)
+ CloseHandle (evt);
+ if (status == STATUS_THREAD_SIGNALED && ret < 0)
+ set_errno (EINTR);
+ else if (status == STATUS_THREAD_CANCELED)
+ pthread::static_cancel_self ();
+ return ret;
+}
+
int
fhandler_pipe::dup (fhandler_base *child, int flags)
{
More information about the Cygwin-cvs
mailing list