https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e4d79e514a43fa9ef3b5c…
commit e4d79e514a43fa9ef3b5c92c8d9f0eba307c8706
Author: Eric Kohl <eric.kohl(a)reactos.org>
AuthorDate: Sun Oct 28 00:02:18 2018 +0200
Commit: Eric Kohl <eric.kohl(a)reactos.org>
CommitDate: Sun Oct 28 00:04:20 2018 +0200
[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.
---
base/services/schedsvc/job.c | 55 ++++++++++++++++++++++++++++---
base/services/schedsvc/precomp.h | 5 +++
base/services/schedsvc/rpcserver.c | 16 ++++-----
base/services/schedsvc/schedsvc.c | 66 ++++++++++++++++++++++++++------------
4 files changed, 109 insertions(+), 33 deletions(-)
diff --git a/base/services/schedsvc/job.c b/base/services/schedsvc/job.c
index b7abac0873..cc97f4b46b 100644
--- a/base/services/schedsvc/job.c
+++ b/base/services/schedsvc/job.c
@@ -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;
diff --git a/base/services/schedsvc/precomp.h b/base/services/schedsvc/precomp.h
index 6b8e7480e5..405a0dd61e 100644
--- a/base/services/schedsvc/precomp.h
+++ b/base/services/schedsvc/precomp.h
@@ -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);
diff --git a/base/services/schedsvc/rpcserver.c b/base/services/schedsvc/rpcserver.c
index 1ca2b353ee..4ae657f6a2 100644
--- a/base/services/schedsvc/rpcserver.c
+++ b/base/services/schedsvc/rpcserver.c
@@ -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;
}
diff --git a/base/services/schedsvc/schedsvc.c b/base/services/schedsvc/schedsvc.c
index 76f0418ad6..28e639a5a1 100644
--- a/base/services/schedsvc/schedsvc.c
+++ b/base/services/schedsvc/schedsvc.c
@@ -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 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 scheduler event\n");
+ 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;
-
- /* Wait for the next timeout */
- WaitForSingleObject(hEvent, 5000);
- TRACE("Service running!\n");
+ }
+ 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");
+
+ }
}
- /* 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);