ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

time.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS Kernel
00004  * FILE:            ntoskrnl/ex/time.c
00005  * PURPOSE:         Time and Timezone Management
00006  * PROGRAMMERS:     Eric Kohl
00007  *                  Thomas Weidenmueller
00008  */
00009 
00010 /* INCLUDES *****************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 #define TICKSPERMINUTE  600000000
00017 
00018 /* GLOBALS ******************************************************************/
00019 
00020 /* Note: Bias[minutes] = UTC - local time */
00021 TIME_ZONE_INFORMATION ExpTimeZoneInfo;
00022 ULONG ExpLastTimeZoneBias = -1;
00023 LARGE_INTEGER ExpTimeZoneBias;
00024 ULONG ExpAltTimeZoneBias;
00025 ULONG ExpTimeZoneId;
00026 ULONG ExpTickCountMultiplier;
00027 ERESOURCE ExpTimeRefreshLock;
00028 ULONG ExpKernelResolutionCount = 0;
00029 ULONG ExpTimerResolutionCount = 0;
00030 
00031 /* FUNCTIONS ****************************************************************/
00032 
00033 /*++
00034  * @name ExAcquireTimeRefreshLock
00035  *
00036  *     The ExReleaseTimeRefreshLock routine acquires the system-wide lock used
00037  *     to synchronize clock interrupt frequency changes.
00038  *
00039  * @param Wait
00040  *        If TRUE, the system will block the caller thread waiting for the lock
00041  *        to become available. If FALSE, the routine will fail if the lock has
00042  *        already been acquired.
00043  *
00044  * @return Boolean value indicating success or failure of the lock acquisition.
00045  *
00046  * @remarks None.
00047  *
00048  *--*/
00049 BOOLEAN
00050 NTAPI
00051 ExAcquireTimeRefreshLock(
00052     IN BOOLEAN Wait
00053     )
00054 {
00055     /* Block APCs */
00056     KeEnterCriticalRegion();
00057 
00058     /* Attempt lock acquisition */
00059     if (!(ExAcquireResourceExclusiveLite(&ExpTimeRefreshLock, Wait)))
00060     {
00061         /* Lock was not acquired, enable APCs and fail */
00062         KeLeaveCriticalRegion();
00063         return FALSE;
00064     }
00065 
00066     /* Lock has been acquired */
00067     return TRUE;
00068 }
00069 
00070 /*++
00071  * @name ExReleaseTimeRefreshLock
00072  *
00073  *     The ExReleaseTimeRefreshLock routine releases the system-wide lock used
00074  *     to synchronize clock interrupt frequency changes.
00075  *
00076  * @param None.
00077  *
00078  * @return None.
00079  *
00080  * @remarks None.
00081  *
00082  *--*/
00083 VOID
00084 NTAPI
00085 ExReleaseTimeRefreshLock(
00086     VOID
00087     )
00088 {
00089     /* Release the lock and re-enable APCs */
00090     ExReleaseResourceLite(&ExpTimeRefreshLock);
00091     KeLeaveCriticalRegion();
00092 }
00093 
00094 /*++
00095  * @name ExSetTimerResolution
00096  * @exported
00097  *
00098  *     The KiInsertQueueApc routine modifies the frequency at which the system
00099  *     clock interrupts.
00100  *
00101  * @param DesiredTime
00102  *        Specifies the amount of time that should elapse between each timer
00103  *        interrupt, in 100-nanosecond units.
00104  *
00105  *        This parameter is ignored if SetResolution is FALSE.
00106  *
00107  * @param SetResolution
00108  *        If TRUE, the call is a request to set the clock interrupt frequency to
00109  *        the value specified by DesiredTime. If FALSE, the call is a request to
00110  *        restore the clock interrupt frequency to the system's default value.
00111  *
00112  * @return New timer resolution, in 100-nanosecond ticks.
00113  *
00114  * @remarks (1) The clock frequency is changed only if the DesiredTime value is
00115  *              less than the current setting.
00116  *
00117  *          (2) The routine just returns the current setting if the DesiredTime
00118  *              value is greater than what is currently set.
00119  *
00120  *          (3) If the DesiredTime value is less than the system clock can
00121  *              support, the routine uses the smallest resolution the system can
00122  *              support, and returns that value.
00123  *
00124  *          (4) If multiple drivers have attempted to change the clock interrupt
00125  *              frequency, the system will only restore the default frequency
00126  *              once ALL drivers have called the routine with SetResolution set
00127  *              to FALSE.
00128  *
00129  *          NB. This routine synchronizes with IRP_MJ_POWER requests through the
00130  *              TimeRefreshLock.
00131  *
00132  *--*/
00133 ULONG
00134 NTAPI
00135 ExSetTimerResolution(IN ULONG DesiredTime,
00136                      IN BOOLEAN SetResolution)
00137 {
00138     ULONG CurrentIncrement;
00139 
00140     /* Wait for clock interrupt frequency and power requests to synchronize */
00141     ExAcquireTimeRefreshLock(TRUE);
00142 
00143     /* Obey remark 2*/
00144     CurrentIncrement = KeTimeIncrement;
00145 
00146     /* Check the type of operation this is */
00147     if (SetResolution)
00148     {
00149         /*
00150          * If this is the first kernel change, bump the timer resolution change
00151          * count, then bump the kernel change count as well.
00152          *
00153          * These two variables are tracked differently since user-mode processes
00154          * can also change the timer resolution through the NtSetTimerResolution
00155          * system call. A per-process flag in the EPROCESS then stores the per-
00156          * process change state.
00157          *
00158          */
00159         if (!ExpKernelResolutionCount++) ExpTimerResolutionCount++;
00160 
00161         /* Obey remark 3 */
00162         if (DesiredTime < KeMinimumIncrement) DesiredTime = KeMinimumIncrement;
00163 
00164         /* Obey remark 1 */
00165         if (DesiredTime < KeTimeIncrement)
00166         {
00167             /* Force this thread on CPU zero, since we don't want it to drift */
00168             KeSetSystemAffinityThread(1);
00169 
00170             /* Now call the platform driver (HAL) to make the change */
00171             CurrentIncrement = HalSetTimeIncrement(DesiredTime);
00172 
00173             /* Put the thread back to its original affinity */
00174             KeRevertToUserAffinityThread();
00175 
00176             /* Finally, keep track of the new value in the kernel */
00177             KeTimeIncrement = CurrentIncrement;
00178         }
00179     }
00180     else
00181     {
00182         /* First, make sure that a driver has actually changed the resolution */
00183         if (ExpKernelResolutionCount)
00184         {
00185             /* Obey remark 4 */
00186             if (--ExpKernelResolutionCount)
00187             {
00188                 /*
00189                  * All kernel drivers have requested the original frequency to
00190                  * be restored, but there might still be user processes with an
00191                  * ongoing clock interrupt frequency change, so make sure that
00192                  * this isn't the case.
00193                  */
00194                 if (--ExpTimerResolutionCount)
00195                 {
00196                     /* Force this thread on one CPU so that it doesn't drift */
00197                     KeSetSystemAffinityThread(1);
00198 
00199                     /* Call the HAL to restore the frequency to its default */
00200                     CurrentIncrement = HalSetTimeIncrement(KeMaximumIncrement);
00201 
00202                     /* Put the thread back to its original affinity */
00203                     KeRevertToUserAffinityThread();
00204 
00205                     /* Finally, keep track of the new value in the kernel */
00206                     KeTimeIncrement = CurrentIncrement;
00207                 }
00208             }
00209         }
00210     }
00211 
00212     /* Release the clock interrupt frequency lock since changes are done */
00213     ExReleaseTimeRefreshLock();
00214 
00215     /* And return the current value -- which could reflect the new frequency */
00216     return CurrentIncrement;
00217 }
00218 
00219 VOID
00220 NTAPI
00221 ExUpdateSystemTimeFromCmos(IN BOOLEAN UpdateInterruptTime,
00222                            IN ULONG MaxSepInSeconds)
00223 {
00224     /* FIXME: TODO */
00225     return;
00226 }
00227 
00228 BOOLEAN
00229 NTAPI
00230 ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
00231 {
00232     LARGE_INTEGER CurrentTime;
00233     NTSTATUS Status;
00234 
00235     /* Read time zone information from the registry */
00236     Status = RtlQueryTimeZoneInformation(&ExpTimeZoneInfo);
00237     if (!NT_SUCCESS(Status))
00238     {
00239         /* Failed, clear all data */
00240         RtlZeroMemory(&ExpTimeZoneInfo, sizeof(TIME_ZONE_INFORMATION));
00241         ExpTimeZoneBias.QuadPart = (LONGLONG)0;
00242         ExpTimeZoneId = TIME_ZONE_ID_UNKNOWN;
00243     }
00244     else
00245     {
00246         /* FIXME: Calculate transition dates */
00247 
00248         /* Set bias and ID */
00249         ExpTimeZoneBias.QuadPart = ((LONGLONG)(ExpTimeZoneInfo.Bias +
00250             ExpTimeZoneInfo.StandardBias)) *
00251             TICKSPERMINUTE;
00252         ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
00253     }
00254 
00255     /* Change it for user-mode applications */
00256     SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
00257     SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
00258     SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
00259     SharedUserData->TimeZoneId = ExpTimeZoneId;
00260 
00261     /* Convert boot time from local time to UTC */
00262     KeBootTime.QuadPart += ExpTimeZoneBias.QuadPart;
00263 
00264     /* Convert system time from local time to UTC */
00265     do
00266     {
00267         CurrentTime.u.HighPart = SharedUserData->SystemTime.High1Time;
00268         CurrentTime.u.LowPart = SharedUserData->SystemTime.LowPart;
00269     } while (CurrentTime.u.HighPart != SharedUserData->SystemTime.High2Time);
00270 
00271     /* Change it for user-mode applications */
00272     CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
00273     SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
00274     SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
00275     SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
00276 
00277     /* Return success */
00278     return TRUE;
00279 }
00280 
00281 NTSTATUS
00282 ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation)
00283 {
00284     LARGE_INTEGER LocalTime, SystemTime, OldTime;
00285     TIME_FIELDS TimeFields;
00286     DPRINT("ExpSetTimeZoneInformation() called\n");
00287 
00288     DPRINT("Old time zone bias: %d minutes\n", ExpTimeZoneInfo.Bias);
00289     DPRINT("Old time zone standard bias: %d minutes\n",
00290             ExpTimeZoneInfo.StandardBias);
00291     DPRINT("New time zone bias: %d minutes\n", TimeZoneInformation->Bias);
00292     DPRINT("New time zone standard bias: %d minutes\n",
00293             TimeZoneInformation->StandardBias);
00294 
00295     /* Get the local time */
00296     HalQueryRealTimeClock(&TimeFields);
00297     RtlTimeFieldsToTime(&TimeFields, &LocalTime);
00298 
00299     /* FIXME: Calculate transition dates */
00300 
00301     /* Calculate the bias and set the ID */
00302     ExpTimeZoneBias.QuadPart = ((LONGLONG)(TimeZoneInformation->Bias +
00303                                            TimeZoneInformation->StandardBias)) *
00304                                            TICKSPERMINUTE;
00305     ExpTimeZoneId = TIME_ZONE_ID_STANDARD;
00306 
00307     /* Copy the timezone information */
00308     RtlCopyMemory(&ExpTimeZoneInfo,
00309                   TimeZoneInformation,
00310                   sizeof(TIME_ZONE_INFORMATION));
00311 
00312     /* Set the new time zone information */
00313     SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
00314     SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
00315     SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
00316     SharedUserData->TimeZoneId = ExpTimeZoneId;
00317 
00318     DPRINT("New time zone bias: %I64d minutes\n",
00319             ExpTimeZoneBias.QuadPart / TICKSPERMINUTE);
00320 
00321     /* Calculate the new system time */
00322     ExLocalTimeToSystemTime(&LocalTime, &SystemTime);
00323 
00324     /* Set the new system time */
00325     KeSetSystemTime(&SystemTime, &OldTime, FALSE, NULL);
00326 
00327     /* Return success */
00328     DPRINT("ExpSetTimeZoneInformation() done\n");
00329     return STATUS_SUCCESS;
00330 }
00331 
00332 /*
00333  * FUNCTION: Sets the system time.
00334  * PARAMETERS:
00335  *        NewTime - Points to a variable that specified the new time
00336  *        of day in the standard time format.
00337  *        OldTime - Optionally points to a variable that receives the
00338  *        old time of day in the standard time format.
00339  * RETURNS: Status
00340  */
00341 NTSTATUS
00342 NTAPI
00343 NtSetSystemTime(IN PLARGE_INTEGER SystemTime,
00344                 OUT PLARGE_INTEGER PreviousTime OPTIONAL)
00345 {
00346     LARGE_INTEGER OldSystemTime;
00347     LARGE_INTEGER NewSystemTime;
00348     LARGE_INTEGER LocalTime;
00349     TIME_FIELDS TimeFields;
00350     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00351     NTSTATUS Status = STATUS_SUCCESS;
00352     PAGED_CODE();
00353 
00354     /* Check if we were called from user-mode */
00355     if (PreviousMode != KernelMode)
00356     {
00357         _SEH2_TRY
00358         {
00359             /* Verify the time pointers */
00360             NewSystemTime = ProbeForReadLargeInteger(SystemTime);
00361             if(PreviousTime) ProbeForWriteLargeInteger(PreviousTime);
00362         }
00363         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00364         {
00365             /* Return the exception code */
00366             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00367         }
00368         _SEH2_END;
00369     }
00370     else
00371     {
00372         /* Reuse the pointer */
00373         NewSystemTime = *SystemTime;
00374     }
00375 
00376     /* Make sure we have permission to change the time */
00377     if (!SeSinglePrivilegeCheck(SeSystemtimePrivilege, PreviousMode))
00378     {
00379         DPRINT1("NtSetSystemTime: Caller requires the "
00380                 "SeSystemtimePrivilege privilege!\n");
00381         return STATUS_PRIVILEGE_NOT_HELD;
00382     }
00383 
00384     /* Convert the time and set it in HAL */
00385     ExSystemTimeToLocalTime(&NewSystemTime, &LocalTime);
00386     RtlTimeToTimeFields(&LocalTime, &TimeFields);
00387     HalSetRealTimeClock(&TimeFields);
00388 
00389     /* Now set system time */
00390     KeSetSystemTime(&NewSystemTime, &OldSystemTime, FALSE, NULL);
00391 
00392     /* Check if caller wanted previous time */
00393     if (PreviousTime)
00394     {
00395         /* Enter SEH Block for return */
00396         _SEH2_TRY
00397         {
00398             /* Return the previous time */
00399             *PreviousTime = OldSystemTime;
00400         }
00401         _SEH2_EXCEPT(ExSystemExceptionFilter())
00402         {
00403             /* Get the exception code */
00404             Status = _SEH2_GetExceptionCode();
00405         }
00406         _SEH2_END;
00407     }
00408 
00409     /* Return status */
00410     return Status;
00411 }
00412 
00413 /*
00414  * FUNCTION: Retrieves the system time.
00415  * PARAMETERS:
00416  *          CurrentTime - Points to a variable that receives the current
00417  *          time of day in the standard time format.
00418  */
00419 NTSTATUS
00420 NTAPI
00421 NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
00422 {
00423     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00424     NTSTATUS Status = STATUS_SUCCESS;
00425     PAGED_CODE();
00426 
00427     /* Check if we were called from user-mode */
00428     if (PreviousMode != KernelMode)
00429     {
00430         _SEH2_TRY
00431         {
00432             /* Verify the time pointer */
00433             ProbeForWriteLargeInteger(SystemTime);
00434 
00435             /*
00436              * It's safe to pass the pointer directly to KeQuerySystemTime as
00437              * it's just a basic copy to this pointer. If it raises an
00438              * exception nothing dangerous can happen!
00439              */
00440             KeQuerySystemTime(SystemTime);
00441         }
00442         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00443         {
00444             /* Get the exception code */
00445             Status = _SEH2_GetExceptionCode();
00446         }
00447         _SEH2_END;
00448     }
00449     else
00450     {
00451         /* Query the time directly */
00452         KeQuerySystemTime(SystemTime);
00453     }
00454 
00455     /* Return status to caller */
00456     return Status;
00457 }
00458 
00459 /*
00460  * @implemented
00461  */
00462 VOID
00463 NTAPI
00464 ExLocalTimeToSystemTime(PLARGE_INTEGER LocalTime,
00465                         PLARGE_INTEGER SystemTime)
00466 {
00467     SystemTime->QuadPart = LocalTime->QuadPart + ExpTimeZoneBias.QuadPart;
00468 }
00469 
00470 /*
00471  * @implemented
00472  */
00473 VOID
00474 NTAPI
00475 ExSystemTimeToLocalTime(PLARGE_INTEGER SystemTime,
00476                         PLARGE_INTEGER LocalTime)
00477 {
00478     LocalTime->QuadPart = SystemTime->QuadPart - ExpTimeZoneBias.QuadPart;
00479 }
00480 
00481 /* EOF */

Generated on Mon May 28 2012 04:18:04 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.