diff --git a/src/gc.c b/src/gc.c
index 8fbfa89452281657559a4cf66d8c43a9462662a8..06c08dbf1ea61cc569ae876a210997e8c9468b49 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -8,6 +8,8 @@
 
 #ifdef GC2
 
+struct callback *gc_evaluator_callback=0;
+
 #include "array.h"
 #include "multiset.h"
 #include "mapping.h"
@@ -197,7 +199,7 @@ static INT32 hashprimes[] =
   2147483647,/* ~ 2^31 = 2147483648 */
 };
 
-void do_gc(void)
+void do_gc()
 {
   double tmp;
   INT32 tmp2;
@@ -282,6 +284,14 @@ void do_gc(void)
     fprintf(stderr,"done (freed %ld of %ld objects).\n",
 	    (long)(tmp2-num_objects),(long)tmp2);
 #endif
+
+#ifndef ALWAYS_GC
+  if(d_flag < 3 && gc_evaluator_callback)
+  {
+    remove_callback(gc_evaluator_callback);
+    gc_evaluator_callback=0;
+  }
+#endif
 }
 
 #endif
diff --git a/src/gc.h b/src/gc.h
index cf9ab58e1b7ad299d36257746899f5dfd5e22d7a..927d1a5e0504ba6e1932eb15b79ad6f0fa5bf3e0 100644
--- a/src/gc.h
+++ b/src/gc.h
@@ -4,22 +4,27 @@
 #ifdef GC2
 
 #include "types.h"
+#include "callback.h"
 
 extern INT32 num_objects;
 extern INT32 num_allocs;
 extern INT32 alloc_threshold;
 
-#define GC_ALLOC() do{ num_objects++; num_allocs++;  } while(0)
-#ifdef DEBUG
-#define GC_FREE() do { num_objects-- ; if(num_objects < 0) fatal("Panic!! less than zero objects!\n"); }while(0)
+extern struct callback *gc_evaluator_callback;
+extern struct callback *evaluator_callbacks;
+
+#define ADD_GC_CALLBACK() gc_evaluator_callback=add_to_callback(&evaluator_callbacks,(callback_func)do_gc,0,0)
+
+#ifdef ALWAYS_GC
+#define GC_ALLOC() do{ num_objects++; num_allocs++;  if(!gc_evaluator_callback) ADD_GC_CALLBACK(); } while(0)
 #else
-#define GC_FREE() do { num_objects-- ; }while(0)
+#define GC_ALLOC() do{ num_objects++; num_allocs++;  if(num_allocs == alloc_threshold && !gc_evaluator_callback) ADD_GC_CALLBACK(); } while(0)
 #endif
 
-#ifdef ALWAYS_GC
-#define CHECK_FOR_GC(); do { do_gc(); } while(0)
+#ifdef DEBUG
+#define GC_FREE() do { num_objects-- ; if(num_objects < 0) fatal("Panic!! less than zero objects!\n"); }while(0)
 #else
-#define CHECK_FOR_GC(); do { if(num_allocs > alloc_threshold || d_flag > 3) do_gc(); } while(0)
+#define GC_FREE() do { num_objects-- ; }while(0)
 #endif
 
 /* Prototypes begin here */
@@ -29,7 +34,7 @@ void gc_check(void *a);
 int gc_is_referenced(void *a);
 int gc_mark(void *a);
 int gc_do_free(void *a);
-void do_gc(void);
+void do_gc();
 /* Prototypes end here */
 
 #else
diff --git a/src/interpret.c b/src/interpret.c
index ef8e77c7d69d86030aae8c951b8c1506804bc6c4..9ab9009051f97f3016cac54d8a6f37c939a79660 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -25,6 +25,7 @@
 #include "signal_handler.h"
 #include "gc.h"
 #include "threads.h"
+#include "callback.h"
 
 #include <fcntl.h>
 
@@ -293,20 +294,15 @@ void pop_n_elems(INT32 x)
   free_svalues(sp,x,BIT_MIXED);
 }
 
+
+struct callback *evaluator_callbacks =0;
+
 /* This function is called 'every now and then'. (1-10000 / sec or so)
  * It should do anything that needs to be done fairly often.
  */
 void check_threads_etc()
 {
-  THREADS_ALLOW();
-
-  /* Allow other threads to run */
-
-  THREADS_DISALLOW();
-
-  check_signals();
-  if(objects_to_destruct) destruct_objects_to_destruct();
-  CHECK_FOR_GC();
+  call_callback(& evaluator_callbacks, (void *)0);
 }
 
 #ifdef DEBUG
diff --git a/src/interpret.h b/src/interpret.h
index 6669cdb15ff2a52362984950c3a0c0622c43fedc..073342956868ebc31da63d6d33872c2feb888909 100644
--- a/src/interpret.h
+++ b/src/interpret.h
@@ -102,5 +102,7 @@ extern struct svalue **mark_stack;
 extern struct frame *fp; /* frame pointer */
 extern int stack_size;
 extern int evaluator_stack_malloced, mark_stack_malloced;
+struct callback;
+extern struct callback *evaluator_callbacks;
 #endif
 
diff --git a/src/las.c b/src/las.c
index e821d295791c0e85ef6fec7f1ad84aee5307f195..c6f08de89697af4d8731f8bd7985223575030a33 100644
--- a/src/las.c
+++ b/src/las.c
@@ -21,6 +21,7 @@
 #include "main.h"
 #include "memory.h"
 #include "operators.h"
+#include "callback.h"
 
 #define LASDEBUG
 
@@ -1295,6 +1296,15 @@ static void optimize(node *n)
 	goto use_tmp1;
       }
 
+      /* for(;1;); -> for(;1;) sleep(255); (saves cpu) */
+      if(node_is_true(CAR(n)) &&
+	 (!CDR(n) || (CDR(n)->token==':' && !CADR(n) && !CDDR(n))))
+      {
+	tmp1=mknode(F_FOR, CAR(n), mknode(':',mkefuncallnode("sleep",mkintnode(255)),0));
+	CAR(n)=0;
+	goto use_tmp1;
+      }
+
       /*
        * if X and Y are free from 'continue' or X is null,
        * then the following optimizations can be done:
@@ -1507,6 +1517,22 @@ static void optimize(node *n)
   current_line = save_line;
 }
 
+struct timer_oflo
+{
+  INT32 counter;
+  int yes;
+};
+
+static void check_evaluation_time(struct callback *cb,void *ignored,void *tmp)
+{
+  struct timer_oflo *foo=(struct timer_oflo *)tmp;
+  if(foo->counter-- < 0)
+  {
+    foo->yes=1;
+    throw();
+  }
+}
+
 int eval_low(node *n)
 {
   unsigned INT16 num_strings, num_constants;
@@ -1530,7 +1556,19 @@ int eval_low(node *n)
   ret=-1;
   if(!num_parse_error)
   {
+    struct callback *tmp_callback;
+    struct timer_oflo foo;
+
+    /* This is how long we try to optimize before giving up... */
+    foo.counter=10000;
+    foo.yes=0;
+
     setup_fake_object();
+
+    tmp_callback=add_to_callback(&evaluator_callbacks,
+				 check_evaluation_time,
+				 (void *)&foo,0);
+				 
     if(apply_low_safe_and_stupid(&fake_object, jump))
     {
       /* Generate error message */
@@ -1548,8 +1586,13 @@ int eval_low(node *n)
 	yyerror("Nonstandard error format.");
       }
     }else{
-      ret=sp-save_sp;
+      if(foo.yes)
+	pop_n_elems(sp-save_sp);
+      else
+	ret=sp-save_sp;
     }
+
+    remove_callback(tmp_callback);
   }
 
   while(fake_program.num_strings > num_strings)
diff --git a/src/object.c b/src/object.c
index 0cb3f49b1d62f541b087663835903a22fa2cc9e9..7f39e727caa6d36eb6510fa69768c3075312d15a 100644
--- a/src/object.c
+++ b/src/object.c
@@ -17,6 +17,7 @@
 #include "array.h"
 #include "gc.h"
 #include "backend.h"
+#include "callback.h"
 
 struct object *master_object = 0;
 struct object *first_object;
@@ -225,34 +226,8 @@ void destruct(struct object *o)
 }
 
 
-struct object *objects_to_destruct = 0;
-
-
-/* really_free_objects:
- * This function is called when an object runs out of references.
- * It frees the object if it is destructed, otherwise it moves it to
- * a separate list of objects which will be destructed later.
- */
-
-void really_free_object(struct object *o)
-{
-  if(o->prev)
-    o->prev->next=o->next;
-  else
-    first_object=o->next;
-
-  if(o->next) o->next->prev=o->prev;
-
-  if(o->prog)
-  {
-    o->next=objects_to_destruct;
-    o->prev=0;
-    objects_to_destruct=o;
-  } else {
-    free((char *)o);
-    GC_FREE();
-  }
-}
+static struct object *objects_to_destruct = 0;
+static struct callback *destruct_object_evaluator_callback =0;
 
 /* This function destructs the objects that are scheduled to be
  * destructed by really_free_object. It links the object back into the
@@ -261,6 +236,7 @@ void really_free_object(struct object *o)
 void destruct_objects_to_destruct()
 {
   struct object *o, *next;
+
   while(o=objects_to_destruct)
   {
     /* Link object back to list of objects */
@@ -280,6 +256,45 @@ void destruct_objects_to_destruct()
     free_object(o);
   }
   objects_to_destruct=0;
+  if(destruct_object_evaluator_callback)
+  {
+    remove_callback(destruct_object_evaluator_callback);
+    destruct_object_evaluator_callback=0;
+  }
+}
+
+
+/* really_free_objects:
+ * This function is called when an object runs out of references.
+ * It frees the object if it is destructed, otherwise it moves it to
+ * a separate list of objects which will be destructed later.
+ */
+
+void really_free_object(struct object *o)
+{
+  if(o->prev)
+    o->prev->next=o->next;
+  else
+    first_object=o->next;
+
+  if(o->next) o->next->prev=o->prev;
+
+  if(o->prog)
+  {
+    if(!objects_to_destruct)
+    {
+      destruct_object_evaluator_callback=
+	add_to_callback(&evaluator_callbacks,
+			(callback_func)destruct_objects_to_destruct,
+			0,0);
+    }
+    o->next=objects_to_destruct;
+    o->prev=0;
+    objects_to_destruct=o;
+  } else {
+    free((char *)o);
+    GC_FREE();
+  }
 }
 
 
diff --git a/src/object.h b/src/object.h
index bf424118ce4566fa388a4934150f44bfa2069770..90d7d60a7099e7705d22d1705a1bfb23510db57e 100644
--- a/src/object.h
+++ b/src/object.h
@@ -38,8 +38,8 @@ struct object *clone(struct program *p, int args);
 struct object *get_master();
 struct object *master();
 void destruct(struct object *o);
-void really_free_object(struct object *o);
 void destruct_objects_to_destruct();
+void really_free_object(struct object *o);
 void object_index_no_free(struct svalue *to,
 			  struct object *o,
 			  struct svalue *index);
diff --git a/src/signal_handler.c b/src/signal_handler.c
index c09da9fde55772257a7d6adc0a40f5620d0cdace..c45cecf272f9ac616eea3036c89ee78a73f9a6b0 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -11,6 +11,7 @@
 #include "macros.h"
 #include "backend.h"
 #include "error.h"
+#include "callback.h"
 #include <signal.h>
 #include <sys/wait.h>
 
@@ -30,6 +31,8 @@ static struct svalue signal_callbacks[MAX_SIGNALS];
 
 static unsigned char sigbuf[SIGNAL_BUFFER];
 static int firstsig, lastsig;
+static struct callback *signal_evaluator_callback =0;
+
 
 struct sigdesc
 {
@@ -307,6 +310,13 @@ static void f_signal(int args)
     error("Signal out of range.\n");
   }
 
+  if(!signal_evaluator_callback)
+  {
+    signal_evaluator_callback=add_to_callback(&evaluator_callbacks,
+					      check_signals,
+					      0,0);
+  }
+
   if(args == 1)
   {
     push_int(0);
diff --git a/src/threads.c b/src/threads.c
index c135eed1467d53dc48275a1a36012dabd3c41725..a80e93b77318baa88bd58a87a1e1ec59395315d5 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -1,14 +1,17 @@
 #include "global.h"
+
+int num_threads = 1;
+int threads_disabled = 0;
+
+#ifdef _REENTRANT
 #include "threads.h"
 #include "array.h"
 #include "object.h"
 #include "macros.h"
+#include "callback.h"
 
-int num_threads = 1;
-int threads_disabled = 0;
 struct object *thread_id;
-
-#ifdef _REENTRANT
+static struct callback *threads_evaluator_callback=0;
 
 MUTEX_T interpreter_lock = PTHREAD_MUTEX_INITIALIZER;
 struct program *mutex_key = 0;
@@ -21,6 +24,15 @@ struct thread_starter
   struct array *args;
 };
 
+static void check_threads(struct callback *cb, void *arg)
+{
+  THREADS_ALLOW();
+
+  /* Allow other threads to run */
+
+  THREADS_DISALLOW();
+}
+
 void *new_thread_func(void * data)
 {
   struct thread_starter arg = *(struct thread_starter *)data;
@@ -61,6 +73,11 @@ void *new_thread_func(void * data)
 
   cleanup_interpret();
   num_threads--;
+  if(!num_threads)
+  {
+    remove_callback(threads_evaluator_callback);
+    threads_evaluator_callback=0;
+  }
   mt_unlock(& interpreter_lock);
   th_exit(0);
 }
@@ -78,6 +95,13 @@ void f_thread_create(INT32 args)
   if(!tmp)
   {
     num_threads++;
+
+    if(num_threads == 1 && !threads_evaluator_callback)
+    {
+      threads_evaluator_callback=add_to_callback(&evaluator_callbacks,
+						 check_threads, 0,0);
+    }
+
     push_object(arg->id);
     arg->id->refs++;
   } else {
diff --git a/src/threads.h b/src/threads.h
index b143f3ecb5bbcbadedb4799742e79afe2d702860..40b0b6edd6a8b61d6d0e129ff449d8aa413cf8e8 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -86,7 +86,7 @@ struct thread_state {
 struct thread_starter;
 void *new_thread_func(void * data);
 void f_thread_create(INT32 args);
-void f_this_thread();
+void f_this_thread(INT32 args);
 void th_init();
 struct mutex_storage;
 struct key_storage;