508 lines
11 KiB
C
508 lines
11 KiB
C
/*
|
|
* 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
|
|
*******************/
|
|
|
|
#pragma data_seg(DATA_SEG_PER_INSTANCE)
|
|
|
|
/* critical section used for access serialization */
|
|
|
|
PRIVATE_DATA NONREENTRANTCRITICALSECTION s_nrcs =
|
|
{
|
|
{ 0 },
|
|
|
|
#ifdef DEBUG
|
|
INVALID_THREAD_ID,
|
|
#endif /* DEBUG */
|
|
|
|
FALSE
|
|
};
|
|
|
|
/* information about current process */
|
|
|
|
/*
|
|
* Initialize s_pi so it is actually put in the .instanc section instead of the
|
|
* .bss section.
|
|
*/
|
|
|
|
PRIVATE_DATA PROCESSINFO s_pi =
|
|
{
|
|
NULL
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
#ifdef DEBUG
|
|
|
|
#pragma data_seg(DATA_SEG_SHARED)
|
|
|
|
/* debug flags */
|
|
|
|
PRIVATE_DATA DWORD s_dwSerialModuleFlags = 0;
|
|
|
|
#pragma data_seg(DATA_SEG_READ_ONLY)
|
|
|
|
/* .ini file switch descriptions */
|
|
|
|
PRIVATE_DATA CBOOLINISWITCH s_cbisBreakOnProcessAttach =
|
|
{
|
|
IST_BOOL,
|
|
"BreakOnProcessAttach",
|
|
&s_dwSerialModuleFlags,
|
|
SERIAL_DFL_BREAK_ON_PROCESS_ATTACH
|
|
};
|
|
|
|
PRIVATE_DATA CBOOLINISWITCH s_cbisBreakOnThreadAttach =
|
|
{
|
|
IST_BOOL,
|
|
"BreakOnThreadAttach",
|
|
&s_dwSerialModuleFlags,
|
|
SERIAL_DFL_BREAK_ON_THREAD_ATTACH
|
|
};
|
|
|
|
PRIVATE_DATA const PCVOID s_rgcpcvisSerialModule[] =
|
|
{
|
|
&s_cbisBreakOnProcessAttach,
|
|
&s_cbisBreakOnThreadAttach
|
|
};
|
|
|
|
#pragma data_seg()
|
|
|
|
#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
|
|
|
|
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)));
|
|
}
|
|
|
|
|
|
PRIVATE_CODE BOOL IsValidPCPROCESSINFO(PCPROCESSINFO pcpi)
|
|
{
|
|
return(IS_VALID_READ_PTR(pcpi, CPROCESSINFO) &&
|
|
IS_VALID_HANDLE(pcpi->hModule, MODULE));
|
|
}
|
|
|
|
|
|
PRIVATE_CODE BOOL IsValidPCCRITICAL_SECTION(PCCRITICAL_SECTION pccritsec)
|
|
{
|
|
return(IS_VALID_READ_PTR(pccritsec, CCRITICAL_SECTION));
|
|
}
|
|
|
|
|
|
PRIVATE_CODE BOOL IsValidThreadId(DWORD dwThreadId)
|
|
{
|
|
return(dwThreadId != INVALID_THREAD_ID);
|
|
}
|
|
|
|
|
|
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
|
|
|
|
PUBLIC_CODE BOOL SetSerialModuleIniSwitches(void)
|
|
{
|
|
BOOL bResult;
|
|
|
|
bResult = SetIniSwitches(s_rgcpcvisSerialModule,
|
|
ARRAY_ELEMENTS(s_rgcpcvisSerialModule));
|
|
|
|
ASSERT(FLAGS_ARE_VALID(s_dwSerialModuleFlags, ALL_SERIAL_DFLAGS));
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
PUBLIC_CODE BOOL AttachProcess(HMODULE hmod)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_HANDLE(hmod, MODULE));
|
|
|
|
InitializeNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
bResult = EnterNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
if (bResult)
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
ASSERT(SetAllIniSwitches());
|
|
|
|
TRACE_OUT(("AttachProcess(): Called for module %#lx.",
|
|
hmod));
|
|
|
|
if (IS_FLAG_SET(s_dwSerialModuleFlags, SERIAL_DFL_BREAK_ON_PROCESS_ATTACH))
|
|
{
|
|
WARNING_OUT(("AttachProcess(): Breaking on process attach, as requested."));
|
|
#ifndef MAINWIN
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
s_pi.hModule = hmod;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
|
|
|
|
if (g_cserctrl.AttachProcess)
|
|
bResult = g_cserctrl.AttachProcess(hmod);
|
|
|
|
LeaveNonReentrantCriticalSection(&s_nrcs);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE BOOL DetachProcess(HMODULE hmod)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_HANDLE(hmod, MODULE));
|
|
|
|
bResult = EnterNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
if (bResult)
|
|
{
|
|
ASSERT(hmod == s_pi.hModule);
|
|
|
|
TRACE_OUT(("DetachProcess(): Called for module %#lx.",
|
|
hmod));
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
|
|
|
|
if (g_cserctrl.DetachProcess)
|
|
bResult = g_cserctrl.DetachProcess(hmod);
|
|
|
|
LeaveNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
DeleteNonReentrantCriticalSection(&s_nrcs);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE BOOL AttachThread(HMODULE hmod)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_HANDLE(hmod, MODULE));
|
|
|
|
bResult = EnterNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
if (bResult)
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
ASSERT(SetAllIniSwitches());
|
|
|
|
TRACE_OUT(("AttachThread() called for module %#lx, thread ID %#lx.",
|
|
hmod,
|
|
GetCurrentThreadId()));
|
|
|
|
if (IS_FLAG_SET(s_dwSerialModuleFlags, SERIAL_DFL_BREAK_ON_THREAD_ATTACH))
|
|
{
|
|
WARNING_OUT(("AttachThread(): Breaking on thread attach, as requested."));
|
|
#ifndef MAINWIN
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(&g_cserctrl, CSERIALCONTROL));
|
|
|
|
if (g_cserctrl.AttachThread)
|
|
bResult = g_cserctrl.AttachThread(hmod);
|
|
else
|
|
bResult = TRUE;
|
|
|
|
LeaveNonReentrantCriticalSection(&s_nrcs);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE BOOL DetachThread(HMODULE hmod)
|
|
{
|
|
BOOL bResult;
|
|
|
|
ASSERT(IS_VALID_HANDLE(hmod, MODULE));
|
|
|
|
bResult = EnterNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
if (bResult)
|
|
{
|
|
TRACE_OUT(("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(&s_nrcs);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
#pragma warning(default:4100) /* "unreferenced formal parameter" warning */
|
|
|
|
|
|
PUBLIC_CODE void InitializeNonReentrantCriticalSection(
|
|
PNONREENTRANTCRITICALSECTION pnrcs)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
|
|
|
|
InitializeCriticalSection(&(pnrcs->critsec));
|
|
|
|
pnrcs->bEntered = FALSE;
|
|
#ifdef DEBUG
|
|
pnrcs->dwOwnerThread = INVALID_THREAD_ID;
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
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)
|
|
TRACE_OUT(("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)
|
|
TRACE_OUT(("EnterNonReentrantCriticalSection(): Unblocking thread %lx. Critical section is now owned by this thread.",
|
|
pnrcs->dwOwnerThread));
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
LeaveCriticalSection(&(pnrcs->critsec));
|
|
|
|
ERROR_OUT(("EnterNonReentrantCriticalSection(): Thread %#lx attempted to reenter non-reentrant code.",
|
|
GetCurrentThreadId()));
|
|
}
|
|
|
|
return(bEntered);
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
PUBLIC_CODE void DeleteNonReentrantCriticalSection(
|
|
PNONREENTRANTCRITICALSECTION pnrcs)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pnrcs, CNONREENTRANTCRITICALSECTION));
|
|
|
|
ASSERT(! pnrcs->bEntered);
|
|
ASSERT(pnrcs->dwOwnerThread == INVALID_THREAD_ID);
|
|
|
|
DeleteCriticalSection(&(pnrcs->critsec));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
PUBLIC_CODE BOOL NonReentrantCriticalSectionIsOwned(
|
|
PCNONREENTRANTCRITICALSECTION pcnrcs)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcnrcs, CNONREENTRANTCRITICALSECTION));
|
|
|
|
return(pcnrcs->bEntered);
|
|
}
|
|
|
|
|
|
PUBLIC_CODE DWORD GetNonReentrantCriticalSectionOwner(
|
|
PCNONREENTRANTCRITICALSECTION pcnrcs)
|
|
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR(pcnrcs, CNONREENTRANTCRITICALSECTION));
|
|
|
|
return(pcnrcs->dwOwnerThread);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
PUBLIC_CODE BOOL BeginExclusiveAccess(void)
|
|
{
|
|
return(EnterNonReentrantCriticalSection(&s_nrcs));
|
|
}
|
|
|
|
|
|
PUBLIC_CODE void EndExclusiveAccess(void)
|
|
{
|
|
LeaveNonReentrantCriticalSection(&s_nrcs);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
PUBLIC_CODE BOOL AccessIsExclusive(void)
|
|
{
|
|
return(NonReentrantCriticalSectionIsOwned(&s_nrcs) &&
|
|
GetNonReentrantCriticalSectionOwner(&s_nrcs) == GetCurrentThreadId());
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
PUBLIC_CODE HMODULE GetThisModulesHandle(void)
|
|
{
|
|
ASSERT(IS_VALID_STRUCT_PTR((PCPROCESSINFO)&s_pi, CPROCESSINFO));
|
|
|
|
return(s_pi.hModule);
|
|
}
|
|
|