mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +00:00
[SCHEDSVC] Improvements to the scheduler service
Use WaitForMultipleObjects in the mail scheduler loop: - Use events to signal service stop and job update events to the main loop. - Use the timeout timer to start the next job.
This commit is contained in:
parent
03294dd097
commit
e4d79e514a
4 changed files with 108 additions and 32 deletions
|
@ -35,6 +35,54 @@ RTL_RESOURCE StartListLock;
|
|||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
DWORD
|
||||
GetNextJobTimeout(VOID)
|
||||
{
|
||||
FILETIME FileTime;
|
||||
SYSTEMTIME SystemTime;
|
||||
ULARGE_INTEGER CurrentTime, Timeout;
|
||||
PJOB pNextJob;
|
||||
|
||||
if (IsListEmpty(&StartListHead))
|
||||
{
|
||||
TRACE("No job in list! Wait until next update.\n");
|
||||
return INFINITE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TRACE("Next event has already gone by!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Timeout.QuadPart = (pNextJob->StartTime.QuadPart - CurrentTime.QuadPart) / 10000;
|
||||
if (Timeout.u.HighPart != 0)
|
||||
{
|
||||
TRACE("Event happens too far in the future!\n");
|
||||
return INFINITE;
|
||||
}
|
||||
|
||||
TRACE("Timeout: %lu\n", Timeout.u.LowPart);
|
||||
return Timeout.u.LowPart;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
VOID
|
||||
GetJobName(
|
||||
|
@ -276,8 +324,6 @@ LoadJobs(VOID)
|
|||
pJob->JobId = dwNextJobId++;
|
||||
dwJobCount++;
|
||||
|
||||
// Cancel the start timer
|
||||
|
||||
/* Append the new job to the job list */
|
||||
InsertTailList(&JobListHead, &pJob->JobEntry);
|
||||
|
||||
|
@ -290,8 +336,6 @@ LoadJobs(VOID)
|
|||
DumpStartList(&StartListHead);
|
||||
#endif
|
||||
|
||||
// Update the start timer
|
||||
|
||||
/* Release the job list lock */
|
||||
RtlReleaseResource(&JobListLock);
|
||||
|
||||
|
@ -333,7 +377,8 @@ DaysOfMonth(
|
|||
|
||||
|
||||
VOID
|
||||
CalculateNextStartTime(PJOB pJob)
|
||||
CalculateNextStartTime(
|
||||
_In_ PJOB pJob)
|
||||
{
|
||||
SYSTEMTIME StartTime;
|
||||
FILETIME FileTime;
|
||||
|
|
|
@ -52,9 +52,14 @@ extern RTL_RESOURCE JobListLock;
|
|||
extern LIST_ENTRY StartListHead;
|
||||
extern RTL_RESOURCE StartListLock;
|
||||
|
||||
extern HANDLE Events[2];
|
||||
|
||||
|
||||
/* job.c */
|
||||
|
||||
DWORD
|
||||
GetNextJobTimeout(VOID);
|
||||
|
||||
LONG
|
||||
SaveJob(
|
||||
PJOB pJob);
|
||||
|
|
|
@ -112,8 +112,6 @@ NetrJobAdd(
|
|||
pJob->JobId = dwNextJobId++;
|
||||
dwJobCount++;
|
||||
|
||||
// Cancel the start timer
|
||||
|
||||
/* Append the new job to the job list */
|
||||
InsertTailList(&JobListHead, &pJob->JobEntry);
|
||||
|
||||
|
@ -129,11 +127,13 @@ NetrJobAdd(
|
|||
DumpStartList(&StartListHead);
|
||||
#endif
|
||||
|
||||
// Update the start timer
|
||||
|
||||
/* Release the job list lock */
|
||||
RtlReleaseResource(&JobListLock);
|
||||
|
||||
/* Set the update event */
|
||||
if (Events[1] != NULL)
|
||||
SetEvent(Events[1]);
|
||||
|
||||
/* Return the new job ID */
|
||||
*pJobId = pJob->JobId;
|
||||
|
||||
|
@ -162,8 +162,6 @@ NetrJobDel(
|
|||
/* Acquire the job list lock exclusively */
|
||||
RtlAcquireResourceExclusive(&JobListLock, TRUE);
|
||||
|
||||
// Cancel the start timer
|
||||
|
||||
JobEntry = JobListHead.Flink;
|
||||
while (JobEntry != &JobListHead)
|
||||
{
|
||||
|
@ -193,11 +191,13 @@ NetrJobDel(
|
|||
JobEntry = JobEntry->Flink;
|
||||
}
|
||||
|
||||
// Update the start timer
|
||||
|
||||
/* Release the job list lock */
|
||||
RtlReleaseResource(&JobListLock);
|
||||
|
||||
/* Set the update event */
|
||||
if (Events[1] != NULL)
|
||||
SetEvent(Events[1]);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ static WCHAR ServiceName[] = L"Schedule";
|
|||
static SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
||||
static SERVICE_STATUS ServiceStatus;
|
||||
|
||||
static BOOL bStopService = FALSE;
|
||||
HANDLE Events[2] = {NULL, NULL}; // StopEvent, UpdateEvent
|
||||
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
|
@ -77,7 +78,7 @@ ServiceControlHandler(DWORD dwControl,
|
|||
LPVOID lpEventData,
|
||||
LPVOID lpContext)
|
||||
{
|
||||
TRACE("ServiceControlHandler() called\n");
|
||||
TRACE("ServiceControlHandler()\n");
|
||||
|
||||
switch (dwControl)
|
||||
{
|
||||
|
@ -87,7 +88,8 @@ ServiceControlHandler(DWORD dwControl,
|
|||
UpdateServiceStatus(SERVICE_STOP_PENDING);
|
||||
/* Stop listening to incoming RPC messages */
|
||||
RpcMgmtStopServerListening(NULL);
|
||||
bStopService = TRUE;
|
||||
if (Events[0] != NULL)
|
||||
SetEvent(Events[0]);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
case SERVICE_CONTROL_PAUSE:
|
||||
|
@ -106,6 +108,7 @@ ServiceControlHandler(DWORD dwControl,
|
|||
&ServiceStatus);
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
#if 0
|
||||
case 128:
|
||||
TRACE(" Start Shell control received\n");
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -113,6 +116,7 @@ ServiceControlHandler(DWORD dwControl,
|
|||
case 129:
|
||||
TRACE(" Logoff control received\n");
|
||||
return ERROR_SUCCESS;
|
||||
#endif
|
||||
|
||||
default:
|
||||
TRACE(" Control %lu received\n", dwControl);
|
||||
|
@ -123,7 +127,7 @@ ServiceControlHandler(DWORD dwControl,
|
|||
|
||||
static
|
||||
DWORD
|
||||
ServiceInit(PHANDLE phEvent)
|
||||
ServiceInit(VOID)
|
||||
{
|
||||
HANDLE hThread;
|
||||
DWORD dwError;
|
||||
|
@ -160,11 +164,20 @@ ServiceInit(PHANDLE phEvent)
|
|||
|
||||
CloseHandle(hThread);
|
||||
|
||||
/* Create the scheduler event */
|
||||
*phEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (*phEvent == NULL)
|
||||
/* Create the stop event */
|
||||
Events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (Events[0] == NULL)
|
||||
{
|
||||
ERR("Could not create the scheduler event\n");
|
||||
ERR("Could not create the stop event\n");
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
/* Create the update event */
|
||||
Events[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (Events[1] == NULL)
|
||||
{
|
||||
ERR("Could not create the update event\n");
|
||||
CloseHandle(Events[0]);
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
|
@ -175,13 +188,12 @@ ServiceInit(PHANDLE phEvent)
|
|||
VOID WINAPI
|
||||
SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||
{
|
||||
HANDLE hEvent = NULL;
|
||||
DWORD dwError;
|
||||
DWORD dwWait, dwTimeout, dwError;
|
||||
|
||||
UNREFERENCED_PARAMETER(argc);
|
||||
UNREFERENCED_PARAMETER(argv);
|
||||
|
||||
TRACE("SchedServiceMain() called\n");
|
||||
TRACE("SchedServiceMain()\n");
|
||||
|
||||
ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
|
||||
ServiceControlHandler,
|
||||
|
@ -194,7 +206,7 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
|||
|
||||
UpdateServiceStatus(SERVICE_START_PENDING);
|
||||
|
||||
dwError = ServiceInit(&hEvent);
|
||||
dwError = ServiceInit();
|
||||
if (dwError != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Service stopped (dwError: %lu\n", dwError);
|
||||
|
@ -204,19 +216,33 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
|||
|
||||
UpdateServiceStatus(SERVICE_RUNNING);
|
||||
|
||||
dwTimeout = GetNextJobTimeout();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Leave the loop, if the service has to be stopped */
|
||||
if (bStopService)
|
||||
/* Wait for the next event */
|
||||
TRACE("Wait for next event!\n");
|
||||
dwWait = WaitForMultipleObjects(2, Events, FALSE, dwTimeout);
|
||||
if (dwWait == WAIT_OBJECT_0)
|
||||
{
|
||||
TRACE("Stop event signaled!\n");
|
||||
break;
|
||||
}
|
||||
else if (dwWait == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
TRACE("Update event signaled!\n");
|
||||
dwTimeout = GetNextJobTimeout();
|
||||
}
|
||||
else if (dwWait == WAIT_TIMEOUT)
|
||||
{
|
||||
TRACE("Timeout: Start the next job!\n");
|
||||
|
||||
/* Wait for the next timeout */
|
||||
WaitForSingleObject(hEvent, 5000);
|
||||
TRACE("Service running!\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the scheduler event handle */
|
||||
CloseHandle(hEvent);
|
||||
/* Close the start and update event handles */
|
||||
CloseHandle(Events[0]);
|
||||
CloseHandle(Events[1]);
|
||||
|
||||
/* Stop the service */
|
||||
UpdateServiceStatus(SERVICE_STOPPED);
|
||||
|
|
Loading…
Reference in a new issue