]> code.delx.au - gnu-emacs/blobdiff - src/atimer.c
(ses-call-printer-return): Doc fix (Nil -> nil).
[gnu-emacs] / src / atimer.c
index 9dc4f508f8b7883f76ad81a2e8de6c464568debd..8b092270d7b58892cf22af66d19de6890b72be32 100644 (file)
@@ -1,5 +1,6 @@
 /* Asynchronous timers.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2002, 2003, 2004, 2005,
+                 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,17 +16,17 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
-#include <lisp.h>
 #include <signal.h>
+#include <stdio.h>
+#include <lisp.h>
 #include <syssignal.h>
 #include <systime.h>
 #include <blockinput.h>
 #include <atimer.h>
-#include <stdio.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -35,11 +36,6 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/time.h>
 #endif
 
-/* The ubiquitous min/max macros.  */
-
-#define max(X, Y) ((X) > (Y) ? (X) : (Y))
-#define min(X, Y) ((X) < (Y) ? (X) : (Y))
-
 /* Free-list of atimer structures.  */
 
 static struct atimer *free_atimers;
@@ -62,7 +58,7 @@ static struct atimer *atimers;
 
 int pending_atimers;
 
-/* Block/unblock SIGALRM.. */
+/* Block/unblock SIGALRM.  */
 
 #define BLOCK_ATIMERS   sigblock (sigmask (SIGALRM))
 #define UNBLOCK_ATIMERS sigunblock (sigmask (SIGALRM))
@@ -71,6 +67,9 @@ int pending_atimers;
 
 static void set_alarm P_ ((void));
 static void schedule_atimer P_ ((struct atimer *));
+static struct atimer *append_atimer_lists P_ ((struct atimer *,
+                                              struct atimer *));
+SIGTYPE alarm_signal_handler ();
 
 
 /* Start a new atimer of type TYPE.  TIME specifies when the timer is
@@ -100,10 +99,6 @@ start_atimer (type, time, fn, client_data)
 {
   struct atimer *t;
 
-  /* May not be called when some timers are stopped.  */
-  if (stopped_atimers)
-    abort ();
-
   /* Round TIME up to the next full second if we don't have
      itimers.  */
 #ifndef HAVE_SETITIMER
@@ -138,12 +133,12 @@ start_atimer (type, time, fn, client_data)
     case ATIMER_ABSOLUTE:
       t->expiration = time;
       break;
-      
+
     case ATIMER_RELATIVE:
       EMACS_GET_TIME (t->expiration);
       EMACS_ADD_TIME (t->expiration, t->expiration, time);
       break;
-      
+
     case ATIMER_CONTINUOUS:
       EMACS_GET_TIME (t->expiration);
       EMACS_ADD_TIME (t->expiration, t->expiration, time);
@@ -157,7 +152,7 @@ start_atimer (type, time, fn, client_data)
 
   /* Arrange for a SIGALRM at the time the next atimer is ripe.  */
   set_alarm ();
-  
+
   return t;
 }
 
@@ -168,60 +163,92 @@ void
 cancel_atimer (timer)
      struct atimer *timer;
 {
-  struct atimer *t, *prev;
-
-  /* May not be called when some timers are stopped.  */
-  if (stopped_atimers)
-    abort ();
+  int i;
 
   BLOCK_ATIMERS;
 
-  /* See if TIMER is active.  */
-  for (t = atimers, prev = 0; t && t != timer; t = t->next)
-    ;
-
-  /* If it is, take it off the list of active timers, put in on the
-     free-list.  We don't bother to arrange for setting a different
-     alarm time, since a too early one doesn't hurt.  */
-  if (t)
+  for (i = 0; i < 2; ++i)
     {
-      if (prev)
-       prev->next = t->next;
-      else
-       atimers = t->next;
+      struct atimer *t, *prev;
+      struct atimer **list = i ? &stopped_atimers : &atimers;
+
+      /* See if TIMER is active or stopped.  */
+      for (t = *list, prev = NULL; t && t != timer; prev = t, t = t->next)
+       ;
 
-      t->next = free_atimers;
-      free_atimers = t;
+      /* If it is, take it off the its list, and put in on the
+        free-list.  We don't bother to arrange for setting a
+        different alarm time, since a too early one doesn't hurt.  */
+      if (t)
+       {
+         if (prev)
+           prev->next = t->next;
+         else
+           *list = t->next;
+
+         t->next = free_atimers;
+         free_atimers = t;
+         break;
+       }
     }
 
   UNBLOCK_ATIMERS;
 }
 
 
-/* Stop all timers except timer T.  T null means stop all timers.
-   This function may only be called when all timers are running.  Two
-   calls of this function in a row will lead to an abort.  You may not
-   call cancel_atimer or start_atimer while timers are stopped.  */
+/* Append two lists of atimers LIST1 and LIST2 and return the
+   result list.  */
+
+static struct atimer *
+append_atimer_lists (list1, list2)
+     struct atimer *list1, *list2;
+{
+  if (list1 == NULL)
+    return list2;
+  else if (list2 == NULL)
+    return list1;
+  else
+    {
+      struct atimer *p;
+
+      for (p = list1; p->next; p = p->next)
+       ;
+      p->next = list2;
+      return list1;
+    }
+}
+
+
+/* Stop all timers except timer T.  T null means stop all timers.  */
 
 void
 stop_other_atimers (t)
      struct atimer *t;
 {
   BLOCK_ATIMERS;
-  
-  if (stopped_atimers)
-    abort ();
 
   if (t)
     {
-      cancel_atimer (t);
-      if (free_atimers != t)
-       abort ();
-      free_atimers = free_atimers->next;
-      t->next = NULL;
+      struct atimer *p, *prev;
+
+      /* See if T is active.  */
+      for (p = atimers, prev = NULL; p && p != t; prev = p, p = p->next)
+       ;
+
+      if (p == t)
+       {
+         if (prev)
+           prev->next = t->next;
+         else
+           atimers = t->next;
+         t->next = NULL;
+       }
+      else
+       /* T is not active.  Let's handle this like T == 0.  */
+       t = NULL;
     }
-  
-  stopped_atimers = atimers;
+
+  stopped_atimers = append_atimer_lists (atimers, stopped_atimers);
   atimers = t;
   UNBLOCK_ATIMERS;
 }
@@ -236,11 +263,19 @@ run_all_atimers ()
   if (stopped_atimers)
     {
       struct atimer *t = atimers;
+      struct atimer *next;
+
       BLOCK_ATIMERS;
       atimers = stopped_atimers;
       stopped_atimers = NULL;
-      if (t)
-       schedule_atimer (t);
+
+      while (t)
+       {
+         next = t->next;
+         schedule_atimer (t);
+         t = next;
+       }
+
       UNBLOCK_ATIMERS;
     }
 }
@@ -267,7 +302,7 @@ set_alarm ()
      must reestablish each time.  */
   signal (SIGALRM, alarm_signal_handler);
 #endif /* USG */
-  
+
   if (atimers)
     {
       EMACS_TIME now, time;
@@ -286,7 +321,7 @@ set_alarm ()
          EMACS_SET_SECS (time, 0);
          EMACS_SET_USECS (time, 1000);
        }
-      
+
       bzero (&it, sizeof it);
       it.it_value = time;
       setitimer (ITIMER_REAL, &it, 0);
@@ -316,7 +351,7 @@ schedule_atimer (t)
     prev->next = t;
   else
     atimers = t;
-  
+
   t->next = a;
 }
 
@@ -329,20 +364,24 @@ alarm_signal_handler (signo)
      int signo;
 {
   EMACS_TIME now;
-  
+
+  SIGNAL_THREAD_CHECK (signo);
+
   EMACS_GET_TIME (now);
   pending_atimers = 0;
-  
+
   while (atimers
         && (pending_atimers = interrupt_input_blocked) == 0
         && EMACS_TIME_LE (atimers->expiration, now))
     {
       struct atimer *t;
-      
+
       t = atimers;
       atimers = atimers->next;
+#ifndef MAC_OSX
       t->fn (t);
-      
+#endif
+
       if (t->type == ATIMER_CONTINUOUS)
        {
          EMACS_ADD_TIME (t->expiration, now, t->interval);
@@ -353,17 +392,16 @@ alarm_signal_handler (signo)
          t->next = free_atimers;
          free_atimers = t;
        }
-      
+#ifdef MAC_OSX
+      /* Fix for Ctrl-G.  Perhaps this should apply to all platforms. */
+      t->fn (t); 
+#endif
+
       EMACS_GET_TIME (now);
     }
-  
-#if defined (USG) && !defined (POSIX_SIGNALS)
-  /* USG systems forget handlers when they are used;
-     must reestablish each time.  */
-  signal (SIGALRM, alarm_signal_handler);
-#endif /* USG */
-  
-  set_alarm ();
+
+  if (! pending_atimers)
+    set_alarm ();
 }
 
 
@@ -405,3 +443,6 @@ init_atimer ()
   pending_atimers = 0;
   signal (SIGALRM, alarm_signal_handler);
 }
+
+/* arch-tag: e6308261-eec6-404b-89fb-6e5909518d70
+   (do not change this comment) */