diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b1684c608..71b4a4aa8 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,10 @@ +2009-07-17 Christopher Faylor + + * cygtls.cc (_cygtls::init_exception_handler): Test for e, not e->prev + or we could still end up adding our handler twice. Add comment + explaining what we're doing. + * dll_init.cc (dll_dllcrt0_1): Clarify comment. + 2009-07-17 Christopher Faylor * cygtls.cc (_cygtls::init_exception_handler): Avoid adding our diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index f474d9b35..b90b25fa2 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -228,7 +228,23 @@ extern exception_list *_except_list asm ("%fs:0"); void _cygtls::init_exception_handler (exception_handler *eh) { - for (exception_list *e = _except_list; e->prev != NULL && e->prev != (exception_list *)-1; e = e->prev) + /* Here in the distant past of 17-Jul-2009, we had an issue where Windows + 2008 became YA perplexed because the cygwin exception handler was added + at the start of the SEH while still being in the list further on. This + was because we added a loop by setting el.prev to _except_list here. + Since el is reused in this thread, and this function can be called + more than once when a dll is loaded, this is not a good thing. + + So, for now, until the next required tweak, we will just avoid adding the + cygwin exception handler if it is already on this list. This could present + a problem if some previous exception handler tries to do things that are + better left to Cygwin. I await the cygwin mailing list notification of + this event with bated breath. + + (cgf 2009-07-17) */ + for (exception_list *e = _except_list; + e != NULL && e != (exception_list *) -1; + e = e->prev) if (e == &el) return; el.handler = eh; diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 6743d2601..1f83fb9a9 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -312,12 +312,13 @@ dll_dllcrt0_1 (VOID *x) per_process*& p = ((dllcrt0_info *)x)->p; int& res = ((dllcrt0_info *)x)->res; - /* Windows apparently installs a bunch of exception handlers prior to - this function getting called and one of them may trip before cygwin - gets to it. So, install our own exception handler only. - FIXME: It is possible that we may have to save state of the - previous exception handler chain and restore it, if problems - are noted. */ + /* Make sure that our exception handler is installed. + That should always be the case but this just makes sure. + + At some point, we may want to just remove this code since + the exception handler should be guaranteed to be installed. + I'm leaving it in until potentially after the release of + 1.7.1 */ _my_tls.init_exception_handler (_cygtls::handle_exceptions); if (p == NULL) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 465924190..ed2f6eaf3 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -572,19 +572,22 @@ public: friend class fhandler_fifo; }; -enum fifo_state -{ - fifo_unknown, - fifo_wait_for_client, - fifo_wait_for_server, - fifo_ok -}; class fhandler_fifo: public fhandler_base { + enum fifo_state + { + fifo_unknown, + fifo_wait_for_client, + fifo_wait_for_server, + fifo_wait_for_next_client, + fifo_eof, + fifo_ok + }; fifo_state wait_state; HANDLE open_nonserver (const char *, unsigned, LPSECURITY_ATTRIBUTES); OVERLAPPED io_status; bool wait (bool) __attribute__ ((regparm (1))); + char *fifo_name (char *) __attribute__ ((regparm (2))); public: fhandler_fifo (); void raw_read (void *, size_t&); diff --git a/winsup/cygwin/fhandler_fifo.cc b/winsup/cygwin/fhandler_fifo.cc index 517eceb31..9ee4b9a6a 100644 --- a/winsup/cygwin/fhandler_fifo.cc +++ b/winsup/cygwin/fhandler_fifo.cc @@ -56,31 +56,38 @@ fhandler_fifo::open_nonserver (const char *npname, unsigned low_flags, #define FIFO_PIPE_MODE (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE) +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; +} + 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) + DWORD mode = 0; + if (low_flags == O_WRONLY) + /* ok */; + else if (low_flags == O_RDONLY) mode = PIPE_ACCESS_INBOUND; - else if (low_flags == O_WRONLY) - mode = PIPE_ACCESS_OUTBOUND; else if (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 = @@ -90,7 +97,7 @@ fhandler_fifo::open (int flags, mode_t) HANDLE h; DWORD err; bool nonblocking_write = !!((flags & (O_WRONLY | O_NONBLOCK)) == (O_WRONLY | O_NONBLOCK)); - if (nonblocking_write) + if (flags & O_WRONLY) { h = INVALID_HANDLE_VALUE; err = ERROR_ACCESS_DENIED; @@ -111,20 +118,25 @@ fhandler_fifo::open (int flags, mode_t) h = open_nonserver (npname, low_flags, sa_buf); if (h != INVALID_HANDLE_VALUE) { - wait_state = fifo_wait_for_server; + wait_state = fifo_ok; break; } - if (nonblocking_write && GetLastError () == ERROR_FILE_NOT_FOUND) + if (GetLastError () != ERROR_FILE_NOT_FOUND) + __seterrno (); + else if (nonblocking_write) + set_errno (ENXIO); + else { - set_errno (ENXIO); - break; + h = NULL; + nohandle (true); + wait_state = fifo_wait_for_server; } - /* fall through intentionally */ + break; default: __seterrno (); break; } - if (!h || h == INVALID_HANDLE_VALUE) + if (h == INVALID_HANDLE_VALUE) res = 0; else if (!setup_overlapped ()) { @@ -148,17 +160,72 @@ fhandler_fifo::wait (bool iswrite) { switch (wait_state) { + case fifo_wait_for_next_client: + DisconnectNamedPipe (get_handle ()); 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); + int res; + if ((res = ConnectNamedPipe (get_handle (), get_overlapped ())) + || GetLastError () == ERROR_PIPE_CONNECTED) + { + wait_state = fifo_ok; + return true; + } + if (wait_state == fifo_wait_for_next_client) + { + CancelIo (get_handle ()); + res = 0; + } + else + { + DWORD dummy_bytes; + res = wait_overlapped (res, iswrite, &dummy_bytes); + } + wait_state = res ? fifo_ok : fifo_eof; } - case fifo_unknown: + break; case fifo_wait_for_server: - /* CGF FIXME SOON: test if these really need to be handled. */ + if (get_io_handle ()) + break; + 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) + { + wait_state = fifo_ok; + set_io_handle (h); + nohandle (false); + break; + } + if (GetLastError () == ERROR_PIPE_LISTENING) + continue; + else + { + __seterrno (); + return false; + } + } default: break; } @@ -168,10 +235,15 @@ fhandler_fifo::wait (bool iswrite) void 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) + if (!wait (false)) + len = 0; + else + { + read_overlapped (in_ptr, len); + if (!len) + wait_state = fifo_wait_for_next_client; + } } int