windows-nt/Source/XPSP1/NT/base/win32/fusion/tools/st/csrss.cpp
2020-09-26 16:20:57 +08:00

500 lines
16 KiB
C++

#include "stdinc.h"
#include "csrss.h"
#define CSRSS_TEST_DIR_NAME (L"csrss")
#define CSRSS_TEST_DIR_NAME_CCH (NUMBER_OF(CSRSS_TEST_DIR_NAME) - 1)
#define CSRSS_SETTINGS_FILE_NAME (L"csrss.ini")
#define CSRSS_SETTINGS_FILE_NAME_CCH (NUMBER_OF(CSRSS_SETTINGS_FILE_NAME) - 1)
BOOL pOpenStreamOnFile(
PCWSTR pcwszFilename,
IStream** ppStream,
PCWSTR pcwszResourceType = NULL,
PCWSTR pcwszResourceName = NULL,
WORD Language = 0)
{
FN_PROLOG_WIN32
PARAMETER_CHECK(pcwszFilename);
PARAMETER_CHECK(ppStream);
*ppStream = NULL;
//
// If this is non-null, then we have to open the file as an image and get the
// resource specified. Otherwise, we just open the file like a normal file.
//
if ( pcwszResourceName )
{
CResourceStream *pResourceStream = NULL;
IFW32NULL_EXIT(pResourceStream = FUSION_NEW_SINGLETON(CResourceStream));
IFW32FALSE_EXIT(pResourceStream->Initialize(
pcwszFilename,
pcwszResourceType,
pcwszResourceName,
Language));
*ppStream = pResourceStream;
}
else
{
CReferenceCountedFileStream *pFileStream = NULL;
CImpersonationData ImpData;
IFW32NULL_EXIT(pFileStream = FUSION_NEW_SINGLETON(CReferenceCountedFileStream));
IFW32FALSE_EXIT(pFileStream->OpenForRead(pcwszFilename, ImpData, FILE_SHARE_READ, OPEN_EXISTING, 0));
*ppStream = pFileStream;
}
if ( *ppStream ) (*ppStream)->AddRef();
FN_EPILOG
}
BOOL ParseDecimalOrHexString(PCWSTR pcwszString, SIZE_T cch, ULONG &out )
{
BOOL fIsHex;
FN_PROLOG_WIN32
PARAMETER_CHECK(pcwszString != NULL);
fIsHex = ((cch > 2 ) && ( pcwszString[0] == L'0' ) &&
((pcwszString[1] == L'x') || (pcwszString[1] == L'X')));
if ( fIsHex )
{
pcwszString += 2;
cch -= 2;
}
out = 0;
while ( cch )
{
const int val = SxspHexDigitToValue((*pcwszString));
PARAMETER_CHECK( fIsHex || ( val < 10 ) );
out = out * ( fIsHex ? 16 : 10 ) + val;
cch--;
pcwszString++;
}
FN_EPILOG
}
class CCsrssPoundingThreadEntry
{
public:
CDequeLinkage Linkage;
SXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS Request;
ULONG ulRuns;
BOOL fStopNextRound;
BOOL fShouldSucceed;
CThread hOurThreadHandle;
CStringBuffer buffTestDirectory;
CSmallStringBuffer buffTestName;
DWORD dwSleepTime;
CSmallStringBuffer buffProcArch;
CStringBuffer buffAssemblyDirectory;
CStringBuffer buffTextualIdentityString;
CStringBuffer buffManifestStreamPath;
CStringBuffer buffPolicyStreamPath;
CCsrssPoundingThreadEntry() : ulRuns(0), fStopNextRound(FALSE) { }
BOOL AcquireSettingsFrom( PCWSTR pcwszSettingsFile );
DWORD DoWork();
BOOL StopAndWaitForCompletion();
static DWORD WINAPI ThreadProcEntry( PVOID pv )
{
CCsrssPoundingThreadEntry *pEntry = NULL;
pEntry = reinterpret_cast<CCsrssPoundingThreadEntry*>(pv);
return ( pEntry != NULL ) ? pEntry->DoWork() : 0;
}
};
BOOL
CCsrssPoundingThreadEntry::StopAndWaitForCompletion()
{
this->fStopNextRound = true;
return WaitForSingleObject(this->hOurThreadHandle, INFINITE) == WAIT_OBJECT_0;
}
DWORD
CCsrssPoundingThreadEntry::DoWork()
{
if ( !WaitForThreadResumeEvent() )
goto Exit;
while ( !this->fStopNextRound )
{
//
// Call to generate the structure
//
BOOL fResult;
SXS_GENERATE_ACTIVATION_CONTEXT_PARAMETERS TempParams = this->Request;
CSmartRef<IStream> isManifest;
CSmartRef<IStream> isPolicy;
if ( this->buffManifestStreamPath.Cch() != 0 )
{
if (pOpenStreamOnFile(this->buffManifestStreamPath, &isManifest))
{
TempParams.Manifest.Path = this->buffManifestStreamPath;
TempParams.Manifest.PathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
TempParams.Manifest.Stream = isManifest;
}
}
if ( this->buffPolicyStreamPath.Cch() != 0 )
{
if (pOpenStreamOnFile(this->buffPolicyStreamPath, &isPolicy))
{
TempParams.Policy.Path = this->buffManifestStreamPath;
TempParams.Policy.PathType = ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE;
TempParams.Policy.Stream = isPolicy;
}
}
fResult = SxsGenerateActivationContext( &TempParams );
//
// Did we fail when we were to succeed, or succeed when we were to fail?
//
if ( ( !fResult && this->fShouldSucceed ) || ( fResult && this->fShouldSucceed ) )
{
const DWORD dwLastError = ::FusionpGetLastWin32Error();
::ReportFailure("CsrssStress: Test %ls expected %ls, got %ls; Error %ld\n",
static_cast<PCWSTR>(this->buffTestName),
this->fShouldSucceed ? L"success" : L"failure",
fResult ? L"success" : L"failure",
dwLastError);
}
else
{
wprintf(L"CsrssStress: Test %ls passed\n", static_cast<PCWSTR>(this->buffTestName));
}
if ((TempParams.SectionObjectHandle != INVALID_HANDLE_VALUE ) &&
(TempParams.SectionObjectHandle != NULL))
{
CloseHandle(TempParams.SectionObjectHandle);
}
if ( !this->fStopNextRound )
::Sleep(this->dwSleepTime);
}
Exit:
return 0;
}
#define SLEN(n) (NUMBER_OF(n)-1)
#define CSRSS_INI_KEY_PROC_ARCH (L"ProcArch")
#define CSRSS_INI_KEY_PROC_ARCH_CCH SLEN(CSRSS_INI_KEY_PROC_ARCH)
#define CSRSS_INI_KEY_LANGID (L"LangId")
#define CSRSS_INI_KEY_LANGID_CCH SLEN(CSRSS_INI_KEY_PROC_ARCH)
#define CSRSS_INI_KEY_ASMDIR (L"AssemblyDirectory")
#define CSRSS_INI_KEY_ASMDIR_CCH SLEN(CSRSS_INI_KEY_PROC_ARCH)
#define CSRSS_INI_KEY_TEXTUALIDENT (L"TextualIdentity")
#define CSRSS_INI_KEY_TEXTUALIDENT_CCH SLEN(CSRSS_INI_KEY_PROC_ARCH)
#define CSRSS_INI_KEY_MANIFEST (L"ManifestPath")
#define CSRSS_INI_KEY_MANIFEST_CCH SLEN(CSRSS_INI_KEY_PROC_ARCH)
#define CSRSS_INI_KEY_POLICY (L"PolicyPath")
#define CSRSS_INI_KEY_POLICY_CCH SLEN(CSRSS_INI_KEY_PROC_ARCH)
#define CSRSS_INI_KEY_SUCCESS (L"ShouldSucceed")
#define CSRSS_INI_KEY_SUCCESS_CCH SLEN(CSRSS_INI_KEY_SUCCESS)
#define CSRSS_INI_KEY_SLEEP (L"SleepTime")
#define CSRSS_INI_KEY_SLEEP_CCH SLEN(CSRSS_INI_KEY_SLEEP)
#define CSRSS_INI_KEY_SYSDEFAULTIDENTFLAG (L"SysDefaultTextualIdentityFlag")
#define CSRSS_INI_KEY_SYSDEFAULTIDENTFLAG_CCH SLEN(CSRSS_INI_KEY_SYSDEFAULTIDENTFLAG)
#define CSRSS_INI_KEY_TEXTUALIDENTFLAG (L"TextualIdentityFlag")
#define CSRSS_INI_KEY_TEXTUALIDENTFLAG_CCH SLEN(CSRSS_INI_KEY_TEXTUALIDENTFLAG);
BOOL CCsrssPoundingThreadEntry::AcquireSettingsFrom( PCWSTR pcwszSettingsFile )
{
FN_PROLOG_WIN32
LANGID lidCurrentLang = GetUserDefaultUILanguage();
CSmallStringBuffer buffJunk;
BOOL fDumpBool;
ZeroMemory(&this->Request, sizeof(this->Request));
//
// Format of the settings file:
//
// [testname]
// SysDefaultTextualIdentityFlag = yes|no (add SXS_GENERATE_ACTIVATION_CONTEXT_FLAG_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY)
// TextualIdentityFlag = yes|no (add SXS_GENERATE_ACTIVATION_CONTEXT_FLAG_TEXTUAL_ASSEMBLY_IDENTITY)
// ProcArch = PA ident string (will use FusionpParseProcessorArchitecture)
// LangId = number or string
// AssemblyDirectory = dirname
// TextualIdentity = textualIdentityString
// ManifestPath = manifest name under test directory
// PolicyPath = policy path file name under test directory
// ShouldSucceed = yes|no - whether this test succeeds or fails
//
// Flags is required.
// PA and LangId, if not present, are defaulted to the current user's settings.
// AssemblyDirectory, if not present, defaults to %systemroot%\winsxs
// TextualIdentity is required.
// ManifestPath is required.
//
// If textualIdentity is present, then the streams are not created.
//
//
// Flags are set by key names
//
IFW32FALSE_EXIT(SxspIsPrivateProfileStringEqual(buffTestName, CSRSS_INI_KEY_SYSDEFAULTIDENTFLAG, L"yes", fDumpBool, pcwszSettingsFile));
if ( fDumpBool )
this->Request.Flags |= SXS_GENERATE_ACTIVATION_CONTEXT_FLAG_SYSTEM_DEFAULT_TEXTUAL_ASSEMBLY_IDENTITY;
IFW32FALSE_EXIT(SxspIsPrivateProfileStringEqual(buffTestName, CSRSS_INI_KEY_TEXTUALIDENTFLAG, L"yes", fDumpBool, pcwszSettingsFile));
if ( fDumpBool )
this->Request.Flags |= SXS_GENERATE_ACTIVATION_CONTEXT_FLAG_TEXTUAL_ASSEMBLY_IDENTITY;
//
// Get the success/failure value
//
IFW32FALSE_EXIT(SxspIsPrivateProfileStringEqual(buffTestName, CSRSS_INI_KEY_SUCCESS, L"yes", this->fShouldSucceed, pcwszSettingsFile));
//
// And how long this is to sleep
//
INT dump;
IFW32FALSE_EXIT(SxspGetPrivateProfileIntW(buffTestName, CSRSS_INI_KEY_SLEEP, 200, dump, pcwszSettingsFile));
this->dwSleepTime = dump;
//
// PA setting is a string
//
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(buffTestName, CSRSS_INI_KEY_PROC_ARCH, L"x86", buffJunk, pcwszSettingsFile));
if ( buffJunk.Cch() != 0 )
{
bool fValid = false;
IFW32FALSE_EXIT(FusionpParseProcessorArchitecture(
buffJunk,
buffJunk.Cch(),
&this->Request.ProcessorArchitecture,
fValid));
if ( !fValid ) this->Request.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
}
else
{
this->Request.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
}
//
// Maybe this is a string like en-us, or maybe just a number.
//
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(buffTestName, CSRSS_INI_KEY_LANGID, L"", buffJunk, pcwszSettingsFile));
if ( buffJunk.Cch() != 0 )
{
ULONG ulTemp;
if ( !ParseDecimalOrHexString(buffJunk, buffJunk.Cch(), ulTemp) )
{
BOOL fFound = FALSE;
IFW32FALSE_EXIT(SxspMapCultureToLANGID(buffJunk, lidCurrentLang, &fFound));
if ( !fFound )
{
goto Exit;
}
}
else lidCurrentLang = static_cast<LANGID>(ulTemp);
}
this->Request.LangId = lidCurrentLang;
//
// Assembly root directory. Not really required to be present?
//
IFW32FALSE_EXIT(SxspGetAssemblyRootDirectory(buffJunk));
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(buffTestName, CSRSS_INI_KEY_ASMDIR, buffJunk, this->buffAssemblyDirectory, pcwszSettingsFile));
this->Request.AssemblyDirectory = this->buffAssemblyDirectory;
//
// Textual identity string - if not present, null out the value
//
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(buffTestName, CSRSS_INI_KEY_TEXTUALIDENT, L"", this->buffTextualIdentityString, pcwszSettingsFile));
if ( this->buffTextualIdentityString.Cch() != 0 )
{
this->Request.TextualAssemblyIdentity = this->buffTextualIdentityString;
}
//
// File paths
//
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(buffTestName, CSRSS_INI_KEY_MANIFEST, L"", buffJunk, pcwszSettingsFile));
if ( buffJunk.Cch() != 0 )
{
IFW32FALSE_EXIT(this->buffManifestStreamPath.Win32Assign(this->buffTestDirectory));
IFW32FALSE_EXIT(this->buffManifestStreamPath.Win32AppendPathElement(buffJunk));
}
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(buffTestName, CSRSS_INI_KEY_POLICY, L"", buffJunk, pcwszSettingsFile));
if ( buffJunk.Cch() != 0 )
{
IFW32FALSE_EXIT(this->buffPolicyStreamPath.Win32Assign(this->buffTestDirectory));
IFW32FALSE_EXIT(this->buffPolicyStreamPath.Win32AppendPathElement(buffJunk));
}
FN_EPILOG
}
typedef CDeque<CCsrssPoundingThreadEntry, offsetof(CCsrssPoundingThreadEntry, Linkage)> CStressEntryDeque;
typedef CDequeIterator<CCsrssPoundingThreadEntry, offsetof(CCsrssPoundingThreadEntry, Linkage)> CStressEntryDequeIter;
CStressEntryDeque g_CsrssStressers;
BOOL InitializeCsrssStress(
PCWSTR pcwszTargetDirectory,
DWORD dwFlags
)
{
FN_PROLOG_WIN32
CFindFile Finder;
WIN32_FIND_DATAW FindData;
CStringBuffer buffTemp;
CStringBuffer buffTestActualRoot;
//
// The target directory here is the root of all the test case dirs, not the
// csrss-specific directory.
//
IFW32FALSE_EXIT(buffTestActualRoot.Win32Assign(
pcwszTargetDirectory,
wcslen(pcwszTargetDirectory)));
IFW32FALSE_EXIT(buffTestActualRoot.Win32AppendPathElement(
CSRSS_TEST_DIR_NAME,
CSRSS_TEST_DIR_NAME_CCH));
if ((FindData.dwFileAttributes = ::GetFileAttributesW(buffTestActualRoot)) == 0xffffffff
&& (FindData.dwFileAttributes = ::FusionpGetLastWin32Error()) == ERROR_FILE_NOT_FOUND)
{
printf("no %ls tests, skipping\n", CSRSS_TEST_DIR_NAME);
FN_SUCCESSFUL_EXIT();
}
IFW32FALSE_EXIT(buffTestActualRoot.Win32AppendPathElement(L"*", 1));
IFW32FALSE_EXIT(Finder.Win32FindFirstFile(buffTestActualRoot, &FindData));
buffTestActualRoot.RemoveLastPathElement();
do
{
CStringBuffer buffSettingsFile;
CCsrssPoundingThreadEntry *TestEntry;
if (( ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0 ) ||
FusionpIsDotOrDotDot(FindData.cFileName))
{
continue;
}
//
// Tack on the name of this test
//
IFW32NULL_EXIT(TestEntry = FUSION_NEW_SINGLETON(CCsrssPoundingThreadEntry));
IFW32FALSE_EXIT(TestEntry->buffTestName.Win32Assign(
FindData.cFileName,
wcslen(FindData.cFileName)));
IFW32FALSE_EXIT(TestEntry->buffTestDirectory.Win32Assign(buffTestActualRoot));
IFW32FALSE_EXIT(TestEntry->buffTestDirectory.Win32AppendPathElement(
FindData.cFileName,
wcslen(FindData.cFileName)));
IFW32FALSE_EXIT(buffSettingsFile.Win32Assign(TestEntry->buffTestDirectory));
IFW32FALSE_EXIT(buffSettingsFile.Win32AppendPathElement(
CSRSS_SETTINGS_FILE_NAME,
CSRSS_SETTINGS_FILE_NAME_CCH));
//
// Acquire settings for this test
//
IFW32FALSE_EXIT(TestEntry->AcquireSettingsFrom(buffSettingsFile));
g_CsrssStressers.AddToTail(TestEntry);
TestEntry = NULL;
} while (::FindNextFileW(Finder, &FindData));
FN_EPILOG
}
BOOL WaitForCsrssStressShutdown()
{
FN_PROLOG_WIN32
CStressEntryDequeIter Iter(&g_CsrssStressers);
for ( Iter.Reset(); Iter.More(); Iter.Next() )
{
CCsrssPoundingThreadEntry *Item = Iter.Current();
Item->StopAndWaitForCompletion();
Item->hOurThreadHandle.Win32Close();
}
FN_EPILOG
}
BOOL CsrssStressStartThreads( ULONG &ulThreadsCreated )
{
FN_PROLOG_WIN32
CStressEntryDequeIter Iter(&g_CsrssStressers);
ulThreadsCreated = 0;
for ( Iter.Reset(); Iter.More(); Iter.Next() )
{
CCsrssPoundingThreadEntry *Item = Iter.Current();
IFW32FALSE_EXIT(Item->hOurThreadHandle.Win32CreateThread(
Item->ThreadProcEntry,
Item));
ulThreadsCreated++;
}
FN_EPILOG
}
BOOL CleanupCsrssTests()
{
FN_PROLOG_WIN32
g_CsrssStressers.ClearAndDeleteAll();
FN_EPILOG
}
RequestCsrssStressShutdown()
{
FN_PROLOG_WIN32
CStressEntryDequeIter Iter(&g_CsrssStressers);
for ( Iter.Reset(); Iter.More(); Iter.Next() )
{
CCsrssPoundingThreadEntry *Item = Iter.Current();
Item->fStopNextRound = true;
}
FN_EPILOG
}