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