From 45d7b637fa74ac79469892653188e2554f151633 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Tue, 13 Dec 2011 20:06:31 +0000 Subject: [PATCH] * dcrt0.cc (init_windows_system_directory): Record system_wow64_directory information. * exceptions.cc (_cygtls::inside_kernel): Modernize comment. Consider executing a DLL from the Wow64 directory as being "in the kernel". (_cygtls::call_signal_handler): For now, only deal with main_tls signals if main_tls is known to be executing in the cygwin DLL. To more closely emulate linux, consider the operation to be restartable if not executing in the main thread. * globals.cc (windows_system_directory): Remove NO_COPY. (windows_system_directory_length): Ditto. (system_wow64_directory): New variable. (system_wow64_directory_length): Ditto. * select.cc (cygwin_select): Don't issue a EINTR on non-main threads since that seems to be what Linux does. Add missing break to signal case/switch. (select_stuff::wait): Don't issue a EINTR on non-main threads since that seems to be what Linux does. Remove now-unneeded accommodation for WAIT_IO_COMPLETION. Add a comment. * sigproc.h (cygwait): Ditto. Don't return if signal_received noticed and it's not the main thread. * signal.cc (sigprocmask): Add standard syscall debug stuff. * thread.cc (pthread_sigmask): Ditto. --- winsup/cygwin/ChangeLog | 27 +++++++++++++++++++++ winsup/cygwin/dcrt0.cc | 23 +++++++++++++----- winsup/cygwin/exceptions.cc | 20 ++++++++-------- winsup/cygwin/globals.cc | 6 +++-- winsup/cygwin/select.cc | 48 +++++++++++++++++++++---------------- winsup/cygwin/signal.cc | 8 +++++-- winsup/cygwin/sigproc.h | 2 +- winsup/cygwin/thread.cc | 4 +++- 8 files changed, 95 insertions(+), 43 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index cb9579f48..154e608e7 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,30 @@ +2011-12-13 Christopher Faylor + + * dcrt0.cc (init_windows_system_directory): Record + system_wow64_directory information. + * exceptions.cc (_cygtls::inside_kernel): Modernize comment. Consider + executing a DLL from the Wow64 directory as being "in the kernel". + (_cygtls::call_signal_handler): For now, only deal with main_tls + signals if main_tls is known to be executing in the cygwin DLL. To + more closely emulate linux, consider the operation to be restartable if + not executing in the main thread. + * globals.cc (windows_system_directory): Remove NO_COPY. + (windows_system_directory_length): Ditto. + (system_wow64_directory): New variable. + (system_wow64_directory_length): Ditto. + + * select.cc (cygwin_select): Don't issue a EINTR on non-main threads + since that seems to be what Linux does. Add missing break to signal + case/switch. + (select_stuff::wait): Don't issue a EINTR on non-main threads since + that seems to be what Linux does. Remove now-unneeded accommodation + for WAIT_IO_COMPLETION. Add a comment. + * sigproc.h (cygwait): Ditto. Don't return if signal_received noticed + and it's not the main thread. + + * signal.cc (sigprocmask): Add standard syscall debug stuff. + * thread.cc (pthread_sigmask): Ditto. + 2011-12-13 Corinna Vinschen * netdb.cc (open_system_file): Avoid MS-DOS path warning. diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 5364e4dd8..b6392acf2 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -638,12 +638,23 @@ child_info_spawn::handle_spawn () static void init_windows_system_directory () { - windows_system_directory_length = - GetSystemDirectoryW (windows_system_directory, MAX_PATH); - if (windows_system_directory_length == 0) - api_fatal ("can't find windows system directory"); - windows_system_directory[windows_system_directory_length++] = L'\\'; - windows_system_directory[windows_system_directory_length] = L'\0'; + if (!windows_system_directory_length) + { + windows_system_directory_length = + GetSystemDirectoryW (windows_system_directory, MAX_PATH); + if (windows_system_directory_length == 0) + api_fatal ("can't find windows system directory"); + windows_system_directory[windows_system_directory_length++] = L'\\'; + windows_system_directory[windows_system_directory_length] = L'\0'; + + system_wow64_directory_length = + GetSystemWow64DirectoryW (system_wow64_directory, MAX_PATH); + if (system_wow64_directory_length) + { + system_wow64_directory[system_wow64_directory_length++] = L'\\'; + system_wow64_directory[system_wow64_directory_length] = L'\0'; + } + } } static bool NO_COPY wow64_respawn = false; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 97f04b2ec..0ab89441b 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -326,10 +326,7 @@ _cygtls::inside_kernel (CONTEXT *cx) memset (checkdir, 0, size); # define h ((HMODULE) m.AllocationBase) - /* Apparently Windows 95 can sometimes return bogus addresses from - GetThreadContext. These resolve to a strange allocation base. - These should *never* be treated as interruptible. */ - if (!h || m.State != MEM_COMMIT) + if (!h || m.State != MEM_COMMIT) /* Be defensive */ res = true; else if (h == user_data->hmodule) res = false; @@ -340,8 +337,12 @@ _cygtls::inside_kernel (CONTEXT *cx) /* Skip potential long path prefix. */ if (!wcsncmp (checkdir, L"\\\\?\\", 4)) checkdir += 4; - res = !wcsncasecmp (windows_system_directory, checkdir, - windows_system_directory_length); + res = wcsncasecmp (windows_system_directory, checkdir, + windows_system_directory_length) == 0; + if (!res && system_wow64_directory_length) + res = wcsncasecmp (system_wow64_directory, checkdir, + system_wow64_directory_length) == 0; + } sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->Eip, h, res); # undef h @@ -828,7 +829,6 @@ set_sig_errno (int e) { *_my_tls.errno_addr = e; _my_tls.saved_errno = e; - // sigproc_printf ("errno %d", e); } static int setup_handler (int, void *, struct sigaction&, _cygtls *tls) @@ -1328,9 +1328,9 @@ _cygtls::call_signal_handler () else if (this != _main_tls) { _main_tls->lock (); - if (_main_tls->sig) + if (_main_tls->sig && _main_tls->incyg) { - paranoid_printf ("Redirecting to main_tls signal %d", _main_tls->sig); + small_printf ("Redirecting to main_tls signal %d", _main_tls->sig); sig = _main_tls->sig; sa_flags = _main_tls->sa_flags; func = _main_tls->func; @@ -1373,7 +1373,7 @@ _cygtls::call_signal_handler () } unlock (); - return this_sa_flags & SA_RESTART; + return this_sa_flags & SA_RESTART || (this != _main_tls); } void diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index 413c8730a..07bfe2feb 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -23,8 +23,10 @@ HANDLE NO_COPY hProcToken; HANDLE NO_COPY hProcImpToken; HMODULE NO_COPY cygwin_hmodule; int NO_COPY sigExeced; -WCHAR NO_COPY windows_system_directory[MAX_PATH]; -UINT NO_COPY windows_system_directory_length; +WCHAR windows_system_directory[MAX_PATH]; +UINT windows_system_directory_length; +WCHAR system_wow64_directory[MAX_PATH]; +UINT system_wow64_directory_length; /* program exit the program */ diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 77a78c427..5e6baa6f5 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -129,23 +129,28 @@ cygwin_select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fd_set *w = allocfd_set (maxfds); fd_set *e = allocfd_set (maxfds); - int res = 1; + int res = 0; /* Degenerate case. No fds to wait for. Just wait. */ if (sel.start.next == NULL) - switch (cygwait (ms)) - { - case WAIT_OBJECT_0: - select_printf ("signal received"); - set_sig_errno (EINTR); - res = -1; - case WAIT_OBJECT_0 + 1: - sel.destroy (); - pthread::static_cancel_self (); - /*NOTREACHED*/ - default: - res = 1; - break; - } + while (!res) + switch (cygwait (ms)) + { + case WAIT_OBJECT_0: + _my_tls.call_signal_handler (); + if (&_my_tls != _main_tls) + continue; /* Emulate linux behavior */ + select_printf ("signal received"); + set_sig_errno (EINTR); + res = -1; + break; + case WAIT_OBJECT_0 + 1: + sel.destroy (); + pthread::static_cancel_self (); + /*NOTREACHED*/ + default: + res = 1; /* temporary flag. Will be set to zero below. */ + break; + } else if (sel.always_ready || ms == 0) res = 0; else @@ -321,12 +326,11 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, MWMO_INPUTAVAILABLE); switch (wait_ret) - { - case WAIT_IO_COMPLETION: - syscall_printf ("woke due to apc"); - continue; /* Keep going */ - break; + { case WAIT_OBJECT_0: + _my_tls.call_signal_handler (); + if (&_my_tls != _main_tls) + continue; /* Emulate linux behavior */ cleanup (); select_printf ("signal received"); set_sig_errno (EINTR); @@ -338,6 +342,8 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, destroy (); pthread::static_cancel_self (); } + /* This wasn't a cancel event. It was just a normal object to wait + for. */ break; case WAIT_FAILED: cleanup (); @@ -350,7 +356,7 @@ select_stuff::wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, select_printf ("timed out"); res = 1; goto out; - } + } select_printf ("woke up. wait_ret %d. verifying", wait_ret); s = &start; diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 272fb366e..482ccd213 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -182,8 +182,12 @@ sigprocmask (int how, const sigset_t *set, sigset_t *oldset) { int res = handle_sigprocmask (how, set, oldset, _my_tls.sigmask); if (res) - set_errno (res); - return res ? -1 : 0; + { + set_errno (res); + res = -1; + } + syscall_printf ("%R = sigprocmask (%d, %p, %p)", res, set, oldset); + return res; } int __stdcall diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index 0cfac8699..f5547154d 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -100,7 +100,7 @@ cygwait (HANDLE h, DWORD howlong = INFINITE) n++; DWORD res; while ((res = WaitForMultipleObjects (n, w4, FALSE, howlong)) == wait_signal - && _my_tls.call_signal_handler ()) + && (_my_tls.call_signal_handler () || &_my_tls != _main_tls)) continue; return res; } diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 2f7d79460..52bca9839 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -3087,7 +3087,9 @@ pthread_kill (pthread_t thread, int sig) extern "C" int pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) { - return handle_sigprocmask (operation, set, old_set, _my_tls.sigmask); + int res = handle_sigprocmask (operation, set, old_set, _my_tls.sigmask); + syscall_printf ("%d = pthread_sigmask(%d, %p, %p)", operation, set, old_set); + return res; } /* ID */