summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2012-03-05 11:50:25 +0000
committerCorinna Vinschen <corinna@vinschen.de>2012-03-05 11:50:25 +0000
commita3904c655efec2edc27f72b68280afb4a144cc9a (patch)
tree397b8ea082ac19d78d5c8521c2a4a2517415e83d
parent75effa37fcb63c1e72918f6689660e4c3b11a5e8 (diff)
downloadcygnal-a3904c655efec2edc27f72b68280afb4a144cc9a.tar.gz
cygnal-a3904c655efec2edc27f72b68280afb4a144cc9a.tar.bz2
cygnal-a3904c655efec2edc27f72b68280afb4a144cc9a.zip
* cygheap.h (enum fcwd_version_t): Move here from path.cc.
(class fcwd_access_t): Ditto. Only declare methods. (class cwdstuff): Move fast_cwd_ptr and fast_cwd_version from shared DLL section here. * path.cc: Keep fcwd_access_t method definitions. (fcwd_access_t::fast_cwd_version): New method. (find_fast_cwd_pointer): Change comment. Mention test on W8CP. (cwdstuff::init): Initialize fast_cwd_ptr and fast_cwd_version.
-rw-r--r--winsup/cygwin/ChangeLog11
-rw-r--r--winsup/cygwin/cygheap.h92
-rw-r--r--winsup/cygwin/path.cc315
3 files changed, 226 insertions, 192 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 36347c950..b4ae19ced 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,16 @@
2012-03-05 Corinna Vinschen <corinna@vinschen.de>
+ * cygheap.h (enum fcwd_version_t): Move here from path.cc.
+ (class fcwd_access_t): Ditto. Only declare methods.
+ (class cwdstuff): Move fast_cwd_ptr and fast_cwd_version from shared
+ DLL section here.
+ * path.cc: Keep fcwd_access_t method definitions.
+ (fcwd_access_t::fast_cwd_version): New method.
+ (find_fast_cwd_pointer): Change comment. Mention test on W8CP.
+ (cwdstuff::init): Initialize fast_cwd_ptr and fast_cwd_version.
+
+2012-03-05 Corinna Vinschen <corinna@vinschen.de>
+
* dll_init.cc (dll_list::operator[]): Extend comment a bit more to
explain previous patch.
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index 054297bd7..154ad6a84 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -204,7 +204,87 @@ public:
/* cwd cache stuff. */
-class muto;
+enum fcwd_version_t {
+ FCWD_OLD,
+ FCWD_W7,
+ FCWD_W8
+};
+
+/* This class is used to store the CWD starting with Windows Vista.
+ The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
+ an afterthought now. The actual CWD storage is a FAST_CWD structure
+ which is allocated on the process heap. The new method only requires
+ minimal locking and it's much more multi-thread friendly. Presumably
+ it minimizes contention when accessing the CWD.
+ The class fcwd_access_t is supposed to encapsulate the gory implementation
+ details depending on OS version from the calling functions. */
+class fcwd_access_t {
+ /* This is the layout used in Windows 8 developer preview. */
+ struct FAST_CWD_8 {
+ LONG ReferenceCount; /* Only release when this is 0. */
+ HANDLE DirectoryHandle;
+ ULONG OldDismountCount; /* Reflects the system DismountCount
+ at the time the CWD has been set. */
+ UNICODE_STRING Path; /* Path's Buffer member always refers
+ to the following Buffer array. */
+ LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
+ WCHAR Buffer[MAX_PATH];
+ };
+ /* This is the layout used in Windows 7 and Vista. */
+ struct FAST_CWD_7 {
+ UNICODE_STRING Path; /* Path's Buffer member always refers
+ to the following Buffer array. */
+ HANDLE DirectoryHandle;
+ LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
+ LONG ReferenceCount; /* Only release when this is 0. */
+ ULONG OldDismountCount; /* Reflects the system DismountCount
+ at the time the CWD has been set. */
+ WCHAR Buffer[MAX_PATH];
+ };
+ /* This is the old FAST_CWD structure up to the patch from KB 2393802,
+ release in February 2011. */
+ struct FAST_CWD_OLD {
+ LONG ReferenceCount; /* Only release when this is 0. */
+ HANDLE DirectoryHandle;
+ ULONG OldDismountCount; /* Reflects the system DismountCount
+ at the time the CWD has been set. */
+ UNICODE_STRING Path; /* Path's Buffer member always refers
+ to the following Buffer array. */
+ WCHAR Buffer[MAX_PATH];
+ };
+ union {
+ FAST_CWD_OLD fold;
+ FAST_CWD_7 f7;
+ FAST_CWD_8 f8;
+ };
+
+#define IMPLEMENT(type, name) \
+ type name () { \
+ switch (fast_cwd_version ()) { \
+ case FCWD_OLD: \
+ default: \
+ return fold.name; \
+ case FCWD_W7: \
+ return f7.name; \
+ case FCWD_W8: \
+ return f8.name; \
+ } \
+ }
+ IMPLEMENT (LONG &, ReferenceCount)
+ IMPLEMENT (HANDLE &, DirectoryHandle)
+ IMPLEMENT (ULONG &, OldDismountCount)
+ IMPLEMENT (UNICODE_STRING &, Path)
+ IMPLEMENT (WCHAR *, Buffer)
+ void SetFSCharacteristics (LONG val);
+ static fcwd_version_t &fast_cwd_version (void);
+
+public:
+ void CopyPath (UNICODE_STRING &target);
+ void Free (PVOID heap);
+ void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count);
+ static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir);
+ static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer);
+};
class cwdstuff
{
@@ -217,6 +297,16 @@ private:
a native Win32 application. See cwdstuff::set for
how it gets set. See child_info_spawn::worker for how
it's evaluated. */
+
+ friend class fcwd_access_t;
+ /* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in
+ ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD.
+ Unfortunately RtlpCurDirRef is not exported from ntdll.dll. */
+ fcwd_access_t **fast_cwd_ptr;
+ /* Type of FAST_CWD used on this system. Keeping this information
+ available in shared memory avoids to test for the version every time
+ around. Default to new version. */
+ fcwd_version_t fast_cwd_version;
void override_win32_cwd (bool, ULONG);
public:
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 4bc47e100..aa0521d4f 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -3510,205 +3510,132 @@ copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. */
-/* This class is used to store the CWD starting with Windows Vista.
- The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
- an afterthought now. The actual CWD storage is a FAST_CWD structure
- which is allocated on the process heap. The new method only requires
- minimal locking and it's much more multi-thread friendly. Presumably
- it minimizes contention when accessing the CWD.
- The class fcwd_access_t is supposed to encapsulate the gory implementation
- details depending on OS version from the calling functions. */
-class fcwd_access_t {
- /* This is the layout used in Windows 8 developer preview. */
- struct FAST_CWD_8 {
- LONG ReferenceCount; /* Only release when this is 0. */
- HANDLE DirectoryHandle;
- ULONG OldDismountCount; /* Reflects the system DismountCount
- at the time the CWD has been set. */
- UNICODE_STRING Path; /* Path's Buffer member always refers
- to the following Buffer array. */
- LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
- WCHAR Buffer[MAX_PATH];
- };
- /* This is the layout used in Windows 7 and Vista. */
- struct FAST_CWD_7 {
- UNICODE_STRING Path; /* Path's Buffer member always refers
- to the following Buffer array. */
- HANDLE DirectoryHandle;
- LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
- LONG ReferenceCount; /* Only release when this is 0. */
- ULONG OldDismountCount; /* Reflects the system DismountCount
- at the time the CWD has been set. */
- WCHAR Buffer[MAX_PATH];
- };
- /* This is the old FAST_CWD structure up to the patch from KB 2393802,
- release in February 2011. */
- struct FAST_CWD_OLD {
- LONG ReferenceCount; /* Only release when this is 0. */
- HANDLE DirectoryHandle;
- ULONG OldDismountCount; /* Reflects the system DismountCount
- at the time the CWD has been set. */
- UNICODE_STRING Path; /* Path's Buffer member always refers
- to the following Buffer array. */
- WCHAR Buffer[MAX_PATH];
- };
- union {
- FAST_CWD_OLD fold;
- FAST_CWD_7 f7;
- FAST_CWD_8 f8;
- };
-
- /* Type of FAST_CWD used on this system. Keeping this information available
- in shared memory avoids to test for the version every time around.
- Default to new version. */
- enum fcwd_version_t {
- FCWD_OLD,
- FCWD_W7,
- FCWD_W8
- };
- static fcwd_version_t fast_cwd_version;
-
-#define IMPLEMENT(type, name) \
- type name () { \
- switch (fast_cwd_version) { \
- case FCWD_OLD: \
- default: \
- return fold.name; \
- case FCWD_W7: \
- return f7.name; \
- case FCWD_W8: \
- return f8.name; \
- } \
- }
- IMPLEMENT (LONG &, ReferenceCount)
- IMPLEMENT (HANDLE &, DirectoryHandle)
- IMPLEMENT (ULONG &, OldDismountCount)
- IMPLEMENT (UNICODE_STRING &, Path)
- IMPLEMENT (WCHAR *, Buffer)
+void
+fcwd_access_t::SetFSCharacteristics (LONG val)
+{
/* Special case FSCharacteristics. Didn't exist originally. */
- void SetFSCharacteristics (LONG val)
+ switch (fast_cwd_version ())
{
- switch (fast_cwd_version)
- {
- case FCWD_OLD:
- break;
- case FCWD_W7:
- f7.FSCharacteristics = val;
- break;
- case FCWD_W8:
- f8.FSCharacteristics = val;
- break;
- }
- }
-public:
- void CopyPath (UNICODE_STRING &target)
- {
- /* Copy the Path contents over into the UNICODE_STRING referenced by
- target. This is used to set the CurrentDirectoryName in the
- user parameter block. */
- target = Path ();
- }
- void Free (PVOID heap)
- {
- /* Decrement the reference count. If it's down to 0, free
- structure from heap. */
- if (this && InterlockedDecrement (&ReferenceCount ()) == 0)
- {
- /* In contrast to pre-Vista, the handle on init is always a
- fresh one and not the handle inherited from the parent
- process. So we always have to close it here. However, the
- handle could be NULL, if we cd'ed into a virtual dir. */
- HANDLE h = DirectoryHandle ();
- if (h)
- NtClose (h);
- RtlFreeHeap (heap, 0, this);
- }
+ case FCWD_OLD:
+ break;
+ case FCWD_W7:
+ f7.FSCharacteristics = val;
+ break;
+ case FCWD_W8:
+ f8.FSCharacteristics = val;
+ break;
}
- void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count)
+}
+
+fcwd_version_t &
+fcwd_access_t::fast_cwd_version ()
+{
+ return cygheap->cwd.fast_cwd_version;
+}
+
+void
+fcwd_access_t::CopyPath (UNICODE_STRING &target)
+{
+ /* Copy the Path contents over into the UNICODE_STRING referenced by
+ target. This is used to set the CurrentDirectoryName in the
+ user parameter block. */
+ target = Path ();
+}
+
+void
+fcwd_access_t::Free (PVOID heap)
+{
+ /* Decrement the reference count. If it's down to 0, free
+ structure from heap. */
+ if (this && InterlockedDecrement (&ReferenceCount ()) == 0)
{
- /* Fill in all values into this FAST_CWD structure. */
- DirectoryHandle () = dir;
- ReferenceCount () = 1;
- OldDismountCount () = old_dismount_count;
- /* The new structure stores the device characteristics of the
- volume holding the dir. RtlGetCurrentDirectory_U checks
- if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if
- the volume is still the same as the one used when opening
- the directory handle.
- We don't call NtQueryVolumeInformationFile for the \\?\PIPE,
- though. It just returns STATUS_INVALID_HANDLE anyway. */
- if (fast_cwd_version != FCWD_OLD)
- {
- SetFSCharacteristics (0);
- if (name != &ro_u_pipedir)
- {
- IO_STATUS_BLOCK io;
- FILE_FS_DEVICE_INFORMATION ffdi;
- if (NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi,
- sizeof ffdi, FileFsDeviceInformation)))
- SetFSCharacteristics (ffdi.Characteristics);
- }
- }
- RtlInitEmptyUnicodeString (&Path (), Buffer (),
- MAX_PATH * sizeof (WCHAR));
- copy_cwd_str (&Path (), name);
+ /* In contrast to pre-Vista, the handle on init is always a
+ fresh one and not the handle inherited from the parent
+ process. So we always have to close it here. However, the
+ handle could be NULL, if we cd'ed into a virtual dir. */
+ HANDLE h = DirectoryHandle ();
+ if (h)
+ NtClose (h);
+ RtlFreeHeap (heap, 0, this);
}
+}
- static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir)
+void
+fcwd_access_t::FillIn (HANDLE dir, PUNICODE_STRING name,
+ ULONG old_dismount_count)
+{
+ /* Fill in all values into this FAST_CWD structure. */
+ DirectoryHandle () = dir;
+ ReferenceCount () = 1;
+ OldDismountCount () = old_dismount_count;
+ /* The new structure stores the device characteristics of the
+ volume holding the dir. RtlGetCurrentDirectory_U checks
+ if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if
+ the volume is still the same as the one used when opening
+ the directory handle.
+ We don't call NtQueryVolumeInformationFile for the \\?\PIPE,
+ though. It just returns STATUS_INVALID_HANDLE anyway. */
+ if (fast_cwd_version () != FCWD_OLD)
{
- /* Input: The buffer pointer as it's stored in the user parameter block
- and a directory handle.
- This function computes the address to the FAST_CWD structure based
- on the version and overwrites the directory handle. It is only
- used if we couldn't figure out the address of fast_cwd_ptr. */
- fcwd_access_t *f_cwd;
- switch (fast_cwd_version)
+ SetFSCharacteristics (0);
+ if (name != &ro_u_pipedir)
{
- case FCWD_OLD:
- default:
- f_cwd = (fcwd_access_t *)
- ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_OLD, Buffer));
- case FCWD_W7:
- f_cwd = (fcwd_access_t *)
- ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_7, Buffer));
- case FCWD_W8:
- f_cwd = (fcwd_access_t *)
- ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_8, Buffer));
+ IO_STATUS_BLOCK io;
+ FILE_FS_DEVICE_INFORMATION ffdi;
+ if (NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi,
+ sizeof ffdi, FileFsDeviceInformation)))
+ SetFSCharacteristics (ffdi.Characteristics);
}
- f_cwd->DirectoryHandle () = dir;
}
- static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer)
+ RtlInitEmptyUnicodeString (&Path (), Buffer (),
+ MAX_PATH * sizeof (WCHAR));
+ copy_cwd_str (&Path (), name);
+}
+
+void
+fcwd_access_t::SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir)
+{
+ /* Input: The buffer pointer as it's stored in the user parameter block
+ and a directory handle.
+ This function computes the address to the FAST_CWD structure based
+ on the version and overwrites the directory handle. It is only
+ used if we couldn't figure out the address of fast_cwd_ptr. */
+ fcwd_access_t *f_cwd;
+ switch (fast_cwd_version ())
{
- /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a
- pointer to the Buffer within (is_buffer == true), this function
- computes the FAST_CWD version by checking that Path.MaximumLength
- equals MAX_PATH, and that Path.Buffer == Buffer. */
- if (is_buffer)
- buf_p -= __builtin_offsetof (FAST_CWD_8, Buffer);
- fcwd_access_t *f_cwd = (fcwd_access_t *) buf_p;
- if (f_cwd->f8.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
- && f_cwd->f8.Path.Buffer == f_cwd->f8.Buffer)
- fast_cwd_version = FCWD_W8;
- else if (f_cwd->f7.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
- && f_cwd->f7.Path.Buffer == f_cwd->f7.Buffer)
- fast_cwd_version = FCWD_W7;
- else
- fast_cwd_version = FCWD_OLD;
+ case FCWD_OLD:
+ default:
+ f_cwd = (fcwd_access_t *)
+ ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_OLD, Buffer));
+ case FCWD_W7:
+ f_cwd = (fcwd_access_t *)
+ ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_7, Buffer));
+ case FCWD_W8:
+ f_cwd = (fcwd_access_t *)
+ ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_8, Buffer));
}
-};
-fcwd_access_t::fcwd_version_t fcwd_access_t::fast_cwd_version
- __attribute__((section (".cygwin_dll_common"), shared))
- = fcwd_access_t::FCWD_W7;
-/* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in
- ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD.
- Unfortunately RtlpCurDirRef is not exported from ntdll.dll.
- We put the pointer into the common shared DLL segment. This allows to
- restrict the call to find_fast_cwd_pointer() to once per Cygwin session
- per user session. This works, because ASLR randomizes the load address
- of DLLs only once at boot time. */
-static fcwd_access_t **fast_cwd_ptr
- __attribute__((section (".cygwin_dll_common"), shared))
- = (fcwd_access_t **) -1;
+ f_cwd->DirectoryHandle () = dir;
+}
+
+void
+fcwd_access_t::SetVersionFromPointer (PBYTE buf_p, bool is_buffer)
+{
+ /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a
+ pointer to the Buffer within (is_buffer == true), this function
+ computes the FAST_CWD version by checking that Path.MaximumLength
+ equals MAX_PATH, and that Path.Buffer == Buffer. */
+ if (is_buffer)
+ buf_p -= __builtin_offsetof (FAST_CWD_8, Buffer);
+ fcwd_access_t *f_cwd = (fcwd_access_t *) buf_p;
+ if (f_cwd->f8.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
+ && f_cwd->f8.Path.Buffer == f_cwd->f8.Buffer)
+ fast_cwd_version () = FCWD_W8;
+ else if (f_cwd->f7.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
+ && f_cwd->f7.Path.Buffer == f_cwd->f7.Buffer)
+ fast_cwd_version () = FCWD_W7;
+ else
+ fast_cwd_version () = FCWD_OLD;
+}
#define peek32(x) (*(uint32_t *)(x))
@@ -3718,8 +3645,9 @@ static fcwd_access_t **fast_cwd_ptr
Therefore we have to use some knowledge to figure out the address.
This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
- Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
- There's some hope that this will still work for Windows 8... */
+ Windows 7 32/64 bit, Server 2008 R2 (which is only 64 bit anyway),
+ and W8CP 32/64 bit. There's some hope this will still work for
+ Windows 8 RTM... */
static fcwd_access_t **
find_fast_cwd_pointer ()
{
@@ -3950,8 +3878,13 @@ cwdstuff::init ()
if (win32.Buffer)
override_win32_cwd (true, SharedUserData.DismountCount);
else
- /* Initially re-open the cwd to allow POSIX semantics. */
- set (NULL, NULL);
+ {
+ /* Initialize fast_cwd stuff. */
+ fast_cwd_ptr = (fcwd_access_t **) -1;
+ fast_cwd_version = FCWD_W7;
+ /* Initially re-open the cwd to allow POSIX semantics. */
+ set (NULL, NULL);
+ }
}
/* Chdir and fill out the elements of a cwdstuff struct. */