#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(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 isManifest; CSmartRef 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(this->buffTestName), this->fShouldSucceed ? L"success" : L"failure", fResult ? L"success" : L"failure", dwLastError); } else { wprintf(L"CsrssStress: Test %ls passed\n", static_cast(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(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 CStressEntryDeque; typedef CDequeIterator 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 }