[project @ 2000-12-31 16:58:05 by panne]
[ghc-hetmet.git] / ghc / rts / Itimer.c
index 60e30e7..6238391 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
 /* -----------------------------------------------------------------------------
- * $Id: Itimer.c,v 1.13 2000/04/03 15:54:49 simonmar Exp $
+ * $Id: Itimer.c,v 1.19 2000/10/06 11:05:57 rrt Exp $
  *
  * (c) The GHC Team, 1995-1999
  *
  *
  * (c) The GHC Team, 1995-1999
  *
@@ -23,6 +23,7 @@
 #endif
 
 #include "Rts.h"
 #endif
 
 #include "Rts.h"
+#include "RtsFlags.h"
 #include "Itimer.h"
 #include "Proftimer.h"
 #include "Schedule.h"
 #include "Itimer.h"
 #include "Proftimer.h"
 #include "Schedule.h"
  
 lnat total_ticks = 0;
 
  
 lnat total_ticks = 0;
 
+/* ticks left before next pre-emptive context switch */
+int ticks_to_ctxt_switch = 0;
+
 static
 void
 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
 CALLBACK
 static
 void
 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
 CALLBACK
-#endif
+handle_tick(UINT uID STG_UNUSED, UINT uMsg STG_UNUSED, DWORD dwUser STG_UNUSED,
+           DWORD dw1 STG_UNUSED, DWORD d STG_UNUSED);
+#else
 handle_tick(int unused STG_UNUSED);
 handle_tick(int unused STG_UNUSED);
+#endif
 
 /* -----------------------------------------------------------------------------
    Tick handler
 
 
 /* -----------------------------------------------------------------------------
    Tick handler
 
-   We use the ticker for two things: supporting threadDelay, and time
-   profiling.
+   We use the ticker for time profiling.
 
    SMP note: this signal could be delivered to *any* thread.  We have
    to ensure that it doesn't matter which thread actually runs the
 
    SMP note: this signal could be delivered to *any* thread.  We have
    to ensure that it doesn't matter which thread actually runs the
@@ -67,8 +73,11 @@ static
 void
 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
 CALLBACK
 void
 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
 CALLBACK
-#endif
+handle_tick(UINT uID STG_UNUSED, UINT uMsg STG_UNUSED, DWORD dwUser STG_UNUSED,
+           DWORD dw1 STG_UNUSED, DWORD d STG_UNUSED)
+#else
 handle_tick(int unused STG_UNUSED)
 handle_tick(int unused STG_UNUSED)
+#endif
 {
   total_ticks++;
 
 {
   total_ticks++;
 
@@ -76,8 +85,16 @@ handle_tick(int unused STG_UNUSED)
   handleProfTick();
 #endif
 
   handleProfTick();
 #endif
 
-  /* For threadDelay etc., see Select.c */
-  ticks_since_select++;
+  /* so we can get a rough indication of the current time at any point
+   * without having to call gettimeofday() (see Select.c):
+   */
+  ticks_since_timestamp++;
+
+  ticks_to_ctxt_switch--;
+  if (ticks_to_ctxt_switch <= 0) {
+      ticks_to_ctxt_switch = RtsFlags.ConcFlags.ctxtSwitchTicks;
+      context_switch = 1;      /* schedule a context switch */
+  }
 }
 
 
 }
 
 
@@ -94,32 +111,8 @@ handle_tick(int unused STG_UNUSED)
 
 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
 
 
 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
 
-/* 
- * Sigh - to avoid requiring anyone that wants to build ghc to have
- * to augment the Win32 header files that comes with cygwinb20.1,
- * include the missing MM API decls here inline.
- *
- * ToDo: check and remove these once the next version of cygwin is
- * released.
- */
-#define TIMERR_NOERROR   0
-#define TIMERR_NOCANDO   97
-#define TIME_PERIODIC    1
-
-typedef UINT MMRESULT;
-typedef void CALLBACK (*TIMECALLBACK) (UINT, UINT, DWORD, DWORD, DWORD);
-typedef TIMECALLBACK *LPTIMECALLBACK;
-MMRESULT STDCALL  timeSetEvent(UINT, UINT, LPTIMECALLBACK, DWORD, UINT);
-/*
-  vtalrm_handler is assigned and set up in Signals.c
-
-  vtalrm_id (defined in Signals.c) holds
-  the system id for the current timer (used to 
-  later block/kill it.)
-*/
-extern nat vtalrm_id;
-TIMECALLBACK *vtalrm_cback;
+LPTIMECALLBACK vtalrm_cback;
+
 nat
 initialize_virtual_timer(nat ms)
 {
 nat
 initialize_virtual_timer(nat ms)
 {
@@ -130,23 +123,28 @@ initialize_virtual_timer(nat ms)
      
      As the delivery of ticks isn't free, we only
      enable it if we really needed, i.e., when profiling.
      
      As the delivery of ticks isn't free, we only
      enable it if we really needed, i.e., when profiling.
-     (the RTS now also needs timer ticks to implement
-     threadDelay in non-profiling mode, but the pure
-     Win32 port doesn't support that.....yet.)
+     (GetTickCount is used for threadDelay)
   */
   */
-  unsigned int delay,vtalrm_id;
+  unsigned int delay;
+  static unsigned int vtalrm_id;
  
  
-  delay = timeBeginPeriod(1);
-  if (delay == TIMERR_NOCANDO) { /* error of some sort. */
-     return delay;
+  if (ms) {
+    delay = timeBeginPeriod(1);
+    if (delay == TIMERR_NOCANDO) { /* error of some sort. */
+      return delay;
+    }
+    vtalrm_id =
+      timeSetEvent(ms,      /* event every `delay' milliseconds. */
+                  1,       /* precision is within 1 ms */
+                  vtalrm_cback,
+                  TIME_CALLBACK_FUNCTION,     /* ordinary callback */
+                  TIME_PERIODIC);
+  } else {
+    timeKillEvent(vtalrm_id);
+    timeEndPeriod(1);
   }
   }
-  vtalrm_id =
-    timeSetEvent(ms,     /* event every `delay' milliseconds. */
-               1,       /* precision is within 5 millisecs. */
-               (LPTIMECALLBACK)vtalrm_cback,
-               0,
-               TIME_PERIODIC);
 # endif
 # endif
+
   return 0;
 }
  
   return 0;
 }
  
@@ -161,6 +159,9 @@ initialize_virtual_timer(nat ms)
 # else
     struct itimerval it;
 
 # else
     struct itimerval it;
 
+    timestamp = getourtimeofday();
+    ticks_since_timestamp = 0;
+
     it.it_value.tv_sec = ms / 1000;
     it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
     it.it_interval = it.it_value;
     it.it_value.tv_sec = ms / 1000;
     it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
     it.it_interval = it.it_value;
@@ -179,6 +180,9 @@ initialize_virtual_timer(nat ms)
     struct itimerspec it;
     timer_t tid;
 
     struct itimerspec it;
     timer_t tid;
 
+    timestamp = getourtimeofday();
+    ticks_since_timestamp = 0;
+
     se.sigev_notify = SIGEV_SIGNAL;
     se.sigev_signo = SIGVTALRM;
     se.sigev_value.sival_int = SIGVTALRM;
     se.sigev_notify = SIGEV_SIGNAL;
     se.sigev_signo = SIGVTALRM;
     se.sigev_value.sival_int = SIGVTALRM;
@@ -237,12 +241,22 @@ unblock_vtalrm_signal(void)
 }
 #endif
 
 }
 #endif
 
-#if !defined(HAVE_SETITIMER) && !defined(mingw32_TARGET_OS)
+/* gettimeofday() takes around 1us on our 500MHz PIII.  Since we're
+ * only calling it 50 times/s, it shouldn't have any great impact.
+ */
+#if !defined(mingw32_TARGET_OS)
 unsigned int 
 getourtimeofday(void)
 {
   struct timeval tv;
   gettimeofday(&tv, (struct timezone *) NULL);
 unsigned int 
 getourtimeofday(void)
 {
   struct timeval tv;
   gettimeofday(&tv, (struct timezone *) NULL);
-  return (tv.tv_sec * 1000000 + tv.tv_usec);
+  return (tv.tv_sec * TICK_FREQUENCY +
+         tv.tv_usec * TICK_FREQUENCY / 1000000);
+}
+#else
+unsigned int
+getourtimeofday(void)
+{
+  return (unsigned int)GetTickCount() * 1000;
 }
 #endif
 }
 #endif