mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[SCHEDSVC] Use a timer to start jobs
This enables the service to start multiple jobs at the same time.
This commit is contained in:
parent
99dcd6f71c
commit
fa607733cb
4 changed files with 117 additions and 159 deletions
|
@ -31,60 +31,59 @@ RTL_RESOURCE JobListLock;
|
||||||
|
|
||||||
LIST_ENTRY StartListHead;
|
LIST_ENTRY StartListHead;
|
||||||
RTL_RESOURCE StartListLock;
|
RTL_RESOURCE StartListLock;
|
||||||
|
FILETIME NextJobStartTime;
|
||||||
|
BOOL bValidNextJobStartTime = FALSE;
|
||||||
|
|
||||||
|
|
||||||
static WORD wDaysArray[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
static WORD wDaysArray[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
DWORD
|
VOID
|
||||||
GetNextJobTimeout(VOID)
|
GetNextJobTimeout(HANDLE hTimer)
|
||||||
{
|
{
|
||||||
FILETIME FileTime;
|
PLIST_ENTRY CurrentEntry;
|
||||||
SYSTEMTIME SystemTime;
|
FILETIME DueTime;
|
||||||
ULARGE_INTEGER CurrentTime, Timeout;
|
PJOB CurrentJob;
|
||||||
PJOB pNextJob;
|
|
||||||
|
|
||||||
if (IsListEmpty(&StartListHead))
|
bValidNextJobStartTime = FALSE;
|
||||||
|
CurrentEntry = JobListHead.Flink;
|
||||||
|
while (CurrentEntry != &JobListHead)
|
||||||
{
|
{
|
||||||
TRACE("No job in list! Wait until next update.\n");
|
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, JobEntry);
|
||||||
return INFINITE;
|
|
||||||
|
if (bValidNextJobStartTime == FALSE)
|
||||||
|
{
|
||||||
|
CopyMemory(&NextJobStartTime, &CurrentJob->StartTime, sizeof(FILETIME));
|
||||||
|
bValidNextJobStartTime = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CompareFileTime(&NextJobStartTime, &CurrentJob->StartTime) > 0)
|
||||||
|
CopyMemory(&NextJobStartTime, &CurrentJob->StartTime, sizeof(FILETIME));
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNextJob = CONTAINING_RECORD((&StartListHead)->Flink, JOB, StartEntry);
|
if (bValidNextJobStartTime == FALSE)
|
||||||
|
|
||||||
FileTime.dwLowDateTime = pNextJob->StartTime.u.LowPart;
|
|
||||||
FileTime.dwHighDateTime = pNextJob->StartTime.u.HighPart;
|
|
||||||
FileTimeToSystemTime(&FileTime, &SystemTime);
|
|
||||||
|
|
||||||
TRACE("Start next job (%lu) at %02hu:%02hu %02hu.%02hu.%hu\n",
|
|
||||||
pNextJob->JobId, SystemTime.wHour, SystemTime.wMinute,
|
|
||||||
SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear);
|
|
||||||
|
|
||||||
GetLocalTime(&SystemTime);
|
|
||||||
SystemTimeToFileTime(&SystemTime, &FileTime);
|
|
||||||
|
|
||||||
CurrentTime.u.LowPart = FileTime.dwLowDateTime;
|
|
||||||
CurrentTime.u.HighPart = FileTime.dwHighDateTime;
|
|
||||||
|
|
||||||
if (CurrentTime.QuadPart >= pNextJob->StartTime.QuadPart)
|
|
||||||
{
|
{
|
||||||
TRACE("Next event has already gone by!\n");
|
TRACE("No valid job!\n");
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeout.QuadPart = (pNextJob->StartTime.QuadPart - CurrentTime.QuadPart) / 10000;
|
LocalFileTimeToFileTime(&DueTime, &NextJobStartTime);
|
||||||
if (Timeout.u.HighPart != 0)
|
|
||||||
{
|
|
||||||
TRACE("Event happens too far in the future!\n");
|
|
||||||
return INFINITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("Timeout: %lu\n", Timeout.u.LowPart);
|
SetWaitableTimer(hTimer,
|
||||||
return Timeout.u.LowPart;
|
(PLARGE_INTEGER)&DueTime,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static
|
static
|
||||||
VOID
|
VOID
|
||||||
ReScheduleJob(
|
ReScheduleJob(
|
||||||
|
@ -117,59 +116,61 @@ ReScheduleJob(
|
||||||
DumpStartList(&StartListHead);
|
DumpStartList(&StartListHead);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
RunNextJob(VOID)
|
RunCurrentJobs(VOID)
|
||||||
{
|
{
|
||||||
PROCESS_INFORMATION ProcessInformation;
|
PROCESS_INFORMATION ProcessInformation;
|
||||||
STARTUPINFOW StartupInfo;
|
STARTUPINFOW StartupInfo;
|
||||||
|
PLIST_ENTRY CurrentEntry;
|
||||||
|
PJOB CurrentJob;
|
||||||
BOOL bRet;
|
BOOL bRet;
|
||||||
PJOB pNextJob;
|
|
||||||
|
|
||||||
if (IsListEmpty(&StartListHead))
|
CurrentEntry = JobListHead.Flink;
|
||||||
|
while (CurrentEntry != &JobListHead)
|
||||||
{
|
{
|
||||||
ERR("No job in list!\n");
|
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, JobEntry);
|
||||||
return;
|
|
||||||
|
if (CompareFileTime(&NextJobStartTime, &CurrentJob->StartTime) == 0)
|
||||||
|
{
|
||||||
|
TRACE("Run job %ld: %S\n", CurrentJob->JobId, CurrentJob->Command);
|
||||||
|
|
||||||
|
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
||||||
|
StartupInfo.cb = sizeof(StartupInfo);
|
||||||
|
StartupInfo.lpTitle = CurrentJob->Command;
|
||||||
|
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
|
||||||
|
StartupInfo.wShowWindow = SW_SHOWDEFAULT;
|
||||||
|
|
||||||
|
if ((CurrentJob->Flags & JOB_NONINTERACTIVE) == 0)
|
||||||
|
{
|
||||||
|
StartupInfo.dwFlags |= STARTF_INHERITDESKTOP;
|
||||||
|
StartupInfo.lpDesktop = L"WinSta0\\Default";
|
||||||
|
}
|
||||||
|
|
||||||
|
bRet = CreateProcessW(NULL,
|
||||||
|
CurrentJob->Command,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
FALSE,
|
||||||
|
CREATE_NEW_CONSOLE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&StartupInfo,
|
||||||
|
&ProcessInformation);
|
||||||
|
if (bRet == FALSE)
|
||||||
|
{
|
||||||
|
ERR("CreateProcessW() failed (Error %lu)\n", GetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseHandle(ProcessInformation.hThread);
|
||||||
|
CloseHandle(ProcessInformation.hProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNextJob = CONTAINING_RECORD((&StartListHead)->Flink, JOB, StartEntry);
|
|
||||||
|
|
||||||
TRACE("Run job %ld: %S\n", pNextJob->JobId, pNextJob->Command);
|
|
||||||
|
|
||||||
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
|
||||||
StartupInfo.cb = sizeof(StartupInfo);
|
|
||||||
StartupInfo.lpTitle = pNextJob->Command;
|
|
||||||
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
|
|
||||||
StartupInfo.wShowWindow = SW_SHOWDEFAULT;
|
|
||||||
|
|
||||||
if ((pNextJob->Flags & JOB_NONINTERACTIVE) == 0)
|
|
||||||
{
|
|
||||||
StartupInfo.dwFlags |= STARTF_INHERITDESKTOP;
|
|
||||||
StartupInfo.lpDesktop = L"WinSta0\\Default";
|
|
||||||
}
|
|
||||||
|
|
||||||
bRet = CreateProcessW(NULL,
|
|
||||||
pNextJob->Command,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
FALSE,
|
|
||||||
CREATE_NEW_CONSOLE,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&StartupInfo,
|
|
||||||
&ProcessInformation);
|
|
||||||
if (bRet == FALSE)
|
|
||||||
{
|
|
||||||
ERR("CreateProcessW() failed (Error %lu)\n", GetLastError());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CloseHandle(ProcessInformation.hThread);
|
|
||||||
CloseHandle(ProcessInformation.hProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReScheduleJob(pNextJob);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -420,8 +421,6 @@ LoadJobs(VOID)
|
||||||
/* Calculate the next start time */
|
/* Calculate the next start time */
|
||||||
CalculateNextStartTime(pJob);
|
CalculateNextStartTime(pJob);
|
||||||
|
|
||||||
/* Insert the job into the start list */
|
|
||||||
InsertJobIntoStartList(&StartListHead, pJob);
|
|
||||||
#if 0
|
#if 0
|
||||||
DumpStartList(&StartListHead);
|
DumpStartList(&StartListHead);
|
||||||
#endif
|
#endif
|
||||||
|
@ -473,6 +472,7 @@ CalculateNextStartTime(
|
||||||
WORD wDaysOffset, wTempOffset, i, wJobDayOfWeek, wJobDayOfMonth;
|
WORD wDaysOffset, wTempOffset, i, wJobDayOfWeek, wJobDayOfMonth;
|
||||||
DWORD_PTR CurrentTimeMs;
|
DWORD_PTR CurrentTimeMs;
|
||||||
BOOL bDaysOffsetValid;
|
BOOL bDaysOffsetValid;
|
||||||
|
ULARGE_INTEGER LocalStartTime;
|
||||||
|
|
||||||
TRACE("CalculateNextStartTime(%p)\n", pJob);
|
TRACE("CalculateNextStartTime(%p)\n", pJob);
|
||||||
TRACE("JobTime: %lu\n", pJob->JobTime);
|
TRACE("JobTime: %lu\n", pJob->JobTime);
|
||||||
|
@ -590,66 +590,18 @@ CalculateNextStartTime(
|
||||||
|
|
||||||
SystemTimeToFileTime(&StartSystemTime, &StartFileTime);
|
SystemTimeToFileTime(&StartSystemTime, &StartFileTime);
|
||||||
|
|
||||||
pJob->StartTime.u.LowPart = StartFileTime.dwLowDateTime;
|
LocalStartTime.u.LowPart = StartFileTime.dwLowDateTime;
|
||||||
pJob->StartTime.u.HighPart = StartFileTime.dwHighDateTime;
|
LocalStartTime.u.HighPart = StartFileTime.dwHighDateTime;
|
||||||
if (bDaysOffsetValid && wDaysOffset != 0)
|
if (bDaysOffsetValid && wDaysOffset != 0)
|
||||||
{
|
{
|
||||||
pJob->StartTime.QuadPart += ((ULONGLONG)wDaysOffset * 24 * 60 * 60 * 10000);
|
LocalStartTime.QuadPart += ((ULONGLONG)wDaysOffset * 24 * 60 * 60 * 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pJob->StartTime.dwLowDateTime = LocalStartTime.u.LowPart;
|
||||||
|
pJob->StartTime.dwHighDateTime = LocalStartTime.u.HighPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
VOID
|
|
||||||
InsertJobIntoStartList(
|
|
||||||
_In_ PLIST_ENTRY StartListHead,
|
|
||||||
_In_ PJOB pJob)
|
|
||||||
{
|
|
||||||
PLIST_ENTRY CurrentEntry, PreviousEntry;
|
|
||||||
PJOB CurrentJob;
|
|
||||||
|
|
||||||
if (IsListEmpty(StartListHead))
|
|
||||||
{
|
|
||||||
InsertHeadList(StartListHead, &pJob->StartEntry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentEntry = StartListHead->Flink;
|
|
||||||
while (CurrentEntry != StartListHead)
|
|
||||||
{
|
|
||||||
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, StartEntry);
|
|
||||||
|
|
||||||
if ((CurrentEntry == StartListHead->Flink) &&
|
|
||||||
(pJob->StartTime.QuadPart < CurrentJob->StartTime.QuadPart))
|
|
||||||
{
|
|
||||||
/* Insert before the first entry */
|
|
||||||
InsertHeadList(StartListHead, &pJob->StartEntry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pJob->StartTime.QuadPart < CurrentJob->StartTime.QuadPart)
|
|
||||||
{
|
|
||||||
/* Insert between the previous and the current entry */
|
|
||||||
PreviousEntry = CurrentEntry->Blink;
|
|
||||||
pJob->StartEntry.Blink = PreviousEntry;
|
|
||||||
pJob->StartEntry.Flink = CurrentEntry;
|
|
||||||
PreviousEntry->Flink = &pJob->StartEntry;
|
|
||||||
CurrentEntry->Blink = &pJob->StartEntry;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((CurrentEntry->Flink == StartListHead) &&
|
|
||||||
(pJob->StartTime.QuadPart >= CurrentJob->StartTime.QuadPart))
|
|
||||||
{
|
|
||||||
/* Insert after the last entry */
|
|
||||||
InsertTailList(StartListHead, &pJob->StartEntry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentEntry = CurrentEntry->Flink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
DumpStartList(
|
DumpStartList(
|
||||||
_In_ PLIST_ENTRY StartListHead)
|
_In_ PLIST_ENTRY StartListHead)
|
||||||
|
@ -657,8 +609,8 @@ DumpStartList(
|
||||||
PLIST_ENTRY CurrentEntry;
|
PLIST_ENTRY CurrentEntry;
|
||||||
PJOB CurrentJob;
|
PJOB CurrentJob;
|
||||||
|
|
||||||
CurrentEntry = StartListHead->Flink;
|
CurrentEntry = JobListHead->Flink;
|
||||||
while (CurrentEntry != StartListHead)
|
while (CurrentEntry != &JobListHead)
|
||||||
{
|
{
|
||||||
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, StartEntry);
|
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, StartEntry);
|
||||||
|
|
||||||
|
@ -667,5 +619,5 @@ DumpStartList(
|
||||||
CurrentEntry = CurrentEntry->Flink;
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -32,8 +32,7 @@ typedef struct _JOB
|
||||||
{
|
{
|
||||||
LIST_ENTRY JobEntry;
|
LIST_ENTRY JobEntry;
|
||||||
|
|
||||||
LIST_ENTRY StartEntry;
|
FILETIME StartTime;
|
||||||
ULARGE_INTEGER StartTime;
|
|
||||||
WCHAR Name[JOB_NAME_LENGTH];
|
WCHAR Name[JOB_NAME_LENGTH];
|
||||||
|
|
||||||
DWORD JobId;
|
DWORD JobId;
|
||||||
|
@ -54,16 +53,17 @@ extern RTL_RESOURCE JobListLock;
|
||||||
extern LIST_ENTRY StartListHead;
|
extern LIST_ENTRY StartListHead;
|
||||||
extern RTL_RESOURCE StartListLock;
|
extern RTL_RESOURCE StartListLock;
|
||||||
|
|
||||||
extern HANDLE Events[2];
|
extern HANDLE Events[3];
|
||||||
|
|
||||||
|
|
||||||
/* job.c */
|
/* job.c */
|
||||||
|
|
||||||
DWORD
|
VOID
|
||||||
GetNextJobTimeout(VOID);
|
GetNextJobTimeout(
|
||||||
|
HANDLE hTimer);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
RunNextJob(VOID);
|
RunCurrentJobs(VOID);
|
||||||
|
|
||||||
LONG
|
LONG
|
||||||
SaveJob(
|
SaveJob(
|
||||||
|
|
|
@ -121,8 +121,6 @@ NetrJobAdd(
|
||||||
/* Calculate the next start time */
|
/* Calculate the next start time */
|
||||||
CalculateNextStartTime(pJob);
|
CalculateNextStartTime(pJob);
|
||||||
|
|
||||||
/* Insert the job into the start list */
|
|
||||||
InsertJobIntoStartList(&StartListHead, pJob);
|
|
||||||
#if 0
|
#if 0
|
||||||
DumpStartList(&StartListHead);
|
DumpStartList(&StartListHead);
|
||||||
#endif
|
#endif
|
||||||
|
@ -169,8 +167,6 @@ NetrJobDel(
|
||||||
|
|
||||||
if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
|
if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
|
||||||
{
|
{
|
||||||
/* Remove the job from the start list */
|
|
||||||
RemoveEntryList(&CurrentJob->StartEntry);
|
|
||||||
#if 0
|
#if 0
|
||||||
DumpStartList(&StartListHead);
|
DumpStartList(&StartListHead);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,7 @@ static WCHAR ServiceName[] = L"Schedule";
|
||||||
static SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
static SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
||||||
static SERVICE_STATUS ServiceStatus;
|
static SERVICE_STATUS ServiceStatus;
|
||||||
|
|
||||||
HANDLE Events[2] = {NULL, NULL}; // StopEvent, UpdateEvent
|
HANDLE Events[3] = {NULL, NULL, NULL}; // StopEvent, UpdateEvent, Timer
|
||||||
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
@ -181,6 +181,15 @@ ServiceInit(VOID)
|
||||||
return GetLastError();
|
return GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Events[2] = CreateWaitableTimerW(NULL, FALSE, NULL);
|
||||||
|
if (Events[2] == NULL)
|
||||||
|
{
|
||||||
|
ERR("Could not create the timer\n");
|
||||||
|
CloseHandle(Events[1]);
|
||||||
|
CloseHandle(Events[0]);
|
||||||
|
return GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +197,7 @@ ServiceInit(VOID)
|
||||||
VOID WINAPI
|
VOID WINAPI
|
||||||
SchedServiceMain(DWORD argc, LPTSTR *argv)
|
SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
{
|
{
|
||||||
DWORD dwWait, dwTimeout, dwError;
|
DWORD dwWait, dwError;
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(argc);
|
UNREFERENCED_PARAMETER(argc);
|
||||||
UNREFERENCED_PARAMETER(argv);
|
UNREFERENCED_PARAMETER(argv);
|
||||||
|
@ -216,13 +225,13 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
|
|
||||||
UpdateServiceStatus(SERVICE_RUNNING);
|
UpdateServiceStatus(SERVICE_RUNNING);
|
||||||
|
|
||||||
dwTimeout = GetNextJobTimeout();
|
GetNextJobTimeout(Events[2]);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* Wait for the next event */
|
/* Wait for the next event */
|
||||||
TRACE("Wait for next event!\n");
|
TRACE("Wait for next event!\n");
|
||||||
dwWait = WaitForMultipleObjects(2, Events, FALSE, dwTimeout);
|
dwWait = WaitForMultipleObjects(3, Events, FALSE, INFINITE);
|
||||||
if (dwWait == WAIT_OBJECT_0)
|
if (dwWait == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
TRACE("Stop event signaled!\n");
|
TRACE("Stop event signaled!\n");
|
||||||
|
@ -233,16 +242,16 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
TRACE("Update event signaled!\n");
|
TRACE("Update event signaled!\n");
|
||||||
|
|
||||||
RtlAcquireResourceShared(&JobListLock, TRUE);
|
RtlAcquireResourceShared(&JobListLock, TRUE);
|
||||||
dwTimeout = GetNextJobTimeout();
|
GetNextJobTimeout(Events[2]);
|
||||||
RtlReleaseResource(&JobListLock);
|
RtlReleaseResource(&JobListLock);
|
||||||
}
|
}
|
||||||
else if (dwWait == WAIT_TIMEOUT)
|
else if (dwWait == WAIT_OBJECT_0 + 2)
|
||||||
{
|
{
|
||||||
TRACE("Timeout: Start the next job!\n");
|
TRACE("Timeout: Start the next job!\n");
|
||||||
|
|
||||||
RtlAcquireResourceExclusive(&JobListLock, TRUE);
|
RtlAcquireResourceExclusive(&JobListLock, TRUE);
|
||||||
RunNextJob();
|
RunCurrentJobs();
|
||||||
dwTimeout = GetNextJobTimeout();
|
GetNextJobTimeout(Events[2]);
|
||||||
RtlReleaseResource(&JobListLock);
|
RtlReleaseResource(&JobListLock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,6 +259,7 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
/* Close the start and update event handles */
|
/* Close the start and update event handles */
|
||||||
CloseHandle(Events[0]);
|
CloseHandle(Events[0]);
|
||||||
CloseHandle(Events[1]);
|
CloseHandle(Events[1]);
|
||||||
|
CloseHandle(Events[2]);
|
||||||
|
|
||||||
/* Stop the service */
|
/* Stop the service */
|
||||||
UpdateServiceStatus(SERVICE_STOPPED);
|
UpdateServiceStatus(SERVICE_STOPPED);
|
||||||
|
|
Loading…
Reference in a new issue