244 lines
3.9 KiB
C
244 lines
3.9 KiB
C
/*++
|
|
|
|
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 <signal.h>
|
|
|
|
|
|
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;
|
|
}
|