NT4/private/windows/rover/filesync/core/serial.c
2020-09-30 17:12:29 +02:00

739 lines
13 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_SHARED)
/*
* 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;
#pragma data_seg(DATA_SEG_PER_INSTANCE)
/* 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
};
#pragma data_seg()
#ifdef DEBUG
#pragma data_seg(DATA_SEG_SHARED)
/* debug flags */
PRIVATE_DATA DWORD MdwSerialModuleFlags = 0;
#pragma data_seg(DATA_SEG_READ_ONLY)
/* .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
};
#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
/*
** 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);
}
/*
* Do not call DeleteCriticalSection(&(Mnrcs->critsec)) here, since doing so
* at the right time would require unprotected access to shared data
* MulcProcesses and Mnrcs->critsec. Assume Kernel32 will clean up
* Mnrcs->critsec for us at termination.
*/
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));
InitializeCriticalSection(&(pnrcs->critsec));
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);
}