[SCHEDSVC] Improvements to the scheduler service
authorEric Kohl <eric.kohl@reactos.org>
Sat, 27 Oct 2018 22:02:18 +0000 (00:02 +0200)
committerEric Kohl <eric.kohl@reactos.org>
Sat, 27 Oct 2018 22:04:20 +0000 (00:04 +0200)
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
base/services/schedsvc/precomp.h
base/services/schedsvc/rpcserver.c
base/services/schedsvc/schedsvc.c

index b7abac0..cc97f4b 100644 (file)
@@ -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;
index 6b8e748..405a0dd 100644 (file)
@@ -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);
index 1ca2b35..4ae657f 100644 (file)
@@ -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;
 }
 
index 76f0418..28e639a 100644 (file)
@@ -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);