📄 watchdog.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include <kernel.h>
#define DEFAULT_WATCHDOG_PRIORITY 100
void FakedRefreshWatchDog (void)
{
}
//
// globals that can be updated by OEM
//
void (* pfnOEMRefreshWatchDog) (void) = FakedRefreshWatchDog;
DWORD dwOEMWatchDogPeriod;
DWORD dwNKWatchDogThreadPriority = DEFAULT_WATCHDOG_PRIORITY;
extern CRITICAL_SECTION WDcs;
extern LPDWORD pIsExiting;
//
// watchdog structure
//
typedef struct _WatchDog {
struct _WatchDog *pNext; // next entry in the timer list
struct _WatchDog *pPrev; // previous entry in the timer list
DWORD dwExpire; // time expired
DWORD dwState; // current state
HANDLE hWDog; // handle to the watchdog timer
DWORD dwPeriod; // watchdog period
DWORD dwWait; // time to wait before default action taken
DWORD dwDfltAction; // default action
DWORD dwParam; // parameter passed to IOCTL_HAL_REBOOT
HANDLE hProc; // process to be watched
} WatchDog, *PWatchDog;
ERRFALSE(sizeof(WatchDog) <= sizeof(FULLREF));
//
// globals internal to watchdog support
//
static PWatchDog pWDList;
static HANDLE hWDEvt;
static HANDLE hWDThrd;
//
// watchdog states
//
#define WD_STATE_STOPPED 0
#define WD_STATE_STARTED 1
#define WD_STATE_SIGNALED 2
HANDLE KillOneThread (HANDLE hTh, DWORD dwRetVal);
BOOL KernelIoctl (DWORD dwIoControlCode, LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf, DWORD nOutBufSize, LPDWORD lpBytesReturned);
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
static void WDenqueue (PWatchDog pWD)
{
if (!pWDList || ((int) (pWD->dwExpire - pWDList->dwExpire) < 0)) {
pWD->pNext = pWDList;
pWD->pPrev = NULL;
pWDList = pWD;
} else {
PWatchDog pPrev = pWDList, pNext;
while ((pNext = pPrev->pNext) && ((int) (pNext->dwExpire - pWD->dwExpire) <= 0)) {
pPrev = pNext;
}
pWD->pPrev = pPrev;
pPrev->pNext = pWD;
if (pWD->pNext = pNext) {
pNext->pPrev = pWD;
}
}
}
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
static void WDdequeue (PWatchDog pWD)
{
PWatchDog pPrev = pWD->pPrev, pNext = pWD->pNext;
if (pPrev) {
pPrev->pNext = pNext;
} else {
// pWD is the head of the list
pWDList = pNext;
}
if (pNext) {
pNext->pPrev = pPrev;
}
}
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
static void WDTakeDfltAction (PWatchDog pWD)
{
PPROCESS pProc;
LPDWORD pProcExiting;
switch (pWD->dwDfltAction) {
case WDOG_KILL_PROCESS:
// don't call SC_ProcTerminate because it'll block waiting for the process to exit
if ((pProc = HandleToProc (pWD->hProc))
&& (pProcExiting = (LPDWORD)MapPtrProc (pIsExiting, pProc))
&& !*pProcExiting) {
KillOneThread (pProc->pMainTh->hTh, 0);
// can't safely make this call because the PSL might be the process being terminated
// pPSLNotify (DLL_PROCESS_EXITING,(DWORD)pWD->hProc,(DWORD)NULL);
}
break;
case WDOG_RESET_DEVICE:
KernelIoctl (IOCTL_HAL_REBOOT, &pWD->dwParam, sizeof(DWORD), NULL, 0, NULL);
break;
default:
// no default action
break;
}
}
//--------------------------------------------------------------------------------------------
// get the watchdog pointer from a watchdog handle
//--------------------------------------------------------------------------------------------
PWatchDog GetWatchDog (HANDLE hWDog)
{
PWatchDog pWD = (PWatchDog) SC_EventGetData (hWDog);
return (IsValidKPtr (pWD) && (hWDog == pWD->hWDog))? pWD : NULL;
}
//--------------------------------------------------------------------------------------------
// associate a watchdog pointer with a watchdog handle
//--------------------------------------------------------------------------------------------
static BOOL SetWatchDog (HANDLE hWDog, PWatchDog pWD)
{
DEBUGCHK (!pWD || (pWD->hWDog == hWDog));
return SC_EventSetData (hWDog, (DWORD) pWD);
}
//--------------------------------------------------------------------------------------------
// the watchdog timer thread
//--------------------------------------------------------------------------------------------
static DWORD WINAPI WatchDogTimerThrd (
LPVOID pParam)
{
DWORD dwTimeout, dwTick, dwDiff;
PWatchDog pWD;
// the watchdog thread run with access to all processes so that it can set the watchdog event
SWITCHKEY (dwTick, 0xffffffff);
do {
// refresh hardware watchdog if exist
pfnOEMRefreshWatchDog ();
// default timeout is either hardware watchdog period, or infinite when there is no
// hardware watchdog
dwTimeout = dwOEMWatchDogPeriod? dwOEMWatchDogPeriod : INFINITE;
// look into the timer queue and see if there is any watchdog to be signaled. Also
// calculate timeout if we need to wakeup before the watchdog period expired
EnterCriticalSection (&WDcs);
while (pWDList) {
// get current time and diff
dwTick = SC_GetTickCount ();
dwDiff = pWDList->dwExpire - dwTick;
if ((int) dwDiff > 0) {
// No need to signal watchdog yet. But we need to
// adjust timeout if we need to wakeup earlier.
if (dwTimeout > dwDiff) {
dwTimeout = dwDiff;
}
break;
}
// there is at least one watchdog needs to be signaled
// remove the watchdog from the list
pWD = pWDList;
if (pWDList = pWDList->pNext) {
pWDList->pPrev = NULL;
}
// take action based on state
switch (pWD->dwState) {
case WD_STATE_STARTED:
// signal the watchdog
pWD->dwState = WD_STATE_SIGNALED;
SetEvent (pWD->hWDog);
// put ourself back to the timer queue if dwWait is specified
if (pWD->dwWait) {
pWD->dwExpire = dwTick + pWD->dwWait;
WDenqueue (pWD);
break;
}
// fall through to take default action
case WD_STATE_SIGNALED:
// watchdog isn't refreshed after dwWait, take default action
WDTakeDfltAction (pWD);
pWD->dwState = WD_STATE_STOPPED;
break;
case WD_STATE_STOPPED:
// watchdog is stopped, just remove ignore the entry
break;
default:
// should not happen
DEBUGCHK (0);
break;
}
}
LeaveCriticalSection (&WDcs);
} while (SC_WaitForMultiple (1, &hWDEvt, FALSE, dwTimeout) != WAIT_FAILED);
DEBUGCHK (0);
SC_NKTerminateThread (0);
return 0;
}
//--------------------------------------------------------------------------------------------
// create the watchdog timer thread
//--------------------------------------------------------------------------------------------
static HANDLE CreateWatchDogThread (void)
{
if (!hWDThrd) {
hWDThrd = CreateKernelThread (WatchDogTimerThrd, NULL, (WORD) dwNKWatchDogThreadPriority, 0);
DEBUGMSG (1, (L"WatchDog Timer thread %8.8lx Created\r\n", hWDThrd));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -