|
|
/*
* serial.c - Access serialization routines module. */
/* Headers
**********/
#include "project.h"
#pragma hdrstop
#include "init.h"
/* Types
********/
/* process information */
typedef struct _processinfo { HANDLE hModule; } PROCESSINFO; DECLARE_STANDARD_TYPES(PROCESSINFO);
#ifdef DEBUG
/* debug flags */
typedef enum _serialdebugflags { SERIAL_DFL_BREAK_ON_PROCESS_ATTACH = 0x0001,
SERIAL_DFL_BREAK_ON_THREAD_ATTACH = 0x0002,
ALL_SERIAL_DFLAGS = (SERIAL_DFL_BREAK_ON_PROCESS_ATTACH | SERIAL_DFL_BREAK_ON_THREAD_ATTACH) } SERIALDEBUGFLAGS;
#endif /* DEBUG */
/* Module Variables
*******************/
/*
* RAIDRAID: (16273) The use of Mnrcs in a shared data section is broken under * NT. To run under NT, this code should be changed to use a shared mutex * referenced by hMutex in Mpi. */
/* critical section used for access serialization */
PRIVATE_DATA NONREENTRANTCRITICALSECTION Mnrcs = { { 0 },
#ifdef DEBUG
INVALID_THREAD_ID, #endif /* DEBUG */
FALSE };
/* number of attached processes */
PRIVATE_DATA ULONG MulcProcesses = 0;
/* information about current process */
/*
* Initialize Mpi so it is actually put in the .instanc section instead of the * .bss section. */
PRIVATE_DATA PROCESSINFO Mpi = { NULL };
#ifdef DEBUG
/* debug flags */
PRIVATE_DATA DWORD MdwSerialModuleFlags = 0;
/* .ini file switch descriptions */
PRIVATE_DATA CBOOLINISWITCH cbisBreakOnProcessAttach = { IST_BOOL, TEXT( "BreakOnProcessAttach"), &MdwSerialModuleFlags, SERIAL_DFL_BREAK_ON_PROCESS_ATTACH };
PRIVATE_DATA CBOOLINISWITCH cbisBreakOnThreadAttach = { IST_BOOL, TEXT("BreakOnThreadAttach"), &MdwSerialModuleFlags, SERIAL_DFL_BREAK_ON_THREAD_ATTACH };
PRIVATE_DATA const PCVOID MrgcpcvisSerialModule[] = { &cbisBreakOnProcessAttach, &cbisBreakOnThreadAttach };
#endif /* DEBUG */
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
#ifdef DEBUG
PRIVATE_CODE BOOL IsValidPCSERIALCONTROL(PCSERIALCONTROL); PRIVATE_CODE BOOL IsValidPCPROCESSINFO(PCPROCESSINFO); PRIVATE_CODE BOOL IsValidPCCRITICAL_SECTION(PCCRITICAL_SECTION); PRIVATE_CODE BOOL IsValidThreadId(DWORD); PRIVATE_CODE BOOL IsValidPCNONREENTRANTCRITICALSECTION(PCNONREENTRANTCRITICALSECTION);
#endif
#ifdef DEBUG
/*
** IsValidPCSERIALCONTROL() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCSERIALCONTROL(PCSERIALCONTROL pcserctrl) { return(IS_VALID_READ_PTR(pcserctrl, CSERIALCONTROL) && (! pcserctrl->AttachProcess || IS_VALID_CODE_PTR(pcserctrl->AttachProcess, AttachProcess)) && (! pcserctrl->DetachProcess || IS_VALID_CODE_PTR(pcserctrl->DetachProcess, DetachProcess)) && (! pcserctrl->AttachThread || IS_VALID_CODE_PTR(pcserctrl->AttachThread, AttachThread)) && (! pcserctrl->DetachThread|| IS_VALID_CODE_PTR(pcserctrl->DetachThread, DetachThread))); }
/*
** IsValidPCPROCESSINFO() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCPROCESSINFO(PCPROCESSINFO pcpi) { return(IS_VALID_READ_PTR(pcpi, CPROCESSINFO) && IS_VALID_HANDLE(pcpi->hModule, MODULE)); }
/*
** IsValidPCCRITICAL_SECTION() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCCRITICAL_SECTION(PCCRITICAL_SECTION pccritsec) { return(IS_VALID_READ_PTR(pccritsec, CCRITICAL_SECTION)); }
/*
** IsValidThreadId() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidThreadId(DWORD dwThreadId) { return(dwThreadId != INVALID_THREAD_ID); }
/*
** IsValidPCNONREENTRANTCRITICALSECTION() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PRIVATE_CODE BOOL IsValidPCNONREENTRANTCRITICALSECTION( PCNONREENTRANTCRITICALSECTION pcnrcs) { /* bEntered may be any value. */
return(IS_VALID_READ_PTR(pcnrcs, CNONREENTRANTCRITICALSECTION) && IS_VALID_STRUCT_PTR(&(pcnrcs->critsec), CCRITICAL_SECTION) && EVAL(pcnrcs->dwOwnerThread == INVALID_THREAD_ID || IsValidThreadId(pcnrcs->dwOwnerThread))); }
#endif
/****************************** Public Functions *****************************/
#pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
#ifdef DEBUG
/*
** SetSerialModuleIniSwitches() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL SetSerialModuleIniSwitches(void) { BOOL bResult;
bResult = SetIniSwitches(MrgcpcvisSerialModule, ARRAY_ELEMENTS(MrgcpcvisSerialModule));
ASSERT(FLAGS_ARE_VALID(MdwSerialModuleFlags, ALL_SERIAL_DFLAGS));
return(bResult); }
#endif
/*
** AttachProcess() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL AttachProcess(HMODULE hmod) { BOOL bResult;
ReinitializeNonReentrantCriticalSection(&Mnrcs);
bResult = EnterNonReentrantCriticalSection(&Mnrcs);
if (bResult) {
#ifdef DEBUG
ASSERT(SetAllIniSwitches());
TRACE_OUT((TEXT("AttachProcess(): Called for module %#lx."), hmod));
if (IS_FLAG_SET(MdwSerialModuleFlags, SERIAL_DFL_BREAK_ON_PROCESS_ATTACH)) { WARNING_OUT((TEXT("AttachProcess(): Breaking on process attach, as requested."))); DebugBreak(); }
#endif /* DEBUG */
Mpi.hModule = hmod;
ASSERT(MulcProcesses < ULONG_MAX);
if (! MulcProcesses++) { TRACE_OUT((TEXT("AttachProcess(): First process attached. Calling InitializeDLL().")));
bResult = InitializeDLL(); } else {
#ifdef PRIVATE_HEAP
bResult = TRUE;
#else
/*
* Initialize the per-instance memory manager heap for * subsequent processes. */
bResult = InitMemoryManagerModule();
#endif
}
if (bResult) { ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
if (g_cserctrl.AttachProcess) bResult = g_cserctrl.AttachProcess(hmod); }
TRACE_OUT((TEXT("AttachProcess(): There are now %lu processes attached."), MulcProcesses));
LeaveNonReentrantCriticalSection(&Mnrcs); }
return(bResult); }
/*
** DetachProcess() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL DetachProcess(HMODULE hmod) { BOOL bResult;
bResult = EnterNonReentrantCriticalSection(&Mnrcs);
if (bResult) { ASSERT(hmod == Mpi.hModule);
ASSERT(MulcProcesses > 0);
TRACE_OUT((TEXT("DetachProcess(): Called for module %#lx."), hmod));
ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
if (g_cserctrl.DetachProcess) bResult = g_cserctrl.DetachProcess(hmod);
if (--MulcProcesses) { bResult = TRUE;
#ifndef PRIVATE_HEAP
/*
* Terminate the per-instance memory manager heap. */
ExitMemoryManagerModule();
#endif
} else { TRACE_OUT((TEXT("DetachProcess(): Last process detached. Calling TerminateDLL().")));
bResult = TerminateDLL(); }
TRACE_OUT((TEXT("DetachProcess(): There are now %lu processes attached."), MulcProcesses));
LeaveNonReentrantCriticalSection(&Mnrcs); }
/*
* TODO: Clean up all this Mnrcs nonsense. It's all leftover goo * from Windows 95 and shared data sections (which we don't ues any * more). */ DeleteCriticalSection(&Mnrcs.critsec);
return(bResult); }
/*
** AttachThread() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL AttachThread(HMODULE hmod) { BOOL bResult;
bResult = EnterNonReentrantCriticalSection(&Mnrcs);
if (bResult) {
#ifdef DEBUG
ASSERT(SetAllIniSwitches());
TRACE_OUT((TEXT("AttachThread() called for module %#lx, thread ID %#lx."), hmod, GetCurrentThreadId()));
if (IS_FLAG_SET(MdwSerialModuleFlags, SERIAL_DFL_BREAK_ON_THREAD_ATTACH)) { WARNING_OUT((TEXT("AttachThread(): Breaking on thread attach, as requested."))); DebugBreak(); }
#endif
ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
if (g_cserctrl.AttachThread) bResult = g_cserctrl.AttachThread(hmod); else bResult = TRUE;
LeaveNonReentrantCriticalSection(&Mnrcs); }
return(bResult); }
/*
** DetachThread() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL DetachThread(HMODULE hmod) { BOOL bResult;
bResult = EnterNonReentrantCriticalSection(&Mnrcs);
if (bResult) { TRACE_OUT((TEXT("DetachThread() called for module %#lx, thread ID %#lx."), hmod, GetCurrentThreadId()));
ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
if (g_cserctrl.DetachThread) bResult = g_cserctrl.DetachThread(hmod); else bResult = TRUE;
LeaveNonReentrantCriticalSection(&Mnrcs); }
return(bResult); }
#pragma warning(default:4100) /* "unreferenced formal parameter" warning */
/*
** ReinitializeNonReentrantCriticalSection() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void ReinitializeNonReentrantCriticalSection( PNONREENTRANTCRITICALSECTION pnrcs) { ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
InitializeCriticalSectionAndSpinCount(&(pnrcs->critsec), 0);
return; }
/*
** EnterNonReentrantCriticalSection() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL EnterNonReentrantCriticalSection( PNONREENTRANTCRITICALSECTION pnrcs) { BOOL bEntered;
#ifdef DEBUG
BOOL bBlocked;
ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
/* Is the critical section already owned by another thread? */
/* Use pnrcs->bEntered and pnrcs->dwOwnerThread unprotected here. */
bBlocked = (pnrcs->bEntered && GetCurrentThreadId() != pnrcs->dwOwnerThread);
if (bBlocked) WARNING_OUT((TEXT("EnterNonReentrantCriticalSection(): Blocking thread %lx. Critical section is already owned by thread %#lx."), GetCurrentThreadId(), pnrcs->dwOwnerThread));
#endif
EnterCriticalSection(&(pnrcs->critsec));
bEntered = (! pnrcs->bEntered);
if (bEntered) { pnrcs->bEntered = TRUE;
#ifdef DEBUG
pnrcs->dwOwnerThread = GetCurrentThreadId();
if (bBlocked) WARNING_OUT((TEXT("EnterNonReentrantCriticalSection(): Unblocking thread %lx. Critical section is now owned by this thread."), pnrcs->dwOwnerThread)); #endif
} else { LeaveCriticalSection(&(pnrcs->critsec));
ERROR_OUT((TEXT("EnterNonReentrantCriticalSection(): Thread %#lx attempted to reenter non-reentrant code."), GetCurrentThreadId())); }
return(bEntered); }
/*
** LeaveNonReentrantCriticalSection() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void LeaveNonReentrantCriticalSection( PNONREENTRANTCRITICALSECTION pnrcs) { ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
if (EVAL(pnrcs->bEntered)) { pnrcs->bEntered = FALSE; #ifdef DEBUG
pnrcs->dwOwnerThread = INVALID_THREAD_ID; #endif
LeaveCriticalSection(&(pnrcs->critsec)); }
return; }
#ifdef DEBUG
/*
** NonReentrantCriticalSectionIsOwned() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL NonReentrantCriticalSectionIsOwned( PCNONREENTRANTCRITICALSECTION pcnrcs) { return(pcnrcs->bEntered); }
#endif
/*
** BeginExclusiveAccess() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL BeginExclusiveAccess(void) { return(EnterNonReentrantCriticalSection(&Mnrcs)); }
/*
** EndExclusiveAccess() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE void EndExclusiveAccess(void) { LeaveNonReentrantCriticalSection(&Mnrcs);
return; }
#ifdef DEBUG
/*
** AccessIsExclusive() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE BOOL AccessIsExclusive(void) { return(NonReentrantCriticalSectionIsOwned(&Mnrcs)); }
#endif /* DEBUG */
/*
** GetThisModulesHandle() ** ** ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ PUBLIC_CODE HMODULE GetThisModulesHandle(void) { ASSERT(IS_VALID_STRUCT_PTR((PCPROCESSINFO)&Mpi, CPROCESSINFO));
return(Mpi.hModule); }
|