[project @ 2001-01-26 16:16:19 by rrt]
[ghc-hetmet.git] / ghc / rts / Itimer.c
index 0db283c..6238391 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
 /* -----------------------------------------------------------------------------
- * $Id: Itimer.c,v 1.8 2000/01/13 12:40:15 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,7 +23,9 @@
 #endif
 
 #include "Rts.h"
 #endif
 
 #include "Rts.h"
+#include "RtsFlags.h"
 #include "Itimer.h"
 #include "Itimer.h"
+#include "Proftimer.h"
 #include "Schedule.h"
 
 /* As recommended in the autoconf manual */
 #include "Schedule.h"
 
 /* As recommended in the autoconf manual */
 #endif
  
 lnat total_ticks = 0;
 #endif
  
 lnat total_ticks = 0;
-rtsBool do_prof_ticks = rtsFalse;
 
 
-static void handle_tick(int unused STG_UNUSED);
+/* 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
+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);
+#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
    signal handler.
    -------------------------------------------------------------------------- */
 
 
    SMP note: this signal could be delivered to *any* thread.  We have
    to ensure that it doesn't matter which thread actually runs the
    signal handler.
    -------------------------------------------------------------------------- */
 
-static void
+static
+void
+#if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
+CALLBACK
+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++;
 
 #ifdef PROFILING
 {
   total_ticks++;
 
 #ifdef PROFILING
-  if (do_prof_ticks = rtsTrue) {
-    CCS_TICK(CCCS);
-  }
+  handleProfTick();
 #endif
 
 #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 */
+  }
 }
 
 
 }
 
 
@@ -87,16 +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))
 
-/*
-  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)
 {
@@ -107,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;
 }
  
@@ -133,11 +154,14 @@ nat
 initialize_virtual_timer(nat ms)
 {
 # ifndef HAVE_SETITIMER
 initialize_virtual_timer(nat ms)
 {
 # ifndef HAVE_SETITIMER
-    fprintf(stderr, "No virtual timer on this system\n");
+  /*    fprintf(stderr, "No virtual timer on this system\n"); */
     return -1;
 # else
     struct itimerval it;
 
     return -1;
 # 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;
@@ -156,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;
@@ -213,3 +240,23 @@ unblock_vtalrm_signal(void)
     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
 }
 #endif
     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
 }
 #endif
+
+/* 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);
+  return (tv.tv_sec * TICK_FREQUENCY +
+         tv.tv_usec * TICK_FREQUENCY / 1000000);
+}
+#else
+unsigned int
+getourtimeofday(void)
+{
+  return (unsigned int)GetTickCount() * 1000;
+}
+#endif