492 lines
13 KiB
C++
492 lines
13 KiB
C++
//+--------------------------------------------------------------
|
|
//
|
|
// 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 <dfhead.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <df32.hxx>
|
|
#include <secdes.hxx> // 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;
|
|
}
|