Source code of Windows XP (NT5)
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.

243 lines
3.9 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dlltimer.c
  5. Abstract:
  6. This module implements client side stubs for timer related APIs
  7. Author:
  8. Mark Lucovsky (markl) 08-Aug-1989
  9. Revision History:
  10. --*/
  11. #include "psxdll.h"
  12. #include <signal.h>
  13. ULONG MagicMultiplier = 10000000;
  14. VOID
  15. SecondsToTime (
  16. OUT PLARGE_INTEGER Time,
  17. IN ULONG Seconds
  18. )
  19. /*++
  20. Routine Description:
  21. This function converts from seconds to an equivalent
  22. relative time value in units of 100ns intervals.
  23. Arguments:
  24. Time - Returns the equivalant relative time value.
  25. Seconds - Supplies the time in seconds.
  26. Return Value:
  27. None.
  28. --*/
  29. {
  30. Time->QuadPart = (LONGLONG)Seconds * (LONGLONG)MagicMultiplier;
  31. Time->QuadPart = -Time->QuadPart;
  32. }
  33. ULONG
  34. TimeToSeconds (
  35. IN PLARGE_INTEGER Time
  36. )
  37. /*++
  38. Routine Description:
  39. This function converts from absolute time in units of 100ns
  40. intervals to seconds.
  41. Arguments:
  42. Time - Supplies an absolute time in units of 100ns intervals.
  43. Return Value:
  44. The value of time in seconds.
  45. --*/
  46. {
  47. LARGE_INTEGER Seconds;
  48. #if 0
  49. Seconds = RtlExtendedMagicDivide(
  50. *Time,
  51. MagicDivisor,
  52. MagicShiftCount
  53. );
  54. #else
  55. ULONG R; // remainder
  56. Seconds = RtlExtendedLargeIntegerDivide(
  57. *Time, // Dividend
  58. MagicMultiplier, // Divisor
  59. &R
  60. );
  61. #endif
  62. return Seconds.LowPart;
  63. }
  64. unsigned int __cdecl
  65. alarm(unsigned int seconds)
  66. {
  67. PSX_API_MSG m;
  68. PPSX_ALARM_MSG args;
  69. NTSTATUS st;
  70. unsigned int PreviousSeconds;
  71. args = &m.u.Alarm;
  72. PSX_FORMAT_API_MSG(m, PsxAlarmApi, sizeof(*args));
  73. if (0 == seconds) {
  74. args->CancelAlarm = TRUE;
  75. } else {
  76. SecondsToTime(&args->Seconds, seconds);
  77. args->CancelAlarm = FALSE;
  78. }
  79. args->PreviousSeconds.LowPart = 0;
  80. args->PreviousSeconds.HighPart = 0;
  81. st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m,
  82. (PPORT_MESSAGE)&m);
  83. #ifdef PSX_MORE_ERRORS
  84. ASSERT(NT_SUCCESS(st));
  85. #endif
  86. PreviousSeconds = TimeToSeconds(&args->PreviousSeconds);
  87. if (args->PreviousSeconds.LowPart != 0 && PreviousSeconds == 0)
  88. PreviousSeconds = 1;
  89. return PreviousSeconds;
  90. }
  91. static void
  92. __cdecl
  93. sigalrm(int signo)
  94. {
  95. //
  96. // XXX.mjb: do we need to do anything here?
  97. //
  98. }
  99. unsigned int
  100. __cdecl
  101. sleep(unsigned int seconds)
  102. {
  103. unsigned int prev, t;
  104. PVOID ohandler;
  105. sigset_t set, oset;
  106. if (seconds == 0) {
  107. getpid(); // encourage context switch
  108. return 0;
  109. }
  110. sigemptyset(&set);
  111. sigaddset(&set, SIGALRM);
  112. sigprocmask(SIG_UNBLOCK, &set, &oset);
  113. prev = alarm(0);
  114. if (0 != prev && prev < seconds) {
  115. //
  116. // There was already an alarm scheduled, and it would
  117. // have gone off before the sleep should have been done.
  118. // We sleep for the shorter amount of time, and return
  119. // with no alarm scheduled.
  120. //
  121. sigset_t s;
  122. // block SIGALRM until we're ready for it.
  123. sigemptyset(&s);
  124. sigaddset(&s, SIGALRM);
  125. sigprocmask(SIG_BLOCK, &s, NULL);
  126. (void)alarm(prev); // restore previous alarm
  127. s = oset;
  128. sigdelset(&s, SIGALRM);
  129. sigsuspend(&s);
  130. sigprocmask(SIG_SETMASK, &oset, NULL);
  131. return seconds - prev;
  132. }
  133. ohandler = signal(SIGALRM, sigalrm);
  134. {
  135. sigset_t s;
  136. #if 1
  137. // block SIGALARM until we're ready for it.
  138. sigemptyset(&s);
  139. sigaddset(&s, SIGALRM);
  140. sigprocmask(SIG_BLOCK, &s, NULL);
  141. #endif
  142. (void)alarm(seconds);
  143. #if 1
  144. s = oset;
  145. sigdelset(&s, SIGALRM);
  146. sigsuspend(&s);
  147. #else
  148. pause();
  149. #endif
  150. }
  151. t = alarm(0);
  152. signal(SIGALRM, ohandler);
  153. if (0 != prev) {
  154. //
  155. // There was a previous alarm scheduled, and we re-schedule
  156. // it to make it look like we hadn't fiddled with it.
  157. //
  158. if (prev - seconds == 0) {
  159. //
  160. // the previously-scheduled alarm would have gone
  161. // off at the same time the sleep was supposed to
  162. // return. We want to make sure two alarms are
  163. // actually delivered, so we add a second to the
  164. // previous alarm time.
  165. //
  166. prev++;
  167. }
  168. (void)alarm(prev - seconds);
  169. }
  170. sigprocmask(SIG_SETMASK, &oset, NULL);
  171. return t;
  172. }