mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +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;
|
||||
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};
|
||||
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
DWORD
|
||||
GetNextJobTimeout(VOID)
|
||||
VOID
|
||||
GetNextJobTimeout(HANDLE hTimer)
|
||||
{
|
||||
FILETIME FileTime;
|
||||
SYSTEMTIME SystemTime;
|
||||
ULARGE_INTEGER CurrentTime, Timeout;
|
||||
PJOB pNextJob;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
FILETIME DueTime;
|
||||
PJOB CurrentJob;
|
||||
|
||||
if (IsListEmpty(&StartListHead))
|
||||
bValidNextJobStartTime = FALSE;
|
||||
CurrentEntry = JobListHead.Flink;
|
||||
while (CurrentEntry != &JobListHead)
|
||||
{
|
||||
TRACE("No job in list! Wait until next update.\n");
|
||||
return INFINITE;
|
||||
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, JobEntry);
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
if (bValidNextJobStartTime == FALSE)
|
||||
{
|
||||
TRACE("Next event has already gone by!\n");
|
||||
return 0;
|
||||
TRACE("No valid job!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Timeout.QuadPart = (pNextJob->StartTime.QuadPart - CurrentTime.QuadPart) / 10000;
|
||||
if (Timeout.u.HighPart != 0)
|
||||
{
|
||||
TRACE("Event happens too far in the future!\n");
|
||||
return INFINITE;
|
||||
}
|
||||
LocalFileTimeToFileTime(&DueTime, &NextJobStartTime);
|
||||
|
||||
TRACE("Timeout: %lu\n", Timeout.u.LowPart);
|
||||
return Timeout.u.LowPart;
|
||||
SetWaitableTimer(hTimer,
|
||||
(PLARGE_INTEGER)&DueTime,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static
|
||||
VOID
|
||||
ReScheduleJob(
|
||||
|
@ -117,59 +116,61 @@ ReScheduleJob(
|
|||
DumpStartList(&StartListHead);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
VOID
|
||||
RunNextJob(VOID)
|
||||
RunCurrentJobs(VOID)
|
||||
{
|
||||
PROCESS_INFORMATION ProcessInformation;
|
||||
STARTUPINFOW StartupInfo;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PJOB CurrentJob;
|
||||
BOOL bRet;
|
||||
PJOB pNextJob;
|
||||
|
||||
if (IsListEmpty(&StartListHead))
|
||||
CurrentEntry = JobListHead.Flink;
|
||||
while (CurrentEntry != &JobListHead)
|
||||
{
|
||||
ERR("No job in list!\n");
|
||||
return;
|
||||
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, JobEntry);
|
||||
|
||||
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 */
|
||||
CalculateNextStartTime(pJob);
|
||||
|
||||
/* Insert the job into the start list */
|
||||
InsertJobIntoStartList(&StartListHead, pJob);
|
||||
#if 0
|
||||
DumpStartList(&StartListHead);
|
||||
#endif
|
||||
|
@ -473,6 +472,7 @@ CalculateNextStartTime(
|
|||
WORD wDaysOffset, wTempOffset, i, wJobDayOfWeek, wJobDayOfMonth;
|
||||
DWORD_PTR CurrentTimeMs;
|
||||
BOOL bDaysOffsetValid;
|
||||
ULARGE_INTEGER LocalStartTime;
|
||||
|
||||
TRACE("CalculateNextStartTime(%p)\n", pJob);
|
||||
TRACE("JobTime: %lu\n", pJob->JobTime);
|
||||
|
@ -590,66 +590,18 @@ CalculateNextStartTime(
|
|||
|
||||
SystemTimeToFileTime(&StartSystemTime, &StartFileTime);
|
||||
|
||||
pJob->StartTime.u.LowPart = StartFileTime.dwLowDateTime;
|
||||
pJob->StartTime.u.HighPart = StartFileTime.dwHighDateTime;
|
||||
LocalStartTime.u.LowPart = StartFileTime.dwLowDateTime;
|
||||
LocalStartTime.u.HighPart = StartFileTime.dwHighDateTime;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
VOID
|
||||
DumpStartList(
|
||||
_In_ PLIST_ENTRY StartListHead)
|
||||
|
@ -657,8 +609,8 @@ DumpStartList(
|
|||
PLIST_ENTRY CurrentEntry;
|
||||
PJOB CurrentJob;
|
||||
|
||||
CurrentEntry = StartListHead->Flink;
|
||||
while (CurrentEntry != StartListHead)
|
||||
CurrentEntry = JobListHead->Flink;
|
||||
while (CurrentEntry != &JobListHead)
|
||||
{
|
||||
CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, StartEntry);
|
||||
|
||||
|
@ -667,5 +619,5 @@ DumpStartList(
|
|||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
/* EOF */
|
||||
|
|
|
@ -32,8 +32,7 @@ typedef struct _JOB
|
|||
{
|
||||
LIST_ENTRY JobEntry;
|
||||
|
||||
LIST_ENTRY StartEntry;
|
||||
ULARGE_INTEGER StartTime;
|
||||
FILETIME StartTime;
|
||||
WCHAR Name[JOB_NAME_LENGTH];
|
||||
|
||||
DWORD JobId;
|
||||
|
@ -54,16 +53,17 @@ extern RTL_RESOURCE JobListLock;
|
|||
extern LIST_ENTRY StartListHead;
|
||||
extern RTL_RESOURCE StartListLock;
|
||||
|
||||
extern HANDLE Events[2];
|
||||
extern HANDLE Events[3];
|
||||
|
||||
|
||||
/* job.c */
|
||||
|
||||
DWORD
|
||||
GetNextJobTimeout(VOID);
|
||||
VOID
|
||||
GetNextJobTimeout(
|
||||
HANDLE hTimer);
|
||||
|
||||
VOID
|
||||
RunNextJob(VOID);
|
||||
RunCurrentJobs(VOID);
|
||||
|
||||
LONG
|
||||
SaveJob(
|
||||
|
|
|
@ -121,8 +121,6 @@ NetrJobAdd(
|
|||
/* Calculate the next start time */
|
||||
CalculateNextStartTime(pJob);
|
||||
|
||||
/* Insert the job into the start list */
|
||||
InsertJobIntoStartList(&StartListHead, pJob);
|
||||
#if 0
|
||||
DumpStartList(&StartListHead);
|
||||
#endif
|
||||
|
@ -169,8 +167,6 @@ NetrJobDel(
|
|||
|
||||
if ((CurrentJob->JobId >= MinJobId) && (CurrentJob->JobId <= MaxJobId))
|
||||
{
|
||||
/* Remove the job from the start list */
|
||||
RemoveEntryList(&CurrentJob->StartEntry);
|
||||
#if 0
|
||||
DumpStartList(&StartListHead);
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,7 @@ static WCHAR ServiceName[] = L"Schedule";
|
|||
static SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
||||
static SERVICE_STATUS ServiceStatus;
|
||||
|
||||
HANDLE Events[2] = {NULL, NULL}; // StopEvent, UpdateEvent
|
||||
HANDLE Events[3] = {NULL, NULL, NULL}; // StopEvent, UpdateEvent, Timer
|
||||
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
@ -181,6 +181,15 @@ ServiceInit(VOID)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -188,7 +197,7 @@ ServiceInit(VOID)
|
|||
VOID WINAPI
|
||||
SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||
{
|
||||
DWORD dwWait, dwTimeout, dwError;
|
||||
DWORD dwWait, dwError;
|
||||
|
||||
UNREFERENCED_PARAMETER(argc);
|
||||
UNREFERENCED_PARAMETER(argv);
|
||||
|
@ -216,13 +225,13 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
|||
|
||||
UpdateServiceStatus(SERVICE_RUNNING);
|
||||
|
||||
dwTimeout = GetNextJobTimeout();
|
||||
GetNextJobTimeout(Events[2]);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Wait for the next event */
|
||||
TRACE("Wait for next event!\n");
|
||||
dwWait = WaitForMultipleObjects(2, Events, FALSE, dwTimeout);
|
||||
dwWait = WaitForMultipleObjects(3, Events, FALSE, INFINITE);
|
||||
if (dwWait == WAIT_OBJECT_0)
|
||||
{
|
||||
TRACE("Stop event signaled!\n");
|
||||
|
@ -233,16 +242,16 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
|||
TRACE("Update event signaled!\n");
|
||||
|
||||
RtlAcquireResourceShared(&JobListLock, TRUE);
|
||||
dwTimeout = GetNextJobTimeout();
|
||||
GetNextJobTimeout(Events[2]);
|
||||
RtlReleaseResource(&JobListLock);
|
||||
}
|
||||
else if (dwWait == WAIT_TIMEOUT)
|
||||
else if (dwWait == WAIT_OBJECT_0 + 2)
|
||||
{
|
||||
TRACE("Timeout: Start the next job!\n");
|
||||
|
||||
RtlAcquireResourceExclusive(&JobListLock, TRUE);
|
||||
RunNextJob();
|
||||
dwTimeout = GetNextJobTimeout();
|
||||
RunCurrentJobs();
|
||||
GetNextJobTimeout(Events[2]);
|
||||
RtlReleaseResource(&JobListLock);
|
||||
}
|
||||
}
|
||||
|
@ -250,6 +259,7 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
|||
/* Close the start and update event handles */
|
||||
CloseHandle(Events[0]);
|
||||
CloseHandle(Events[1]);
|
||||
CloseHandle(Events[2]);
|
||||
|
||||
/* Stop the service */
|
||||
UpdateServiceStatus(SERVICE_STOPPED);
|
||||
|
|
Loading…
Reference in a new issue