/*++ Copyright (c) 1989 Microsoft Corporation Module Name: dlltimer.c Abstract: This module implements client side stubs for timer related APIs Author: Mark Lucovsky (markl) 08-Aug-1989 Revision History: --*/ #include "psxdll.h" #include ULONG MagicMultiplier = 10000000; VOID SecondsToTime ( OUT PLARGE_INTEGER Time, IN ULONG Seconds ) /*++ Routine Description: This function converts from seconds to an equivalent relative time value in units of 100ns intervals. Arguments: Time - Returns the equivalant relative time value. Seconds - Supplies the time in seconds. Return Value: None. --*/ { Time->QuadPart = (LONGLONG)Seconds * (LONGLONG)MagicMultiplier; Time->QuadPart = -Time->QuadPart; } ULONG TimeToSeconds ( IN PLARGE_INTEGER Time ) /*++ Routine Description: This function converts from absolute time in units of 100ns intervals to seconds. Arguments: Time - Supplies an absolute time in units of 100ns intervals. Return Value: The value of time in seconds. --*/ { LARGE_INTEGER Seconds; #if 0 Seconds = RtlExtendedMagicDivide( *Time, MagicDivisor, MagicShiftCount ); #else ULONG R; // remainder Seconds = RtlExtendedLargeIntegerDivide( *Time, // Dividend MagicMultiplier, // Divisor &R ); #endif return Seconds.LowPart; } unsigned int __cdecl alarm(unsigned int seconds) { PSX_API_MSG m; PPSX_ALARM_MSG args; NTSTATUS st; unsigned int PreviousSeconds; args = &m.u.Alarm; PSX_FORMAT_API_MSG(m, PsxAlarmApi, sizeof(*args)); if (0 == seconds) { args->CancelAlarm = TRUE; } else { SecondsToTime(&args->Seconds, seconds); args->CancelAlarm = FALSE; } args->PreviousSeconds.LowPart = 0; args->PreviousSeconds.HighPart = 0; st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m); #ifdef PSX_MORE_ERRORS ASSERT(NT_SUCCESS(st)); #endif PreviousSeconds = TimeToSeconds(&args->PreviousSeconds); if (args->PreviousSeconds.LowPart != 0 && PreviousSeconds == 0) PreviousSeconds = 1; return PreviousSeconds; } static void __cdecl sigalrm(int signo) { // // XXX.mjb: do we need to do anything here? // } unsigned int __cdecl sleep(unsigned int seconds) { unsigned int prev, t; PVOID ohandler; sigset_t set, oset; if (seconds == 0) { getpid(); // encourage context switch return 0; } sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_UNBLOCK, &set, &oset); prev = alarm(0); if (0 != prev && prev < seconds) { // // There was already an alarm scheduled, and it would // have gone off before the sleep should have been done. // We sleep for the shorter amount of time, and return // with no alarm scheduled. // sigset_t s; // block SIGALRM until we're ready for it. sigemptyset(&s); sigaddset(&s, SIGALRM); sigprocmask(SIG_BLOCK, &s, NULL); (void)alarm(prev); // restore previous alarm s = oset; sigdelset(&s, SIGALRM); sigsuspend(&s); sigprocmask(SIG_SETMASK, &oset, NULL); return seconds - prev; } ohandler = signal(SIGALRM, sigalrm); { sigset_t s; #if 1 // block SIGALARM until we're ready for it. sigemptyset(&s); sigaddset(&s, SIGALRM); sigprocmask(SIG_BLOCK, &s, NULL); #endif (void)alarm(seconds); #if 1 s = oset; sigdelset(&s, SIGALRM); sigsuspend(&s); #else pause(); #endif } t = alarm(0); signal(SIGALRM, ohandler); if (0 != prev) { // // There was a previous alarm scheduled, and we re-schedule // it to make it look like we hadn't fiddled with it. // if (prev - seconds == 0) { // // the previously-scheduled alarm would have gone // off at the same time the sleep was supposed to // return. We want to make sure two alarms are // actually delivered, so we add a second to the // previous alarm time. // prev++; } (void)alarm(prev - seconds); } sigprocmask(SIG_SETMASK, &oset, NULL); return t; }