mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
9.7 KiB
355 lines
9.7 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
attime.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for calculating times & runtimes.
|
|
|
|
Author:
|
|
|
|
Vladimir Z. Vulovic (vladimv) 06 - November - 1992
|
|
|
|
Revision History:
|
|
|
|
06-Nov-1992 vladimv
|
|
Created
|
|
|
|
--*/
|
|
|
|
|
|
#include "at.h"
|
|
|
|
#define DAYS_IN_WEEK 7
|
|
#define SECONDS_PER_DAY 60L*60L*24L
|
|
|
|
|
|
DBGSTATIC INT DaysInMonth(
|
|
INT month,
|
|
INT year
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns number of days in a given month - the only exceptional case is
|
|
a leap year February.
|
|
|
|
Arguments:
|
|
|
|
month - integer index, must be between 0 and 11
|
|
year - integer index, any value allowed
|
|
|
|
Return Value:
|
|
|
|
Number of days in a particular month.
|
|
|
|
--*/
|
|
{
|
|
// JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
|
|
static int DaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
|
return( month == 1 && ( (year%4 == 0 && year%100 != 0) || year%400 == 0)
|
|
? 29 : DaysInMonth[ month]);
|
|
}
|
|
|
|
|
|
|
|
VOID AtCalculateRuntime(
|
|
IN OUT PAT_RECORD pRecord,
|
|
IN PAT_TIME pTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills in the next runtime for a given record.
|
|
|
|
Arguments:
|
|
|
|
pRecord pointer to AT schedule record
|
|
pTime pointer to AT time structure
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD BestDelta; // number of days before the best runtime day
|
|
DWORD Delta; // number of days before a possible runtime day
|
|
|
|
DWORD BestJobDay; // the JobDay when to run
|
|
DWORD JobDay; // index of day in week or day in month
|
|
DWORD CurrentDay; // index of the current day (week or month)
|
|
|
|
DWORD DayMask; // mask for days in week or days in month
|
|
BOOL Weekday; // TRUE if next runtime is for a week day
|
|
|
|
DWORD CurrentTime;// day time in miliseconds for the current day
|
|
DWORD JobTime; // day time in miliseconds for this job
|
|
|
|
LARGE_INTEGER Runtime;
|
|
|
|
#ifdef NOT_YET
|
|
if ( (pRecord->Flags & JOB_IS_ENABLED) == 0) {
|
|
//
|
|
// This job is disabled, so this will have the effect of putting
|
|
// it at the end of the queue.
|
|
//
|
|
pRecord->Runtime.LowPart = MAXULONG;
|
|
pRecord->Runtime.HighPart = MAXLONG;
|
|
return;
|
|
}
|
|
#endif // NOT_YET
|
|
|
|
|
|
CurrentTime = pTime->CurrentTime;
|
|
JobTime = pRecord->JobTime;
|
|
|
|
|
|
if ( (pRecord->DaysOfWeek == 0) && (pRecord->DaysOfMonth == 0)) {
|
|
|
|
BestDelta = (CurrentTime > JobTime) ? 1 : 0; // case of single runtime
|
|
|
|
} else {
|
|
|
|
BestDelta = MAXULONG; // initialize to an invalid value
|
|
|
|
if ( (DayMask = pRecord->DaysOfWeek) != 0) {
|
|
|
|
CurrentDay = pTime->CurrentDayOfWeek; // current day of week
|
|
JobDay = 0; // running day of week, starting from Monday
|
|
|
|
// Because of a bug caused by wrong compiler optimization
|
|
// (compiler obtained in mid January 93), the test for DayMask
|
|
// equal to 0 and loop increments have to burried within a body
|
|
// of the for loop. (see bug #7414). An alternative was to
|
|
// disable global optimization for this routine.
|
|
|
|
for ( ; ;) {
|
|
|
|
if ( (DayMask & 1) != 0) {
|
|
|
|
if ( CurrentDay > JobDay ||
|
|
CurrentDay == JobDay && CurrentTime >= JobTime) {
|
|
|
|
Delta = DAYS_IN_WEEK - CurrentDay + JobDay;
|
|
|
|
} else {
|
|
|
|
Delta = JobDay - CurrentDay;
|
|
|
|
}
|
|
|
|
if ( Delta < BestDelta) {
|
|
BestDelta = Delta;
|
|
BestJobDay = JobDay;
|
|
Weekday = TRUE;
|
|
}
|
|
}
|
|
|
|
DayMask >>= 1;
|
|
|
|
if ( DayMask == 0) {
|
|
break;
|
|
}
|
|
|
|
JobDay++;
|
|
}
|
|
}
|
|
|
|
if ( (DayMask = pRecord->DaysOfMonth) != 0) {
|
|
|
|
DWORD ThisMonthLength;
|
|
DWORD NextMonthLength;
|
|
|
|
ThisMonthLength = DaysInMonth(
|
|
pTime->CurrentMonth - 1,
|
|
pTime->CurrentYear
|
|
);
|
|
NextMonthLength = DaysInMonth(
|
|
(pTime->CurrentMonth) % 12,
|
|
pTime->CurrentYear
|
|
);
|
|
|
|
CurrentDay = pTime->CurrentDay; // current day of month
|
|
JobDay = 1; // running day of month, starting from 1-st day
|
|
|
|
for ( ; ;) {
|
|
|
|
if ( (DayMask & 1) != 0) {
|
|
|
|
if ( CurrentDay > JobDay ||
|
|
CurrentDay == JobDay && CurrentTime >= JobTime) {
|
|
|
|
//
|
|
// Must look in the next two months.
|
|
//
|
|
|
|
if ( NextMonthLength >= JobDay) {
|
|
|
|
Delta = ThisMonthLength - CurrentDay + JobDay;
|
|
|
|
} else {
|
|
|
|
Delta = ThisMonthLength - CurrentDay
|
|
+ NextMonthLength + JobDay;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Must look in the current month and the next month.
|
|
//
|
|
|
|
if ( ThisMonthLength >= JobDay) {
|
|
|
|
Delta = JobDay - CurrentDay;
|
|
|
|
} else {
|
|
|
|
Delta = ThisMonthLength - CurrentDay + JobDay;
|
|
|
|
}
|
|
}
|
|
|
|
if ( Delta < BestDelta) {
|
|
BestDelta = Delta;
|
|
BestJobDay = JobDay;
|
|
Weekday = FALSE;
|
|
}
|
|
}
|
|
|
|
DayMask >>= 1;
|
|
|
|
if ( DayMask == 0) {
|
|
break;
|
|
}
|
|
|
|
JobDay++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure we found a valid solution.
|
|
//
|
|
ASSERT( BestDelta != MAXULONG && BestJobDay != JOB_INVALID_DAY);
|
|
|
|
//
|
|
// If this is a NEXT type of job, remember the day to clear when
|
|
// we create the process for this job.
|
|
//
|
|
if ( (pRecord->Flags & JOB_RUN_PERIODICALLY) == 0) {
|
|
if ( Weekday == TRUE) {
|
|
pRecord->Flags |= JOB_CLEAR_WEEKDAY;
|
|
} else {
|
|
pRecord->Flags &= ~JOB_CLEAR_WEEKDAY;
|
|
}
|
|
pRecord->JobDay = (UCHAR)BestJobDay;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The first operation requires large integer when BestDelta > 49.
|
|
//
|
|
Runtime.QuadPart = UInt32x32To64(BestDelta, 24L * 3600L * 1000L);
|
|
// count of miliseconds in a day
|
|
Runtime.QuadPart += JobTime;
|
|
Runtime.QuadPart -= CurrentTime;
|
|
Runtime.QuadPart = Runtime.QuadPart * NT_TICKS_IN_WINDOWS_TICK;
|
|
pRecord->Runtime.QuadPart = pTime->LargeInteger.QuadPart +
|
|
Runtime.QuadPart;
|
|
|
|
// AtLog(( AT_DEBUG_MAIN, "CalculateRuntime: JobId=%d Command=%ws Runtime=%x:%x\n",
|
|
// pRecord->JobId, pRecord->Command, pRecord->Runtime.HighPart, pRecord->Runtime.LowPart));
|
|
//
|
|
// Make sure we return a runtime that is after the current time!
|
|
//
|
|
ASSERT( pRecord->Runtime.QuadPart > pTime->LargeInteger.QuadPart);
|
|
}
|
|
|
|
VOID AtTimeGetCurrents( IN OUT PAT_TIME pTime)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
LargeInteger & TickCount fields in input data structure
|
|
are known at input. Here we just fill in Current fields
|
|
using the input value of LargeInteger field.
|
|
|
|
Arguments:
|
|
|
|
pTime - points to AT_TIME structure.
|
|
|
|
Fields in SYSTEMTIME Structure:
|
|
WORD wYear - the current year.
|
|
WORD wMonth - the current month with January equal to 1.
|
|
WORD wDayOfWeek - the current day of the week where 0=Sunday, 1=Monday...
|
|
WORD wDay - the current day of the month.
|
|
WORD wHour - the current hour.
|
|
WORD wMinute - the current minute within the hour.
|
|
WORD wSecond - the current second within the minute.
|
|
WORD wMilliseconds - the current millisecond within the second.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
TIME_FIELDS TimeFields;
|
|
|
|
RtlTimeToTimeFields( &pTime->LargeInteger, &TimeFields);
|
|
|
|
pTime->CurrentYear = TimeFields.Year;
|
|
pTime->CurrentMonth = TimeFields.Month;
|
|
//
|
|
// Note that Windows structure has Sunday=0, Monday=1, ...
|
|
// while AT command uses: Monday=0, Tuesday=1, ... Here
|
|
// we convert from windows into AT command DayOfWeek units.
|
|
//
|
|
if ( TimeFields.Weekday == 0) {
|
|
pTime->CurrentDayOfWeek = 6; // Sunday
|
|
} else {
|
|
pTime->CurrentDayOfWeek = (WORD)(TimeFields.Weekday - 1);
|
|
}
|
|
pTime->CurrentDay = TimeFields.Day;
|
|
pTime->CurrentTime = (DWORD)TimeFields.Milliseconds +
|
|
1000 * ( TimeFields.Second +
|
|
60 * ( TimeFields.Minute + 60 * TimeFields.Hour));
|
|
}
|
|
|
|
|
|
VOID AtTimeGet( OUT PAT_TIME pTime)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns all time information needed by AT service.
|
|
|
|
Arguments:
|
|
|
|
pTime - points to AT_TIME structure
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER UniversalTime;
|
|
|
|
NtQuerySystemTime( &UniversalTime);
|
|
pTime->TickCount = GetTickCount();
|
|
RtlSystemTimeToLocalTime( &UniversalTime, &pTime->LargeInteger);
|
|
AtTimeGetCurrents( pTime);
|
|
}
|
|
|
|
|
|
|