From e4d79e514a43fa9ef3b5c92c8d9f0eba307c8706 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sun, 28 Oct 2018 00:02:18 +0200 Subject: [PATCH 1/1] [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 b7abac0873e..cc97f4b46bd 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 6b8e7480e54..405a0dd61e1 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 1ca2b353ee2..4ae657f6a2a 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 76f0418ad6d..28e639a5a1c 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); -- 2.17.1