diff --git a/src/threads.c b/src/threads.c index 78a57368217b3371ba03b3a9e42633ce8aa97eed..0ccd6462aa341205ed2a1258d9e5439c77b4cff8 100644 --- a/src/threads.c +++ b/src/threads.c @@ -1,5 +1,5 @@ #include "global.h" -RCSID("$Id: threads.c,v 1.56 1998/02/19 05:15:20 per Exp $"); +RCSID("$Id: threads.c,v 1.57 1998/02/27 20:09:04 marcus Exp $"); int num_threads = 1; int threads_disabled = 0; @@ -138,7 +138,7 @@ struct object *thread_id; static struct callback *threads_evaluator_callback=0; int thread_id_result_variable; -MUTEX_T interpreter_lock; +MUTEX_T interpreter_lock, thread_table_lock; struct program *mutex_key = 0; struct program *thread_id_prog = 0; #ifdef POSIX_THREADS @@ -152,6 +152,116 @@ struct thread_starter struct array *args; }; + +/* Thread hashtable */ + +#define THREAD_TABLE_SIZE 127 /* Totally arbitrary prime */ + +static struct thread_state *thread_table_chains[THREAD_TABLE_SIZE]; + +void thread_table_init() +{ + INT32 x; + for(x=0; x<THREAD_TABLE_SIZE; x++) + thread_table_chains[x] = NULL; +} + +unsigned INT32 thread_table_hash(THREAD_T *tid) +{ + return hashmem((unsigned char *)tid, sizeof(*tid), 16) % THREAD_TABLE_SIZE; +} + +void thread_table_insert(struct object *o) +{ + struct thread_state *s = (struct thread_state *)o->storage; + unsigned INT32 h = thread_table_hash(&s->id); + mt_lock( & thread_table_lock ); + if((s->hashlink = thread_table_chains[h]) != NULL) + s->hashlink->backlink = &s->hashlink; + thread_table_chains[h] = s; + s->backlink = &thread_table_chains[h]; + mt_unlock( & thread_table_lock ); +} + +void thread_table_delete(struct object *o) +{ + struct thread_state *s = (struct thread_state *)o->storage; + mt_lock( & thread_table_lock ); + if(s->hashlink != NULL) + s->hashlink->backlink = s->backlink; + *(s->backlink) = s->hashlink; + mt_unlock( & thread_table_lock ); +} + +struct thread_state *thread_state_for_id(THREAD_T tid) +{ + unsigned INT32 h = thread_table_hash(&tid); + struct thread_state *s = NULL; + mt_lock( & thread_table_lock ); + if(thread_table_chains[h] == NULL) { + /* NULL result */ + } else if((s=thread_table_chains[h])->id == tid) { + /* Quick return */ + } else { + while((s = s->hashlink) != NULL) + if(s->id == tid) + break; + if(s != NULL) { + /* Move the thread_state to the head of the chain, in case + we want to search for it again */ + + /* Unlink */ + if(s->hashlink != NULL) + s->hashlink->backlink = s->backlink; + *(s->backlink) = s->hashlink; + /* And relink at the head of the chain */ + if((s->hashlink = thread_table_chains[h]) != NULL) + s->hashlink->backlink = &s->hashlink; + thread_table_chains[h] = s; + s->backlink = &thread_table_chains[h]; + } + } + mt_unlock( & thread_table_lock ); + return s; + /* NOTEZ BIEN: Return value only guaranteed to remain valid as long + as you have the interpreter lock, unless tid == th_self() */ +} + +struct object *thread_for_id(THREAD_T tid) +{ + struct thread_state *s = thread_state_for_id(tid); + return (s == NULL? NULL : + (struct object *)(((char *)s)-((((struct object *)NULL)->storage)- + ((char*)NULL)))); + /* See NB in thread_state_for_id. Lifespan of result can be prolonged + by incrementing refcount though. */ +} + +void f_all_threads(INT32 args) +{ + /* Return an unordered array containing all threads that was running + at the time this function was invoked */ + + INT32 x; + struct svalue *oldsp; + struct thread_state *s; + + pop_n_elems(args); + oldsp = sp; + mt_lock( & thread_table_lock ); + for(x=0; x<THREAD_TABLE_SIZE; x++) + for(s=thread_table_chains[x]; s; s=s->hashlink) { + struct object *o = + (struct object *)(((char *)s)-((((struct object *)NULL)->storage)- + ((char*)NULL))); + o->refs++; + push_object(o); + } + mt_unlock( & thread_table_lock ); + f_aggregate(sp-oldsp); +} + + static void check_threads(struct callback *cb, void *arg, void * arg2) { static int div_; @@ -219,6 +329,7 @@ void *new_thread_func(void * data) THREADS_FPRINTF((stderr,"THREADS_ALLOW() Thread %08x done\n", (unsigned int)thread_id)); + thread_table_delete(thread_id); free_object(thread_id); thread_id=0; cleanup_interpret(); @@ -255,6 +366,7 @@ void f_thread_create(INT32 args) if(!tmp) { num_threads++; + thread_table_insert(arg->id); if(!threads_evaluator_callback) { @@ -602,6 +714,8 @@ void th_init(void) mt_init( & interpreter_lock); mt_lock( & interpreter_lock); + mt_init( & thread_table_lock); + thread_table_init(); #ifdef POSIX_THREADS pthread_attr_init(&pattr); #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE @@ -625,6 +739,8 @@ void th_init(void) #endif add_efun("this_thread",f_this_thread,"function(:object)", OPT_EXTERNAL_DEPEND); + add_efun("all_threads",f_all_threads,"function(:array(object))", + OPT_EXTERNAL_DEPEND); start_new_program(); add_storage(sizeof(struct mutex_storage)); @@ -675,6 +791,8 @@ void th_init(void) thread_id=clone_object(thread_id_prog,0); SWAP_OUT_THREAD((struct thread_state *)thread_id->storage); /* Init struct */ ((struct thread_state *)thread_id->storage)->swapped=0; + ((struct thread_state *)thread_id->storage)->id=th_self(); + thread_table_insert(thread_id); } void th_cleanup(void) diff --git a/src/threads.h b/src/threads.h index deaacd99c699e08fea6fcd00891fa7d3462a9f88..8b345619cc9b8f84acf306edeac478778a215ce3 100644 --- a/src/threads.h +++ b/src/threads.h @@ -230,6 +230,7 @@ struct thread_state { char status; COND_T status_change; THREAD_T id; + struct thread_state *hashlink, **backlink; /* Swapped variables */ struct svalue *sp,*evaluator_stack;