From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id DDC953858026; Tue, 14 Sep 2021 15:04:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DDC953858026 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin] Cygwin: fhandler_pipe: add raw_read and raw_write X-Act-Checkin: newlib-cygwin X-Git-Author: Ken Brown X-Git-Refname: refs/heads/master X-Git-Oldrev: 72e083c4a01ef5c2bb51a7c05be315d249e442d1 X-Git-Newrev: 4b25687ea3ee2fc6c79e2df999a2fa86fcd39e67 Message-Id: <20210914150443.DDC953858026@sourceware.org> Date: Tue, 14 Sep 2021 15:04:43 +0000 (GMT) X-BeenThere: cygwin-cvs@cygwin.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Cygwin core component git logs List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 14 Sep 2021 15:04:44 -0000 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=4b25687ea3ee2fc6c79e2df999a2fa86fcd39e67 commit 4b25687ea3ee2fc6c79e2df999a2fa86fcd39e67 Author: Ken Brown 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) {