#include "efuns.h" #include "array.h" #include "call_out.h" #include "dynamic_buffer.h" #include "main.h" #include "simulate.h" call_out **pending_calls=NULL; /* pointer to first busy pointer */ int num_pending_calls; /* no of busy pointers in buffer */ static call_out **call_buffer=NULL; /* pointer to buffer */ static int call_buffer_size; /* no of pointers in buffer */ extern int current_time; static void verify_call_outs() { #ifdef DEBUG struct vector *v; int e; if(call_buffer) return; if(num_pending_calls<0 || num_pending_calls>call_buffer_size) fatal("Error in call out tables.\n"); if(pending_calls+num_pending_calls!=call_buffer+call_buffer_size) fatal("Error in call out tables.\n"); for(e=0;e<num_pending_calls;e++) { if(e) { if(pending_calls[e-1]>pending_calls[e]) fatal("Error in call out order.\n"); } if(!(v=pending_calls[e]->args)) fatal("No arguments to call\n"); if(v->ref!=1) fatal("Array should exactly have one reference.\n"); if(v->malloced_size<v->size) fatal("Impossible array.\n"); } #endif } /* start a new call out, return 1 for success */ static int new_call_out(int num_arg,struct svalue *argp) { int e,c; call_out *new,**p,**pos; struct vector *v; #ifdef MALLOC_DEBUG check_sfltable(); #endif if(!call_buffer) { call_buffer_size=20; call_buffer=(call_out **)xalloc(sizeof(call_out *)*call_buffer_size); if(!call_buffer) return 0; pending_calls=call_buffer+call_buffer_size; num_pending_calls=0; } #ifdef MALLOC_DEBUG check_sfltable(); #endif if(num_pending_calls==call_buffer_size) { /* here we need to allocate space for more pointers */ call_out **new_buffer; new_buffer=(call_out **)xalloc(sizeof(call_out *)*call_buffer_size*2); if(!new_buffer) return 0; MEMCPY((char *)(new_buffer+call_buffer_size), (char *)call_buffer, sizeof(call_out *)*call_buffer_size); free((char *)call_buffer); call_buffer=new_buffer; pending_calls=call_buffer+call_buffer_size; call_buffer_size*=2; } #ifdef MALLOC_DEBUG check_sfltable(); #endif /* time to allocate a new call_out struct */ v=allocate_array(num_arg-1); #ifdef MALLOC_DEBUG check_sfltable(); #endif if(!v) return 0; new=(call_out *)xalloc(sizeof(call_out)); #ifdef MALLOC_DEBUG check_sfltable(); #endif if(!new) { free_vector(v); return 0; } #ifdef MALLOC_DEBUG check_sfltable(); #endif new->time=current_time+argp[1].u.number; if(new->time<=current_time) new->time=current_time+1; new->command_giver=command_giver; #ifdef MALLOC_DEBUG check_sfltable(); #endif if(command_giver) add_ref(command_giver, "call_out (command_giver)"); new->args=v; #ifdef MALLOC_DEBUG check_sfltable(); #endif move_svalue(v->item,argp); #ifdef MALLOC_DEBUG check_sfltable(); #endif for(e=1;e<num_arg-1;e++) move_svalue(v->item+e,argp+e+1); #ifdef MALLOC_DEBUG check_sfltable(); #endif /* time to link it into the buffer using binsearch */ pos=pending_calls; if(new->time>current_time+1) /* do we need to search where ?*/ { e=num_pending_calls; while(e>0) { c=e/2; if(new->time>pos[c]->time) { pos+=c+1; e-=c+1; }else{ e=c; } } } pos--; pending_calls--; for(p=pending_calls;p<pos;p++) p[0]=p[1]; *pos=new; num_pending_calls++; #ifdef MALLOC_DEBUG check_sfltable(); #endif return 1; } void f_call_out(int args,struct svalue *argp) { verify_call_outs(); if (!(current_object->flags & O_DESTRUCTED)) { if(argp[0].u.ob!=current_object) { error("Call out only permitted to this_object()\n"); } new_call_out(args,argp); } verify_call_outs(); pop_n_elems(args); } void do_call_outs() { call_out *c; int e,args; verify_call_outs(); while(num_pending_calls && pending_calls[0]->time<=current_time) { /* unlink call out */ c=pending_calls[0]; pending_calls++; num_pending_calls--; if((command_giver=c->command_giver)) free_object(command_giver, "call_out (command_giver)"); args=c->args->size; for(e=0;e<args;e++) push_svalue(c->args->item+e); free_vector(c->args); free((char *)c); f_call_function(args,sp-args+1); pop_stack(); verify_call_outs(); } command_giver=0; } static int find_call_out(struct svalue *fun) { int e; for(e=0;e<num_pending_calls;e++) { if(pending_calls[e]->args->item[0].u.ob==fun->u.ob && pending_calls[e]->args->item[0].type==fun->type && pending_calls[e]->args->item[0].subtype==fun->subtype) return e; } return -1; } void f_find_call_out(int argc,struct svalue *argp) { int e; verify_call_outs(); e=find_call_out(argp); if(e==-1) { free_svalue(sp); SET_TO_UNDEFINED(*sp); }else{ pop_stack(); push_number(pending_calls[e]->time-current_time); } verify_call_outs(); } void f_remove_call_out(int args,struct svalue *argp) { int e; verify_call_outs(); e=find_call_out(argp); if(e!=-1) { pop_stack(); push_number(pending_calls[e]->time-current_time); free_vector(pending_calls[e]->args); if(pending_calls[e]->command_giver) free_object(pending_calls[e]->command_giver, "remove_call_out (command_giver)"); free((char*)(pending_calls[e])); for(;e>0;e--) pending_calls[e]=pending_calls[e-1]; pending_calls++; num_pending_calls--; }else{ free_svalue(sp); SET_TO_UNDEFINED(*sp); } verify_call_outs(); } char *print_call_out_usage(int verbose) { int i,svalues,len; char b[100]; verify_call_outs(); init_buf(); for (len=svalues=i=0; i<num_pending_calls; i++) { len+=pending_calls[i]->time-current_time; svalues+=pending_calls[i]->args->size; } if(num_pending_calls) len/=num_pending_calls; if (verbose) { my_strcat("\nCall out information:\n"); my_strcat("---------------------\n"); sprintf(b,"Number of allocated call outs: %8d, %8d bytes\n", num_pending_calls, (int)(num_pending_calls * (sizeof(call_out) + sizeof(struct vector) - sizeof(struct svalue))+ svalues*sizeof(struct svalue) )); my_strcat(b); sprintf(b,"Average length: %d\n", len); my_strcat(b); } else { sprintf(b,"call out:\t\t\t%8d %8d (current length %d)\n", num_pending_calls, (int)(num_pending_calls * (sizeof(call_out) + sizeof(struct vector) - sizeof(struct svalue))+ svalues*sizeof(struct svalue)), len ); my_strcat(b); } return free_buf(); } /* return a vector containing info about all call outs: * ({ ({ delay, command_giver, function, args, ... }), ... }) */ struct vector *get_all_call_outs() { int e,d; struct vector *ret; verify_call_outs(); ret=allocate_array(num_pending_calls); for(e=0;e<num_pending_calls;e++) { struct vector *v; v=allocate_array(pending_calls[e]->args->size+2); v->item[0].u.number=pending_calls[e]->time-current_time; if(pending_calls[e]->command_giver) { add_ref(pending_calls[e]->command_giver,"get_all_call_outs"); v->item[1].u.ob=pending_calls[e]->command_giver; v->item[1].type=T_OBJECT; } for(d=0;d<pending_calls[e]->args->size;d++) assign_svalue(v->item+d+2,pending_calls[e]->args->item+d); ret->item[e].u.vec=v; ret->item[e].type=T_POINTER; } return ret; } void f_call_out_info(int num_arg,struct svalue *argp) { push_vector(get_all_call_outs()); sp->u.vec->ref--; /* Was set to 1 at allocation */ } void free_all_call_outs() { int e; verify_call_outs(); for(e=0;e<num_pending_calls;e++) { free_vector(pending_calls[e]->args); if(pending_calls[e]->command_giver) free_object(pending_calls[e]->command_giver, "free_all_call_outs (command_giver)"); free((char*)(pending_calls[e])); } if(call_buffer) free((char*)call_buffer); num_pending_calls=0; call_buffer=NULL; pending_calls=NULL; }