From 5988926dc0e06bef24819b0aa6d820c856315bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net> Date: Sat, 5 Oct 1996 05:18:07 +0200 Subject: [PATCH] mutex locks re-implemented to allow more dynamic usage Rev: src/threads.c:1.2 Rev: src/threads.h:1.3 --- src/threads.c | 150 ++++++++++++++++++++++++++++++++++++++------------ src/threads.h | 2 +- 2 files changed, 117 insertions(+), 35 deletions(-) diff --git a/src/threads.c b/src/threads.c index 766fdb6ed4..a2cdb2df9f 100644 --- a/src/threads.c +++ b/src/threads.c @@ -8,7 +8,7 @@ int threads_disabled = 0; #ifdef _REENTRANT -MUTEX_T interpreter_lock, compiler_lock; +MUTEX_T interpreter_lock; struct program *mutex_key = 0; pthread_attr_t pattr; @@ -56,6 +56,7 @@ void f_thread_create(INT32 args) void th_init() { + thr_setconcurrency(9); mt_lock( & interpreter_lock); pthread_attr_init(&pattr); pthread_attr_setstacksize(&pattr, 2 * 1024 * 1204); @@ -65,84 +66,164 @@ void th_init() } -#define THIS_MUTEX ((MUTEX_T *)(fp->current_storage)) +#define THIS_MUTEX ((struct mutex_storage *)(fp->current_storage)) + + +/* Note: + * No reference is kept to the key object, it is destructed if the + * mutex is destructed. The key pointer is set to zero by the + * key object when the key is destructed. + */ + +struct mutex_storage +{ + COND_T condition; + struct object *key; +}; + +struct key_storage +{ + struct mutex_storage *mut; + int initialized; +}; + +static MUTEX_T mutex_kluge; + +#define OB2KEY(X) ((struct key_storage *)((X)->storage)) void f_mutex_lock(INT32 args) { - MUTEX_T *m; + struct mutex_storage *m; struct object *o; + pop_n_elems(args); m=THIS_MUTEX; + o=clone(mutex_key,0); + mt_lock(& mutex_kluge); THREADS_ALLOW(); - mt_lock(m); + while(m->key) co_wait(& m->condition, & mutex_kluge); + OB2KEY(o)->mut=m; + m->key=o; + mt_unlock(&mutex_kluge); THREADS_DISALLOW(); - o=clone(mutex_key,0); - ((struct object **)(o->storage))[0]=fp->current_object; - fp->current_object->refs++; push_object(o); } void f_mutex_trylock(INT32 args) { - MUTEX_T *m; - int i; + struct mutex_storage *m; + struct object *o; + int i=0; pop_n_elems(args); + o=clone(mutex_key,0); m=THIS_MUTEX; + mt_lock(& mutex_kluge); THREADS_ALLOW(); - i=mt_lock(m); + if(!m->key) + { + OB2KEY(o)->mut=THIS_MUTEX; + m->key=o; + i=1; + } + mt_unlock(&mutex_kluge); THREADS_DISALLOW(); if(i) { - struct object *o; - o=clone(mutex_key,0); - ((struct object **)o->storage)[0]=fp->current_object; - fp->current_object->refs++; push_object(o); } else { + destruct(o); + free_object(o); push_int(0); } } -void init_mutex_obj(struct object *o) { mt_init(THIS_MUTEX); } -void exit_mutex_obj(struct object *o) { mt_destroy(THIS_MUTEX); } +void init_mutex_obj(struct object *o) +{ + co_init(& THIS_MUTEX->condition); + THIS_MUTEX->key=0; +} -#define THIS_KEY (*(struct object **)fp->current_storage) -void init_mutex_key_obj(struct object *o) { THIS_KEY=0; } +void exit_mutex_obj(struct object *o) +{ + if(THIS_MUTEX->key) destruct(THIS_MUTEX->key); + co_destroy(& THIS_MUTEX->condition); +} + +#define THIS_KEY ((struct key_storage *)(fp->current_storage)) +void init_mutex_key_obj(struct object *o) +{ + THIS_KEY->mut=0; + THIS_KEY->initialized=1; +} void exit_mutex_key_obj(struct object *o) { - if(THIS_KEY) + mt_lock(& mutex_kluge); + if(THIS_KEY->mut) { - mt_unlock((MUTEX_T *)THIS_KEY->storage); - init_mutex_key_obj(o); +#ifdef DEBUG + if(THIS_KEY->mut->key != o) + fatal("Mutex unlock from wrong key %p != %p!\n",THIS_KEY->mut->key,o); +#endif + THIS_KEY->mut->key=0; + co_signal(& THIS_KEY->mut->condition); + THIS_KEY->mut=0; + THIS_KEY->initialized=0; } + mt_unlock(& mutex_kluge); } #define THIS_COND ((COND_T *)(fp->current_storage)) void f_cond_wait(INT32 args) { COND_T *c; + struct object *key; if(args > 1) pop_n_elems(args - 1); - - if(sp[-1].type != T_OBJECT) - error("Bad argument 1 to condition->wait()\n"); - if(sp[-1].u.object->prog) + c=THIS_COND; + + if(args > 0) { - if(sp[-1].u.object->prog != mutex_key) + struct mutex_storage *mut; + + if(sp[-1].type != T_OBJECT) error("Bad argument 1 to condition->wait()\n"); + + key=sp[-1].u.object; + + if(key->prog != mutex_key) + error("Bad argument 1 to condition->wait()\n"); + + mt_lock(&mutex_kluge); + mut=OB2KEY(key)->mut; + THREADS_ALLOW(); + + /* Unlock mutex */ + mut->key=0; + OB2KEY(key)->mut=0; + co_signal(& mut->condition); - destruct(sp[-1].u.object); + /* Wait and allow mutex operations */ + co_wait(c,&mutex_kluge); + + if(OB2KEY(key)->initialized) + { + /* Lock mutex */ + while(mut->key) co_wait(& mut->condition, & mutex_kluge); + mut->key=key; + OB2KEY(key)->mut=mut; + } + mt_unlock(&mutex_kluge); + THREADS_DISALLOW(); pop_stack(); + } else { + THREADS_ALLOW(); + co_wait(c, 0); + THREADS_DISALLOW(); } - - c=THIS_COND; - THREADS_ALLOW(); - co_wait(c,0); - THREADS_DISALLOW(); } void f_cond_signal(INT32 args) { pop_n_elems(args); co_signal(THIS_COND); } @@ -153,7 +234,7 @@ void exit_cond_obj(struct object *o) { co_destroy(THIS_COND); } void th_init_programs() { start_new_program(); - add_storage(sizeof(MUTEX_T)); + add_storage(sizeof(struct mutex_storage)); add_function("lock",f_mutex_lock,"function(:object)",0); add_function("trylock",f_mutex_trylock,"function(:object)",0); set_init_callback(init_mutex_obj); @@ -161,7 +242,8 @@ void th_init_programs() end_c_program("/precompiled/mutex"); start_new_program(); - add_storage(sizeof(struct object *)); + add_storage(sizeof(struct key_storage)); + set_init_callback(init_mutex_key_obj); set_exit_callback(exit_mutex_key_obj); mutex_key=end_c_program("/precompiled/mutex_key"); diff --git a/src/threads.h b/src/threads.h index af5213f91e..3653fade56 100644 --- a/src/threads.h +++ b/src/threads.h @@ -21,7 +21,7 @@ extern int num_threads; #define mt_unlock(X) pthread_mutex_unlock(X) #define mt_destroy(X) pthread_mutex_destroy(X) -extern MUTEX_T interpreter_lock, compiler_lock; +extern MUTEX_T interpreter_lock; #define th_create(ID,fun,arg) pthread_create(ID,&pattr,fun,arg) #define th_exit(foo) pthread_exit(foo) -- GitLab