diff options
author | Christopher Faylor <me@cgf.cx> | 2009-07-25 00:54:33 +0400 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2009-07-25 00:54:33 +0400 |
commit | 43c23d4b822cc23f35c3668272526bebf3630454 (patch) | |
tree | 90bda14088be11218540c2b991cabb39f062a9ee /winsup/cygwin/fhandler_fifo.cc | |
parent | a58ebe50c216947d748e51c16d3fa93f9b98ed30 (diff) |
* sigproc.h (wait_for_sigthread): Eliminate parameter.
* sigproc.cc (wait_for_sigthread): Ditto. Don't synchronize with wait_sig
after receiving an event that it is ready to go.
(init_sig_pipe): New function.
(wait_sig): Call init_sig_pipe to create pipes for communicating signals to
this process. Don't send sigCONT signal when initializing.
* fork.cc (frok::child): Accommodate wait_for_sigpipe parameter change.
* fhandler.h (fhandler_*::write): Make ssize_t/__stdcall.
(fhandler_*::write_overlapped): Ditto.
(fhandler_*::raw_write): Ditto.
(fhandler_*::readv): Ditto.
(fhandler_*::writev): Ditto.
(fhandler_*::raw_read): Make __stdcall.
* fhandler: Accommodate changes to read/write functions throughout.
* fhandler_clipboard.cc: Ditto.
* fhandler_console.cc: Ditto.
* fhandler_dsp.cc: Ditto.
* fhandler_fifo.cc: Ditto.
* fhandler_mailslot.cc: Ditto.
* fhandler_mem.cc: Ditto.
* fhandler_mem.cc: Ditto.
* fhandler_random.cc: Ditto.
* fhandler_tape.cc: Ditto.
* fhandler_tty.cc: Ditto.
* fhandler_virtual.cc: Ditto.
* fhandler_windows.cc: Ditto.
* fhandler_zero.cc: Ditto.
* syscalls.cc (readv): Use ssize_t as temp variable.
* fhandler.cc (fhandler_base::read): Coerce returned len to signed or it will
never be treated as < 0.
(fhandler_base::wait_overlapped): Minimize calls to GetLastError. Remove
duplicate debugging test. Fix error return.
* fhandler.h (fhandler_fifo::fifo_name): Declare new function.
(fhandler_fifo::close): Ditto.
(fhandler_fifo::dup): Ditto.
(fhandler_fifo::close_on_exec): Ditto.
* fhandler.cc (fhandler_fifo::fifo_name): Define new function.
(FIFO_BUF_SIZE): New define.
(cnp): Ditto.
(fhandler_fifo::open): Rework. Use cnp to open named pipe. Always open write
side as a client. Open dummy client when writing and can't connect.
(wait): Rework. Implement fifo_wait_for_next_client. Handle signals during
connect better. Add new fifo_wait_for_server code which polls
(sigh) waiting for server.
(fhandler_fifo::raw_read): Handle transition states when one client closes and
another is available.
(fhandler_fifo::close): Define.
(fhandler_fifo::dup): Ditto.
(fhandler_fifo::close_on_exec): Ditto.
Diffstat (limited to 'winsup/cygwin/fhandler_fifo.cc')
-rw-r--r-- | winsup/cygwin/fhandler_fifo.cc | 235 |
1 files changed, 182 insertions, 53 deletions
diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc index 517eceb31..d96616fc5 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -21,7 +21,7 @@ #include "cygtls.h" fhandler_fifo::fhandler_fifo (): - wait_state (fifo_unknown) + wait_state (fifo_unknown), dummy_client (NULL) { get_overlapped ()->hEvent = NULL; need_fork_fixup (true); @@ -54,80 +54,87 @@ fhandler_fifo::open_nonserver (const char *npname, unsigned low_flags, } } +char * +fhandler_fifo::fifo_name (char *buf) +{ + /* Generate a semi-unique name to associate with this fifo. */ + __small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%08x_%016X", + get_dev (), get_ino ()); + 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) + int fhandler_fifo::open (int flags, mode_t) { - int res; + int res = 1; char npname[MAX_PATH]; - DWORD mode = 0; - - /* Generate a semi-unique name to associate with this fifo. */ - __small_sprintf (npname, "\\\\.\\pipe\\__cygfifo__%08x_%016X", - get_dev (), get_ino ()); + fifo_name (npname); unsigned low_flags = flags & O_ACCMODE; - if (low_flags == O_RDONLY) - mode = PIPE_ACCESS_INBOUND; - else if (low_flags == O_WRONLY) + DWORD mode = 0; + if (low_flags == O_WRONLY) mode = PIPE_ACCESS_OUTBOUND; - else if (low_flags == O_RDWR) + else if (low_flags == O_RDONLY || low_flags == O_RDWR) mode = PIPE_ACCESS_DUPLEX; - - if (!mode) + else { set_errno (EINVAL); res = 0; } - else + + if (res) { char char_sa_buf[1024]; LPSECURITY_ATTRIBUTES sa_buf = sec_user ((PSECURITY_ATTRIBUTES) char_sa_buf, cygheap->user.sid()); - mode |= FILE_FLAG_OVERLAPPED; HANDLE h; - DWORD err; bool nonblocking_write = !!((flags & (O_WRONLY | O_NONBLOCK)) == (O_WRONLY | O_NONBLOCK)); - if (nonblocking_write) + wait_state = fifo_unknown; + if (mode != PIPE_ACCESS_OUTBOUND) { - h = INVALID_HANDLE_VALUE; - err = ERROR_ACCESS_DENIED; + h = cnp (mode | FILE_FLAG_OVERLAPPED, FIFO_BUF_SIZE); + wait_state = fifo_wait_for_client; } else { - h = CreateNamedPipe(npname, mode, FIFO_PIPE_MODE, - PIPE_UNLIMITED_INSTANCES, 0, 0, - NMPWAIT_WAIT_FOREVER, sa_buf); - err = GetLastError (); - } - if (h != INVALID_HANDLE_VALUE) - wait_state = fifo_wait_for_client; - else - switch (err) + h = open_nonserver (npname, low_flags, sa_buf); + if (h != INVALID_HANDLE_VALUE) + wait_state = fifo_ok; + else if (nonblocking_write) + set_errno (ENXIO); + else if ((h = cnp (PIPE_ACCESS_DUPLEX, 1)) != INVALID_HANDLE_VALUE) { - case ERROR_ACCESS_DENIED: - h = open_nonserver (npname, low_flags, sa_buf); - if (h != INVALID_HANDLE_VALUE) + if ((dummy_client = open_nonserver (npname, low_flags, sa_buf)) + != INVALID_HANDLE_VALUE) { wait_state = fifo_wait_for_server; - break; + ProtectHandle (dummy_client); } - if (nonblocking_write && GetLastError () == ERROR_FILE_NOT_FOUND) + else { - set_errno (ENXIO); - break; + DWORD saveerr = GetLastError (); + CloseHandle (h); + h = INVALID_HANDLE_VALUE; + SetLastError (saveerr); } - /* fall through intentionally */ - default: - __seterrno (); - break; } - if (!h || h == INVALID_HANDLE_VALUE) - res = 0; + } + if (h == INVALID_HANDLE_VALUE) + { + __seterrno (); + res = 0; + } else if (!setup_overlapped ()) { + CloseHandle (h); __seterrno (); res = 0; } @@ -146,35 +153,116 @@ fhandler_fifo::open (int flags, mode_t) bool fhandler_fifo::wait (bool iswrite) { + DWORD ninstances; switch (wait_state) { + case fifo_wait_for_next_client: + DisconnectNamedPipe (get_handle ()); + if (!GetNamedPipeHandleState (get_handle (), NULL, &ninstances, NULL, NULL, NULL, 0)) + { + __seterrno (); + wait_state = fifo_error; + return false; + } + if (ninstances <= 1) + { + wait_state = fifo_eof; + return false; + } case fifo_wait_for_client: { - bool res = ConnectNamedPipe (get_handle (), get_overlapped ()); DWORD dummy_bytes; - if (res || GetLastError () == ERROR_PIPE_CONNECTED) - return true; - return wait_overlapped (res, iswrite, &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); + 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; + } } - case fifo_unknown: + break; case fifo_wait_for_server: - /* CGF FIXME SOON: test if these really need to be handled. */ + char npname[MAX_PATH]; + fifo_name (npname); + char char_sa_buf[1024]; + LPSECURITY_ATTRIBUTES sa_buf; + sa_buf = sec_user ((PSECURITY_ATTRIBUTES) char_sa_buf, cygheap->user.sid()); + while (1) + { + if (WaitNamedPipe (npname, 10)) + /* connected, maybe */; + else if (GetLastError () != ERROR_SEM_TIMEOUT) + { + __seterrno (); + return false; + } + else if (WaitForSingleObject (signal_arrived, 0) != WAIT_OBJECT_0) + 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: break; } return true; } -void +void __stdcall fhandler_fifo::raw_read (void *in_ptr, size_t& len) { - if (!wait (false)) - len = 0; - else - read_overlapped (in_ptr, len); + while (wait_state != fifo_eof && wait_state != fifo_error && wait_state != fifo_eintr) + if (!wait (false)) + len = (wait_state == fifo_error || wait_state == fifo_eintr) ? (size_t) -1 : 0; + else + { + size_t prev_len = len; + read_overlapped (in_ptr, len); + if (len) + break; + wait_state = fifo_wait_for_next_client; + len = prev_len; + } + if (wait_state == fifo_eintr) + wait_state = fifo_wait_for_client; + debug_printf ("returning %d, mode %d, %E\n", len, get_errno ()); } -int +ssize_t __stdcall fhandler_fifo::raw_write (const void *ptr, size_t len) { return wait (true) ? write_overlapped (ptr, len) : -1; @@ -187,3 +275,44 @@ fhandler_fifo::fstatvfs (struct statvfs *sfs) fh.get_device () = FH_FS; return fh.fstatvfs (sfs); } + +int +fhandler_fifo::close () +{ + wait_state = fifo_eof; + if (dummy_client) + { + ForceCloseHandle (dummy_client); + dummy_client = NULL; + } + return fhandler_base::close (); +} + +int +fhandler_fifo::dup (fhandler_base *child) +{ + int res = fhandler_base::dup (child); + fhandler_fifo *fifo_child = (fhandler_fifo *) child; + if (res == 0 && dummy_client) + { + bool dres = DuplicateHandle (hMainProc, dummy_client, hMainProc, + &fifo_child->dummy_client, 0, + TRUE, DUPLICATE_SAME_ACCESS); + if (!dres) + { + fifo_child->dummy_client = NULL; + child->close (); + __seterrno (); + res = -1; + } + } + return res; +} + +void +fhandler_fifo::set_close_on_exec (bool val) +{ + fhandler_base::set_close_on_exec (val); + if (dummy_client) + set_no_inheritance (dummy_client, val); +} |