* fhandler.h (fhandler_pipe::create_selectable): Remove optional argument, take
an options argument for CreateNamedPipe/CreateFile. Change handle arguments to expect pointers. (fhandler_fifo::fifo_state): Delete. (fhandler_fifo::dummy_client): Ditto. (fhandler_fifo::open_nonserver): Ditto. (fhandler_fifo::wait_state): Ditto. (fhandler_fifo::raw_write): Ditto. (fhandler_fifo::read_ready): New field. (fhandler_fifo::write_ready): Ditto. (fhandler_fifo::wait): Modify argument. (fhandler_fifo::fifo_name): Add a new argument. (fhandler_fifo::fixup_after_fork): New function. * fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove initialization of expunged elements. Initialize new handles to NULL. (fhandler_fifo::open_nonserver): Delete. (fnevent): New macro for creating a named event. (fnpipe): New macro for creating a unique named pipe name. (create_pipe): New macro for simplification of named pipe creation. (fhandler_fifo::fifo_name): Use new argument when creating a shared name. (fhandler_fifo::open): Rewrite. Use events to synchronize. (pure_debug_printf): New macro, active only when DEBUGGING. (fhandler_fifo::wait): Rewrite to wait for new fifo events which are supplied as a parameter. (fhandler_fifo::raw_read): Rewrite to use handle mechanism to detect client-side disconnect. (fhandler_fifo::raw_write): Delete. (fhandler_fifo::close): Remove accommodations for expunged fields. Close event handles. (fhandler_fifo::dup): Remove accommodations for expunged fields. Duplicate event handles. (fhandler_fifo::fixup_after_fork): New function. Perform fixups on event handles. (fhandler_fifo::set_close_on_exec): Remove accommodations for expunged fields. Set inheritance for new handle fields. * miscfuncs.cc (CreatePipeOverlapped): Accommodate changes in fhandler_pipe::create_selectable. * tty.cc (tty::not_allocated): Ditto. * pipe.cc (fhandler_pipe::create): Ditto. (fhandler_pipe::create_selectable): Accept an extra open_mode argument. Pass arguments by reference and allow opening one end of the pipe at a time. * sys/strace.h (debug_only_printf): Define new macro which calls debug_printf only when DEBUGGING is defined.
This commit is contained in:
		| @@ -1,3 +1,52 @@ | |||||||
|  | 2011-10-30  Christopher Faylor  <me.cygwin2011@cgf.cx> | ||||||
|  |  | ||||||
|  | 	* fhandler.h (fhandler_pipe::create_selectable): Remove optional | ||||||
|  | 	argument, take an options argument for CreateNamedPipe/CreateFile. | ||||||
|  | 	Change handle arguments to expect pointers. | ||||||
|  | 	(fhandler_fifo::fifo_state): Delete. | ||||||
|  | 	(fhandler_fifo::dummy_client): Ditto. | ||||||
|  | 	(fhandler_fifo::open_nonserver): Ditto. | ||||||
|  | 	(fhandler_fifo::wait_state): Ditto. | ||||||
|  | 	(fhandler_fifo::raw_write): Ditto. | ||||||
|  | 	(fhandler_fifo::read_ready): New field. | ||||||
|  | 	(fhandler_fifo::write_ready): Ditto. | ||||||
|  | 	(fhandler_fifo::wait): Modify argument. | ||||||
|  | 	(fhandler_fifo::fifo_name): Add a new argument. | ||||||
|  | 	(fhandler_fifo::fixup_after_fork): New function. | ||||||
|  | 	* fhandler_fifo.cc (fhandler_fifo::fhandler_fifo): Remove | ||||||
|  | 	initialization of expunged elements.  Initialize new handles to NULL. | ||||||
|  | 	(fhandler_fifo::open_nonserver): Delete. | ||||||
|  | 	(fnevent): New macro for creating a named event. | ||||||
|  | 	(fnpipe): New macro for creating a unique named pipe name. | ||||||
|  | 	(create_pipe): New macro for simplification of named pipe creation. | ||||||
|  | 	(fhandler_fifo::fifo_name): Use new argument when creating a shared | ||||||
|  | 	name. | ||||||
|  | 	(fhandler_fifo::open): Rewrite.  Use events to synchronize. | ||||||
|  | 	(pure_debug_printf): New macro, active only when DEBUGGING. | ||||||
|  | 	(fhandler_fifo::wait): Rewrite to wait for new fifo events which are | ||||||
|  | 	supplied as a parameter. | ||||||
|  | 	(fhandler_fifo::raw_read): Rewrite to use handle mechanism to detect | ||||||
|  | 	client-side disconnect. | ||||||
|  | 	(fhandler_fifo::raw_write): Delete. | ||||||
|  | 	(fhandler_fifo::close): Remove accommodations for expunged fields. | ||||||
|  | 	Close event handles. | ||||||
|  | 	(fhandler_fifo::dup): Remove accommodations for expunged fields. | ||||||
|  | 	Duplicate event handles. | ||||||
|  | 	(fhandler_fifo::fixup_after_fork): New function.  Perform fixups on | ||||||
|  | 	event handles. | ||||||
|  | 	(fhandler_fifo::set_close_on_exec): Remove accommodations for expunged | ||||||
|  | 	fields.  Set inheritance for new handle fields. | ||||||
|  | 	* miscfuncs.cc (CreatePipeOverlapped): Accommodate changes in | ||||||
|  | 	fhandler_pipe::create_selectable. | ||||||
|  | 	* tty.cc (tty::not_allocated): Ditto. | ||||||
|  | 	* pipe.cc (fhandler_pipe::create): Ditto. | ||||||
|  | 	(fhandler_pipe::create_selectable): Accept an extra open_mode argument. | ||||||
|  | 	Pass arguments by reference and allow opening one end of the pipe at a | ||||||
|  | 	time. | ||||||
|  |  | ||||||
|  | 	* sys/strace.h (debug_only_printf): Define new macro which calls | ||||||
|  | 	debug_printf only when DEBUGGING is defined. | ||||||
|  |  | ||||||
| 2011-10-28  Christopher Faylor  <me.cygwin2011@cgf.cx> | 2011-10-28  Christopher Faylor  <me.cygwin2011@cgf.cx> | ||||||
|  |  | ||||||
| 	* exceptions.cc (sigpacket::process): Avoid a potential deadlock when | 	* exceptions.cc (sigpacket::process): Avoid a potential deadlock when | ||||||
|   | |||||||
| @@ -275,8 +275,8 @@ retry: | |||||||
|  |  | ||||||
| /* Cover function to WriteFile to provide Posix interface and semantics | /* Cover function to WriteFile to provide Posix interface and semantics | ||||||
|    (as much as possible).  */ |    (as much as possible).  */ | ||||||
| static LARGE_INTEGER off_current = { QuadPart:FILE_USE_FILE_POINTER_POSITION }; | static NO_COPY LARGE_INTEGER off_current = { QuadPart:FILE_USE_FILE_POINTER_POSITION }; | ||||||
| static LARGE_INTEGER off_append = { QuadPart:FILE_WRITE_TO_END_OF_FILE }; | static NO_COPY LARGE_INTEGER off_append = { QuadPart:FILE_WRITE_TO_END_OF_FILE }; | ||||||
|  |  | ||||||
| ssize_t __stdcall | ssize_t __stdcall | ||||||
| fhandler_base::raw_write (const void *ptr, size_t len) | fhandler_base::raw_write (const void *ptr, size_t len) | ||||||
| @@ -1914,7 +1914,7 @@ fhandler_base_overlapped::wait_overlapped (bool inres, bool writing, DWORD *byte | |||||||
|     } |     } | ||||||
|   else if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE) |   else if (err == ERROR_HANDLE_EOF || err == ERROR_BROKEN_PIPE) | ||||||
|     { |     { | ||||||
|       debug_printf ("EOF"); |       debug_printf ("EOF, %E"); | ||||||
|       *bytes = 0; |       *bytes = 0; | ||||||
|       res = overlapped_success; |       res = overlapped_success; | ||||||
|       if (writing && err == ERROR_BROKEN_PIPE) |       if (writing && err == ERROR_BROKEN_PIPE) | ||||||
|   | |||||||
| @@ -129,16 +129,16 @@ class fhandler_base | |||||||
|  |  | ||||||
|   struct status_flags |   struct status_flags | ||||||
|   { |   { | ||||||
|     unsigned rbinary            : 1; /* binary read mode */ |     unsigned rbinary		: 1; /* binary read mode */ | ||||||
|     unsigned rbinset            : 1; /* binary read mode explicitly set */ |     unsigned rbinset	    	: 1; /* binary read mode explicitly set */ | ||||||
|     unsigned wbinary            : 1; /* binary write mode */ |     unsigned wbinary		: 1; /* binary write mode */ | ||||||
|     unsigned wbinset            : 1; /* binary write mode explicitly set */ |     unsigned wbinset		: 1; /* binary write mode explicitly set */ | ||||||
|     unsigned nohandle           : 1; /* No handle associated with fhandler. */ |     unsigned nohandle		: 1; /* No handle associated with fhandler. */ | ||||||
|     unsigned did_lseek          : 1; /* set when lseek is called as a flag that |     unsigned did_lseek		: 1; /* set when lseek is called as a flag that | ||||||
| 					_write should check if we've moved | 					_write should check if we've moved | ||||||
| 					beyond EOF, zero filling or making | 					beyond EOF, zero filling or making | ||||||
| 					file sparse if so. */ | 					file sparse if so. */ | ||||||
|     unsigned query_open         : 3; /* open file without requesting either |     unsigned query_open		: 3; /* open file without requesting either | ||||||
| 					read or write access */ | 					read or write access */ | ||||||
|     unsigned close_on_exec      : 1; /* close-on-exec */ |     unsigned close_on_exec      : 1; /* close-on-exec */ | ||||||
|     unsigned need_fork_fixup    : 1; /* Set if need to fixup after fork. */ |     unsigned need_fork_fixup    : 1; /* Set if need to fixup after fork. */ | ||||||
| @@ -511,12 +511,12 @@ class fhandler_socket: public fhandler_base | |||||||
|   char *peer_sun_path; |   char *peer_sun_path; | ||||||
|   struct status_flags |   struct status_flags | ||||||
|   { |   { | ||||||
|     unsigned async_io              : 1; /* async I/O */ |     unsigned async_io		   : 1; /* async I/O */ | ||||||
|     unsigned saw_shutdown_read     : 1; /* Socket saw a SHUT_RD */ |     unsigned saw_shutdown_read     : 1; /* Socket saw a SHUT_RD */ | ||||||
|     unsigned saw_shutdown_write    : 1; /* Socket saw a SHUT_WR */ |     unsigned saw_shutdown_write    : 1; /* Socket saw a SHUT_WR */ | ||||||
|     unsigned saw_reuseaddr         : 1; /* Socket saw SO_REUSEADDR call */ |     unsigned saw_reuseaddr	   : 1; /* Socket saw SO_REUSEADDR call */ | ||||||
|     unsigned listener              : 1; /* listen called */ |     unsigned listener		   : 1; /* listen called */ | ||||||
|     unsigned connect_state         : 2; |     unsigned connect_state	   : 2; | ||||||
|    public: |    public: | ||||||
|     status_flags () : |     status_flags () : | ||||||
|       async_io (0), saw_shutdown_read (0), saw_shutdown_write (0), |       async_io (0), saw_shutdown_read (0), saw_shutdown_write (0), | ||||||
| @@ -690,9 +690,8 @@ public: | |||||||
|   int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); |   int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); | ||||||
|   int init (HANDLE, DWORD, mode_t); |   int init (HANDLE, DWORD, mode_t); | ||||||
|   static int create (fhandler_pipe *[2], unsigned, int); |   static int create (fhandler_pipe *[2], unsigned, int); | ||||||
|   static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD, const char * = NULL); |   static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE *, HANDLE *, DWORD, | ||||||
|   friend class fhandler_fifo; | 				const char *, DWORD); | ||||||
|  |  | ||||||
|   fhandler_pipe (void *) {} |   fhandler_pipe (void *) {} | ||||||
|  |  | ||||||
|   void copyto (fhandler_base *x) |   void copyto (fhandler_base *x) | ||||||
| @@ -713,31 +712,19 @@ public: | |||||||
|  |  | ||||||
| class fhandler_fifo: public fhandler_base_overlapped | class fhandler_fifo: public fhandler_base_overlapped | ||||||
| { | { | ||||||
|   enum fifo_state |   HANDLE read_ready; | ||||||
|   { |   HANDLE write_ready; | ||||||
|     fifo_unknown, |   bool wait (HANDLE) __attribute__ ((regparm (2))); | ||||||
|     fifo_wait_for_client, |   char *fifo_name (char *, const char *) __attribute__ ((regparm (2))); | ||||||
|     fifo_wait_for_server, |  | ||||||
|     fifo_wait_for_next_client, |  | ||||||
|     fifo_eof, |  | ||||||
|     fifo_error, |  | ||||||
|     fifo_eintr, |  | ||||||
|     fifo_ok |  | ||||||
|   }; |  | ||||||
|   fifo_state wait_state; |  | ||||||
|   HANDLE dummy_client; |  | ||||||
|   HANDLE open_nonserver (const char *, unsigned, LPSECURITY_ATTRIBUTES); |  | ||||||
|   bool wait (bool) __attribute__ ((regparm (1))); |  | ||||||
|   char *fifo_name (char *) __attribute__ ((regparm (2))); |  | ||||||
| public: | public: | ||||||
|   fhandler_fifo (); |   fhandler_fifo (); | ||||||
|   void __stdcall raw_read (void *, size_t&) __attribute__ ((regparm (3))); |  | ||||||
|   ssize_t __stdcall raw_write (const void *, size_t) __attribute__ ((regparm (3))); |  | ||||||
|   int open (int, mode_t); |   int open (int, mode_t); | ||||||
|   int close (); |   int close (); | ||||||
|   int dup (fhandler_base *child, int); |   int dup (fhandler_base *child, int); | ||||||
|   bool isfifo () const { return true; } |   bool isfifo () const { return true; } | ||||||
|   void set_close_on_exec (bool val); |   void set_close_on_exec (bool val); | ||||||
|  |   void __stdcall raw_read (void *ptr, size_t& ulen) __attribute__ ((regparm (3))); | ||||||
|  |   void fixup_after_fork (HANDLE); | ||||||
|   int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); |   int __stdcall fstatvfs (struct statvfs *buf) __attribute__ ((regparm (2))); | ||||||
|   select_record *select_read (select_stuff *); |   select_record *select_read (select_stuff *); | ||||||
|   select_record *select_write (select_stuff *); |   select_record *select_write (select_stuff *); | ||||||
|   | |||||||
| @@ -24,52 +24,27 @@ | |||||||
| #include "ntdll.h" | #include "ntdll.h" | ||||||
|  |  | ||||||
| fhandler_fifo::fhandler_fifo (): | fhandler_fifo::fhandler_fifo (): | ||||||
|   fhandler_base_overlapped (), wait_state (fifo_unknown), dummy_client (NULL) |   fhandler_base_overlapped (), | ||||||
|  |   read_ready (NULL), write_ready (NULL) | ||||||
| { | { | ||||||
|   max_atomic_write = DEFAULT_PIPEBUFSIZE; |   max_atomic_write = DEFAULT_PIPEBUFSIZE; | ||||||
|   need_fork_fixup (true); |   need_fork_fixup (true); | ||||||
| } | } | ||||||
|  |  | ||||||
| HANDLE | #define fnevent(w) fifo_name (npbuf, w "-event") | ||||||
| fhandler_fifo::open_nonserver (const char *npname, unsigned low_flags, | #define fnpipe() fifo_name (npbuf, "fifo") | ||||||
| 			       LPSECURITY_ATTRIBUTES sa_buf) | #define create_pipe(r, w) \ | ||||||
| { |   fhandler_pipe::create_selectable (sa_buf, (r), (w), 0, fnpipe (), open_mode) | ||||||
|   DWORD mode = 0; |  | ||||||
|   if (low_flags == O_RDONLY) |  | ||||||
|     mode = GENERIC_READ; |  | ||||||
|   else if (low_flags == O_WRONLY) |  | ||||||
|     mode = GENERIC_WRITE; |  | ||||||
|   else |  | ||||||
|     mode = GENERIC_READ | GENERIC_WRITE; |  | ||||||
|   while (1) |  | ||||||
|     { |  | ||||||
|       HANDLE h = CreateFile (npname, mode, 0, sa_buf, OPEN_EXISTING, |  | ||||||
| 			     FILE_FLAG_OVERLAPPED, NULL); |  | ||||||
|       if (h != INVALID_HANDLE_VALUE || GetLastError () != ERROR_PIPE_NOT_CONNECTED) |  | ||||||
| 	return h; |  | ||||||
|       if (IsEventSignalled (signal_arrived)) |  | ||||||
| 	{ |  | ||||||
| 	  set_errno (EINTR); |  | ||||||
| 	  return NULL; |  | ||||||
| 	} |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| char * | char * | ||||||
| fhandler_fifo::fifo_name (char *buf) | fhandler_fifo::fifo_name (char *buf, const char *what) | ||||||
| { | { | ||||||
|   /* Generate a semi-unique name to associate with this fifo. */ |   /* Generate a semi-unique name to associate with this fifo. */ | ||||||
|   __small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%S_%08x_%016X", |   __small_sprintf (buf, "%s.%08x.%016X", what, get_dev (), | ||||||
| 		   &installation_key, get_dev (), get_ino ()); | 		   get_ino ()); | ||||||
|   return buf; |   return buf; | ||||||
| } | } | ||||||
|  |  | ||||||
| #define FIFO_PIPE_MODE (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE) |  | ||||||
| #define FIFO_BUF_SIZE  4096 |  | ||||||
| #define cnp(m, s) CreateNamedPipe(npname, (m), FIFO_PIPE_MODE, \ |  | ||||||
| 			       PIPE_UNLIMITED_INSTANCES, (s), (s), \ |  | ||||||
| 			       NMPWAIT_WAIT_FOREVER, sa_buf) |  | ||||||
|  |  | ||||||
| inline PSECURITY_ATTRIBUTES | inline PSECURITY_ATTRIBUTES | ||||||
| sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid) | sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid) | ||||||
| { | { | ||||||
| @@ -79,207 +54,242 @@ sec_user_cloexec (bool cloexec, PSECURITY_ATTRIBUTES sa, PSID sid) | |||||||
| int | int | ||||||
| fhandler_fifo::open (int flags, mode_t) | fhandler_fifo::open (int flags, mode_t) | ||||||
| { | { | ||||||
|   int res = 1; |   enum | ||||||
|   char npname[MAX_PATH]; |   { | ||||||
|  |     success, | ||||||
|  |     error_errno_set, | ||||||
|  |     error_set_errno | ||||||
|  |   } res; | ||||||
|  |   bool reader, writer; | ||||||
|  |   DWORD open_mode = FILE_FLAG_OVERLAPPED; | ||||||
|  |  | ||||||
|   fifo_name (npname); |   /* Determine what we're doing with this fhandler: reading, writing, both */ | ||||||
|   unsigned low_flags = flags & O_ACCMODE; |   switch (flags & O_ACCMODE) | ||||||
|   DWORD mode = 0; |     { | ||||||
|   if (low_flags == O_WRONLY) |     case O_RDONLY: | ||||||
|     mode = PIPE_ACCESS_OUTBOUND; |       reader = true; | ||||||
|   else if (low_flags == O_RDONLY || low_flags == O_RDWR) |       writer = false; | ||||||
|     mode = PIPE_ACCESS_DUPLEX; |       break; | ||||||
|  |     case O_WRONLY: | ||||||
|  |       writer = true; | ||||||
|  |       reader = false; | ||||||
|  |       break; | ||||||
|  |     case O_RDWR: | ||||||
|  |       reader = true; | ||||||
|  |       writer = true; | ||||||
|  |       open_mode |= PIPE_ACCESS_DUPLEX; | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       set_errno (EINVAL); | ||||||
|  |       res = error_errno_set; | ||||||
|  |       goto out; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   set_flags (flags); | ||||||
|  |   char char_sa_buf[1024]; | ||||||
|  |   LPSECURITY_ATTRIBUTES sa_buf; | ||||||
|  |   sa_buf = sec_user_cloexec (flags & O_CLOEXEC, (PSECURITY_ATTRIBUTES) char_sa_buf, | ||||||
|  | 		      cygheap->user.sid()); | ||||||
|  |   char npbuf[MAX_PATH]; | ||||||
|  |  | ||||||
|  |   /* Create control events for this named pipe */ | ||||||
|  |   if (!(read_ready = CreateEvent (sa_buf, true, false, fnevent ("r")))) | ||||||
|  |     { | ||||||
|  |       debug_printf ("CreatEvent for %s failed, %E", npbuf); | ||||||
|  |       res = error_set_errno; | ||||||
|  |       goto out; | ||||||
|  |     } | ||||||
|  |   if (!(write_ready = CreateEvent (sa_buf, true, false, fnevent ("w")))) | ||||||
|  |     { | ||||||
|  |       debug_printf ("CreatEvent for %s failed, %E", npbuf); | ||||||
|  |       res = error_set_errno; | ||||||
|  |       goto out; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   /* If we're reading, create the pipe, signal that we're ready and wait for | ||||||
|  |      a writer. | ||||||
|  |      FIXME: Probably need to special case O_RDWR case.  */ | ||||||
|  |   if (!reader) | ||||||
|  |     /* We are not a reader */; | ||||||
|  |   else if (create_pipe (&get_io_handle (), NULL)) | ||||||
|  |     { | ||||||
|  |       debug_printf ("create of reader failed"); | ||||||
|  |       res = error_set_errno; | ||||||
|  |       goto out; | ||||||
|  |     } | ||||||
|  |   else if (!SetEvent (read_ready)) | ||||||
|  |     { | ||||||
|  |       debug_printf ("SetEvent for read_ready failed, %E"); | ||||||
|  |       res = error_set_errno; | ||||||
|  |       goto out; | ||||||
|  |     } | ||||||
|  |   else if (!writer && !wait (write_ready)) | ||||||
|  |     { | ||||||
|  |       debug_printf ("wait for write_ready failed, %E"); | ||||||
|  |       res = error_errno_set; | ||||||
|  |       goto out; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   /* If we're writing, it's a little tricky since it is possible that | ||||||
|  |      we're attempting to open the other end of a pipe which is already | ||||||
|  |      connected.  In that case, we detect ERROR_PIPE_BUSY, reset the | ||||||
|  |      read_ready event and wait for the reader to allow us to connect | ||||||
|  |      by signalling read_ready. | ||||||
|  |  | ||||||
|  |      Once the pipe has been set up, we signal write_ready.  */ | ||||||
|  |   if (writer) | ||||||
|  |     { | ||||||
|  |       int err; | ||||||
|  |       while (1) | ||||||
|  | 	if (!wait (read_ready)) | ||||||
|  | 	  { | ||||||
|  | 	    res = error_errno_set; | ||||||
|  | 	    goto out; | ||||||
|  | 	  } | ||||||
|  | 	else if ((err = create_pipe (NULL, &get_io_handle ())) == 0) | ||||||
|  | 	  break; | ||||||
|  | 	else if (err == ERROR_PIPE_BUSY) | ||||||
|  | 	  { | ||||||
|  | 	    debug_only_printf ("pipe busy"); | ||||||
|  | 	    ResetEvent (read_ready); | ||||||
|  | 	  } | ||||||
|  | 	else | ||||||
|  | 	  { | ||||||
|  | 	    debug_printf ("create of writer failed"); | ||||||
|  | 	    res = error_set_errno; | ||||||
|  | 	    goto out; | ||||||
|  | 	  } | ||||||
|  |       if (!SetEvent (write_ready)) | ||||||
|  | 	{ | ||||||
|  | 	  debug_printf ("SetEvent for write_ready failed, %E"); | ||||||
|  | 	  res = error_set_errno; | ||||||
|  | 	  goto out; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   /* If setup_overlapped() succeeds (and why wouldn't it?) we are all set. */ | ||||||
|  |   if (setup_overlapped () == 0) | ||||||
|  |     res = success; | ||||||
|   else |   else | ||||||
|     { |     { | ||||||
|       set_errno (EINVAL); |       debug_printf ("setup_overlapped failed, %E"); | ||||||
|       res = 0; |       res = error_set_errno; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (res) | out: | ||||||
|  |   if (res == error_set_errno) | ||||||
|  |     __seterrno (); | ||||||
|  |   if (res != success) | ||||||
|     { |     { | ||||||
|       char char_sa_buf[1024]; |       if (read_ready) | ||||||
|       LPSECURITY_ATTRIBUTES sa_buf = |  | ||||||
| 	sec_user_cloexec (flags & O_CLOEXEC, (PSECURITY_ATTRIBUTES) char_sa_buf, |  | ||||||
| 			  cygheap->user.sid()); |  | ||||||
|       bool do_seterrno = true; |  | ||||||
|  |  | ||||||
|       HANDLE h; |  | ||||||
|       bool nonblocking_write = !!((flags & (O_WRONLY | O_NONBLOCK)) == (O_WRONLY | O_NONBLOCK)); |  | ||||||
|       wait_state = fifo_unknown; |  | ||||||
|       if (mode != PIPE_ACCESS_OUTBOUND) |  | ||||||
| 	{ | 	{ | ||||||
| 	  h = cnp (mode |  FILE_FLAG_OVERLAPPED, FIFO_BUF_SIZE); | 	  CloseHandle (read_ready); | ||||||
| 	  wait_state = fifo_wait_for_client; | 	  read_ready = NULL; | ||||||
| 	} | 	} | ||||||
|       else |       if (write_ready) | ||||||
| 	{ | 	{ | ||||||
| 	  h = open_nonserver (npname, low_flags, sa_buf); | 	  CloseHandle (write_ready); | ||||||
| 	  if (h != INVALID_HANDLE_VALUE) | 	  write_ready = NULL; | ||||||
| 	    wait_state = fifo_ok; |  | ||||||
| 	  else if (nonblocking_write) |  | ||||||
| 	    { |  | ||||||
| 	      set_errno (ENXIO); |  | ||||||
| 	      do_seterrno = false; |  | ||||||
| 	    } |  | ||||||
| 	  else if ((h = cnp (PIPE_ACCESS_DUPLEX, 1)) != INVALID_HANDLE_VALUE) |  | ||||||
| 	    { |  | ||||||
| 	      if ((dummy_client = open_nonserver (npname, low_flags, sa_buf)) |  | ||||||
| 		  != INVALID_HANDLE_VALUE) |  | ||||||
| 		{ |  | ||||||
| 		  wait_state = fifo_wait_for_server; |  | ||||||
| 		  ProtectHandle (dummy_client); |  | ||||||
| 		} |  | ||||||
| 	      else |  | ||||||
| 		{ |  | ||||||
| 		  DWORD saveerr = GetLastError (); |  | ||||||
| 		  CloseHandle (h); |  | ||||||
| 		  h = INVALID_HANDLE_VALUE; |  | ||||||
| 		  SetLastError (saveerr); |  | ||||||
| 		} |  | ||||||
| 	    } |  | ||||||
| 	} |  | ||||||
|       if (h == INVALID_HANDLE_VALUE) |  | ||||||
| 	{ |  | ||||||
| 	  if (do_seterrno) |  | ||||||
| 	    __seterrno (); |  | ||||||
| 	  res = 0; |  | ||||||
| 	} |  | ||||||
|       else if (setup_overlapped ()) |  | ||||||
| 	{ |  | ||||||
| 	  CloseHandle (h); |  | ||||||
| 	  __seterrno (); |  | ||||||
| 	  res = 0; |  | ||||||
| 	} |  | ||||||
|       else |  | ||||||
| 	{ |  | ||||||
| 	  set_io_handle (h); |  | ||||||
| 	  set_flags (flags); |  | ||||||
| 	  res = 1; |  | ||||||
| 	} | 	} | ||||||
|  |       if (get_io_handle ()) | ||||||
|  | 	CloseHandle (get_io_handle ()); | ||||||
|     } |     } | ||||||
|  |   debug_printf ("res %d", res); | ||||||
|   debug_printf ("returning %d, errno %d", res, get_errno ()); |   return res == success; | ||||||
|   return res; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bool | bool | ||||||
| fhandler_fifo::wait (bool iswrite) | fhandler_fifo::wait (HANDLE h) | ||||||
| { | { | ||||||
|   DWORD ninstances; | #ifdef DEBUGGING | ||||||
|   switch (wait_state) |   const char *what; | ||||||
|  |   if (h == read_ready) | ||||||
|  |     what = "reader"; | ||||||
|  |   else if (h == write_ready) | ||||||
|  |     what = "writer"; | ||||||
|  |   else | ||||||
|  |     what = "overlapped event"; | ||||||
|  | #endif | ||||||
|  |   HANDLE w4[3] = {h, signal_arrived, pthread::get_cancel_event ()}; | ||||||
|  |  | ||||||
|  |   /* Set the wait to zero for non-blocking I/O-related events. */ | ||||||
|  |   DWORD wait = ((h == read_ready || h == write_ready) | ||||||
|  | 		&& get_flags () & O_NONBLOCK) ? 0 : INFINITE; | ||||||
|  |  | ||||||
|  |   debug_only_printf ("waiting for %s", what); | ||||||
|  |   /* Wait for the event.  Set errno, as appropriate if something goes wrong. */ | ||||||
|  |   switch (WaitForMultipleObjects (3, w4, false, wait)) | ||||||
|     { |     { | ||||||
|     case fifo_wait_for_next_client: |     case WAIT_OBJECT_0: | ||||||
|       DisconnectNamedPipe (get_handle ()); |       debug_only_printf ("successfully waited for %s", what); | ||||||
|       if (!GetNamedPipeHandleState (get_handle (), NULL, &ninstances, NULL, NULL, NULL, 0)) |       return true; | ||||||
|  |     case WAIT_TIMEOUT: | ||||||
|  |       if (h == write_ready) | ||||||
| 	{ | 	{ | ||||||
| 	  __seterrno (); | 	  debug_only_printf ("wait timed out waiting for write but will still open reader since non-blocking mode"); | ||||||
| 	  wait_state = fifo_error; | 	  return true; | ||||||
|  | 	} | ||||||
|  |       else | ||||||
|  | 	{ | ||||||
|  | 	  set_errno (ENXIO); | ||||||
| 	  return false; | 	  return false; | ||||||
| 	} | 	} | ||||||
|       if (ninstances <= 1) |  | ||||||
| 	{ |  | ||||||
| 	  wait_state = fifo_eof; |  | ||||||
| 	  return false; |  | ||||||
| 	} |  | ||||||
|     case fifo_wait_for_client: |  | ||||||
|       { |  | ||||||
| 	DWORD dummy_bytes; |  | ||||||
| 	while (1) |  | ||||||
| 	  { |  | ||||||
| 	    int res = ConnectNamedPipe (get_handle (), get_overlapped ()); |  | ||||||
| 	    if (GetLastError () != ERROR_NO_DATA && GetLastError () != ERROR_PIPE_CONNECTED) |  | ||||||
| 	      { |  | ||||||
| 		res = wait_overlapped (res, iswrite, &dummy_bytes, false); |  | ||||||
| 		if (!res) |  | ||||||
| 		  { |  | ||||||
| 		    if (get_errno () != EINTR) |  | ||||||
| 		      wait_state = fifo_error; |  | ||||||
| 		    else if (!_my_tls.call_signal_handler ()) |  | ||||||
| 		      wait_state = fifo_eintr; |  | ||||||
| 		    else |  | ||||||
| 		      continue; |  | ||||||
| 		    return false; |  | ||||||
| 		  } |  | ||||||
| 	      } |  | ||||||
| 	    wait_state = fifo_ok; |  | ||||||
| 	    break; |  | ||||||
| 	  } |  | ||||||
|       } |  | ||||||
|       break; |       break; | ||||||
|     case fifo_wait_for_server: |     case WAIT_OBJECT_0 + 1: | ||||||
|       char npname[MAX_PATH]; |       debug_only_printf ("interrupted by signal while waiting for %s", what); | ||||||
|       fifo_name (npname); |       set_errno (EINTR); | ||||||
|       char char_sa_buf[1024]; |       return false; | ||||||
|       LPSECURITY_ATTRIBUTES sa_buf; |     case WAIT_OBJECT_0 + 2: | ||||||
|       sa_buf = sec_user_cloexec (close_on_exec (), |       debug_only_printf ("cancellable interruption while waiting for %s", what); | ||||||
| 				 (PSECURITY_ATTRIBUTES) char_sa_buf, |       pthread::static_cancel_self ();	/* never returns */ | ||||||
| 				 cygheap->user.sid()); |       break; | ||||||
|       while (1) |  | ||||||
| 	{ |  | ||||||
| 	  if (WaitNamedPipe (npname, 10)) |  | ||||||
| 	    /* connected, maybe */; |  | ||||||
| 	  else if (GetLastError () != ERROR_SEM_TIMEOUT) |  | ||||||
| 	    { |  | ||||||
| 	      __seterrno (); |  | ||||||
| 	      return false; |  | ||||||
| 	    } |  | ||||||
| 	  else if (!IsEventSignalled (signal_arrived)) |  | ||||||
| 	    continue; |  | ||||||
| 	  else if (_my_tls.call_signal_handler ()) |  | ||||||
| 	    continue; |  | ||||||
| 	  else |  | ||||||
| 	    { |  | ||||||
| 	      set_errno (EINTR); |  | ||||||
| 	      return false; |  | ||||||
| 	    } |  | ||||||
| 	  HANDLE h = open_nonserver (npname, get_flags () & O_ACCMODE, sa_buf); |  | ||||||
| 	  if (h != INVALID_HANDLE_VALUE) |  | ||||||
| 	    { |  | ||||||
| 	      ForceCloseHandle (get_handle ()); |  | ||||||
| 	      ForceCloseHandle (dummy_client); |  | ||||||
| 	      dummy_client = NULL; |  | ||||||
| 	      wait_state = fifo_ok; |  | ||||||
| 	      set_io_handle (h); |  | ||||||
| 	      break; |  | ||||||
| 	    } |  | ||||||
| 	  if (GetLastError () == ERROR_PIPE_LISTENING) |  | ||||||
| 	    continue; |  | ||||||
| 	  else |  | ||||||
| 	    { |  | ||||||
| 	      __seterrno (); |  | ||||||
| 	      return false; |  | ||||||
| 	    } |  | ||||||
| 	} |  | ||||||
|     default: |     default: | ||||||
|       break; |       debug_only_printf ("unknown error while waiting for %s", what); | ||||||
|     } |       __seterrno (); | ||||||
|     return true; |       return false; | ||||||
|  |    } | ||||||
| } | } | ||||||
|  |  | ||||||
| void __stdcall | void __stdcall | ||||||
| fhandler_fifo::raw_read (void *in_ptr, size_t& len) | fhandler_fifo::raw_read (void *in_ptr, size_t& len) | ||||||
| { | { | ||||||
|   while (wait_state != fifo_eof && wait_state != fifo_error && wait_state != fifo_eintr) |   size_t orig_len = len; | ||||||
|     if (!wait (false)) |   for (int i = 0; i < 2; i++) | ||||||
|       len = (wait_state == fifo_error || wait_state == fifo_eintr) ? (size_t) -1 : 0; |     { | ||||||
|     else |       fhandler_base_overlapped::raw_read (in_ptr, len); | ||||||
|       { |       if (len || i || WaitForSingleObject (read_ready, 0) == WAIT_OBJECT_0) | ||||||
| 	size_t prev_len = len; | 	break; | ||||||
| 	fhandler_base_overlapped::raw_read (in_ptr, len); |       /* If we got here, then fhandler_base_overlapped::raw_read returned 0, | ||||||
| 	if (len) | 	 indicating "EOF" and something has set read_ready to zero.  That means | ||||||
| 	  break; | 	 we should have a client waiting to connect. | ||||||
| 	wait_state = fifo_wait_for_next_client; | 	 FIXME: If the client CTRL-C's the open during this time then this | ||||||
| 	len = prev_len; | 	 could hang indefinitely.  Maybe implement a timeout?  */ | ||||||
|       } |       if (!DisconnectNamedPipe (get_io_handle ())) | ||||||
|   if (wait_state == fifo_eintr) | 	{ | ||||||
|     wait_state = fifo_wait_for_client; | 	  debug_printf ("DisconnecttNamedPipe failed, %E"); | ||||||
|   debug_printf ("returning %d, mode %d, %E\n", len, get_errno ()); | 	  goto errno_out; | ||||||
| } | 	} | ||||||
|  |       else if (!ConnectNamedPipe (get_io_handle (), get_overlapped ()) | ||||||
|  | 	       && GetLastError () != ERROR_IO_PENDING) | ||||||
|  | 	{ | ||||||
|  | 	  debug_printf ("ConnectNamedPipe failed, %E"); | ||||||
|  | 	  goto errno_out; | ||||||
|  | 	} | ||||||
|  |       else if (!SetEvent (read_ready)) | ||||||
|  | 	{ | ||||||
|  | 	  debug_printf ("SetEvent (read_ready) failed, %E"); | ||||||
|  | 	  goto errno_out; | ||||||
|  | 	} | ||||||
|  |       else if (!wait (get_overlapped_buffer ()->hEvent)) | ||||||
|  | 	goto errout;	/* If wait() fails, errno is set so no need to set it */ | ||||||
|  |       len = orig_len;	/* Reset since raw_read above set it to zero. */ | ||||||
|  |     } | ||||||
|  |   return; | ||||||
|  |  | ||||||
| ssize_t __stdcall | errno_out: | ||||||
| fhandler_fifo::raw_write (const void *ptr, size_t len) |   __seterrno (); | ||||||
| { | errout: | ||||||
|   return wait (true) ? fhandler_base_overlapped::raw_write (ptr, len) : -1; |   len = -1; | ||||||
| } | } | ||||||
|  |  | ||||||
| int __stdcall | int __stdcall | ||||||
| @@ -293,41 +303,52 @@ fhandler_fifo::fstatvfs (struct statvfs *sfs) | |||||||
| int | int | ||||||
| fhandler_fifo::close () | fhandler_fifo::close () | ||||||
| { | { | ||||||
|   wait_state = fifo_eof; |   CloseHandle (read_ready); | ||||||
|   if (dummy_client) |   CloseHandle (write_ready); | ||||||
|     { |  | ||||||
|       ForceCloseHandle (dummy_client); |  | ||||||
|       dummy_client = NULL; |  | ||||||
|     } |  | ||||||
|   return fhandler_base::close (); |   return fhandler_base::close (); | ||||||
| } | } | ||||||
|  |  | ||||||
| int | int | ||||||
| fhandler_fifo::dup (fhandler_base *child, int flags) | fhandler_fifo::dup (fhandler_base *child, int flags) | ||||||
| { | { | ||||||
|   int res = fhandler_base_overlapped::dup (child, flags); |   if (fhandler_base_overlapped::dup (child, flags)) | ||||||
|   fhandler_fifo *fifo_child = (fhandler_fifo *) child; |  | ||||||
|   if (res == 0 && dummy_client) |  | ||||||
|     { |     { | ||||||
|       bool dres = DuplicateHandle (GetCurrentProcess (), dummy_client, |       __seterrno (); | ||||||
| 				   GetCurrentProcess (), |       return -1; | ||||||
| 				   &fifo_child->dummy_client, 0, |  | ||||||
| 				   TRUE, DUPLICATE_SAME_ACCESS); |  | ||||||
|       if (!dres) |  | ||||||
| 	{ |  | ||||||
| 	  fifo_child->dummy_client = NULL; |  | ||||||
| 	  child->close (); |  | ||||||
| 	  __seterrno (); |  | ||||||
| 	  res = -1; |  | ||||||
| 	} |  | ||||||
|     } |     } | ||||||
|   return res; |   fhandler_fifo *fhf = (fhandler_fifo *) child; | ||||||
|  |   if (!DuplicateHandle (GetCurrentProcess (), read_ready, | ||||||
|  | 			GetCurrentProcess (), &fhf->read_ready, | ||||||
|  | 			0, true, DUPLICATE_SAME_ACCESS)) | ||||||
|  |     { | ||||||
|  |       fhf->close (); | ||||||
|  |       __seterrno (); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |   if (!DuplicateHandle (GetCurrentProcess (), write_ready, | ||||||
|  | 			GetCurrentProcess (), &fhf->write_ready, | ||||||
|  | 			0, true, DUPLICATE_SAME_ACCESS)) | ||||||
|  |     { | ||||||
|  |       CloseHandle (fhf->read_ready); | ||||||
|  |       fhf->close (); | ||||||
|  |       __seterrno (); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | fhandler_fifo::fixup_after_fork (HANDLE parent) | ||||||
|  | { | ||||||
|  |   fhandler_base_overlapped::fixup_after_fork (parent); | ||||||
|  |   fork_fixup (parent, read_ready, "read_ready"); | ||||||
|  |   fork_fixup (parent, write_ready, "write_ready"); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | void | ||||||
| fhandler_fifo::set_close_on_exec (bool val) | fhandler_fifo::set_close_on_exec (bool val) | ||||||
| { | { | ||||||
|   fhandler_base::set_close_on_exec (val); |   fhandler_base::set_close_on_exec (val); | ||||||
|   if (dummy_client) |   set_no_inheritance (read_ready, val); | ||||||
|     set_no_inheritance (dummy_client, val); |   set_no_inheritance (write_ready, val); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1624,8 +1624,8 @@ fhandler_pty_master::setup () | |||||||
|  |  | ||||||
|   char pipename[sizeof("ptyNNNN-from-master")]; |   char pipename[sizeof("ptyNNNN-from-master")]; | ||||||
|   __small_sprintf (pipename, "pty%d-to-master", unit); |   __small_sprintf (pipename, "pty%d-to-master", unit); | ||||||
|   res = fhandler_pipe::create_selectable (&sec_none, get_io_handle (), |   res = fhandler_pipe::create_selectable (&sec_none, &get_io_handle (), | ||||||
| 					  to_master, 128 * 1024, pipename); | 					  &to_master, 128 * 1024, pipename, 0); | ||||||
|   if (res) |   if (res) | ||||||
|     { |     { | ||||||
|       errstr = "output pipe"; |       errstr = "output pipe"; | ||||||
|   | |||||||
| @@ -125,6 +125,11 @@ void strace_printf (unsigned, const char *func, const char *, ...); | |||||||
|     })) |     })) | ||||||
| #endif /*NOSTRACE*/ | #endif /*NOSTRACE*/ | ||||||
|  |  | ||||||
|  | #ifdef DEBUGGING | ||||||
|  | #define debug_only_printf(fmt, args...) debug_printf (fmt , ## args) | ||||||
|  | #else | ||||||
|  | #define debug_only_printf(fmt, args...) do {} while (0) | ||||||
|  | #endif | ||||||
| #define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args) | #define debug_printf(fmt, args...) strace_printf_wrap(DEBUG, fmt , ## args) | ||||||
| #define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args) | #define malloc_printf(fmt, args...) strace_printf_wrap1(MALLOC, fmt , ## args) | ||||||
| #define minimal_printf(fmt, args...) strace_printf_wrap1(MINIMAL, fmt , ## args) | #define minimal_printf(fmt, args...) strace_printf_wrap1(MINIMAL, fmt , ## args) | ||||||
|   | |||||||
| @@ -337,7 +337,8 @@ nice_to_winprio (int &nice) | |||||||
| BOOL WINAPI | BOOL WINAPI | ||||||
| CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa) | CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa) | ||||||
| { | { | ||||||
|   int ret = fhandler_pipe::create_selectable (sa, *hr, *hw, 0); |   int ret = fhandler_pipe::create_selectable (sa, hr, hw, 0, NULL, | ||||||
|  | 					      FILE_FLAG_OVERLAPPED); | ||||||
|   if (ret) |   if (ret) | ||||||
|     SetLastError (ret); |     SetLastError (ret); | ||||||
|   return ret == 0; |   return ret == 0; | ||||||
|   | |||||||
| @@ -197,11 +197,14 @@ fhandler_pipe::dup (fhandler_base *child, int flags) | |||||||
|    Note that the return value is either 0 or GetLastError, |    Note that the return value is either 0 or GetLastError, | ||||||
|    unlike CreatePipe, which returns a bool for success or failure.  */ |    unlike CreatePipe, which returns a bool for success or failure.  */ | ||||||
| int | int | ||||||
| fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE *r, | ||||||
| 				  HANDLE& w, DWORD psize, const char *name) | 				  HANDLE *w, DWORD psize, const char *name, DWORD open_mode) | ||||||
| { | { | ||||||
|   /* Default to error. */ |   /* Default to error. */ | ||||||
|   r = w = INVALID_HANDLE_VALUE; |   if (r) | ||||||
|  |     *r = NULL; | ||||||
|  |   if (w) | ||||||
|  |     *w = NULL; | ||||||
|  |  | ||||||
|   /* Ensure that there is enough pipe buffer space for atomic writes.  */ |   /* Ensure that there is enough pipe buffer space for atomic writes.  */ | ||||||
|   if (psize < DEFAULT_PIPEBUFSIZE) |   if (psize < DEFAULT_PIPEBUFSIZE) | ||||||
| @@ -210,26 +213,24 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | |||||||
|   char pipename[MAX_PATH]; |   char pipename[MAX_PATH]; | ||||||
|   const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", |   const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-", | ||||||
| 				      &installation_key); | 				      &installation_key); | ||||||
|  |   if (name) | ||||||
|  |     strcpy (pipename + len, name); | ||||||
|  |  | ||||||
|   /* FIXME: Eventually make ttys work with overlapped I/O. */ |   open_mode |= PIPE_ACCESS_INBOUND; | ||||||
|   DWORD overlapped = name ? 0 : FILE_FLAG_OVERLAPPED; |  | ||||||
|  |  | ||||||
|   /* Retry CreateNamedPipe as long as the pipe name is in use. |   /* Retry CreateNamedPipe as long as the pipe name is in use. | ||||||
|      Retrying will probably never be necessary, but we want |      Retrying will probably never be necessary, but we want | ||||||
|      to be as robust as possible.  */ |      to be as robust as possible.  */ | ||||||
|   DWORD err; |   DWORD err = 0; | ||||||
|   do |   while (r && !*r) | ||||||
|     { |     { | ||||||
|       static volatile ULONG pipe_unique_id; |       static volatile ULONG pipe_unique_id; | ||||||
|       if (!name) |       if (!name) | ||||||
| 	__small_sprintf (pipename + len, "pipe-%p-%p", myself->pid, | 	__small_sprintf (pipename + len, "pipe-%p-%p", myself->pid, | ||||||
| 			InterlockedIncrement ((LONG *) &pipe_unique_id)); | 			InterlockedIncrement ((LONG *) &pipe_unique_id)); | ||||||
|       else |  | ||||||
| 	strcpy (pipename + len, name); |  | ||||||
|  |  | ||||||
|       debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize); |       debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize); | ||||||
|  |  | ||||||
|       err = 0; |  | ||||||
|       /* Use CreateNamedPipe instead of CreatePipe, because the latter |       /* Use CreateNamedPipe instead of CreatePipe, because the latter | ||||||
| 	 returns a write handle that does not permit FILE_READ_ATTRIBUTES | 	 returns a write handle that does not permit FILE_READ_ATTRIBUTES | ||||||
| 	 access, on versions of win32 earlier than WinXP SP2. | 	 access, on versions of win32 earlier than WinXP SP2. | ||||||
| @@ -245,13 +246,14 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | |||||||
| 	 definitely required for pty handling since fhandler_pty_master | 	 definitely required for pty handling since fhandler_pty_master | ||||||
| 	 writes to the pipe in chunks, terminated by newline when CANON mode | 	 writes to the pipe in chunks, terminated by newline when CANON mode | ||||||
| 	 is specified.  */ | 	 is specified.  */ | ||||||
|       r = CreateNamedPipe (pipename, PIPE_ACCESS_INBOUND | overlapped, |       *r = CreateNamedPipe (pipename, open_mode, | ||||||
| 			   PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE, 1, psize, | 			   PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE, 1, psize, | ||||||
| 			   psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); | 			   psize, NMPWAIT_USE_DEFAULT_WAIT, sa_ptr); | ||||||
|  |  | ||||||
|       if (r != INVALID_HANDLE_VALUE) |       if (*r != INVALID_HANDLE_VALUE) | ||||||
| 	{ | 	{ | ||||||
| 	  debug_printf ("pipe read handle %p", r); | 	  debug_printf ("pipe read handle %p", *r); | ||||||
|  | 	  err = 0; | ||||||
| 	  break; | 	  break; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -261,43 +263,58 @@ fhandler_pipe::create_selectable (LPSECURITY_ATTRIBUTES sa_ptr, HANDLE& r, | |||||||
| 	case ERROR_PIPE_BUSY: | 	case ERROR_PIPE_BUSY: | ||||||
| 	  /* The pipe is already open with compatible parameters. | 	  /* The pipe is already open with compatible parameters. | ||||||
| 	     Pick a new name and retry.  */ | 	     Pick a new name and retry.  */ | ||||||
| 	  debug_printf ("pipe busy", name ? ", retrying" : ""); | 	  debug_printf ("pipe busy", !name ? ", retrying" : ""); | ||||||
|  | 	  if (!*name) | ||||||
|  | 	    *r = NULL; | ||||||
| 	  break; | 	  break; | ||||||
| 	case ERROR_ACCESS_DENIED: | 	case ERROR_ACCESS_DENIED: | ||||||
| 	  /* The pipe is already open with incompatible parameters. | 	  /* The pipe is already open with incompatible parameters. | ||||||
| 	     Pick a new name and retry.  */ | 	     Pick a new name and retry.  */ | ||||||
| 	  debug_printf ("pipe access denied%s", name ? ", retrying" : ""); | 	  debug_printf ("pipe access denied%s", !name ? ", retrying" : ""); | ||||||
|  | 	  if (!*name) | ||||||
|  | 	    *r = NULL; | ||||||
| 	  break; | 	  break; | ||||||
| 	default: | 	default: | ||||||
| 	  { | 	  { | ||||||
| 	    err = GetLastError (); | 	    err = GetLastError (); | ||||||
| 	    debug_printf ("CreatePipe failed, %E"); | 	    debug_printf ("failed, %E"); | ||||||
| 	    return err; |  | ||||||
| 	  } | 	  } | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|   while (!name); |  | ||||||
|  |  | ||||||
|   if (err) |   if (err) | ||||||
|     return err; |  | ||||||
|  |  | ||||||
|   debug_printf ("CreateFile: name %s", pipename); |  | ||||||
|  |  | ||||||
|   /* Open the named pipe for writing. |  | ||||||
|      Be sure to permit FILE_READ_ATTRIBUTES access.  */ |  | ||||||
|   w = CreateFile (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, sa_ptr, |  | ||||||
| 		  OPEN_EXISTING, overlapped, 0); |  | ||||||
|  |  | ||||||
|   if (!w || w == INVALID_HANDLE_VALUE) |  | ||||||
|     { |     { | ||||||
|       /* Failure. */ |       *r = NULL; | ||||||
|       DWORD err = GetLastError (); |  | ||||||
|       debug_printf ("CreateFile failed, %E"); |  | ||||||
|       CloseHandle (r); |  | ||||||
|       return err; |       return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   debug_printf ("pipe write handle %p", w); |   if (!w) | ||||||
|  |     debug_printf ("pipe write handle NULL"); | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       debug_printf ("CreateFile: name %s", pipename); | ||||||
|  |  | ||||||
|  |       /* Open the named pipe for writing. | ||||||
|  | 	 Be sure to permit FILE_READ_ATTRIBUTES access.  */ | ||||||
|  |       DWORD access = GENERIC_WRITE | FILE_READ_ATTRIBUTES; | ||||||
|  |       if ((open_mode & PIPE_ACCESS_DUPLEX) == PIPE_ACCESS_DUPLEX) | ||||||
|  | 	access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; | ||||||
|  |       *w = CreateFile (pipename, access, 0, sa_ptr, OPEN_EXISTING, | ||||||
|  | 		      open_mode & FILE_FLAG_OVERLAPPED, 0); | ||||||
|  |  | ||||||
|  |       if (!*w || *w == INVALID_HANDLE_VALUE) | ||||||
|  | 	{ | ||||||
|  | 	  /* Failure. */ | ||||||
|  | 	  DWORD err = GetLastError (); | ||||||
|  | 	  debug_printf ("CreateFile failed, %E"); | ||||||
|  | 	  if (r) | ||||||
|  | 	    CloseHandle (*r); | ||||||
|  | 	  *w = NULL; | ||||||
|  | 	  return err; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |       debug_printf ("pipe write handle %p", *w); | ||||||
|  |     } | ||||||
|  |  | ||||||
|   /* Success. */ |   /* Success. */ | ||||||
|   return 0; |   return 0; | ||||||
| @@ -310,7 +327,7 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) | |||||||
|   SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); |   SECURITY_ATTRIBUTES *sa = sec_none_cloexec (mode); | ||||||
|   int res = -1; |   int res = -1; | ||||||
|  |  | ||||||
|   int ret = create_selectable (sa, r, w, psize); |   int ret = create_selectable (sa, &r, &w, psize, NULL, FILE_FLAG_OVERLAPPED); | ||||||
|   if (ret) |   if (ret) | ||||||
|     __seterrno_from_win_error (ret); |     __seterrno_from_win_error (ret); | ||||||
|   else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) |   else if ((fhs[0] = (fhandler_pipe *) build_fh_dev (*piper_dev)) == NULL) | ||||||
|   | |||||||
| @@ -159,8 +159,8 @@ tty::not_allocated (HANDLE& r, HANDLE& w) | |||||||
|   char pipename[sizeof("ptyNNNN-from-master")]; |   char pipename[sizeof("ptyNNNN-from-master")]; | ||||||
|   __small_sprintf (pipename, "pty%d-from-master", get_unit ()); |   __small_sprintf (pipename, "pty%d-from-master", get_unit ()); | ||||||
|   /* fhandler_pipe::create_selectable returns 0 when creation succeeds */ |   /* fhandler_pipe::create_selectable returns 0 when creation succeeds */ | ||||||
|   return fhandler_pipe::create_selectable (&sec_none, r, w, 128 * 1024, |   return fhandler_pipe::create_selectable (&sec_none, &r, &w, 128 * 1024, | ||||||
| 					   pipename) == 0; | 					   pipename, 0) == 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool | bool | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user