diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 132e6002133b..a2de4301521b 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -462,6 +462,7 @@ public: virtual HANDLE& get_output_handle_nat () { return io_handle; } virtual HANDLE get_stat_handle () { return pc.handle () ?: io_handle; } virtual HANDLE get_echo_handle () const { return NULL; } + virtual HANDLE get_query_handle () const { return NULL; } virtual bool hit_eof () {return false;} virtual select_record *select_read (select_stuff *); virtual select_record *select_write (select_stuff *); @@ -1171,6 +1172,7 @@ class fhandler_socket_unix : public fhandler_socket class fhandler_pipe: public fhandler_base { private: + HANDLE query_hdl; pid_t popen_pid; size_t max_atomic_write; void set_pipe_non_blocking (bool nonblocking); @@ -1179,6 +1181,12 @@ public: bool ispipe() const { return true; } + HANDLE get_query_handle () + { + return (get_device () == FH_PIPEW) ? query_hdl : get_handle (); + } + void set_query_handle (HANDLE qh) { query_hdl = qh; } + void set_popen_pid (pid_t pid) {popen_pid = pid;} pid_t get_popen_pid () const {return popen_pid;} off_t lseek (off_t offset, int whence); @@ -1187,7 +1195,9 @@ public: select_record *select_except (select_stuff *); char *get_proc_fd_name (char *buf); int open (int flags, mode_t mode = 0); + void fixup_after_fork (HANDLE); 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 *); diff --git a/winsup/cygwin/fhandler_pipe.cc b/winsup/cygwin/fhandler_pipe.cc index b99f00c099f8..f698f9063207 100644 --- a/winsup/cygwin/fhandler_pipe.cc +++ b/winsup/cygwin/fhandler_pipe.cc @@ -405,22 +405,45 @@ fhandler_pipe::raw_write (const void *ptr, size_t len) return ret; } +void +fhandler_pipe::fixup_after_fork (HANDLE parent) +{ + if (query_hdl) + fork_fixup (parent, query_hdl, "query_hdl"); + fhandler_base::fixup_after_fork (parent); +} + int fhandler_pipe::dup (fhandler_base *child, int flags) { fhandler_pipe *ftp = (fhandler_pipe *) child; ftp->set_popen_pid (0); - int res; - if (get_handle () && fhandler_base::dup (child, flags)) + int res = 0; + if (fhandler_base::dup (child, flags)) res = -1; - else - res = 0; + else if (query_hdl && + !DuplicateHandle (GetCurrentProcess (), query_hdl, + GetCurrentProcess (), &ftp->query_hdl, + 0, !(flags & O_CLOEXEC), DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + ftp->close (); + res = -1; + } debug_printf ("res %d", res); return res; } +int +fhandler_pipe::close () +{ + if (query_hdl) + NtClose (query_hdl); + return fhandler_base::close (); +} + #define PIPE_INTRO "\\\\.\\pipe\\cygwin-" /* Create a pipe, and return handles to the read and write ends, @@ -608,6 +631,7 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) else if ((fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev)) == NULL) { delete fhs[0]; + CloseHandle (r); CloseHandle (w); } else @@ -617,7 +641,17 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) unique_id); fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, mode, unique_id); - res = 0; + if (!DuplicateHandle (GetCurrentProcess (), r, GetCurrentProcess (), + &fhs[1]->query_hdl, FILE_READ_ATTRIBUTES, + !(mode & O_CLOEXEC), 0)) + { + delete fhs[0]; + CloseHandle (r); + delete fhs[1]; + CloseHandle (w); + } + else + res = 0; } debug_printf ("%R = pipe([%p, %p], %d, %y)", res, fhs[0], fhs[1], psize, mode); diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 83e1c00e0ac7..dc0563a45729 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -608,11 +608,14 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) } if (writing) { - /* If there is anything available in the pipe buffer then signal - that. This means that a pipe could still block since you could - be trying to write more to the pipe than is available in the - buffer but that is the hazard of select(). */ - fpli.WriteQuotaAvailable = fpli.OutboundQuota - fpli.ReadDataAvailable; + /* If there is anything available in the pipe buffer then signal + that. This means that a pipe could still block since you could + be trying to write more to the pipe than is available in the + buffer but that is the hazard of select(). + Note that WriteQuotaAvailable is unreliable. The only reliable + information is available on the read side, which is why we fetch + the info from the read side via the pipe-specific query handle. */ + fpli.WriteQuotaAvailable = fpli.InboundQuota - fpli.ReadDataAvailable; if (fpli.WriteQuotaAvailable > 0) { paranoid_printf ("fd %d, %s, write: size %u, avail %u", fd, @@ -718,7 +721,7 @@ out: fhandler_pty_master *fhm = (fhandler_pty_master *) fh; fhm->set_mask_flusho (s->read_ready); } - h = fh->get_output_handle (); + h = fh->get_query_handle (); if (s->write_selected && dev != FH_PIPER) { gotone += s->write_ready = pipe_data_available (s->fd, fh, h, true);