mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +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 *****************************************************************/
|
/* 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
|
static
|
||||||
VOID
|
VOID
|
||||||
GetJobName(
|
GetJobName(
|
||||||
|
@ -276,8 +324,6 @@ LoadJobs(VOID)
|
||||||
pJob->JobId = dwNextJobId++;
|
pJob->JobId = dwNextJobId++;
|
||||||
dwJobCount++;
|
dwJobCount++;
|
||||||
|
|
||||||
// Cancel the start timer
|
|
||||||
|
|
||||||
/* Append the new job to the job list */
|
/* Append the new job to the job list */
|
||||||
InsertTailList(&JobListHead, &pJob->JobEntry);
|
InsertTailList(&JobListHead, &pJob->JobEntry);
|
||||||
|
|
||||||
|
@ -290,8 +336,6 @@ LoadJobs(VOID)
|
||||||
DumpStartList(&StartListHead);
|
DumpStartList(&StartListHead);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Update the start timer
|
|
||||||
|
|
||||||
/* Release the job list lock */
|
/* Release the job list lock */
|
||||||
RtlReleaseResource(&JobListLock);
|
RtlReleaseResource(&JobListLock);
|
||||||
|
|
||||||
|
@ -333,7 +377,8 @@ DaysOfMonth(
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
CalculateNextStartTime(PJOB pJob)
|
CalculateNextStartTime(
|
||||||
|
_In_ PJOB pJob)
|
||||||
{
|
{
|
||||||
SYSTEMTIME StartTime;
|
SYSTEMTIME StartTime;
|
||||||
FILETIME FileTime;
|
FILETIME FileTime;
|
||||||
|
|
|
@ -52,9 +52,14 @@ extern RTL_RESOURCE JobListLock;
|
||||||
extern LIST_ENTRY StartListHead;
|
extern LIST_ENTRY StartListHead;
|
||||||
extern RTL_RESOURCE StartListLock;
|
extern RTL_RESOURCE StartListLock;
|
||||||
|
|
||||||
|
extern HANDLE Events[2];
|
||||||
|
|
||||||
|
|
||||||
/* job.c */
|
/* job.c */
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
GetNextJobTimeout(VOID);
|
||||||
|
|
||||||
LONG
|
LONG
|
||||||
SaveJob(
|
SaveJob(
|
||||||
PJOB pJob);
|
PJOB pJob);
|
||||||
|
|
|
@ -112,8 +112,6 @@ NetrJobAdd(
|
||||||
pJob->JobId = dwNextJobId++;
|
pJob->JobId = dwNextJobId++;
|
||||||
dwJobCount++;
|
dwJobCount++;
|
||||||
|
|
||||||
// Cancel the start timer
|
|
||||||
|
|
||||||
/* Append the new job to the job list */
|
/* Append the new job to the job list */
|
||||||
InsertTailList(&JobListHead, &pJob->JobEntry);
|
InsertTailList(&JobListHead, &pJob->JobEntry);
|
||||||
|
|
||||||
|
@ -129,11 +127,13 @@ NetrJobAdd(
|
||||||
DumpStartList(&StartListHead);
|
DumpStartList(&StartListHead);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Update the start timer
|
|
||||||
|
|
||||||
/* Release the job list lock */
|
/* Release the job list lock */
|
||||||
RtlReleaseResource(&JobListLock);
|
RtlReleaseResource(&JobListLock);
|
||||||
|
|
||||||
|
/* Set the update event */
|
||||||
|
if (Events[1] != NULL)
|
||||||
|
SetEvent(Events[1]);
|
||||||
|
|
||||||
/* Return the new job ID */
|
/* Return the new job ID */
|
||||||
*pJobId = pJob->JobId;
|
*pJobId = pJob->JobId;
|
||||||
|
|
||||||
|
@ -162,8 +162,6 @@ NetrJobDel(
|
||||||
/* Acquire the job list lock exclusively */
|
/* Acquire the job list lock exclusively */
|
||||||
RtlAcquireResourceExclusive(&JobListLock, TRUE);
|
RtlAcquireResourceExclusive(&JobListLock, TRUE);
|
||||||
|
|
||||||
// Cancel the start timer
|
|
||||||
|
|
||||||
JobEntry = JobListHead.Flink;
|
JobEntry = JobListHead.Flink;
|
||||||
while (JobEntry != &JobListHead)
|
while (JobEntry != &JobListHead)
|
||||||
{
|
{
|
||||||
|
@ -193,11 +191,13 @@ NetrJobDel(
|
||||||
JobEntry = JobEntry->Flink;
|
JobEntry = JobEntry->Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the start timer
|
|
||||||
|
|
||||||
/* Release the job list lock */
|
/* Release the job list lock */
|
||||||
RtlReleaseResource(&JobListLock);
|
RtlReleaseResource(&JobListLock);
|
||||||
|
|
||||||
|
/* Set the update event */
|
||||||
|
if (Events[1] != NULL)
|
||||||
|
SetEvent(Events[1]);
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ static WCHAR ServiceName[] = L"Schedule";
|
||||||
static SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
static SERVICE_STATUS_HANDLE ServiceStatusHandle;
|
||||||
static SERVICE_STATUS ServiceStatus;
|
static SERVICE_STATUS ServiceStatus;
|
||||||
|
|
||||||
static BOOL bStopService = FALSE;
|
HANDLE Events[2] = {NULL, NULL}; // StopEvent, UpdateEvent
|
||||||
|
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ ServiceControlHandler(DWORD dwControl,
|
||||||
LPVOID lpEventData,
|
LPVOID lpEventData,
|
||||||
LPVOID lpContext)
|
LPVOID lpContext)
|
||||||
{
|
{
|
||||||
TRACE("ServiceControlHandler() called\n");
|
TRACE("ServiceControlHandler()\n");
|
||||||
|
|
||||||
switch (dwControl)
|
switch (dwControl)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +88,8 @@ ServiceControlHandler(DWORD dwControl,
|
||||||
UpdateServiceStatus(SERVICE_STOP_PENDING);
|
UpdateServiceStatus(SERVICE_STOP_PENDING);
|
||||||
/* Stop listening to incoming RPC messages */
|
/* Stop listening to incoming RPC messages */
|
||||||
RpcMgmtStopServerListening(NULL);
|
RpcMgmtStopServerListening(NULL);
|
||||||
bStopService = TRUE;
|
if (Events[0] != NULL)
|
||||||
|
SetEvent(Events[0]);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
case SERVICE_CONTROL_PAUSE:
|
case SERVICE_CONTROL_PAUSE:
|
||||||
|
@ -106,6 +108,7 @@ ServiceControlHandler(DWORD dwControl,
|
||||||
&ServiceStatus);
|
&ServiceStatus);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
|
#if 0
|
||||||
case 128:
|
case 128:
|
||||||
TRACE(" Start Shell control received\n");
|
TRACE(" Start Shell control received\n");
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
@ -113,6 +116,7 @@ ServiceControlHandler(DWORD dwControl,
|
||||||
case 129:
|
case 129:
|
||||||
TRACE(" Logoff control received\n");
|
TRACE(" Logoff control received\n");
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TRACE(" Control %lu received\n", dwControl);
|
TRACE(" Control %lu received\n", dwControl);
|
||||||
|
@ -123,7 +127,7 @@ ServiceControlHandler(DWORD dwControl,
|
||||||
|
|
||||||
static
|
static
|
||||||
DWORD
|
DWORD
|
||||||
ServiceInit(PHANDLE phEvent)
|
ServiceInit(VOID)
|
||||||
{
|
{
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
DWORD dwError;
|
DWORD dwError;
|
||||||
|
@ -160,11 +164,20 @@ ServiceInit(PHANDLE phEvent)
|
||||||
|
|
||||||
CloseHandle(hThread);
|
CloseHandle(hThread);
|
||||||
|
|
||||||
/* Create the scheduler event */
|
/* Create the stop event */
|
||||||
*phEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
Events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
if (*phEvent == 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();
|
return GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,13 +188,12 @@ ServiceInit(PHANDLE phEvent)
|
||||||
VOID WINAPI
|
VOID WINAPI
|
||||||
SchedServiceMain(DWORD argc, LPTSTR *argv)
|
SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
{
|
{
|
||||||
HANDLE hEvent = NULL;
|
DWORD dwWait, dwTimeout, dwError;
|
||||||
DWORD dwError;
|
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(argc);
|
UNREFERENCED_PARAMETER(argc);
|
||||||
UNREFERENCED_PARAMETER(argv);
|
UNREFERENCED_PARAMETER(argv);
|
||||||
|
|
||||||
TRACE("SchedServiceMain() called\n");
|
TRACE("SchedServiceMain()\n");
|
||||||
|
|
||||||
ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
|
ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
|
||||||
ServiceControlHandler,
|
ServiceControlHandler,
|
||||||
|
@ -194,7 +206,7 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
|
|
||||||
UpdateServiceStatus(SERVICE_START_PENDING);
|
UpdateServiceStatus(SERVICE_START_PENDING);
|
||||||
|
|
||||||
dwError = ServiceInit(&hEvent);
|
dwError = ServiceInit();
|
||||||
if (dwError != ERROR_SUCCESS)
|
if (dwError != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
ERR("Service stopped (dwError: %lu\n", dwError);
|
ERR("Service stopped (dwError: %lu\n", dwError);
|
||||||
|
@ -204,19 +216,33 @@ SchedServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
|
|
||||||
UpdateServiceStatus(SERVICE_RUNNING);
|
UpdateServiceStatus(SERVICE_RUNNING);
|
||||||
|
|
||||||
|
dwTimeout = GetNextJobTimeout();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* Leave the loop, if the service has to be stopped */
|
/* Wait for the next event */
|
||||||
if (bStopService)
|
TRACE("Wait for next event!\n");
|
||||||
|
dwWait = WaitForMultipleObjects(2, Events, FALSE, dwTimeout);
|
||||||
|
if (dwWait == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
TRACE("Stop event signaled!\n");
|
||||||
break;
|
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 */
|
/* Close the start and update event handles */
|
||||||
CloseHandle(hEvent);
|
CloseHandle(Events[0]);
|
||||||
|
CloseHandle(Events[1]);
|
||||||
|
|
||||||
/* Stop the service */
|
/* Stop the service */
|
||||||
UpdateServiceStatus(SERVICE_STOPPED);
|
UpdateServiceStatus(SERVICE_STOPPED);
|
||||||
|
|
Loading…
Reference in a new issue