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;