From: Christopher Faylor Date: Sun, 16 Dec 2007 21:21:23 +0000 (+0000) Subject: * dtable.cc (POSIX_NAMED_PIPE): New define. X-Git-Tag: sid-snapshot-20080101~10 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=634a41403c1439e1c6f3ee4252cf5a091bcc6921;p=newlib-cygwin.git * dtable.cc (POSIX_NAMED_PIPE): New define. (POSIX_NAMED_PIPE_LEN): Ditto. (dtable::add_archetype): Use crealloc_abort. (dtable::init_std_file_from_handle): Specifically detect pipe stdin/stdout. Pass name to build_fh_dev so that proper name is recorded. Use binmode of fh if it is set before using get_default_mode. Set proper read/write access when calling init(). (handle_to_fn): Handle pipes. * fhandler.cc (fhandler_base::wait_overlapped): Add some debugging. * fhandler.h (fhandler_base::set_name): Default to just setting the path_conv name. (fhandler_pipe::init): Declare. * pipe.cc (struct pipesync): New struct. (getov_result): New function. Blocks and retrieves the result of an overlay I/O operation. (pipe_handler): New function. (pipesync::pipesync): New function. Initializer for pipesync struct. (handler_pipe::init): Define. Detects attempts to set up a "native" pipe fhandler and creates a thread which accepts input from or output to the non-cygwin pipe, creating a cygwin pipe wrapper around the non-cygwin pipe. (fhandler_pipe::create): Add pipe-specific flags to call to init(). * exceptions.cc (ctrl_c_handler): Lock process while we determine what to do. --- diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index eb54da9f8..4ea56f4e1 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2007-12-16 Christopher Faylor + + * dtable.cc (POSIX_NAMED_PIPE): New define. + (POSIX_NAMED_PIPE_LEN): Ditto. + (dtable::add_archetype): Use crealloc_abort. + (dtable::init_std_file_from_handle): Specifically detect pipe + stdin/stdout. Pass name to build_fh_dev so that proper name is + recorded. Use binmode of fh if it is set before using + get_default_mode. Set proper read/write access when calling init(). + (handle_to_fn): Handle pipes. + * fhandler.cc (fhandler_base::wait_overlapped): Add some debugging. + * fhandler.h (fhandler_base::set_name): Default to just setting the + path_conv name. + (fhandler_pipe::init): Declare. + * pipe.cc (struct pipesync): New struct. + (getov_result): New function. Blocks and retrieves the result of an + overlay I/O operation. + (pipe_handler): New function. + (pipesync::pipesync): New function. Initializer for pipesync struct. + (handler_pipe::init): Define. Detects attempts to set up a "native" + pipe fhandler and creates a thread which accepts input from or output + to the non-cygwin pipe, creating a cygwin pipe wrapper around the + non-cygwin pipe. + (fhandler_pipe::create): Add pipe-specific flags to call to init(). + + * exceptions.cc (ctrl_c_handler): Lock process while we determine what + to do. + 2007-12-14 Corinna Vinschen * include/cygwin/socket.h: Include sys/uio.h instead of cygwin/uio.h. diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 575384650..6fcf7086e 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -41,6 +41,17 @@ static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, static const char *handle_to_fn (HANDLE, char *); +#define DEVICE_PREFIX "\\device\\" +#define DEVICE_PREFIX_LEN sizeof (DEVICE_PREFIX) - 1 +#define REMOTE "\\Device\\LanmanRedirector\\" +#define REMOTE_LEN sizeof (REMOTE) - 1 +#define REMOTE1 "\\Device\\WinDfs\\Root\\" +#define REMOTE1_LEN sizeof (REMOTE1) - 1 +#define NAMED_PIPE "\\Device\\NamedPipe\\" +#define NAMED_PIPE_LEN sizeof (NAMED_PIPE) - 1 +#define POSIX_NAMED_PIPE "/Device/NamedPipe/" +#define POSIX_NAMED_PIPE_LEN sizeof (POSIX_NAMED_PIPE) - 1 + /* Set aside space for the table of fds */ void dtable_init () @@ -187,7 +198,7 @@ fhandler_base ** dtable::add_archetype () { if (farchetype++ >= narchetypes) - archetypes = (fhandler_base **) crealloc (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]); + archetypes = (fhandler_base **) crealloc_abort (archetypes, (narchetypes += initial_archetype_size) * sizeof archetypes[0]); return archetypes + farchetype - 1; } @@ -283,13 +294,6 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle) else dev = *console_dev; } - else if (ft == FILE_TYPE_PIPE) - { - if (fd == 0) - dev = *piper_dev; - else - dev = *pipew_dev; - } else if (wsock_started && getpeername ((SOCKET) handle, &sa, &sal) == 0) dev = *tcp_dev; else if (GetCommState (handle, &dcb)) @@ -297,7 +301,12 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle) else { name = handle_to_fn (handle, (char *) alloca (CYG_MAX_PATH + 100)); - bin = 0; + if (!strncasematch (name, POSIX_NAMED_PIPE, POSIX_NAMED_PIPE_LEN)) + /* nothing */; + else if (fd == 0) + dev = *piper_dev; + else + dev = *pipew_dev; } } @@ -308,25 +317,31 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle) fhandler_base *fh; if (dev) - fh = build_fh_dev (dev); + fh = build_fh_dev (dev, name); else fh = build_fh_name (name); if (fh) cygheap->fdtab[fd] = fh; - if (!bin) + if (name) { - bin = fh->get_default_fmode (O_RDWR); - if (bin) - /* nothing */; - else if (dev) - bin = O_BINARY; - else if (name != unknown_file) - bin = fh->pc_binmode (); + bin = fh->pc_binmode (); + if (!bin) + { + bin = fh->get_default_fmode (O_RDWR); + if (!bin && dev) + bin = O_BINARY; + } } - fh->init (handle, GENERIC_READ | GENERIC_WRITE, bin); + DWORD access; + if (fd == 0) + access = GENERIC_READ; + else + access = GENERIC_WRITE; /* Should be rdwr for stderr but not sure that's + possible for some versions of handles */ + fh->init (handle, access, bin); set_std_handle (fd); paranoid_printf ("fd %d, handle %p", fd, handle); } @@ -824,11 +839,6 @@ dtable::vfork_child_fixup () } #endif /*NEWVFORK*/ -#define DEVICE_PREFIX "\\device\\" -#define DEVICE_PREFIX_LEN sizeof (DEVICE_PREFIX) - 1 -#define REMOTE "\\Device\\LanmanRedirector\\" -#define REMOTE_LEN sizeof (REMOTE) - 1 - static const char * handle_to_fn (HANDLE h, char *posix_fn) { @@ -900,6 +910,7 @@ handle_to_fn (HANDLE h, char *posix_fn) } char *w32 = win32_fn; + bool justslash = false; if (maxmatchlen) { n = strlen (maxmatchdos); @@ -909,15 +920,38 @@ handle_to_fn (HANDLE h, char *posix_fn) memcpy (w32, maxmatchdos, n); w32[n] = '\\'; } + else if (strncasematch (w32, NAMED_PIPE, NAMED_PIPE_LEN)) + { + debug_printf ("pipe"); + justslash = true; + } else if (strncasematch (w32, REMOTE, REMOTE_LEN)) { w32 += REMOTE_LEN - 2; *w32 = '\\'; debug_printf ("remote drive"); + justslash = true; + } + else if (strncasematch (w32, REMOTE1, REMOTE1_LEN)) + { + w32 += REMOTE1_LEN - 2; + *w32 = '\\'; + debug_printf ("remote drive"); + justslash = true; } + if (!justslash) + cygwin_conv_to_full_posix_path (w32, posix_fn); + else + { + char *s, *d; + for (s = w32, d = posix_fn; *s; s++, d++) + if (*s == '\\') + *d = '/'; + else + *d = *s; + } - debug_printf ("derived path '%s'", w32); - cygwin_conv_to_full_posix_path (w32, posix_fn); + debug_printf ("derived path '%s', posix '%s'", w32, posix_fn); return posix_fn; } diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 06a9b5409..fc361b59b 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -888,6 +888,7 @@ static BOOL WINAPI ctrl_c_handler (DWORD type) { static bool saw_close; + lock_process now; if (!cygwin_finished_initializing) { diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index bc30a396c..a479d1b28 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1639,6 +1639,7 @@ fhandler_base::wait_overlapped (bool& res, bool writing, DWORD *bytes) switch (WaitForMultipleObjects (n, w4, false, INFINITE)) { case WAIT_OBJECT_0: + debug_printf ("normal read"); if (!bytes || GetOverlappedResult (h, get_overlapped (), bytes, false)) res = 1; @@ -1649,12 +1650,14 @@ fhandler_base::wait_overlapped (bool& res, bool writing, DWORD *bytes) } break; case WAIT_OBJECT_0 + 1: + debug_printf ("got a signal"); CancelIo (h); set_errno (EINTR); res = 0; break; default: err = GetLastError (); + debug_printf ("WFMO error, %E"); goto err; break; } diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 665dd51e1..45588fef9 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -149,6 +149,7 @@ class fhandler_base path_conv pc; virtual void set_name (path_conv &pc); + virtual void set_name (const char *s) {pc.set_normalized_path (s, false);} int error () const {return pc.error;} void set_error (int error) {pc.error = error;} bool exists () const {return pc.exists ();} @@ -546,6 +547,7 @@ public: int __stdcall fadvise (_off64_t, _off64_t, int) __attribute__ ((regparm (3))); int __stdcall ftruncate (_off64_t, bool) __attribute__ ((regparm (3))); int ready_for_read (int fd, DWORD howlong); + void init (HANDLE, DWORD, mode_t); static int create (fhandler_pipe *[2], unsigned, int); static int create_selectable (LPSECURITY_ATTRIBUTES, HANDLE&, HANDLE&, DWORD); }; diff --git a/winsup/cygwin/pipe.cc b/winsup/cygwin/pipe.cc index b9314aa4f..a6e4fff56 100644 --- a/winsup/cygwin/pipe.cc +++ b/winsup/cygwin/pipe.cc @@ -34,6 +34,157 @@ fhandler_pipe::fhandler_pipe () need_fork_fixup (true); } +struct pipesync +{ + bool reader; + HANDLE ev, non_cygwin_h, ret_handle; + pipesync(HANDLE, DWORD); + int operator == (int x) const {return !!ev;} + static DWORD WINAPI handler (LPVOID *); +}; + +inline bool +getov_result (HANDLE h, DWORD& nbytes, LPOVERLAPPED ov) +{ + if (ov && (GetLastError () != ERROR_IO_PENDING + || !GetOverlappedResult (h, ov, &nbytes, true))) + { + __seterrno (); + return false; + } + return true; +} + +static DWORD WINAPI +pipe_handler (LPVOID in_ps) +{ + pipesync ps = *(pipesync *) in_ps; + HANDLE in, out; + DWORD err = fhandler_pipe::create_selectable (&sec_none_nih, in, out, 0); + if (err) + { + SetLastError (err); + system_printf ("couldn't create a shadow pipe for non-cygwin pipe I/O, %E"); + return 0; + } + ((pipesync *) in_ps)->ret_handle = ps.reader ? in : out; + SetEvent (ps.ev); + + char buf[4096]; + DWORD read_bytes, write_bytes; + HANDLE hread, hwrite, hclose; + OVERLAPPED ov, *rov, *wov; + memset (&ov, 0, sizeof (ov)); + ov.hEvent = CreateEvent (&sec_none_nih, true, false, NULL); + if (ps.reader) + { + hread = ps.non_cygwin_h; + hclose = hwrite = out; + wov = &ov; + rov = NULL; + } + else + { + hclose = hread = in; + hwrite = ps.non_cygwin_h; + rov = &ov; + wov = NULL; + } + + while (1) + { + ResetEvent (ov.hEvent); + BOOL res = ReadFile (hread, buf, 4096, &read_bytes, rov); + if (!res && !getov_result (hread, read_bytes, rov)) + break; + if (!read_bytes) + break; + + res = WriteFile (hwrite, buf, read_bytes, &write_bytes, wov); + if (!res && !getov_result (hwrite, write_bytes, wov)) + break; + if (write_bytes != read_bytes) + break; + } + + err = GetLastError (); + CloseHandle (ov.hEvent); + CloseHandle (hclose); + CloseHandle (ps.non_cygwin_h); + SetLastError (err); + return 0; +} + + +pipesync::pipesync (HANDLE f, DWORD is_reader): + reader (false), ret_handle (NULL) +{ + ev = CreateEvent (&sec_none_nih, true, false, NULL); + if (!ev) + { + system_printf ("couldn't create synchronization event for non-cygwin pipe, %E"); + goto out; + } + non_cygwin_h = f; + reader = !!is_reader; + ret_handle = NULL; + + DWORD tid; + HANDLE ht = CreateThread (&sec_none_nih, 0, pipe_handler, this, 0, &tid); + + if (!ht) + goto out; + CloseHandle (ht); + + switch (WaitForSingleObject (ev, INFINITE)) + { + case WAIT_OBJECT_0: + break; + default: + system_printf ("WFSO failed waiting for synchronization event for non-cygwin pipe, %E"); + break; + } + +out: + if (ev) + { + CloseHandle (ev); + ev = NULL; + } + return; +} + +#define WINPIPE "\\\\.\\pipe\\" +void +fhandler_pipe::init (HANDLE f, DWORD a, mode_t bin) +{ + // FIXME: Have to clean this up someday + if (!*get_win32_name () && get_name ()) + { + char *hold_normalized_name = (char *) alloca (strlen (get_name ()) + 1); + strcpy (hold_normalized_name, get_name ()); + char *s, *d; + for (s = hold_normalized_name, d = (char *) get_win32_name (); *s; s++, d++) + if (*s == '/') + *d = '\\'; + else + *d = *s; + *d = '\0'; + set_name (hold_normalized_name); + } + + bool opened_properly = a & FILE_CREATE_PIPE_INSTANCE; + a &= ~FILE_CREATE_PIPE_INSTANCE; + if (!opened_properly) + { + pipesync ps (f, a & GENERIC_READ); + f = ps.ret_handle; + } + + fhandler_base::init (f, a, bin); + setup_overlapped (); +} + extern "C" int sscanf (const char *, const char *, ...); int @@ -284,16 +435,14 @@ fhandler_pipe::create (fhandler_pipe *fhs[2], unsigned psize, int mode) fhs[1] = (fhandler_pipe *) build_fh_dev (*pipew_dev); int binmode = mode & O_TEXT ?: O_BINARY; - fhs[0]->init (r, GENERIC_READ, binmode); - fhs[1]->init (w, GENERIC_WRITE, binmode); + fhs[0]->init (r, FILE_CREATE_PIPE_INSTANCE | GENERIC_READ, binmode); + fhs[1]->init (w, FILE_CREATE_PIPE_INSTANCE | GENERIC_WRITE, binmode); if (mode & O_NOINHERIT) { fhs[0]->close_on_exec (true); fhs[1]->close_on_exec (true); } - fhs[0]->setup_overlapped (); - fhs[1]->setup_overlapped (); res = 0; }