https://git.reactos.org/?p=reactos.git;a=commitdiff;h=fa607733cb063d233ca04c090b03e328d8645be7

commit fa607733cb063d233ca04c090b03e328d8645be7
Author:     Eric Kohl <[email protected]>
AuthorDate: Sat Dec 25 14:18:53 2021 +0100
Commit:     Eric Kohl <[email protected]>
CommitDate: Sat Dec 25 14:18:53 2021 +0100

    [SCHEDSVC] Use a timer to start jobs
    
    This enables the service to start multiple jobs at the same time.
---
 base/services/schedsvc/job.c       | 220 +++++++++++++++----------------------
 base/services/schedsvc/precomp.h   |  12 +-
 base/services/schedsvc/rpcserver.c |   4 -
 base/services/schedsvc/schedsvc.c  |  26 +++--
 4 files changed, 110 insertions(+), 152 deletions(-)

diff --git a/base/services/schedsvc/job.c b/base/services/schedsvc/job.c
index 558ac3797dd..e29d2732716 100644
--- a/base/services/schedsvc/job.c
+++ b/base/services/schedsvc/job.c
@@ -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;
-    }
-
-    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);
+        CurrentJob = CONTAINING_RECORD(CurrentEntry, JOB, JobEntry);
 
-    CurrentTime.u.LowPart = FileTime.dwLowDateTime;
-    CurrentTime.u.HighPart = FileTime.dwHighDateTime;
+        if (bValidNextJobStartTime == FALSE)
+        {
+            CopyMemory(&NextJobStartTime, &CurrentJob->StartTime, 
sizeof(FILETIME));
+            bValidNextJobStartTime = TRUE;
+        }
+        else
+        {
+            if (CompareFileTime(&NextJobStartTime, &CurrentJob->StartTime) > 0)
+                CopyMemory(&NextJobStartTime, &CurrentJob->StartTime, 
sizeof(FILETIME));
+        }
 
-    if (CurrentTime.QuadPart >= pNextJob->StartTime.QuadPart)
-    {
-        TRACE("Next event has already gone by!\n");
-        return 0;
+        CurrentEntry = CurrentEntry->Flink;
     }
 
-    Timeout.QuadPart = (pNextJob->StartTime.QuadPart - CurrentTime.QuadPart) / 
10000;
-    if (Timeout.u.HighPart != 0)
+    if (bValidNextJobStartTime == FALSE)
     {
-        TRACE("Event happens too far in the future!\n");
-        return INFINITE;
+        TRACE("No valid job!\n");
+        return;
     }
 
-    TRACE("Timeout: %lu\n", Timeout.u.LowPart);
-    return Timeout.u.LowPart;
-}
+    LocalFileTimeToFileTime(&DueTime, &NextJobStartTime);
 
+    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);
 
-    pNextJob = CONTAINING_RECORD((&StartListHead)->Flink, JOB, StartEntry);
+        if (CompareFileTime(&NextJobStartTime, &CurrentJob->StartTime) == 0)
+        {
+            TRACE("Run job %ld: %S\n", CurrentJob->JobId, CurrentJob->Command);
 
-    TRACE("Run job %ld: %S\n", pNextJob->JobId, pNextJob->Command);
+            ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+            StartupInfo.cb = sizeof(StartupInfo);
+            StartupInfo.lpTitle = CurrentJob->Command;
+            StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+            StartupInfo.wShowWindow = SW_SHOWDEFAULT;
 
-    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
-    StartupInfo.cb = sizeof(StartupInfo);
-    StartupInfo.lpTitle = pNextJob->Command;
-    StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
-    StartupInfo.wShowWindow = SW_SHOWDEFAULT;
+            if ((CurrentJob->Flags & JOB_NONINTERACTIVE) == 0)
+            {
+                StartupInfo.dwFlags |= STARTF_INHERITDESKTOP;
+                StartupInfo.lpDesktop = L"WinSta0\\Default";
+            }
 
-    if ((pNextJob->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);
+            }
+        }
 
-    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);
+        CurrentEntry = CurrentEntry->Flink;
     }
-
-    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);
-    }
-}
-
-
-VOID
-InsertJobIntoStartList(
-    _In_ PLIST_ENTRY StartListHead,
-    _In_ PJOB pJob)
-{
-    PLIST_ENTRY CurrentEntry, PreviousEntry;
-    PJOB CurrentJob;
-
-    if (IsListEmpty(StartListHead))
-    {
-         InsertHeadList(StartListHead, &pJob->StartEntry);
-         return;
+        LocalStartTime.QuadPart += ((ULONGLONG)wDaysOffset * 24 * 60 * 60 * 
10000);
     }
 
-    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;
-    }
+    pJob->StartTime.dwLowDateTime = LocalStartTime.u.LowPart;
+    pJob->StartTime.dwHighDateTime = LocalStartTime.u.HighPart;
 }
 
-
+#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 */
diff --git a/base/services/schedsvc/precomp.h b/base/services/schedsvc/precomp.h
index 992e16796d8..f3c3e4255cf 100644
--- a/base/services/schedsvc/precomp.h
+++ b/base/services/schedsvc/precomp.h
@@ -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(
diff --git a/base/services/schedsvc/rpcserver.c 
b/base/services/schedsvc/rpcserver.c
index 4ae657f6a2a..ca3c8fd5b99 100644
--- a/base/services/schedsvc/rpcserver.c
+++ b/base/services/schedsvc/rpcserver.c
@@ -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
diff --git a/base/services/schedsvc/schedsvc.c 
b/base/services/schedsvc/schedsvc.c
index ba96195839f..dea78455141 100644
--- a/base/services/schedsvc/schedsvc.c
+++ b/base/services/schedsvc/schedsvc.c
@@ -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);

Reply via email to