Preliminary change to make fifos/pipes interruptible and fifos reliable.
* dtable.cc (dtable::find_fifo): Eliminate definition. * dtable.h (dtable::find_fifo): Ditto for declaration. * fhandler.cc (fhandler_base::raw_read): Remove pipe-specific stuff. (fhandler_base::fhandler_base): Ditto. (fhandler_base::close): Handle overlapped I/O structure if appropriate. (fhandler_base::dup): Ditto. (fhandler_base::fork_fixup): Ditto. (fhandler_base::setup_overlapped): Define new function. (fhandler_base::destroy_overlapped): Ditto. (fhandler_base::wait_overlapped): Ditto. (fhandler_base::read_overlapped): Ditto. (fhandler_base::write_overlapped): Ditto. * fhandler.h (fhandler_base::get_overlapped): Declare new function. (fhandler_base::setup_overlapped): Ditto. (fhandler_base::destroy_overlapped): Ditto. (fhandler_base::wait_overlapped): Ditto. (fhandler_base::read_overlapped): Ditto. (fhandler_base::write_overlapped): Ditto. (fhandler_base::get_guard): Eliminate. (fhandler_pipe::*): Rework to eliminate most Win9x related cruft, removing many variables and defining a new overlapped capability. (fhandler_fifo::*): Ditto. (fifo_state): Declare new enum. * fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove old Win9x stuff. Initialize overlapped handle to NULL. (fhandler_fifo::set_use): Eliminate. (fhandler_fifo::open_nonserver): Define. (fhandler_fifo::open): Rework to use named pipes and overlapped I/O. (fhandler_fifo::wait): Define new function to wait for named pipe connection. (fhandler_fifo::read): Rework to use wait() and new overlapped I/O functionality. (fhandler_fifo::write): Ditto. (fhandler_fifo::dup): Eliminate. * pinfo.cc (commune_process): Remove fifo handling. (_pinfo::commune_request): Ditto. * pinfo.h (picom): Ditto. * pipe.cc (fhandler_pipe::fhandler_pipe): Remove Win9x stuff. Initialize overlapped handle to NULL. (fhandler_pipe::open): Eliminate Win9x stuff. (fhandler_pipe::set_close_on_exec): Eliminate. (read_pipe): Eliminate. (fhandler_pipe::close): Ditto. (fhandler_pipe::fixup_after_exec): Ditto. (fhandler_pipe::fixup_in_child): Ditto. (fhandler_pipe::read): Rework to use overlapped I/O. (fhandler_pipe::write): New function using overlapped I/O. (fhandler_pipe::dup): Rework to eliminate Win9x stuff. (fhandler_pipe::create_selectable): Rework to eliminate Win9x and use overlapped I/O. * select.cc (peek_pipe): Rework to eliminate Win9x stuff and use overlapped I/O. (fhandler_base::ready_for_read): Ditto.
This commit is contained in:
		| @@ -1,3 +1,60 @@ | |||||||
|  | 2007-07-07  Christopher Faylor  <me+cygwin@cgf.cx> | ||||||
|  |  | ||||||
|  | 	Preliminary change to make pipes interruptible and fifos reliable. | ||||||
|  | 	* dtable.cc (dtable::find_fifo): Eliminate definition. | ||||||
|  | 	* dtable.h (dtable::find_fifo): Ditto for declaration. | ||||||
|  | 	* fhandler.cc (fhandler_base::raw_read): Remove pipe-specific stuff. | ||||||
|  | 	(fhandler_base::fhandler_base): Ditto. | ||||||
|  | 	(fhandler_base::close): Handle overlapped I/O structure if appropriate. | ||||||
|  | 	(fhandler_base::dup): Ditto. | ||||||
|  | 	(fhandler_base::fork_fixup): Ditto. | ||||||
|  | 	(fhandler_base::setup_overlapped): Define new function. | ||||||
|  | 	(fhandler_base::destroy_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::wait_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::read_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::write_overlapped): Ditto. | ||||||
|  | 	* fhandler.h (fhandler_base::get_overlapped): Declare new function. | ||||||
|  | 	(fhandler_base::setup_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::destroy_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::wait_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::read_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::write_overlapped): Ditto. | ||||||
|  | 	(fhandler_base::get_guard): Eliminate. | ||||||
|  | 	(fhandler_pipe::*): Rework to eliminate most Win9x related cruft, | ||||||
|  | 	removing many variables and defining a new overlapped capability. | ||||||
|  | 	(fhandler_fifo::*): Ditto. | ||||||
|  | 	(fifo_state): Declare new enum. | ||||||
|  | 	* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove old Win9x | ||||||
|  | 	stuff.  Initialize overlapped handle to NULL. | ||||||
|  | 	(fhandler_fifo::set_use): Eliminate. | ||||||
|  | 	(fhandler_fifo::open_nonserver): Define. | ||||||
|  | 	(fhandler_fifo::open): Rework to use named pipes and overlapped I/O. | ||||||
|  | 	(fhandler_fifo::wait): Define new function to wait for named pipe | ||||||
|  | 	connection. | ||||||
|  | 	(fhandler_fifo::read): Rework to use wait() and new overlapped I/O | ||||||
|  | 	functionality. | ||||||
|  | 	(fhandler_fifo::write): Ditto. | ||||||
|  | 	(fhandler_fifo::dup): Eliminate. | ||||||
|  | 	* pinfo.cc (commune_process): Remove fifo handling. | ||||||
|  | 	(_pinfo::commune_request): Ditto. | ||||||
|  | 	* pinfo.h (picom): Ditto. | ||||||
|  | 	* pipe.cc (fhandler_pipe::fhandler_pipe): Remove Win9x stuff. | ||||||
|  | 	Initialize overlapped handle to NULL. | ||||||
|  | 	(fhandler_pipe::open): Eliminate Win9x stuff. | ||||||
|  | 	(fhandler_pipe::set_close_on_exec): Eliminate. | ||||||
|  | 	(read_pipe): Eliminate. | ||||||
|  | 	(fhandler_pipe::close): Ditto. | ||||||
|  | 	(fhandler_pipe::fixup_after_exec): Ditto. | ||||||
|  | 	(fhandler_pipe::fixup_in_child): Ditto. | ||||||
|  | 	(fhandler_pipe::read): Rework to use overlapped I/O. | ||||||
|  | 	(fhandler_pipe::write): New function using overlapped I/O. | ||||||
|  | 	(fhandler_pipe::dup): Rework to eliminate Win9x stuff. | ||||||
|  | 	(fhandler_pipe::create_selectable): Rework to eliminate Win9x and use | ||||||
|  | 	overlapped I/O. | ||||||
|  | 	* select.cc (peek_pipe): Rework to eliminate Win9x stuff and use | ||||||
|  | 	overlapped I/O. | ||||||
|  | 	(fhandler_base::ready_for_read): Ditto. | ||||||
|  |  | ||||||
| 2007-07-07  Christopher Faylor  <me+cygwin@cgf.cx> | 2007-07-07  Christopher Faylor  <me+cygwin@cgf.cx> | ||||||
|  |  | ||||||
| 	* path.cc (symlink_info::check_shortcut): Handle device "symlinks" | 	* path.cc (symlink_info::check_shortcut): Handle device "symlinks" | ||||||
|   | |||||||
| @@ -580,24 +580,6 @@ done: | |||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| fhandler_fifo * |  | ||||||
| dtable::find_fifo (const char *path) |  | ||||||
| { |  | ||||||
|   lock (); |  | ||||||
|   fhandler_fifo *fh_res = NULL; |  | ||||||
|   for (unsigned i = 0; i < size; i++) |  | ||||||
|     { |  | ||||||
|       fhandler_base *fh = fds[i]; |  | ||||||
|       if (fh && fh->isfifo () && strcmp (path, fh->get_win32_name ()) == 0) |  | ||||||
| 	{ |  | ||||||
| 	  fh_res = (fhandler_fifo *) fh; |  | ||||||
| 	  break; |  | ||||||
| 	} |  | ||||||
|     } |  | ||||||
|   unlock (); |  | ||||||
|   return fh_res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| select_record * | select_record * | ||||||
| dtable::select_read (int fd, select_record *s) | dtable::select_read (int fd, select_record *s) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ details. */ | |||||||
| #include "sync.h" | #include "sync.h" | ||||||
|  |  | ||||||
| class suffix_info; | class suffix_info; | ||||||
| class fhandler_fifo; |  | ||||||
|  |  | ||||||
| #define BFH_OPTS (PC_NULLEMPTY | PC_FULL | PC_POSIX) | #define BFH_OPTS (PC_NULLEMPTY | PC_FULL | PC_POSIX) | ||||||
| class dtable | class dtable | ||||||
| @@ -78,7 +77,6 @@ public: | |||||||
| #ifdef NEWVFORK | #ifdef NEWVFORK | ||||||
|   bool in_vfork_cleanup () {return fds_on_hold == fds;} |   bool in_vfork_cleanup () {return fds_on_hold == fds;} | ||||||
| #endif | #endif | ||||||
|   fhandler_fifo *find_fifo (const char *); |  | ||||||
|   fhandler_base *find_archetype (device& dev); |   fhandler_base *find_archetype (device& dev); | ||||||
|   fhandler_base **add_archetype (); |   fhandler_base **add_archetype (); | ||||||
|   void delete_archetype (fhandler_base *); |   void delete_archetype (fhandler_base *); | ||||||
|   | |||||||
| @@ -32,6 +32,8 @@ details. */ | |||||||
| #include <winioctl.h> | #include <winioctl.h> | ||||||
| #include <ntdef.h> | #include <ntdef.h> | ||||||
| #include "ntdll.h" | #include "ntdll.h" | ||||||
|  | #include "cygtls.h" | ||||||
|  | #include "sigproc.h" | ||||||
|  |  | ||||||
| static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */ | static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */ | ||||||
|  |  | ||||||
| @@ -222,26 +224,12 @@ fhandler_base::raw_read (void *ptr, size_t& ulen) | |||||||
| { | { | ||||||
| #define bytes_read ulen | #define bytes_read ulen | ||||||
|  |  | ||||||
|   HANDLE h = NULL;	/* grumble */ |  | ||||||
|   int prio = 0;		/* ditto */ |  | ||||||
|   int try_noreserve = 1; |   int try_noreserve = 1; | ||||||
|   DWORD len = ulen; |   DWORD len = ulen; | ||||||
|  |  | ||||||
| retry: | retry: | ||||||
|   ulen = (size_t) -1; |   ulen = (size_t) -1; | ||||||
|   if (read_state) |   BOOL res = ReadFile (get_handle (), ptr, len, (DWORD *) &ulen, NULL); | ||||||
|     { |  | ||||||
|       h = GetCurrentThread (); |  | ||||||
|       prio = GetThreadPriority (h); |  | ||||||
|       SetThreadPriority (h, THREAD_PRIORITY_TIME_CRITICAL); |  | ||||||
|       signal_read_state (1); |  | ||||||
|     } |  | ||||||
|   BOOL res = ReadFile (get_handle (), ptr, len, (DWORD *) &ulen, 0); |  | ||||||
|   if (read_state) |  | ||||||
|     { |  | ||||||
|       signal_read_state (1); |  | ||||||
|       SetThreadPriority (h, prio); |  | ||||||
|     } |  | ||||||
|   if (!res) |   if (!res) | ||||||
|     { |     { | ||||||
|       /* Some errors are not really errors.  Detect such cases here.  */ |       /* Some errors are not really errors.  Detect such cases here.  */ | ||||||
| @@ -996,6 +984,7 @@ fhandler_base::close () | |||||||
|  |  | ||||||
|       __seterrno (); |       __seterrno (); | ||||||
|     } |     } | ||||||
|  |   destroy_overlapped (); | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1201,6 +1190,8 @@ fhandler_base::dup (fhandler_base *child) | |||||||
|       VerifyHandle (nh); |       VerifyHandle (nh); | ||||||
|       child->set_io_handle (nh); |       child->set_io_handle (nh); | ||||||
|     } |     } | ||||||
|  |   if (get_overlapped ()) | ||||||
|  |     child->setup_overlapped (); | ||||||
|   set_flags (child->get_flags ()); |   set_flags (child->get_flags ()); | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
| @@ -1332,7 +1323,6 @@ fhandler_base::fhandler_base () : | |||||||
|   raixput (0), |   raixput (0), | ||||||
|   rabuflen (0), |   rabuflen (0), | ||||||
|   fs_flags (0), |   fs_flags (0), | ||||||
|   read_state (NULL), |  | ||||||
|   archetype (NULL), |   archetype (NULL), | ||||||
|   usecount (0) |   usecount (0) | ||||||
| { | { | ||||||
| @@ -1381,6 +1371,8 @@ fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name) | |||||||
| 	VerifyHandle (h); | 	VerifyHandle (h); | ||||||
|       res = true; |       res = true; | ||||||
|     } |     } | ||||||
|  |   if (get_overlapped ()) | ||||||
|  |     setup_overlapped (); | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1399,12 +1391,16 @@ fhandler_base::fixup_after_fork (HANDLE parent) | |||||||
|   debug_printf ("inheriting '%s' from parent", get_name ()); |   debug_printf ("inheriting '%s' from parent", get_name ()); | ||||||
|   if (!nohandle ()) |   if (!nohandle ()) | ||||||
|     fork_fixup (parent, io_handle, "io_handle"); |     fork_fixup (parent, io_handle, "io_handle"); | ||||||
|  |   if (get_overlapped ()) | ||||||
|  |     setup_overlapped (); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| fhandler_base::fixup_after_exec () | fhandler_base::fixup_after_exec () | ||||||
| { | { | ||||||
|   debug_printf ("here for '%s'", get_name ()); |   debug_printf ("here for '%s'", get_name ()); | ||||||
|  |   if (get_overlapped ()) | ||||||
|  |     setup_overlapped (); | ||||||
| } | } | ||||||
|  |  | ||||||
| bool | bool | ||||||
| @@ -1678,3 +1674,86 @@ fhandler_base::fpathconf (int v) | |||||||
|     } |     } | ||||||
|   return -1; |   return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Overlapped I/O */ | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | fhandler_base::setup_overlapped () | ||||||
|  | { | ||||||
|  |   OVERLAPPED *ov = get_overlapped (); | ||||||
|  |   memset (ov, 0, sizeof (*ov)); | ||||||
|  |   return ov->hEvent = CreateEvent (&sec_none_nih, true, false, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | fhandler_base::destroy_overlapped () | ||||||
|  | { | ||||||
|  |   OVERLAPPED *ov = get_overlapped (); | ||||||
|  |   if (ov && ov->hEvent) | ||||||
|  |     { | ||||||
|  |       CloseHandle (ov->hEvent); | ||||||
|  |       ov->hEvent = NULL; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | fhandler_base::wait_overlapped (bool& res, bool writing) | ||||||
|  | { | ||||||
|  |   if (!res && GetLastError () != ERROR_IO_PENDING) | ||||||
|  |     __seterrno (); | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  | #ifdef DEBUGGING | ||||||
|  |       if (!get_overlapped ()) | ||||||
|  | 	system_printf ("get_overlapped is zero?"); | ||||||
|  |       if (!get_overlapped ()->hEvent) | ||||||
|  | 	system_printf ("hEvent is zero?"); | ||||||
|  | #endif | ||||||
|  |       DWORD n = 1; | ||||||
|  |       HANDLE w4[2]; | ||||||
|  |       w4[0] = get_overlapped ()->hEvent; | ||||||
|  |       if (&_my_tls == _main_tls) | ||||||
|  | 	w4[n++] = signal_arrived; | ||||||
|  |       switch (WaitForMultipleObjects (n, w4, false, INFINITE)) | ||||||
|  | 	{ | ||||||
|  | 	case WAIT_OBJECT_0: | ||||||
|  | 	  res = true; | ||||||
|  | 	  break; | ||||||
|  | 	case WAIT_OBJECT_0 + 1: | ||||||
|  | 	  CancelIo (writing ? get_output_handle () : get_handle ()); | ||||||
|  | 	  set_errno (EINTR); | ||||||
|  | 	  res = false; | ||||||
|  | 	  break; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |   ResetEvent (get_overlapped ()->hEvent); | ||||||
|  |   return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | fhandler_base::read_overlapped (void *ptr, size_t& len) | ||||||
|  | { | ||||||
|  | #ifdef DEBUGGING | ||||||
|  |   assert (get_overlapped ()); | ||||||
|  |   assert (get_overlapped ()->hEvent); | ||||||
|  | #endif | ||||||
|  |   bool res = ReadFile (get_handle (), ptr, len, (DWORD *) &len, | ||||||
|  | 		       get_overlapped ()); | ||||||
|  |   if (!wait_overlapped (res, false) | ||||||
|  |       || !GetOverlappedResult (get_handle (), get_overlapped (), (DWORD *) &len, false)) | ||||||
|  |     len = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | fhandler_base::write_overlapped (const void *ptr, size_t len) | ||||||
|  | { | ||||||
|  |   DWORD bytes_written; | ||||||
|  |  | ||||||
|  |   bool res = WriteFile (get_output_handle (), ptr, len, &bytes_written, | ||||||
|  | 			get_overlapped ()); | ||||||
|  |   if (!wait_overlapped (res, true) | ||||||
|  |       || !GetOverlappedResult (get_handle (), get_overlapped (), | ||||||
|  | 			       &bytes_written, false)) | ||||||
|  |     return -1; | ||||||
|  |   return bytes_written; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -141,6 +141,9 @@ class fhandler_base | |||||||
|   DWORD fs_flags; |   DWORD fs_flags; | ||||||
|   HANDLE read_state; |   HANDLE read_state; | ||||||
|   path_conv pc; |   path_conv pc; | ||||||
|  |   bool wait_overlapped (bool&, bool) __attribute__ ((regparm (2))); | ||||||
|  |   bool setup_overlapped () __attribute__ ((regparm (1))); | ||||||
|  |   void destroy_overlapped () __attribute__ ((regparm (1))); | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   class fhandler_base *archetype; |   class fhandler_base *archetype; | ||||||
| @@ -294,7 +297,9 @@ class fhandler_base | |||||||
|   virtual int fcntl (int cmd, void *); |   virtual int fcntl (int cmd, void *); | ||||||
|   virtual char const *ttyname () { return get_name (); } |   virtual char const *ttyname () { return get_name (); } | ||||||
|   virtual void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3))); |   virtual void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3))); | ||||||
|   virtual int write (const void *ptr, size_t len); |   virtual void __stdcall read_overlapped (void *ptr, size_t& len) __attribute__ ((regparm (3))); | ||||||
|  |   virtual int __stdcall write (const void *ptr, size_t len); | ||||||
|  |   virtual int __stdcall write_overlapped (const void *ptr, size_t len); | ||||||
|   virtual ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1); |   virtual ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1); | ||||||
|   virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1); |   virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1); | ||||||
|   virtual ssize_t __stdcall pread (void *, size_t, _off64_t) __attribute__ ((regparm (3))); |   virtual ssize_t __stdcall pread (void *, size_t, _off64_t) __attribute__ ((regparm (3))); | ||||||
| @@ -334,6 +339,7 @@ class fhandler_base | |||||||
|  |  | ||||||
|   virtual void raw_read (void *ptr, size_t& ulen); |   virtual void raw_read (void *ptr, size_t& ulen); | ||||||
|   virtual int raw_write (const void *ptr, size_t ulen); |   virtual int raw_write (const void *ptr, size_t ulen); | ||||||
|  |   virtual OVERLAPPED *get_overlapped () {return NULL;} | ||||||
|  |  | ||||||
|   /* Virtual accessor functions to hide the fact |   /* Virtual accessor functions to hide the fact | ||||||
|      that some fd's have two handles. */ |      that some fd's have two handles. */ | ||||||
| @@ -356,7 +362,6 @@ class fhandler_base | |||||||
|     rabuf = NULL; |     rabuf = NULL; | ||||||
|   } |   } | ||||||
|   void operator delete (void *); |   void operator delete (void *); | ||||||
|   virtual HANDLE get_guard () const {return NULL;} |  | ||||||
|   virtual void set_eof () {} |   virtual void set_eof () {} | ||||||
|   virtual int mkdir (mode_t mode); |   virtual int mkdir (mode_t mode); | ||||||
|   virtual int rmdir (); |   virtual int rmdir (); | ||||||
| @@ -372,7 +377,6 @@ class fhandler_base | |||||||
|   bool issymlink () {return pc.issymlink ();} |   bool issymlink () {return pc.issymlink ();} | ||||||
|   bool device_access_denied (int) __attribute__ ((regparm (2))); |   bool device_access_denied (int) __attribute__ ((regparm (2))); | ||||||
|   int fhaccess (int flags) __attribute__ ((regparm (2))); |   int fhaccess (int flags) __attribute__ ((regparm (2))); | ||||||
|   friend class fhandler_fifo; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class fhandler_mailslot : public fhandler_base | class fhandler_mailslot : public fhandler_base | ||||||
| @@ -521,13 +525,12 @@ class fhandler_socket: public fhandler_base | |||||||
|  |  | ||||||
| class fhandler_pipe: public fhandler_base | class fhandler_pipe: public fhandler_base | ||||||
| { | { | ||||||
| protected: |  | ||||||
|   HANDLE guard; |  | ||||||
|   bool broken_pipe; |  | ||||||
| private: | private: | ||||||
|   pid_t popen_pid; |   pid_t popen_pid; | ||||||
|  |   OVERLAPPED io_status; | ||||||
| public: | public: | ||||||
|   fhandler_pipe (); |   fhandler_pipe (); | ||||||
|  |   OVERLAPPED *get_overlapped () {return &io_status;} | ||||||
|   void set_popen_pid (pid_t pid) {popen_pid = pid;} |   void set_popen_pid (pid_t pid) {popen_pid = pid;} | ||||||
|   pid_t get_popen_pid () const {return popen_pid;} |   pid_t get_popen_pid () const {return popen_pid;} | ||||||
|   _off64_t lseek (_off64_t offset, int whence); |   _off64_t lseek (_off64_t offset, int whence); | ||||||
| @@ -535,53 +538,40 @@ public: | |||||||
|   select_record *select_write (select_record *s); |   select_record *select_write (select_record *s); | ||||||
|   select_record *select_except (select_record *s); |   select_record *select_except (select_record *s); | ||||||
|   char *get_proc_fd_name (char *buf); |   char *get_proc_fd_name (char *buf); | ||||||
|   void set_close_on_exec (bool val); |  | ||||||
|   void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3))); |   void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3))); | ||||||
|  |   int __stdcall write (const void *, size_t); | ||||||
|   int open (int flags, mode_t mode = 0); |   int open (int flags, mode_t mode = 0); | ||||||
|   int close (); |  | ||||||
|   void create_guard (SECURITY_ATTRIBUTES *sa) |  | ||||||
|   { |  | ||||||
|     guard = CreateMutex (sa, FALSE, NULL); |  | ||||||
|     ProtectHandleINH (guard); |  | ||||||
|   } |  | ||||||
|   int dup (fhandler_base *child); |   int dup (fhandler_base *child); | ||||||
|   int ioctl (unsigned int cmd, void *); |   int ioctl (unsigned int cmd, void *); | ||||||
|   int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); |   int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); | ||||||
|   int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3))); |   int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3))); | ||||||
|   int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); |   int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); | ||||||
|   void fixup_in_child (); |  | ||||||
|   virtual void fixup_after_fork (HANDLE); |  | ||||||
|   void fixup_after_exec (); |  | ||||||
|   bool hit_eof () {return broken_pipe;} |  | ||||||
|   void set_eof () {broken_pipe = true;} |  | ||||||
|   HANDLE get_guard () const {return guard;} |  | ||||||
|   int ready_for_read (int fd, DWORD howlong); |   int ready_for_read (int fd, DWORD howlong); | ||||||
|   static int create (fhandler_pipe *[2], unsigned, int, bool = false); |   static int create (fhandler_pipe *[2], unsigned, int, bool = false); | ||||||
|   bool is_slow () {return true;} |  | ||||||
|   static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD, bool); |   static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD, bool); | ||||||
|   friend class fhandler_fifo; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class fhandler_fifo: public fhandler_pipe | enum fifo_state | ||||||
| { | { | ||||||
|   HANDLE output_handle; |   fifo_unknown, | ||||||
|   long read_use; |   fifo_wait_for_client, | ||||||
|   long write_use; |   fifo_wait_for_server, | ||||||
|   virtual HANDLE& get_io_handle () { return io_handle ?: output_handle; } |   fifo_ok | ||||||
|  | }; | ||||||
|  | class fhandler_fifo: public fhandler_base | ||||||
|  | { | ||||||
|  |   fifo_state wait_state; | ||||||
|  |   HANDLE open_nonserver (const char *, unsigned, LPSECURITY_ATTRIBUTES); | ||||||
|  |   OVERLAPPED io_status; | ||||||
|  |   bool wait (bool) __attribute__ ((regparm (1))); | ||||||
| public: | public: | ||||||
|   fhandler_fifo (); |   fhandler_fifo (); | ||||||
|   int open (int flags, mode_t mode = 0); |   void __stdcall read (void *, size_t&) __attribute__ ((regparm (3))); | ||||||
|   int open_not_mine (int flags) __attribute__ ((regparm (2))); |   int __stdcall write (const void *, size_t); | ||||||
|   int close (); |   int open (int, mode_t); | ||||||
|   void set_use (int flags) __attribute__ ((regparm (2))); |  | ||||||
|   bool isfifo () { return true; } |   bool isfifo () { return true; } | ||||||
|   HANDLE& get_output_handle () { return output_handle; } |  | ||||||
|   void set_output_handle (HANDLE h) { output_handle = h; } |  | ||||||
|   void set_use (); |  | ||||||
|   int dup (fhandler_base *child); |  | ||||||
|   int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); |   int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); | ||||||
|   bool is_slow () {return true;} |   OVERLAPPED *get_overlapped () {return &io_status;} | ||||||
|   void close_one_end (); |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class fhandler_dev_raw: public fhandler_base | class fhandler_dev_raw: public fhandler_base | ||||||
|   | |||||||
| @@ -22,223 +22,143 @@ | |||||||
| #include "dtable.h" | #include "dtable.h" | ||||||
| #include "cygheap.h" | #include "cygheap.h" | ||||||
| #include "pinfo.h" | #include "pinfo.h" | ||||||
|  | #include "sigproc.h" | ||||||
|  | #include "cygtls.h" | ||||||
|  |  | ||||||
| fhandler_fifo::fhandler_fifo () | fhandler_fifo::fhandler_fifo (): | ||||||
|   : fhandler_pipe (), output_handle (NULL), |   wait_state (fifo_unknown) | ||||||
|     read_use (0), write_use (0) |  | ||||||
| { | { | ||||||
| } |   get_overlapped ()->hEvent = NULL; | ||||||
|  |  | ||||||
| void |  | ||||||
| fhandler_fifo::set_use (int incr) |  | ||||||
| { |  | ||||||
|   long oread_use = read_use; |  | ||||||
|  |  | ||||||
|   if (get_flags () & (O_WRONLY | O_APPEND)) |  | ||||||
|     write_use += incr; |  | ||||||
|   else if (get_flags () & O_RDWR) |  | ||||||
|     { |  | ||||||
|       write_use += incr; |  | ||||||
|       read_use += incr; |  | ||||||
|     } |  | ||||||
|   else |  | ||||||
|     read_use += incr; |  | ||||||
|  |  | ||||||
|   if (incr >= 0) |  | ||||||
|     return; |  | ||||||
|   if (read_use <= 0 && oread_use != read_use) |  | ||||||
|     { |  | ||||||
|       HANDLE h = get_handle (); |  | ||||||
|       if (h) |  | ||||||
| 	{ |  | ||||||
| 	  set_io_handle (NULL); |  | ||||||
| 	  CloseHandle (h); |  | ||||||
| 	} |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int |  | ||||||
| fhandler_fifo::close () |  | ||||||
| { |  | ||||||
|   fhandler_pipe::close (); |  | ||||||
|   if (get_output_handle ()) |  | ||||||
|     CloseHandle (get_output_handle ()); |  | ||||||
|   if (!hExeced) |  | ||||||
|     set_use (-1); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define DUMMY_O_RDONLY 4 |  | ||||||
|  |  | ||||||
| void |  | ||||||
| fhandler_fifo::close_one_end () |  | ||||||
| { |  | ||||||
|   int testflags = (get_flags () & (O_RDWR | O_WRONLY | O_APPEND)) ?: DUMMY_O_RDONLY; |  | ||||||
|   static int flagtypes[] = {DUMMY_O_RDONLY | O_RDWR, O_WRONLY | O_APPEND | O_RDWR}; |  | ||||||
|   HANDLE *handles[2] = {&(get_handle ()), &(get_output_handle ())}; |  | ||||||
|   for (int i = 0; i < 2; i++) |  | ||||||
|     if (!(testflags & flagtypes[i])) |  | ||||||
|       { |  | ||||||
| 	CloseHandle (*handles[i]); |  | ||||||
| 	*handles[i] = NULL; |  | ||||||
|       } |  | ||||||
|     else if (i == 0 && !read_state) |  | ||||||
|       { |  | ||||||
| 	create_read_state (2); |  | ||||||
|   need_fork_fixup (true); |   need_fork_fixup (true); | ||||||
| } | } | ||||||
| } |  | ||||||
| int |  | ||||||
| fhandler_fifo::open_not_mine (int flags) |  | ||||||
| { |  | ||||||
|   winpids pids ((DWORD) 0); |  | ||||||
|   int res = 0; |  | ||||||
|  |  | ||||||
|   for (unsigned i = 0; i < pids.npids; i++) | HANDLE | ||||||
|  | fhandler_fifo::open_nonserver (const char *npname, unsigned low_flags, | ||||||
|  | 			       LPSECURITY_ATTRIBUTES sa_buf) | ||||||
| { | { | ||||||
|       _pinfo *p = pids[i]; |   DWORD mode = 0; | ||||||
|       commune_result r; |   if (low_flags == O_RDONLY) | ||||||
|       if (p->pid != myself->pid) |     mode = GENERIC_READ; | ||||||
| 	{ |   else if (low_flags = O_WRONLY) | ||||||
| 	  r = p->commune_request (PICOM_FIFO, get_win32_name ()); |     mode = GENERIC_WRITE; | ||||||
| 	  if (r.handles[0] == NULL) |  | ||||||
| 	    continue;		// process doesn't own fifo |  | ||||||
| 	  debug_printf ("pid %d, handles[0] %p, handles[1] %p", p->pid, |  | ||||||
| 			r.handles[0], r.handles[1]); |  | ||||||
| 	} |  | ||||||
|   else |   else | ||||||
|  |     mode = GENERIC_READ | GENERIC_WRITE; | ||||||
|  |   while (1) | ||||||
|     { |     { | ||||||
| 	  /* FIXME: racy? */ |       HANDLE h = CreateFile (npname, mode, 0, sa_buf, OPEN_EXISTING, | ||||||
| 	  fhandler_fifo *fh = cygheap->fdtab.find_fifo (get_win32_name ()); | 			     FILE_FLAG_OVERLAPPED, NULL); | ||||||
| 	  if (!fh) |       if (h != INVALID_HANDLE_VALUE || GetLastError () != ERROR_PIPE_NOT_CONNECTED) | ||||||
| 	    continue; | 	return h; | ||||||
| 	  if (!DuplicateHandle (hMainProc, fh->get_handle (), hMainProc, |       if (&_my_tls != _main_tls) | ||||||
| 				&r.handles[0], 0, false, DUPLICATE_SAME_ACCESS)) | 	low_priority_sleep (0); | ||||||
|  |       else if (WaitForSingleObject (signal_arrived, 0) == WAIT_OBJECT_0) | ||||||
| 	{ | 	{ | ||||||
| 	      __seterrno (); | 	  set_errno (EINTR); | ||||||
| 	      goto out; | 	  return NULL; | ||||||
| 	} | 	} | ||||||
| 	  if (!DuplicateHandle (hMainProc, fh->get_output_handle (), hMainProc, |  | ||||||
| 				&r.handles[1], 0, false, DUPLICATE_SAME_ACCESS)) |  | ||||||
| 	    { |  | ||||||
| 	      CloseHandle (r.handles[0]); |  | ||||||
| 	      __seterrno (); |  | ||||||
| 	      goto out; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|       set_io_handle (r.handles[0]); | #define FIFO_PIPE_MODE (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE) | ||||||
|       set_output_handle (r.handles[1]); |  | ||||||
|       set_flags (flags); |  | ||||||
|       close_one_end (); |  | ||||||
|       res = 1; |  | ||||||
|       goto out; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   set_errno (EAGAIN); |  | ||||||
|  |  | ||||||
| out: |  | ||||||
|   debug_printf ("res %d", res); |  | ||||||
|   return res; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #define FIFO_PREFIX "_cygfifo_" |  | ||||||
|  |  | ||||||
| int | int | ||||||
| fhandler_fifo::open (int flags, mode_t) | fhandler_fifo::open (int flags, mode_t) | ||||||
| { | { | ||||||
|   int res = 1; |   int res; | ||||||
|   char mutex[CYG_MAX_PATH]; |   char npname[CYG_MAX_PATH]; | ||||||
|   char *emutex = mutex + CYG_MAX_PATH; |   DWORD mode = 0; | ||||||
|   char *p, *p1; |  | ||||||
|   DWORD resw; |  | ||||||
|  |  | ||||||
|   /* Generate a semi-unique name to associate with this fifo but try to ensure |   /* Generate a semi-unique name to associate with this fifo. | ||||||
|      that it is no larger than CYG_MAX_PATH */ |      FIXME: Probably should use "inode" and "dev" from stat for this. */ | ||||||
|   strcpy (mutex, cygheap->shared_prefix); |   __small_sprintf (npname, "\\\\.\\pipe\\__cygfifo__%lx", get_namehash ()); | ||||||
|   for (p = mutex + strlen (mutex), p1 = strchr (get_name (), '\0'); |  | ||||||
|        --p1 >= get_name () && p < emutex ; p++) |  | ||||||
|     *p = (*p1 == '/') ? '_' : *p1; |  | ||||||
|   strncpy (p, FIFO_PREFIX, emutex - p); |  | ||||||
|   mutex[CYG_MAX_PATH - 1] = '\0'; |  | ||||||
|  |  | ||||||
|   /* Create a mutex lock access to this fifo to prevent a race by two processes |   unsigned low_flags = flags & O_ACCMODE; | ||||||
|      trying to figure out if they own the fifo or if they should create it. */ |   if (low_flags == O_RDONLY) | ||||||
|   HANDLE h = CreateMutex (&sec_none_nih, false, mutex); |     mode = PIPE_ACCESS_INBOUND; | ||||||
|   if (!h) |   else if (low_flags == O_WRONLY) | ||||||
|  |     mode = PIPE_ACCESS_OUTBOUND; | ||||||
|  |   else if (low_flags == O_RDWR) | ||||||
|  |     mode = PIPE_ACCESS_DUPLEX; | ||||||
|  |  | ||||||
|  |   if (!mode) | ||||||
|     { |     { | ||||||
|       __seterrno (); |       set_errno (EINVAL); | ||||||
|       system_printf ("couldn't open fifo mutex '%s', %E", mutex); |  | ||||||
|       res = 0; |       res = 0; | ||||||
|       goto out; |  | ||||||
|     } |     } | ||||||
|  |   else | ||||||
|   lock_process::locker.release ();	/* Since we may be a while, release the |  | ||||||
| 					   process lock that is held when we |  | ||||||
| 					   open an fd. */ |  | ||||||
|   /* FIXME? Need to wait for signal here? |  | ||||||
|      This shouldn't block for long, but... */ |  | ||||||
|   resw = WaitForSingleObject (h, INFINITE); |  | ||||||
|   lock_process::locker.acquire ();	/* Restore the lock */ |  | ||||||
|   if (resw != WAIT_OBJECT_0 && resw != WAIT_ABANDONED_0) |  | ||||||
|     { |     { | ||||||
|       __seterrno (); |       char char_sa_buf[1024]; | ||||||
|       system_printf ("Wait for fifo mutex '%s' failed, %E", mutex); |       LPSECURITY_ATTRIBUTES sa_buf = | ||||||
|       goto out; | 	sec_user ((PSECURITY_ATTRIBUTES) char_sa_buf, cygheap->user.sid()); | ||||||
|  |       mode |= FILE_FLAG_OVERLAPPED; | ||||||
|  |       HANDLE h = CreateNamedPipe(npname, mode, FIFO_PIPE_MODE, | ||||||
|  | 				 PIPE_UNLIMITED_INSTANCES, 0, 0, | ||||||
|  | 				 NMPWAIT_WAIT_FOREVER, sa_buf); | ||||||
|  |       if (h != INVALID_HANDLE_VALUE) | ||||||
|  | 	wait_state = fifo_wait_for_client; | ||||||
|  |       else | ||||||
|  | 	  switch (GetLastError ()) | ||||||
|  | 	    { | ||||||
|  | 	    case ERROR_ACCESS_DENIED: | ||||||
|  | 	      h = open_nonserver (npname, low_flags, sa_buf); | ||||||
|  | 	      if (h != INVALID_HANDLE_VALUE) | ||||||
|  | 		{ | ||||||
|  | 		  wait_state = fifo_wait_for_server; | ||||||
|  | 		  break; | ||||||
| 		} | 		} | ||||||
|  | 	      /* fall through intentionally */ | ||||||
|   set_io_handle (NULL); | 	    default: | ||||||
|   set_output_handle (NULL); | 	      __seterrno (); | ||||||
|   if (open_not_mine (flags)) | 	      break; | ||||||
|     goto out; | 	    } | ||||||
|  |       if (!h || h == INVALID_HANDLE_VALUE) | ||||||
|   fhandler_pipe *fhs[2]; | 	res = 0; | ||||||
|   if (create (fhs, 1, flags, true)) |       else if (!setup_overlapped ()) | ||||||
| 	{ | 	{ | ||||||
| 	  __seterrno (); | 	  __seterrno (); | ||||||
| 	  res = 0; | 	  res = 0; | ||||||
| 	} | 	} | ||||||
|       else |       else | ||||||
| 	{ | 	{ | ||||||
|  | 	  set_io_handle (h); | ||||||
| 	  set_flags (flags); | 	  set_flags (flags); | ||||||
|       set_io_handle (fhs[0]->get_handle ()); | 	  res = 1; | ||||||
|       set_output_handle (fhs[1]->get_handle ()); | 	} | ||||||
|       guard = fhs[0]->guard; |  | ||||||
|       read_state = fhs[0]->read_state; |  | ||||||
|       delete (fhs[0]); |  | ||||||
|       delete (fhs[1]); |  | ||||||
|       set_use (1); |  | ||||||
|       need_fork_fixup (true); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| out: |  | ||||||
|   if (h) |  | ||||||
|     { |  | ||||||
|       ReleaseMutex (h); |  | ||||||
|       CloseHandle (h); |  | ||||||
|     } |  | ||||||
|   debug_printf ("returning %d, errno %d", res, get_errno ()); |   debug_printf ("returning %d, errno %d", res, get_errno ()); | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | fhandler_fifo::wait (bool iswrite) | ||||||
|  | { | ||||||
|  |   switch (wait_state) | ||||||
|  |     { | ||||||
|  |     case fifo_wait_for_client: | ||||||
|  |       bool res = ConnectNamedPipe (get_handle (), get_overlapped ()); | ||||||
|  |       if (res || GetLastError () == ERROR_PIPE_CONNECTED) | ||||||
|  | 	return true; | ||||||
|  |       return wait_overlapped (res, iswrite); | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | fhandler_fifo::read (void *in_ptr, size_t& len) | ||||||
|  | { | ||||||
|  |   if (!wait (false)) | ||||||
|  |     len = 0; | ||||||
|  |   else | ||||||
|  |     read_overlapped (in_ptr, len); | ||||||
|  | } | ||||||
|  |  | ||||||
| int | int | ||||||
| fhandler_fifo::dup (fhandler_base *child) | fhandler_fifo::write (const void *ptr, size_t len) | ||||||
| { | { | ||||||
|   int res = fhandler_pipe::dup (child); |   return wait (true) ? write_overlapped (ptr, len) : -1; | ||||||
|   if (!res) |  | ||||||
|     { |  | ||||||
|       fhandler_fifo *ff = (fhandler_fifo *) child; |  | ||||||
|       if (get_output_handle () |  | ||||||
| 	  && !DuplicateHandle (hMainProc, get_output_handle (), hMainProc, |  | ||||||
| 			       &ff->get_output_handle (), false, true, |  | ||||||
| 			       DUPLICATE_SAME_ACCESS)) |  | ||||||
| 	{ |  | ||||||
| 	  __seterrno (); |  | ||||||
| 	  child->close (); |  | ||||||
| 	  res = -1; |  | ||||||
| 	} |  | ||||||
|     } |  | ||||||
|   return res; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int __stdcall | int __stdcall | ||||||
|   | |||||||
| @@ -517,31 +517,6 @@ commune_process (void *arg) | |||||||
| 	  sigproc_printf ("WriteFile fd failed, %E"); | 	  sigproc_printf ("WriteFile fd failed, %E"); | ||||||
| 	break; | 	break; | ||||||
|       } |       } | ||||||
|     case PICOM_FIFO: |  | ||||||
|       { |  | ||||||
| 	sigproc_printf ("processing PICOM_FIFO for %s", si._si_commune._si_str); |  | ||||||
| 	fhandler_fifo *fh = cygheap->fdtab.find_fifo (si._si_commune._si_str); |  | ||||||
| 	HANDLE it[2]; |  | ||||||
| 	if (fh == NULL) |  | ||||||
| 	  it[0] = it[1] = NULL; |  | ||||||
| 	else |  | ||||||
| 	  { |  | ||||||
| 	    it[0] = fh->get_handle (); |  | ||||||
| 	    it[1] = fh->get_output_handle (); |  | ||||||
| 	  } |  | ||||||
|  |  | ||||||
| 	debug_printf ("fifo %sfound %p, %p", fh ? "" : "not ", it[0], it[1]); |  | ||||||
| 	if (!WriteFile (tothem, it, sizeof (it), &nr, NULL)) |  | ||||||
| 	  { |  | ||||||
| 	    /*__seterrno ();*/	// this is run from the signal thread, so don't set errno |  | ||||||
| 	    sigproc_printf ("WriteFile read handle failed, %E"); |  | ||||||
| 	  } |  | ||||||
| 	WaitForSingleObject (process_sync, INFINITE); |  | ||||||
| 	process_sync = NULL; |  | ||||||
| 	if (fh) |  | ||||||
| 	  fh->close_one_end (); |  | ||||||
| 	break; |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   if (process_sync) |   if (process_sync) | ||||||
|     { |     { | ||||||
| @@ -591,8 +566,6 @@ _pinfo::commune_request (__uint32_t code, ...) | |||||||
|       si._si_commune._si_fd = va_arg (args, int); |       si._si_commune._si_fd = va_arg (args, int); | ||||||
|       break; |       break; | ||||||
|  |  | ||||||
|     case PICOM_FIFO: |  | ||||||
|       si._si_commune._si_str = va_arg (args, char *); |  | ||||||
|     break; |     break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -642,26 +615,6 @@ _pinfo::commune_request (__uint32_t code, ...) | |||||||
| 	  res.n = p - res.s; | 	  res.n = p - res.s; | ||||||
| 	} | 	} | ||||||
|       break; |       break; | ||||||
|     case PICOM_FIFO: |  | ||||||
|       { |  | ||||||
| 	lock_process now (); |  | ||||||
| 	DWORD x = ReadFile (fromthem, res.handles, sizeof (res.handles), &nr, NULL); |  | ||||||
| 	if (!x || nr != sizeof (res.handles)) |  | ||||||
| 	  { |  | ||||||
| 	    __seterrno (); |  | ||||||
| 	    goto err; |  | ||||||
| 	  } |  | ||||||
| 	for (int i = 0; i < 2; i++) |  | ||||||
| 	  if (!DuplicateHandle (hp, res.handles[i], hMainProc, &res.handles[i], |  | ||||||
| 				0, false, DUPLICATE_SAME_ACCESS)) |  | ||||||
| 	    { |  | ||||||
| 	      if (i) |  | ||||||
| 		CloseHandle (res.handles[0]); |  | ||||||
| 	      res.handles[0] = res.handles[1] = NULL;	/* FIXME: possibly left a handle open in child? */ |  | ||||||
| 	      goto err; |  | ||||||
| 	    } |  | ||||||
| 	break; |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   goto out; |   goto out; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,12 +24,11 @@ enum picom | |||||||
| { | { | ||||||
|   PICOM_EXTRASTR = 0x80000000, |   PICOM_EXTRASTR = 0x80000000, | ||||||
|   PICOM_CMDLINE = 1, |   PICOM_CMDLINE = 1, | ||||||
|   PICOM_FIFO = PICOM_EXTRASTR | 2, |   PICOM_CWD = 2, | ||||||
|   PICOM_CWD = 3, |   PICOM_ROOT = 3, | ||||||
|   PICOM_ROOT = 4, |   PICOM_FDS = 4, | ||||||
|   PICOM_FDS = 5, |   PICOM_FD = 5, | ||||||
|   PICOM_FD = 6, |   PICOM_PIPE_FHANDLER = 6 | ||||||
|   PICOM_PIPE_FHANDLER = 7 |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define EXITCODE_SET	0x8000000 | #define EXITCODE_SET	0x8000000 | ||||||
|   | |||||||
| @@ -28,8 +28,9 @@ details. */ | |||||||
| #include "ntdll.h" | #include "ntdll.h" | ||||||
|  |  | ||||||
| fhandler_pipe::fhandler_pipe () | fhandler_pipe::fhandler_pipe () | ||||||
|   : fhandler_base (), guard (NULL), broken_pipe (false), popen_pid (0) |   : fhandler_base (), popen_pid (0) | ||||||
| { | { | ||||||
|  |   get_overlapped ()->hEvent = NULL; | ||||||
|   need_fork_fixup (true); |   need_fork_fixup (true); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -97,18 +98,6 @@ fhandler_pipe::open (int flags, mode_t mode) | |||||||
|       __seterrno (); |       __seterrno (); | ||||||
|       goto out; |       goto out; | ||||||
|     } |     } | ||||||
|   if (!fh->guard) |  | ||||||
|     /* nothing to do */; |  | ||||||
|   else if (DuplicateHandle (proc, fh->guard, hMainProc, &guard, |  | ||||||
| 			    0, inh, DUPLICATE_SAME_ACCESS)) |  | ||||||
|     ProtectHandle (guard); |  | ||||||
|   else |  | ||||||
|     { |  | ||||||
|       __seterrno (); |  | ||||||
|       goto out; |  | ||||||
|     } |  | ||||||
|   if (fh->read_state) |  | ||||||
|     create_read_state (2); |  | ||||||
|   init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY); |   init (nio_hdl, fh->get_access (), mode & O_TEXT ?: O_BINARY); | ||||||
|   if (flags & O_NOINHERIT) |   if (flags & O_NOINHERIT) | ||||||
|     close_on_exec (true); |     close_on_exec (true); | ||||||
| @@ -117,8 +106,6 @@ fhandler_pipe::open (int flags, mode_t mode) | |||||||
|   CloseHandle (proc); |   CloseHandle (proc); | ||||||
|   return 1; |   return 1; | ||||||
| out: | out: | ||||||
|   if (guard) |  | ||||||
|     CloseHandle (guard); |  | ||||||
|   if (nio_hdl) |   if (nio_hdl) | ||||||
|     CloseHandle (nio_hdl); |     CloseHandle (nio_hdl); | ||||||
|   if (fh) |   if (fh) | ||||||
| @@ -150,17 +137,6 @@ fhandler_pipe::ftruncate (_off64_t length, bool allow_truncate) | |||||||
|   return -1; |   return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| void |  | ||||||
| fhandler_pipe::set_close_on_exec (bool val) |  | ||||||
| { |  | ||||||
|   fhandler_base::set_close_on_exec (val); |  | ||||||
|   if (guard) |  | ||||||
|     { |  | ||||||
|       set_no_inheritance (guard, val); |  | ||||||
|       ModifyHandle (guard, !val); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| char * | char * | ||||||
| fhandler_pipe::get_proc_fd_name (char *buf) | fhandler_pipe::get_proc_fd_name (char *buf) | ||||||
| { | { | ||||||
| @@ -168,120 +144,30 @@ fhandler_pipe::get_proc_fd_name (char *buf) | |||||||
|   return buf; |   return buf; | ||||||
| } | } | ||||||
|  |  | ||||||
| struct pipeargs |  | ||||||
| { |  | ||||||
|   fhandler_base *fh; |  | ||||||
|   void *ptr; |  | ||||||
|   size_t *len; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static DWORD WINAPI |  | ||||||
| read_pipe (void *arg) |  | ||||||
| { |  | ||||||
|   pipeargs *pi = (pipeargs *) arg; |  | ||||||
|   pi->fh->fhandler_base::read (pi->ptr, *pi->len); |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void __stdcall | void __stdcall | ||||||
| fhandler_pipe::read (void *in_ptr, size_t& in_len) | fhandler_pipe::read (void *in_ptr, size_t& in_len) | ||||||
| { | { | ||||||
|   if (broken_pipe) |   return read_overlapped (in_ptr, in_len); | ||||||
|     in_len = 0; |  | ||||||
|   else |  | ||||||
|     { |  | ||||||
|       pipeargs pi = {dynamic_cast<fhandler_base *>(this), in_ptr, &in_len}; |  | ||||||
|       cygthread *th = new cygthread (read_pipe, 0, &pi, "read_pipe"); |  | ||||||
|       if (th->detach (read_state) && !in_len) |  | ||||||
| 	in_len = (size_t) -1;	/* received a signal */ |  | ||||||
|     } |  | ||||||
|   ReleaseMutex (guard); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int | int | ||||||
| fhandler_pipe::close () | fhandler_pipe::write (const void *ptr, size_t len) | ||||||
| { | { | ||||||
|   if (guard) |   return write_overlapped (ptr, len); | ||||||
|     ForceCloseHandle (guard); |  | ||||||
| #ifndef NEWVFORK |  | ||||||
|   if (read_state) |  | ||||||
| #else |  | ||||||
|   // FIXME is this vfork_cleanup test right?  Is it responsible for some of |  | ||||||
|   // the strange pipe behavior that has been reported in the cygwin mailing |  | ||||||
|   // list? |  | ||||||
|   if (read_state && !cygheap->fdtab.in_vfork_cleanup ()) |  | ||||||
| #endif |  | ||||||
|     ForceCloseHandle (read_state); |  | ||||||
|   return fhandler_base::close (); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| fhandler_pipe::fixup_in_child () |  | ||||||
| { |  | ||||||
|   if (read_state) |  | ||||||
|     create_read_state (2); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| fhandler_pipe::fixup_after_exec () |  | ||||||
| { |  | ||||||
|   if (!close_on_exec ()) |  | ||||||
|     fixup_in_child (); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void |  | ||||||
| fhandler_pipe::fixup_after_fork (HANDLE parent) |  | ||||||
| { |  | ||||||
|   fhandler_base::fixup_after_fork (parent); |  | ||||||
|   if (guard && fork_fixup (parent, guard, "guard")) |  | ||||||
|     ProtectHandle (guard); |  | ||||||
|   fixup_in_child (); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int | int | ||||||
| fhandler_pipe::dup (fhandler_base *child) | fhandler_pipe::dup (fhandler_base *child) | ||||||
| { | { | ||||||
|   int res = -1; |  | ||||||
|   fhandler_pipe *ftp = (fhandler_pipe *) child; |   fhandler_pipe *ftp = (fhandler_pipe *) child; | ||||||
|   ftp->set_popen_pid (0); |   ftp->set_popen_pid (0); | ||||||
|   ftp->guard = ftp->read_state = NULL; |  | ||||||
|  |  | ||||||
|  |   int res; | ||||||
|   if (get_handle () && fhandler_base::dup (child)) |   if (get_handle () && fhandler_base::dup (child)) | ||||||
|     goto err; |     res = -1; | ||||||
|  |  | ||||||
|   if (!guard) |  | ||||||
|     /* nothing to do */; |  | ||||||
|   else if (DuplicateHandle (hMainProc, guard, hMainProc, &ftp->guard, 0, true, |  | ||||||
| 			    DUPLICATE_SAME_ACCESS)) |  | ||||||
|     ProtectHandle1 (ftp->guard, guard); |  | ||||||
|   else |   else | ||||||
|     { |  | ||||||
|       debug_printf ("couldn't duplicate guard %p, %E", guard); |  | ||||||
|       goto err; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   if (!read_state) |  | ||||||
|     /* nothing to do */; |  | ||||||
|   else if (DuplicateHandle (hMainProc, read_state, hMainProc, |  | ||||||
| 			    &ftp->read_state, 0, false, |  | ||||||
| 			    DUPLICATE_SAME_ACCESS)) |  | ||||||
|     ProtectHandle1 (ftp->read_state, read_state); |  | ||||||
|   else |  | ||||||
|     { |  | ||||||
|       debug_printf ("couldn't duplicate read_state %p, %E", read_state); |  | ||||||
|       goto err; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     res = 0; |     res = 0; | ||||||
|   goto out; |  | ||||||
|  |  | ||||||
| err: |  | ||||||
|   if (ftp->guard) |  | ||||||
|     ForceCloseHandle1 (ftp->guard, guard); |  | ||||||
|   if (ftp->read_state) |  | ||||||
|     ForceCloseHandle1 (ftp->read_state, read_state); |  | ||||||
|  |  | ||||||
| out: |  | ||||||
|   debug_printf ("res %d", res); |   debug_printf ("res %d", res); | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
| @@ -327,7 +213,7 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | |||||||
| 	 the pipe was not created earlier by some other process, even if | 	 the pipe was not created earlier by some other process, even if | ||||||
| 	 the pid has been reused.  We avoid FILE_FLAG_FIRST_PIPE_INSTANCE | 	 the pid has been reused.  We avoid FILE_FLAG_FIRST_PIPE_INSTANCE | ||||||
| 	 because that is only available for Win2k SP2 and WinXP.  */ | 	 because that is only available for Win2k SP2 and WinXP.  */ | ||||||
|       r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND, |       r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, | ||||||
| 			   PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, psize, | 			   PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, psize, | ||||||
| 			   psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); | 			   psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); | ||||||
|  |  | ||||||
| @@ -352,28 +238,20 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | |||||||
| 	  debug_printf ("pipe access denied, retrying"); | 	  debug_printf ("pipe access denied, retrying"); | ||||||
| 	  break; | 	  break; | ||||||
| 	default: | 	default: | ||||||
| 	  /* CreateNamePipe failed.  Maybe we are on an older Win9x platform without |  | ||||||
| 	     named pipes.  Return an anonymous pipe as the best approximation.  */ |  | ||||||
| 	  debug_printf ("CreateNamedPipe failed, resorting to CreatePipe size %lu", |  | ||||||
| 			psize); |  | ||||||
| 	  if (CreatePipe (&r, &w, sa_ptr, psize)) |  | ||||||
| 	  { | 	  { | ||||||
| 	      debug_printf ("pipe read handle %p", r); |  | ||||||
| 	      debug_printf ("pipe write handle %p", w); |  | ||||||
| 	      return 0; |  | ||||||
| 	    } |  | ||||||
| 	    err = GetLastError (); | 	    err = GetLastError (); | ||||||
| 	    debug_printf ("CreatePipe failed, %E"); | 	    debug_printf ("CreatePipe failed, %E"); | ||||||
| 	    return err; | 	    return err; | ||||||
| 	  } | 	  } | ||||||
| 	} | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|   debug_printf ("CreateFile: name %s", pipename); |   debug_printf ("CreateFile: name %s", pipename); | ||||||
|  |  | ||||||
|   /* Open the named pipe for writing. |   /* Open the named pipe for writing. | ||||||
|      Be sure to permit FILE_READ_ATTRIBUTES access.  */ |      Be sure to permit FILE_READ_ATTRIBUTES access.  */ | ||||||
|   w = CreateFile (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, sa_ptr, |   w = CreateFile (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, sa_ptr, | ||||||
| 		  OPEN_EXISTING, 0, 0); | 		  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); | ||||||
|  |  | ||||||
|   if (!w || w == INVALID_HANDLE_VALUE) |   if (!w || w == INVALID_HANDLE_VALUE) | ||||||
|     { |     { | ||||||
| @@ -414,10 +292,9 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode, bool fif | |||||||
| 	 fhs[1]->close_on_exec (true); | 	 fhs[1]->close_on_exec (true); | ||||||
|        } |        } | ||||||
|  |  | ||||||
|       fhs[0]->create_read_state (2); |       fhs[0]->setup_overlapped (); | ||||||
|  |       fhs[1]->setup_overlapped (); | ||||||
|       res = 0; |       res = 0; | ||||||
|       fhs[0]->create_guard (sa); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   syscall_printf ("%d = pipe ([%p, %p], %d, %p)", res, fhs[0], fhs[1], psize, mode); |   syscall_printf ("%d = pipe ([%p, %p], %d, %p)", res, fhs[0], fhs[1], psize, mode); | ||||||
|   | |||||||
| @@ -429,15 +429,6 @@ peek_pipe (select_record *s, bool from_select) | |||||||
|   HANDLE h; |   HANDLE h; | ||||||
|   set_handle_or_return_if_not_open (h, s); |   set_handle_or_return_if_not_open (h, s); | ||||||
|  |  | ||||||
|   /* pipes require a guard mutex to guard against the situation where multiple |  | ||||||
|      readers are attempting to read from the same pipe.  In this scenario, it |  | ||||||
|      is possible for PeekNamedPipe to report available data to two readers but |  | ||||||
|      only one will actually get the data.  This will result in the other reader |  | ||||||
|      entering fhandler_base::raw_read and blocking indefinitely in an interruptible |  | ||||||
|      state.  This causes things like "make -j2" to hang.  So, for the non-select case |  | ||||||
|      we use the pipe mutex, if it is available. */ |  | ||||||
|   HANDLE guard_mutex = from_select ? NULL : fh->get_guard (); |  | ||||||
|  |  | ||||||
|   /* Don't perform complicated tests if we don't need to. */ |   /* Don't perform complicated tests if we don't need to. */ | ||||||
|   if (!s->read_selected && !s->except_selected) |   if (!s->read_selected && !s->except_selected) | ||||||
|     goto out; |     goto out; | ||||||
| @@ -484,30 +475,9 @@ peek_pipe (select_record *s, bool from_select) | |||||||
|       select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ()); |       select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ()); | ||||||
|       n = -1; |       n = -1; | ||||||
|     } |     } | ||||||
|   else if (!n || !guard_mutex) |  | ||||||
|     /* no guard mutex or nothing to read from the pipe. */; |  | ||||||
|   else if (WaitForSingleObject (guard_mutex, 0) != WAIT_OBJECT_0) |  | ||||||
|     { |  | ||||||
|       select_printf ("%s, couldn't get mutex %p, %E", fh->get_name (), |  | ||||||
| 		     guard_mutex); |  | ||||||
|       n = 0; |  | ||||||
|     } |  | ||||||
|   else |  | ||||||
|     { |  | ||||||
|       /* Now that we have the mutex, make sure that no one else has snuck |  | ||||||
| 	 in and grabbed the data that we originally saw. */ |  | ||||||
|       if (!PeekNamedPipe (h, NULL, 0, NULL, (DWORD *) &n, NULL)) |  | ||||||
| 	{ |  | ||||||
| 	  select_printf ("%s, PeekNamedPipe failed, %E", fh->get_name ()); |  | ||||||
| 	  n = -1; |  | ||||||
| 	} |  | ||||||
|       if (n <= 0) |  | ||||||
| 	ReleaseMutex (guard_mutex);	/* Oops.  We lost the race.  */ |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   if (n < 0) |   if (n < 0) | ||||||
|     { |     { | ||||||
|       fh->set_eof ();		/* Flag that other end of pipe is gone */ |  | ||||||
|       select_printf ("%s, n %d", fh->get_name (), n); |       select_printf ("%s, n %d", fh->get_name (), n); | ||||||
|       if (s->except_selected) |       if (s->except_selected) | ||||||
| 	gotone += s->except_ready = true; | 	gotone += s->except_ready = true; | ||||||
| @@ -546,10 +516,6 @@ out: | |||||||
| /* FIXME: This code is not quite correct.  There's no better solution | /* FIXME: This code is not quite correct.  There's no better solution | ||||||
|    so far but to always treat the write side of the pipe as writable. */ |    so far but to always treat the write side of the pipe as writable. */ | ||||||
|  |  | ||||||
| 	  /* We don't worry about the guard mutex, because that only applies |  | ||||||
| 	     when from_select is false, and peek_pipe is never called that |  | ||||||
| 	     way for writes.  */ |  | ||||||
|  |  | ||||||
| 	  IO_STATUS_BLOCK iosb = {0}; | 	  IO_STATUS_BLOCK iosb = {0}; | ||||||
| 	  FILE_PIPE_LOCAL_INFORMATION fpli = {0}; | 	  FILE_PIPE_LOCAL_INFORMATION fpli = {0}; | ||||||
|  |  | ||||||
| @@ -685,25 +651,8 @@ fhandler_pipe::ready_for_read (int fd, DWORD howlong) | |||||||
|   int res; |   int res; | ||||||
|   if (!howlong) |   if (!howlong) | ||||||
|     res = fhandler_base::ready_for_read (fd, howlong); |     res = fhandler_base::ready_for_read (fd, howlong); | ||||||
|   else if (!get_guard ()) |  | ||||||
|     res = 1; |  | ||||||
|   else |   else | ||||||
|     { |  | ||||||
|       const HANDLE w4[2] = {get_guard (), signal_arrived}; |  | ||||||
|       switch (WaitForMultipleObjects (2, w4, 0, INFINITE)) |  | ||||||
| 	{ |  | ||||||
| 	case WAIT_OBJECT_0: |  | ||||||
|     res = 1; |     res = 1; | ||||||
| 	  break; |  | ||||||
| 	case WAIT_OBJECT_0 + 1: |  | ||||||
| 	  set_sig_errno (EINTR); |  | ||||||
| 	  res = 0; |  | ||||||
| 	  break; |  | ||||||
| 	default: |  | ||||||
| 	  __seterrno (); |  | ||||||
| 	  res = 0; |  | ||||||
| 	} |  | ||||||
|     } |  | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1202,9 +1151,6 @@ fhandler_base::ready_for_read (int fd, DWORD howlong) | |||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (get_guard () && !avail && me.read_ready) |  | ||||||
|     ReleaseMutex (get_guard ()); |  | ||||||
|  |  | ||||||
|   select_printf ("read_ready %d, avail %d", me.read_ready, avail); |   select_printf ("read_ready %d, avail %d", me.read_ready, avail); | ||||||
|   return avail; |   return avail; | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user