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,<=,¤t_time)) + my_timercmp(&CALL(0)->tv,<=,¤t_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; }