//+-------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1992 // // File: fastlock.cxx // // Contents: Implementation of CDfMutex methods for DocFiles // // History: 26-Jul-94 DonnaLi Created // //--------------------------------------------------------------- #include #pragma hdrstop #include #include // from com\inc #ifdef UNICODE #define GLOBAL_CS L"GlobalCsMutex" #else #define GLOBAL_CS "GlobalCsMutex" #endif // // This is the number of characters to skip over in the name // pased to CDfMutex::Init. The name consists of the string // OleDfRoot followed by the hex representation of a unique // number for each Docfile. We skip CHARS_TO_SKIP number of // characters in the name to produce a related and yet unique // name for the file mapping containing global state for the // critical section. // #define CHARS_TO_SKIP 3 //+-------------------------------------------------------------- // // Member: CDfMutex::Init, public // // Synopsis: This routine creates and initializes the global // critical section if it does not already exist. // It then attaches to the global critical section. // // Arguments: [lpName] - Supplies the critical section name // // Returns: Appropriate status code // // History: 26-Jul-94 DonnaLi Created // // Algorithm: Uses a mutex to serialize global critical section // creation and initialization // The name passed in is used to create or open the // semaphore embedded in the global critical section. // The name with the first CHARS_TO_SKIP characters // skipped is used to create or open the file mapping // containing global state of the critical section. // If a file mapping with that name already exists, // it is not reinitialized. The caller instead just // attaches to it. // //--------------------------------------------------------------- SCODE CDfMutex::Init( TCHAR * lpName ) { HANDLE hGlobalMutex; SCODE scResult = S_OK; DWORD dwResult; LPSECURITY_ATTRIBUTES lpsa = NULL; #if WIN32 == 100 || WIN32 > 200 CGlobalSecurity gs; if (FAILED(scResult = gs.Init(TRUE))) return scResult; #else LPSECURITY_ATTRIBUTES gs = NULL; #endif #ifndef MULTIHEAP #if WIN32 == 100 || WIN32 > 200 CWorldSecurityDescriptor wsd; SECURITY_ATTRIBUTES secattr; secattr.nLength = sizeof(SECURITY_ATTRIBUTES); secattr.lpSecurityDescriptor = &wsd; secattr.bInheritHandle = FALSE; #endif // // Serialize all global critical section initialization // hGlobalMutex = CreateMutex( #if WIN32 == 100 || WIN32 > 200 &secattr, // LPSECURITY_ATTRIBUTES lpsa #else gs, #endif TRUE, // BOOL fInitialOwner GLOBAL_CS // LPCTSTR lpszMutexName ); // // If the mutex create/open failed, then bail // if ( !hGlobalMutex ) { return LAST_SCODE; } if ( GetLastError() == ERROR_ALREADY_EXISTS ) { // // Since the mutex already existed, the request for ownership has // no effect. // // wait for the mutex // if ( WaitForSingleObject (hGlobalMutex, INFINITE) == WAIT_FAILED ) { scResult = LAST_SCODE; CloseHandle (hGlobalMutex); return scResult; } } // // We now own the global critical section creation mutex. Create/Open the // named semaphore. // #endif _hLockSemaphore = CreateSemaphore ( gs, // LPSECURITY_ATTRIBUTES lpsa 0, // LONG cSemInitial MAXLONG-1, // LONG cSemMax lpName // LPCTSTR lpszSemName ); // // If the semaphore create/open failed, then bail // if ( !_hLockSemaphore ) { scResult = LAST_SCODE; } else { // // Create/open a shared file mapping object // If we created it, we need to initialize the global structure. // Otherwise just point to it. // The global critical section creation mutex allows us to do // this safely. // _hSharedMapping = CreateFileMappingT ( INVALID_HANDLE_VALUE, // HANDLE hFile gs, // LPSECURITY_ATTRIBUTES lpsa PAGE_READWRITE, // DWORD fdwProtect 0, // DWORD dwMaximumSizeHigh 1024, // DWORD dwMaximumSizeLow lpName+CHARS_TO_SKIP// LPCTSTR lpszMapName ); if ( !_hSharedMapping ) { scResult = LAST_SCODE; CloseHandle (_hLockSemaphore); _hLockSemaphore = (HANDLE)NULL; } else { dwResult = GetLastError(); _pGlobalPortion = (PGLOBAL_SHARED_CRITICAL_SECTION) MapViewOfFile ( _hSharedMapping, // HANDLE hMapObject FILE_MAP_WRITE, // DWORD fdwAccess 0, // DWORD dwOffsetHigh 0, // DWORD dwOffsetLow 0 // DWORD cbMap ); if (!_pGlobalPortion) { scResult = LAST_SCODE; CloseHandle (_hLockSemaphore); _hLockSemaphore = (HANDLE)NULL; CloseHandle (_hSharedMapping); _hSharedMapping = (HANDLE)NULL; } else if (dwResult != ERROR_ALREADY_EXISTS ) { // // We created the file mapping, so initialize the // global portion. // _pGlobalPortion->LockCount = -1; #ifdef SUPPORT_RECURSIVE_LOCK _pGlobalPortion->RecursionCount = 0; _pGlobalPortion->OwningThread = 0; #else #if DBG == 1 _pGlobalPortion->OwningThread = 0; #endif #endif _pGlobalPortion->Reserved = 0; } } } #ifndef MULTIHEAP ReleaseMutex (hGlobalMutex); CloseHandle (hGlobalMutex); #endif return scResult; } //+-------------------------------------------------------------- // // Member: CDfMutex::~CDfMutex, public // // Synopsis: This routine detaches from an existing global // critical section. // // History: 26-Jul-94 DonnaLi Created // // Algorithm: Create or get the entry from the multistream // //--------------------------------------------------------------- CDfMutex::~CDfMutex( void ) { //If we're holding the mutex, we need to get rid of it here. #ifdef SUPPORT_RECURSIVE_LOCK if ((_pGlobalPortion) && (_pGlobalPortion->OwningThread == GetCurrentThreadId())) { #else if (_pGlobalPortion) { #if DBG == 1 olAssert (_pGlobalPortion->OwningThread == 0 || _pGlobalPortion->OwningThread == GetCurrentThreadId()); #endif #endif Release(); } if ( _pGlobalPortion ) { UnmapViewOfFile (_pGlobalPortion); } if ( _hLockSemaphore ) { CloseHandle (_hLockSemaphore); } if ( _hSharedMapping ) { CloseHandle (_hSharedMapping); } } //+-------------------------------------------------------------- // // Member: CDfMutex::Take, public // // Synopsis: This routine enters the global critical section. // // Arguments: [dwTimeout] - Supplies the timeout // // Returns: Appropriate status code // // History: 26-Jul-94 DonnaLi Created // // Algorithm: Enters the critical section if nobody owns it or // if the current thread already owns it. // Waits for the critical section otherwise. // //--------------------------------------------------------------- SCODE CDfMutex::Take ( DWORD dwTimeout ) { olAssert (_pGlobalPortion->LockCount >= -1); #ifdef SUPPORT_RECURSIVE_LOCK olAssert (_pGlobalPortion->RecursionCount >= 0); DWORD ThreadId; ThreadId = GetCurrentThreadId(); #endif // // Increment the lock variable. On the transition to 0, the caller // becomes the absolute owner of the lock. Otherwise, the caller is // either recursing, or is going to have to wait // if ( !InterlockedIncrement (&_pGlobalPortion->LockCount) ) { // // lock count went from -1 to 0, so the caller // is the owner of the lock // #ifdef SUPPORT_RECURSIVE_LOCK _pGlobalPortion->RecursionCount = 1; _pGlobalPortion->OwningThread = ThreadId; #else #if DBG == 1 _pGlobalPortion->OwningThread = GetCurrentThreadId(); #endif #endif return S_OK; } else { #ifdef SUPPORT_RECURSIVE_LOCK // // If the caller is recursing, then increment the recursion count // if ( _pGlobalPortion->OwningThread == ThreadId ) { _pGlobalPortion->RecursionCount++; return S_OK; } else { #else #if DBG == 1 olAssert (_pGlobalPortion->OwningThread != GetCurrentThreadId()); #endif #endif switch (WaitForSingleObject( _hLockSemaphore, dwTimeout )) { case WAIT_OBJECT_0: case WAIT_ABANDONED: #ifdef SUPPORT_RECURSIVE_LOCK _pGlobalPortion->RecursionCount = 1; _pGlobalPortion->OwningThread = ThreadId; #else #if DBG == 1 _pGlobalPortion->OwningThread = GetCurrentThreadId(); #endif #endif return S_OK; case WAIT_TIMEOUT: return STG_E_INUSE; default: return LAST_SCODE; } #ifdef SUPPORT_RECURSIVE_LOCK } #endif } } //+-------------------------------------------------------------- // // Member: CDfMutex::Release, public // // Synopsis: This routine leaves the global critical section // // History: 26-Jul-94 DonnaLi Created // // Algorithm: Leaves the critical section if this is the owning // thread. // //--------------------------------------------------------------- VOID CDfMutex::Release( void ) { #ifdef SUPPORT_RECURSIVE_LOCK if ( _pGlobalPortion->OwningThread != GetCurrentThreadId() ) return; #else #if DBG == 1 olAssert (_pGlobalPortion->OwningThread == 0 || _pGlobalPortion->OwningThread == GetCurrentThreadId()); #endif #endif olAssert (_pGlobalPortion->LockCount >= -1); #ifdef SUPPORT_RECURSIVE_LOCK olAssert (_pGlobalPortion->RecursionCount >= 0); // // decrement the recursion count. If it is still non-zero, then // we are still the owner so don't do anything other than dec the lock // count // if ( --_pGlobalPortion->RecursionCount ) { InterlockedDecrement(&_pGlobalPortion->LockCount); } else { // // We are really leaving, so give up ownership and decrement the // lock count // _pGlobalPortion->OwningThread = 0; #else #if DBG == 1 _pGlobalPortion->OwningThread = 0; #endif #endif // // Check to see if there are other waiters. If so, then wake up a waiter // if ( InterlockedDecrement(&_pGlobalPortion->LockCount) >= 0 ) { ReleaseSemaphore( _hLockSemaphore, // HANDLE hSemaphore 1, // LONG cReleaseCount NULL // LPLONG lplPreviousCount ); } #ifdef SUPPORT_RECURSIVE_LOCK } #endif } //+-------------------------------------------------------------- // // Member: CDfMutex::IsHandleValid, public // // Synopsis: This routine checks the mutex handle for validity // // History: 09-May-2001 HenryLee created // //--------------------------------------------------------------- BOOL CDfMutex::IsHandleValid (TCHAR *ptcsName) { #if WIN32 == 100 BOOL fValid = FALSE; NTSTATUS nts = STATUS_SUCCESS; WCHAR wcsBuffer[MAX_PATH] = L""; OBJECT_NAME_INFORMATION *poni = (OBJECT_NAME_INFORMATION *) wcsBuffer; nts = NtQueryObject (_hLockSemaphore, ObjectNameInformation, poni, sizeof(wcsBuffer), NULL); if (NT_SUCCESS(nts)) { if (poni->Name.Length < sizeof(wcsBuffer) - sizeof (*poni)) { poni->Name.Buffer[poni->Name.Length / sizeof(WCHAR)] = L'\0'; if (!lstrcmp (poni->Name.Buffer, ptcsName)) fValid = TRUE; } } #else BOOL fValid = TRUE; #endif return fValid; }