diff --git a/src/modules/call_out/call_out.c b/src/modules/call_out/call_out.c
index 978fb7f0c0d23a8715413e53ac32714bd4318453..fe3e236af82b9102df297df6d6c721b6b9c03708 100644
--- a/src/modules/call_out/call_out.c
+++ b/src/modules/call_out/call_out.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $");
+RCSID("$Id: call_out.c,v 1.21 1998/05/22 00:34:16 hubbe Exp $");
 #include "array.h"
 #include "dynamic_buffer.h"
 #include "object.h"
@@ -20,6 +20,7 @@ RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $");
 #include "builtin_functions.h"
 #include "gc.h"
 #include "threads.h"
+#include "stuff.h"
 
 #include "callback.h"
 
@@ -31,17 +32,58 @@ RCSID("$Id: call_out.c,v 1.20 1998/04/20 18:53:58 grubba Exp $");
 
 struct call_out_s
 {
+  INT32 pos;
   struct timeval tv;
+  struct call_out_s *next; /* For block alloc */
+  struct call_out_s *next_fun;
+  struct call_out_s **prev_fun;
+  struct call_out_s *next_arr;
+  struct call_out_s **prev_arr;
   struct object *caller;
   struct array *args;
 };
 
+#include "block_alloc.h"
+
+#ifdef DEBUG
+#define MESS_UP_BLOCK(X) \
+ (X)->next_arr=(struct call_out_s *)-1; \
+ (X)->next_fun=(struct call_out_s *)-1; \
+ (X)->prev_arr=(struct call_out_s **)-1; \
+ (X)->prev_fun=(struct call_out_s **)-1; \
+ (X)->caller=(struct object *)-1; \
+ (X)->args=(struct array *)-1; \
+ (X)->pos=-1;
+#else
+#define MESS_UP_BLOCK(X)
+#endif
+
+#undef EXIT_BLOCK
+#define EXIT_BLOCK(X) \
+  *(X->prev_arr)=X->next_arr; \
+  if(X->next_arr) X->next_arr->prev_arr=X->prev_arr; \
+  *(X->prev_fun)=X->next_fun; \
+  if(X->next_fun) X->next_fun->prev_fun=X->prev_fun; \
+  MESS_UP_BLOCK(X) ;
+BLOCK_ALLOC(call_out_s, 1022 )
+
 typedef struct call_out_s call_out;
 
+struct hash_ent
+{
+  call_out *arr;
+  call_out *fun;
+};
+
+
 int num_pending_calls;           /* no of busy pointers in buffer */
-static call_out *call_buffer=0;  /* pointer to buffer */
+static call_out **call_buffer=0;  /* pointer to buffer */
 static int call_buffer_size;     /* no of pointers in buffer */
 
+static unsigned int hash_size=0;
+static unsigned int hash_order=7;
+static struct hash_ent *call_hash=0;
+
 #undef CAR
 #undef CDR
 
@@ -49,8 +91,9 @@ static int call_buffer_size;     /* no of pointers in buffer */
 #define CDR(X) (((X)<<1)+2)
 #define PARENT(X) (((X)-1)>>1)
 #define CALL(X) (call_buffer[(X)])
-#define CMP(X,Y) my_timercmp(& CALL(X).tv, <, & CALL(Y).tv)
-#define SWAP(X,Y) do{ call_out _tmp=CALL(X); CALL(X)=CALL(Y); CALL(Y)=_tmp; } while(0)
+#define MOVECALL(X,Y) do { INT32 p_=(X); (CALL(p_)=CALL(Y))->pos=p_; }while(0)
+#define CMP(X,Y) my_timercmp(& CALL(X)->tv, <, & CALL(Y)->tv)
+#define SWAP(X,Y) do{ call_out *_tmp=CALL(X); (CALL(X)=CALL(Y))->pos=(X); (CALL(Y)=_tmp)->pos=(Y); } while(0)
 
 #ifdef DEBUG
 static int inside_call_out=0;
@@ -84,8 +127,8 @@ static void verify_call_outs(void)
       if(CMP(e, PARENT(e)))
 	fatal("Error in call out heap. (@ %d)\n",e);
     }
-    
-    if(!(v=CALL(e).args))
+
+    if(!(v=CALL(e)->args))
       fatal("No arguments to call\n");
 
     if(v->refs < 1)
@@ -97,19 +140,48 @@ static void verify_call_outs(void)
     if(!v->size)
       fatal("Call out array of zero size!\n");
 
+    if(CALL(e)->prev_arr[0] != CALL(e))
+      fatal("call_out[%d]->prev_arr[0] is wrong!\n",e);
+
+    if(CALL(e)->prev_fun[0] != CALL(e))
+      fatal("call_out[%d]->prev_fun[0] is wrong!\n",e);
+
+    if(CALL(e)->pos != e)
+      fatal("Call_out->pos is not correct!\n");
+
     if(d_flag>4)
     {
       for(d=e+1;d<num_pending_calls;d++)
-	if(CALL(e).args == CALL(d).args)
+	if(CALL(e)->args == CALL(d)->args)
 	  fatal("Duplicate call out in heap.\n");
     }
   }
 
   for(d=0;d<10 && e<call_buffer_size;d++,e++)
+    CALL(e)=(call_out *)-1;
+
+  for(e=0;e<(int)hash_size;e++)
   {
-    CALL(e).caller=(struct object *)1; /* Illegal value */
-    CALL(e).args=(struct array *)1; /* Illegal value */
+    call_out *c,**prev;
+    for(prev=& call_hash[e].arr;(c=*prev);prev=& c->next_arr)
+    {
+      if(c->prev_arr != prev)
+	fatal("c->prev_arr is wrong %p.\n",c);
+
+      if(c->pos<0)
+	fatal("Free call_out in call_out hash table %p.\n",c);
+    }
+
+    for(prev=& call_hash[e].fun;(c=*prev);prev=& c->next_fun)
+    {
+      if(c->prev_fun != prev)
+	fatal("c->prev_fun is wrong %p.\n",c);
+
+      if(c->pos<0)
+	fatal("Free call_out in call_out hash table %p.\n",c);
+    }
   }
+    
 }
 
 static struct callback *verify_call_out_callback=0;
@@ -124,7 +196,6 @@ void do_verify_call_outs(struct callback *foo, void *x, void *y)
 #endif
 
 
-
 static void adjust_down(int pos)
 {
   while(1)
@@ -185,46 +256,106 @@ static struct array * new_call_out(int num_arg,struct svalue *argp)
   int e,c;
   call_out *new,**p,**pos;
   struct array *args;
+  unsigned long hval;
 
   PROTECT_CALL_OUTS();
   if(num_pending_calls==call_buffer_size)
   {
     /* here we need to allocate space for more pointers */
-    call_out *new_buffer;
+    call_out **new_buffer;
 
     if(!call_buffer)
     {
       call_buffer_size=128;
-      call_buffer=(call_out *)xalloc(sizeof(call_out)*call_buffer_size);
+      call_buffer=(call_out **)xalloc(sizeof(call_out *)*call_buffer_size);
       if(!call_buffer) return 0;
       num_pending_calls=0;
+
+      hash_size=hashprimes[hash_order];
+      call_hash=(struct hash_ent *)xalloc(sizeof(struct hash_ent)*hash_size);
+      MEMSET(call_hash, 0, sizeof(struct hash_ent)*hash_size);
     }else{
-      new_buffer=(call_out *)realloc((char *)call_buffer, sizeof(call_out)*call_buffer_size*2);
+      struct hash_ent *new_hash;
+      int e;
+
+      new_buffer=(call_out **)realloc((char *)call_buffer, sizeof(call_out *)*call_buffer_size*2);
       if(!new_buffer)
 	error("Not enough memory for another call_out\n");
       call_buffer_size*=2;
       call_buffer=new_buffer;
+
+      if((new_hash=(struct hash_ent *)malloc(sizeof(struct hash_ent)*
+					      hashprimes[hash_order+1])))
+      {
+	free((char *)call_hash);
+	call_hash=new_hash;
+	hash_size=hashprimes[++hash_order];
+	MEMSET(call_hash, 0, sizeof(struct hash_ent)*hash_size);
+
+	/* Re-hash */
+	for(e=0;e<num_pending_calls;e++)
+	{
+	  call_out *c=CALL(e);
+	  
+	  hval=(unsigned long)c->args;
+	  hval%=hash_size;
+	  
+	  if((c->next_arr=call_hash[hval].arr))
+	    c->next_arr->prev_arr=&c->next_arr;
+	  c->prev_arr=&call_hash[hval].arr;
+	  call_hash[hval].arr=c;
+	  
+	  hval=hash_svalue(c->args->item);
+	  hval%=hash_size;
+	  
+	  if((c->next_fun=call_hash[hval].fun))
+	    c->next_fun->prev_fun=&c->next_fun;
+	  c->prev_fun=&call_hash[hval].fun;
+	  call_hash[hval].fun=c;
+	}
+      }
     }
   }
 
   /* time to allocate a new call_out struct */
-  f_aggregate(num_arg-1);
+  args=aggregate_array(num_arg-1);
 
-  new=&CALL(num_pending_calls);
+  CALL(num_pending_calls)=new=alloc_call_out_s();
+  new->pos=num_pending_calls;
 
-  if(argp[0].type==T_INT)
-  {
-    new->tv.tv_sec=argp[0].u.integer;
-    new->tv.tv_usec=0;
-  }
-  else if(argp[0].type == T_FLOAT)
   {
-    FLOAT_TYPE tmp=argp[0].u.float_number;
-    new->tv.tv_sec=floor(tmp);
-    new->tv.tv_usec=(long)(1000000.0 * (tmp - floor(tmp)));
+    hval=(unsigned long)args;
+    hval%=hash_size;
+
+    if((new->next_arr=call_hash[hval].arr))
+      new->next_arr->prev_arr=&new->next_arr;
+    new->prev_arr=&call_hash[hval].arr;
+    call_hash[hval].arr=new;
+
+    hval=hash_svalue(args->item);
+    hval%=hash_size;
+    if((new->next_fun=call_hash[hval].fun))
+      new->next_fun->prev_fun=&new->next_fun;
+    new->prev_fun=&call_hash[hval].fun;
+    call_hash[hval].fun=new;
   }
-  else
+
+  switch(argp[0].type)
   {
+    case T_INT:
+      new->tv.tv_sec=argp[0].u.integer;
+      new->tv.tv_usec=0;
+      break;
+
+    case T_FLOAT:
+    {
+      FLOAT_TYPE tmp=argp[0].u.float_number;
+      new->tv.tv_sec=floor(tmp);
+      new->tv.tv_usec=(long)(1000000.0 * (tmp - floor(tmp)));
+      break;
+    }
+
+    default:
     fatal("Bad timeout to new_call_out!\n");
   }
 
@@ -245,8 +376,10 @@ static struct array * new_call_out(int num_arg,struct svalue *argp)
     new->caller=0;
   }
 
-  new->args=args=sp[-1].u.array;
-  sp -= 2;
+  new->args=args;
+  sp--;
+
+  
 
   num_pending_calls++;
   adjust_up(num_pending_calls-1);
@@ -267,6 +400,8 @@ static void count_memory_in_call_outs(struct callback *foo,
   push_text("num_call_outs");
   push_int(num_pending_calls);
   push_text("call_out_bytes");
+
+  /* FIXME */
   push_int(call_buffer_size * sizeof(call_out **)+
 	   num_pending_calls * sizeof(call_out));
 }
@@ -281,9 +416,9 @@ static void mark_call_outs(struct callback *foo, void *bar, void *gazonk)
   int e;
   for(e=0;e<num_pending_calls;e++)
   {
-    gc_external_mark(CALL(e).args);
-    if(CALL(e).caller)
-      gc_external_mark(CALL(e).caller);
+    gc_external_mark(CALL(e)->args);
+    if(CALL(e)->caller)
+      gc_external_mark(CALL(e)->caller);
   }
 }
 #endif
@@ -337,19 +472,21 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
   {
     tmp=(time_t)TIME(0);
     while(num_pending_calls &&
-	  my_timercmp(&CALL(0).tv,<=,&current_time))
+	  my_timercmp(&CALL(0)->tv,<=,&current_time))
     {
       /* unlink call out */
-      call_out c;
+      call_out c,*cc;
 
       PROTECT_CALL_OUTS();
-      c=CALL(0);
+      cc=CALL(0);
       if(--num_pending_calls)
       {
-	CALL(0)=CALL(num_pending_calls);
+	MOVECALL(0,num_pending_calls);
 	adjust_down(0);
       }
       UNPROTECT_CALL_OUTS();
+      c=*cc;
+      free_call_out_s(cc);
 
       if(c.caller) free_object(c.caller);
 
@@ -372,9 +509,9 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
   {
     if(num_pending_calls)
     {
-      if(my_timercmp(& CALL(0).tv, < , &next_timeout))
+      if(my_timercmp(& CALL(0)->tv, < , &next_timeout))
       {
-	next_timeout = CALL(0).tv;
+	next_timeout = CALL(0)->tv;
       }
     }else{
       if(call_out_backend_callback)
@@ -391,17 +528,55 @@ void do_call_outs(struct callback *ignored, void *ignored_too, void *arg)
 
 static int find_call_out(struct svalue *fun)
 {
+#if 0
   int e;
 
   if(fun->type == T_ARRAY)
     for(e=0;e<num_pending_calls;e++)
-      if(CALL(e).args == fun->u.array)
+      if(CALL(e)->args == fun->u.array)
 	return e;
 
   for(e=0;e<num_pending_calls;e++)
-    if(is_eq(fun, ITEM(CALL(e).args)))
+    if(is_eq(fun, ITEM(CALL(e)->args)))
       return e;
 
+#else
+  unsigned long hval;
+  call_out *c;
+
+  if(!num_pending_calls) return -1;
+
+  if(fun->type == T_ARRAY)
+  {
+    hval=(unsigned long)fun->u.array;
+    hval%=hash_size;
+    for(c=call_hash[hval].arr;c;c=c->next_arr)
+    {
+      if(c->args == fun->u.array)
+      {
+#ifdef DEBUG
+	if(CALL(c->pos) != c)
+	  fatal("Call_out->pos not correct!\n");
+#endif
+	return c->pos;
+      }
+    }
+  }
+
+  hval=hash_svalue(fun);
+  hval%=hash_size;
+  for(c=call_hash[hval].fun;c;c=c->next_fun)
+  {
+    if(is_eq(fun, ITEM(c->args)))
+    {
+#ifdef DEBUG
+      if(CALL(c->pos) != c)
+	fatal("Call_out->pos not correct!\n");
+#endif
+      return c->pos;
+    }
+  }
+#endif
   return -1;
 }
 
@@ -429,7 +604,7 @@ void f_find_call_out(INT32 args)
     sp->u.integer=-1;
     sp++;
   }else{
-    push_int(CALL(e).tv.tv_sec - current_time.tv_sec);
+    push_int(CALL(e)->tv.tv_sec - current_time.tv_sec);
   }
   UNPROTECT_CALL_OUTS();
   verify_call_outs();
@@ -438,20 +613,22 @@ void f_find_call_out(INT32 args)
 void f_remove_call_out(INT32 args)
 {
   int e;
-  verify_call_outs();
   PROTECT_CALL_OUTS();
+  verify_call_outs();
   e=find_call_out(sp-args);
+  verify_call_outs();
   if(e!=-1)
   {
     pop_n_elems(args);
-    push_int(CALL(e).tv.tv_sec - current_time.tv_sec);
-    free_array(CALL(e).args);
-    if(CALL(e).caller)
-      free_object(CALL(e).caller);
+    push_int(CALL(e)->tv.tv_sec - current_time.tv_sec);
+    free_array(CALL(e)->args);
+    if(CALL(e)->caller)
+      free_object(CALL(e)->caller);
+    free_call_out_s(CALL(e));
     --num_pending_calls;
     if(e!=num_pending_calls)
     {
-      CALL(e)=CALL(num_pending_calls);
+      MOVECALL(e,num_pending_calls);
       adjust(e);
     }
   }else{
@@ -461,8 +638,8 @@ void f_remove_call_out(INT32 args)
     sp->u.integer=-1;
     sp++;
   }
-  UNPROTECT_CALL_OUTS();
   verify_call_outs();
+  UNPROTECT_CALL_OUTS();
 }
 
 /* return an array containing info about all call outs:
@@ -479,22 +656,22 @@ struct array *get_all_call_outs(void)
   for(e=0;e<num_pending_calls;e++)
   {
     struct array *v;
-    v=allocate_array_no_init(CALL(e).args->size+2, 0);
+    v=allocate_array_no_init(CALL(e)->args->size+2, 0);
     ITEM(v)[0].type=T_INT;
     ITEM(v)[0].subtype=NUMBER_NUMBER;
-    ITEM(v)[0].u.integer=CALL(e).tv.tv_sec - current_time.tv_sec;
+    ITEM(v)[0].u.integer=CALL(e)->tv.tv_sec - current_time.tv_sec;
 
-    if(CALL(e).caller)
+    if(CALL(e)->caller)
     {
       ITEM(v)[1].type=T_OBJECT;
-      add_ref(ITEM(v)[1].u.object=CALL(e).caller);
+      add_ref(ITEM(v)[1].u.object=CALL(e)->caller);
     }else{
       ITEM(v)[1].type=T_INT;
       ITEM(v)[1].subtype=NUMBER_NUMBER;
       ITEM(v)[1].u.integer=0;
     }
 
-    assign_svalues_no_free(ITEM(v)+2,ITEM(CALL(e).args),CALL(e).args->size,BIT_MIXED);
+    assign_svalues_no_free(ITEM(v)+2,ITEM(CALL(e)->args),CALL(e)->args->size,BIT_MIXED);
 
     ITEM(ret)[e].type=T_ARRAY;
     ITEM(ret)[e].u.array=v;
@@ -515,10 +692,13 @@ void free_all_call_outs(void)
   verify_call_outs();
   for(e=0;e<num_pending_calls;e++)
   {
-    free_array(CALL(e).args);
-    if(CALL(e).caller) free_object(CALL(e).caller);
+    free_array(CALL(e)->args);
+    if(CALL(e)->caller) free_object(CALL(e)->caller);
+    free_call_out_s(CALL(e));
   }
   if(call_buffer) free((char*)call_buffer);
+  if(call_hash) free((char*)call_hash);
+  free_all_call_out_s_blocks();
   num_pending_calls=0;
   call_buffer=NULL;
 }