From 1cb1472404cb050827a8902b862815ddb3973b71 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 17 Feb 2012 14:26:18 +0000 Subject: [PATCH] * ntdll.h (struct _PEB): Add EnvironmentUpdateCount member. * spawn.cc (child_info_spawn::worker): Speed up job recognition. Expand comment to explain every little detail and so we never forget. * wincap.h (wincaps::has_program_compatibility_assitant): New element. * wincap.cc: Implement above element throughout. --- winsup/cygwin/ChangeLog | 8 ++++++ winsup/cygwin/ntdll.h | 6 +++-- winsup/cygwin/spawn.cc | 58 +++++++++++++++++++++++++++++------------ winsup/cygwin/wincap.cc | 10 ++++++- winsup/cygwin/wincap.h | 4 ++- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index b016fc62c..6bbfb4d89 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,11 @@ +2012-02-17 Corinna Vinschen + + * ntdll.h (struct _PEB): Add EnvironmentUpdateCount member. + * spawn.cc (child_info_spawn::worker): Speed up job recognition. Expand + comment to explain every little detail and so we never forget. + * wincap.h (wincaps::has_program_compatibility_assitant): New element. + * wincap.cc: Implement above element throughout. + 2012-02-17 Corinna Vinschen * mount.cc (get_disk_type): Drop unneeded toupper call. Convert case diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index bb4a70dd0..d921867bd 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -1,7 +1,7 @@ /* ntdll.h. Contains ntdll specific stuff not defined elsewhere. Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010, 2011 Red Hat, Inc. + 2009, 2010, 2011, 2012 Red Hat, Inc. This file is part of Cygwin. @@ -689,7 +689,9 @@ typedef struct _PEB BYTE Reserved3[4]; PVOID ProcessHeap; PRTL_CRITICAL_SECTION FastPebLock; - BYTE Reserved4[436]; + BYTE Reserved4[8]; + ULONG EnvironmentUpdateCount; + BYTE Reserved5[424]; ULONG SessionId; } PEB, *PPEB; diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index b42e450c2..f052d350b 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -455,23 +455,49 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT; - /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround issues - with the "Program Compatibility Assistant (PCA) Service" observed on - Windows 7. For some reason, when starting long running sessions from - mintty, the affected svchost.exe process takes more and more memory and - at one point takes over the CPU. At this point the machine becomes - unresponsive. The only way to get back to normal is to stop the entire - mintty session, or to stop the PCA service. However, a process which - is controlled by PCA is part of a compatibility job, which allows child - processes to break away from the job. This helps to avoid this issue. */ - JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo; - if (QueryInformationJobObject (NULL, JobObjectBasicLimitInformation, - &jobinfo, sizeof jobinfo, NULL) - && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK - | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) + if (wincap.has_program_compatibility_assitant ()) { - debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB"); - c_flags |= CREATE_BREAKAWAY_FROM_JOB; + /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround + issues with the "Program Compatibility Assistant (PCA) Service" + starting with Windows Vista. For some reason, when starting long + running sessions from mintty(*), the affected svchost.exe process + takes more and more memory and at one point takes over the CPU. At + this point the machine becomes unresponsive. The only way to get + back to normal is to stop the entire mintty session, or to stop the + PCA service. However, a process which is controlled by PCA is part + of a compatibility job, which allows child processes to break away + from the job. This helps to avoid this issue. + + (*) Note that this is not mintty's fault. It has just been observed + with mintty in the first place. See the archives for more info: + http://cygwin.com/ml/cygwin-developers/2012-02/msg00018.html */ + + JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo; + + /* Calling QueryInformationJobObject costs time. Starting with + Windows XP there's a function IsProcessInJob, which fetches the + information whether or not we're part of a job 20 times faster than + the call to QueryInformationJobObject. But we're still + supporting Windows 2000, so we can't just link to that function. + On the other hand, loading the function pointer at runtime is a + time comsuming operation, too. So, what we do here is to emulate + the IsProcessInJob function when called for the own process and with + a NULL job handle. In this case it just returns the value of the + lowest bit from PEB->EnvironmentUpdateCount (observed with WinDbg). + The name of this PEB member is the same in all (inofficial) + documentations of the PEB. Apparently it's a bit misleading. + As a result, we only call QueryInformationJobObject if we're on + Vista or later *and* if the PEB indicates we're running in a job. + Tested on Vista/32, Vista/64, W7/32, W7/64, W8/64. */ + if ((NtCurrentTeb ()->Peb->EnvironmentUpdateCount & 1) != 0 + && QueryInformationJobObject (NULL, JobObjectBasicLimitInformation, + &jobinfo, sizeof jobinfo, NULL) + && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK + | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) + { + debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB"); + c_flags |= CREATE_BREAKAWAY_FROM_JOB; + } } if (mode == _P_DETACH) diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 3272d8948..91af3c624 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -2,7 +2,7 @@ capability class to the appropriate values. Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010, 2011 Red Hat, Inc. + 2009, 2010, 2011, 2012 Red Hat, Inc. This file is part of Cygwin. @@ -53,6 +53,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:false, has_console_logon_sid:false, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:false, }; wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -85,6 +86,7 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_stack_size_param_is_a_reservation:false, has_console_logon_sid:false, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:false, }; wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -117,6 +119,7 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:true, has_console_logon_sid:false, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:false, }; wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -149,6 +152,7 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:true, has_console_logon_sid:false, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:false, }; wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -181,6 +185,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:true, has_console_logon_sid:false, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:false, }; wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -213,6 +218,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:true, has_console_logon_sid:false, wow64_has_secondary_stack:true, + has_program_compatibility_assitant:false, }; wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -245,6 +251,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:true, has_console_logon_sid:false, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:true, }; wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -277,6 +284,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { has_stack_size_param_is_a_reservation:true, has_console_logon_sid:true, wow64_has_secondary_stack:false, + has_program_compatibility_assitant:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index 5ea915b47..87620286d 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -1,7 +1,7 @@ /* wincap.h: Header for OS capability class. Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010, 2011 Red Hat, Inc. + 2009, 2010, 2011, 2012 Red Hat, Inc. This file is part of Cygwin. @@ -43,6 +43,7 @@ struct wincaps unsigned has_stack_size_param_is_a_reservation : 1; unsigned has_console_logon_sid : 1; unsigned wow64_has_secondary_stack : 1; + unsigned has_program_compatibility_assitant : 1; }; class wincapc @@ -94,6 +95,7 @@ public: bool IMPLEMENT (has_stack_size_param_is_a_reservation) bool IMPLEMENT (has_console_logon_sid) bool IMPLEMENT (wow64_has_secondary_stack) + bool IMPLEMENT (has_program_compatibility_assitant) #undef IMPLEMENT };