Cygwin: FIFO: add support for the duplex case
If a FIFO is opened with O_RDWR access, create the pipe with read/write access, and make the first client have the handle of that pipe as its I/O handle. Adjust fhandler_fifo::raw_read to account for the result of trying to read from that client if there's no data.
This commit is contained in:
		
				
					committed by
					
						 Corinna Vinschen
						Corinna Vinschen
					
				
			
			
				
	
			
			
			
						parent
						
							40db74128a
						
					
				
				
					commit
					a137da74ba
				
			| @@ -1253,6 +1253,10 @@ struct fifo_client_handler | ||||
|   HANDLE dummy_evt;		/* Never signaled. */ | ||||
|   fifo_client_handler () : fh (NULL), state (fc_unknown), connect_evt (NULL), | ||||
| 			   dummy_evt (NULL) {} | ||||
|   fifo_client_handler (fhandler_base *_fh, fifo_client_connect_state _state, | ||||
| 		       HANDLE _connect_evt, HANDLE _dummy_evt) | ||||
|     : fh (_fh), state (_state), connect_evt (_connect_evt), | ||||
|       dummy_evt (_dummy_evt) {} | ||||
|   int connect (); | ||||
|   int close (); | ||||
| }; | ||||
| @@ -1268,6 +1272,7 @@ class fhandler_fifo: public fhandler_base | ||||
|   fifo_client_handler client[MAX_CLIENTS]; | ||||
|   int nclients, nconnected; | ||||
|   af_unix_spinlock_t _fifo_client_lock; | ||||
|   bool _duplexer; | ||||
|   bool __reg2 wait (HANDLE); | ||||
|   NTSTATUS npfs_handle (HANDLE &); | ||||
|   HANDLE create_pipe_instance (bool); | ||||
|   | ||||
| @@ -33,7 +33,7 @@ STATUS_PIPE_EMPTY simply means there's no data to be read. */ | ||||
| fhandler_fifo::fhandler_fifo (): | ||||
|   fhandler_base (), read_ready (NULL), write_ready (NULL), | ||||
|   listen_client_thr (NULL), lct_termination_evt (NULL), nclients (0), | ||||
|   nconnected (0) | ||||
|   nconnected (0), _duplexer (false) | ||||
| { | ||||
|   pipe_name_buf[0] = L'\0'; | ||||
|   need_fork_fixup (true); | ||||
| @@ -224,6 +224,8 @@ fhandler_fifo::create_pipe_instance (bool first) | ||||
|     } | ||||
|   access = GENERIC_READ | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | ||||
|     | SYNCHRONIZE; | ||||
|   if (first && _duplexer) | ||||
|     access |= GENERIC_WRITE; | ||||
|   sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; | ||||
|   hattr = OBJ_INHERIT; | ||||
|   if (first) | ||||
| @@ -437,7 +439,7 @@ fhandler_fifo::open (int flags, mode_t) | ||||
|     case O_RDWR: | ||||
|       reader = true; | ||||
|       writer = false; | ||||
|       duplexer = true; | ||||
|       duplexer = _duplexer = true; | ||||
|       break; | ||||
|     default: | ||||
|       set_errno (EINVAL); | ||||
| @@ -447,7 +449,7 @@ fhandler_fifo::open (int flags, mode_t) | ||||
|  | ||||
|   debug_only_printf ("reader %d, writer %d, duplexer %d", reader, writer, duplexer); | ||||
|   set_flags (flags); | ||||
|   if (reader) | ||||
|   if (reader && !duplexer) | ||||
|     nohandle (true); | ||||
|  | ||||
|   /* Create control events for this named pipe */ | ||||
| @@ -472,6 +474,48 @@ fhandler_fifo::open (int flags, mode_t) | ||||
|       goto out; | ||||
|     } | ||||
|  | ||||
|   /* If we're a duplexer, create the pipe and the first client. */ | ||||
|   if (duplexer) | ||||
|     { | ||||
|       HANDLE ph, connect_evt, dummy_evt; | ||||
|       fhandler_base *fh; | ||||
|  | ||||
|       ph = create_pipe_instance (true); | ||||
|       if (!ph) | ||||
| 	{ | ||||
| 	  res = error_errno_set; | ||||
| 	  goto out; | ||||
| 	} | ||||
|       set_io_handle (ph); | ||||
|       set_pipe_non_blocking (ph, true); | ||||
|       if (!(fh = build_fh_dev (dev ()))) | ||||
| 	{ | ||||
| 	  set_errno (EMFILE); | ||||
| 	  res = error_errno_set; | ||||
| 	  goto out; | ||||
| 	} | ||||
|       fh->set_io_handle (ph); | ||||
|       fh->set_flags (flags); | ||||
|       if (!(connect_evt = create_event ())) | ||||
| 	{ | ||||
| 	  res = error_errno_set; | ||||
| 	  fh->close (); | ||||
| 	  delete fh; | ||||
| 	  goto out; | ||||
| 	} | ||||
|       if (!(dummy_evt = create_event ())) | ||||
| 	{ | ||||
| 	  res = error_errno_set; | ||||
| 	  delete fh; | ||||
| 	  fh->close (); | ||||
| 	  CloseHandle (connect_evt); | ||||
| 	  goto out; | ||||
| 	} | ||||
|       client[0] = fifo_client_handler (fh, fc_connected, connect_evt, | ||||
| 				       dummy_evt); | ||||
|       nconnected = nclients = 1; | ||||
|     } | ||||
|  | ||||
|   /* If we're reading, start the listen_client thread (which should | ||||
|      signal read_ready), and wait for a writer. */ | ||||
|   if (reader) | ||||
| @@ -482,8 +526,8 @@ fhandler_fifo::open (int flags, mode_t) | ||||
| 	  res = error_errno_set; | ||||
| 	  goto out; | ||||
| 	} | ||||
|       /* Wait for the listen_client thread to create the pipe and | ||||
| 	 signal read_ready.  This should be quick.  */ | ||||
|       /* Wait for the listen_client thread to signal read_ready.  This | ||||
| 	 should be quick.  */ | ||||
|       HANDLE w[2] = { listen_client_thr, read_ready }; | ||||
|       switch (WaitForMultipleObjects (2, w, FALSE, INFINITE)) | ||||
| 	{ | ||||
| @@ -703,12 +747,25 @@ fhandler_fifo::raw_read (void *in_ptr, size_t& len) | ||||
| 		fifo_client_unlock (); | ||||
| 		return; | ||||
| 	      } | ||||
| 	    else if (nread < 0 && GetLastError () != ERROR_NO_DATA) | ||||
| 	    /* In the duplex case with no data, we seem to get nread | ||||
| 	       == -1 with ERROR_PIPE_LISTENING on the first attempt to | ||||
| 	       read from the duplex pipe (client[0]), and nread == 0 | ||||
| 	       on subsequent attempts. */ | ||||
| 	    else if (nread < 0) | ||||
| 	      switch (GetLastError ()) | ||||
| 		{ | ||||
| 		case ERROR_NO_DATA: | ||||
| 		  break; | ||||
| 		case ERROR_PIPE_LISTENING: | ||||
| 		  if (_duplexer && i == 0) | ||||
| 		    break; | ||||
| 		  /* Fall through. */ | ||||
| 		default: | ||||
| 		  fifo_client_unlock (); | ||||
| 		  goto errout; | ||||
| 		} | ||||
| 	    else if (nread == 0) /* Client has disconnected. */ | ||||
| 	    else if (nread == 0 && (!_duplexer || i > 0)) | ||||
| 	      /* Client has disconnected. */ | ||||
| 	      { | ||||
| 		client[i].state = fc_invalid; | ||||
| 		nconnected--; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user