From a91ca08061772d46b266776f56201c5f1fc58885 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Fri, 10 Jul 1998 17:52:10 +0200
Subject: [PATCH] Added support for interleaved mutexes.

Rev: src/main.c:1.55
Rev: src/modules/system/passwords.c:1.17
Rev: src/program.c:1.96
Rev: src/threads.c:1.75
Rev: src/threads.h:1.45
---
 src/main.c                     |   4 +-
 src/modules/system/passwords.c | 108 +++++++++++-------
 src/program.c                  |  15 +--
 src/threads.c                  | 199 ++++++++++++++++++++++++---------
 src/threads.h                  |  91 +++++++++++----
 5 files changed, 294 insertions(+), 123 deletions(-)

diff --git a/src/main.c b/src/main.c
index 9e7563d17a..0f30eee002 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: main.c,v 1.54 1998/05/25 19:34:11 grubba Exp $");
+RCSID("$Id: main.c,v 1.55 1998/07/10 15:52:03 grubba Exp $");
 #include "fdlib.h"
 #include "backend.h"
 #include "module.h"
@@ -321,6 +321,8 @@ int dbm_main(int argc, char **argv)
   init_cpp();
   init_lex();
 
+  low_th_init();
+
   init_modules();
   master();
   call_callback(& post_master_callbacks, 0);
diff --git a/src/modules/system/passwords.c b/src/modules/system/passwords.c
index 6236624975..7a9d64e5c2 100644
--- a/src/modules/system/passwords.c
+++ b/src/modules/system/passwords.c
@@ -1,5 +1,5 @@
 /*
- * $Id: passwords.c,v 1.16 1998/07/09 21:03:22 grubba Exp $
+ * $Id: passwords.c,v 1.17 1998/07/10 15:52:10 grubba Exp $
  *
  * Password handling for Pike.
  *
@@ -22,7 +22,7 @@
 #include "system_machine.h"
 #include "system.h"
 
-RCSID("$Id: passwords.c,v 1.16 1998/07/09 21:03:22 grubba Exp $");
+RCSID("$Id: passwords.c,v 1.17 1998/07/10 15:52:10 grubba Exp $");
 
 #include "module_support.h"
 #include "interpret.h"
@@ -53,7 +53,7 @@ RCSID("$Id: passwords.c,v 1.16 1998/07/09 21:03:22 grubba Exp $");
  * Emulation
  */
 
-DEFINE_MUTEX(password_protection_mutex);
+DEFINE_IMUTEX(password_protection_mutex);
 
 #ifdef HAVE_GETPWENT
 #ifndef HAVE_GETPWNAM
@@ -120,9 +120,9 @@ void push_pwent(struct passwd *ent)
   if(!strcmp(ent->pw_passwd, "x"))
   {
     struct spwd *foo;
-    THREADS_ALLOW_UID();
+    THREADS_ALLOW();
     foo = getspnam(ent->pw_name);
-    THREADS_DISALLOW_UID();
+    THREADS_DISALLOW();
     if(foo)
       push_text(foo->sp_pwdp);
     else
@@ -171,13 +171,16 @@ void f_getgrgid(INT32 args)
   int gid;
   struct group *foo;
   get_all_args("getgrgid", args, "%d", &gid);
+
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   foo = getgrgid( gid );
   THREADS_DISALLOW_UID();
   pop_n_elems( args );
   push_grent( foo );
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 #endif /* HAVE_GETGRGID */
 
@@ -188,13 +191,16 @@ void f_getgrnam(INT32 args)
   char *str;
   struct group *foo;
   get_all_args("getgrnam", args, "%s", &str);
+
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   foo = getgrnam( str );
   THREADS_DISALLOW_UID();
   pop_n_elems( args );
   push_grent( foo );
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 #endif /* HAVE_GETGRNAM */
 
@@ -207,14 +213,16 @@ void f_getpwnam(INT32 args)
 
   get_all_args("getpwnam", args, "%s", &str);
 
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   foo = getpwnam(str);
   THREADS_DISALLOW_UID();
 
   pop_n_elems(args);
   push_pwent(foo);
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 #endif /* HAVE_GETPWNAM */
 
@@ -227,14 +235,16 @@ void f_getpwuid(INT32 args)
   
   get_all_args("getpwuid", args, "%i", &uid);
 
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   foo = getpwuid(uid);
   THREADS_DISALLOW_UID();
 
   pop_n_elems(args);
   push_pwent(foo);
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 #endif /* HAVE_GETPWUID */
 
@@ -242,13 +252,15 @@ void f_getpwuid(INT32 args)
 /* int setpwent() */
 void f_setpwent(INT32 args)
 {
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   setpwent();
-  mt_unlock(&password_protection_mutex);
   THREADS_DISALLOW_UID();
   pop_n_elems(args);
   push_int(0);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 #endif /* HAVE_SETPWENT */
  
@@ -256,13 +268,15 @@ void f_setpwent(INT32 args)
 /* int endpwent() */
 void f_endpwent(INT32 args)
 {
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   endpwent();
-  mt_unlock(&password_protection_mutex);
   THREADS_DISALLOW_UID();
   pop_n_elems(args);
   push_int(0);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 #endif /* HAVE_ENDPWENT */
 
@@ -272,8 +286,10 @@ void f_getpwent(INT32 args)
 {
   struct passwd *foo;
   pop_n_elems(args);
+
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   foo = getpwent();
   THREADS_DISALLOW_UID();
   if(!foo)
@@ -283,7 +299,8 @@ void f_getpwent(INT32 args)
     return;
   }
   push_pwent(foo);
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 
 void f_get_all_users(INT32 args)
@@ -293,12 +310,7 @@ void f_get_all_users(INT32 args)
   pop_n_elems(args);
   a = low_allocate_array(0, 10);
 
-  /* NOTE: We need THREADS_ALLOW_UID()/THREADS_DISALLOW_UID() here
-   * to avoid deadlocks.
-   */
-  THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
-  THREADS_DISALLOW_UID();
+  LOCK_IMUTEX(&password_protection_mutex);
 
   setpwent();
   while(1)
@@ -318,7 +330,7 @@ void f_get_all_users(INT32 args)
   }
   endpwent();
 
-  mt_unlock(&password_protection_mutex);
+  UNLOCK_IMUTEX(&password_protection_mutex);
 
   push_array(a);
 }
@@ -329,11 +341,14 @@ void f_get_all_users(INT32 args)
 /* int setgrent() */
 void f_setgrent(INT32 args)
 {
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   setgrent();
-  mt_unlock(&password_protection_mutex);
   THREADS_DISALLOW_UID();
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
+
   pop_n_elems(args);
   push_int(0);
 }
@@ -343,11 +358,14 @@ void f_setgrent(INT32 args)
 /* int endgrent() */
 void f_endgrent(INT32 args)
 {
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   endgrent();
-  mt_unlock(&password_protection_mutex);
   THREADS_DISALLOW_UID();
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
+
   pop_n_elems(args);
   push_int(0);
 }
@@ -359,8 +377,10 @@ void f_getgrent(INT32 args)
 {
   struct group *foo;
   pop_n_elems(args);
+
+  LOCK_IMUTEX(&password_protection_mutex);
+
   THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
   foo = getgrent();
   THREADS_DISALLOW_UID();
   if(!foo)
@@ -369,7 +389,8 @@ void f_getgrent(INT32 args)
     return;
   }
   push_grent(foo);
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
 }
 
 void f_get_all_groups(INT32 args)
@@ -380,12 +401,7 @@ void f_get_all_groups(INT32 args)
 
   a = low_allocate_array(0, 10);
 
-  /* NOTE: We need THREADS_ALLOW_UID()/THREADS_DISALLOW_UID() here
-   * to avoid deadlocks.
-   */
-  THREADS_ALLOW_UID();
-  mt_lock(&password_protection_mutex);
-  THREADS_DISALLOW_UID();
+  LOCK_IMUTEX(&password_protection_mutex);
 
   setgrent();
   while(1)
@@ -404,7 +420,7 @@ void f_get_all_groups(INT32 args)
   }
   endgrent();
 
-  mt_unlock(&password_protection_mutex);
+  UNLOCK_IMUTEX(&password_protection_mutex);
 
   push_array(a);
 }
@@ -425,8 +441,10 @@ void f_get_groups_for_user(INT32 arg)
   if(sp[-1].type == T_INT)
   {
     int uid=sp[-1].u.integer;
+
+    LOCK_IMUTEX(&password_protection_mutex);
+
     THREADS_ALLOW_UID();
-    mt_lock(&password_protection_mutex);
     pw=getpwuid(uid);
     THREADS_DISALLOW_UID();
 
@@ -435,8 +453,10 @@ void f_get_groups_for_user(INT32 arg)
     user=sp[-1].u.string->str;
   }else{
     user=sp[-1].u.string->str;
+
+    LOCK_IMUTEX(&password_protection_mutex);
+
     THREADS_ALLOW_UID();
-    mt_lock(&password_protection_mutex);
     pw=getpwnam(user);
     THREADS_DISALLOW_UID();
   }
@@ -479,7 +499,9 @@ void f_get_groups_for_user(INT32 arg)
     pop_stack();
   }
   endgrent();
-  mt_unlock(&password_protection_mutex);
+
+  UNLOCK_IMUTEX(&password_protection_mutex);
+ 
   pop_stack();
   push_array(a);
 }
@@ -488,6 +510,8 @@ void f_get_groups_for_user(INT32 arg)
 
 void init_passwd(void)
 {
+  init_interleave_mutex(&password_protection_mutex);
+
   /*
    * From passwords.c
    */
diff --git a/src/program.c b/src/program.c
index fd07cf4eed..8f37cedc69 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.95 1998/06/24 04:56:46 hubbe Exp $");
+RCSID("$Id: program.c,v 1.96 1998/07/10 15:52:04 grubba Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -507,7 +507,8 @@ void low_start_new_program(struct program *p,
 {
   int e,id=0;
 
-  threads_disabled++;
+  init_threads_disable(NULL);
+
   compilation_depth++;
 
   /* fprintf(stderr, "low_start_new_program(): compilation_depth:%d\n", compilation_depth); */
@@ -945,8 +946,8 @@ struct program *end_first_pass(int finish)
 
 
   compilation_depth--;
-  if(!--threads_disabled)
-    co_broadcast(&threads_disabled_change);
+
+  exit_threads_disable(NULL);
 
   /* fprintf(stderr, "end_first_pass(): compilation_depth:%d\n", compilation_depth); */
 
@@ -2307,10 +2308,10 @@ struct program *compile(struct pike_string *prog)
 	  threads_disabled, saved_threads_disabled);
   }
 #endif /* DEBUG */
-  threads_disabled = saved_threads_disabled;
+  threads_disabled = saved_threads_disabled + 1;
   /* fprintf(stderr, "compile() Leave: threads_disabled:%d, compilation_depth:%d\n", threads_disabled, compilation_depth); */
-  if(!threads_disabled)
-    co_broadcast(&threads_disabled_change);
+
+  exit_threads_disable(NULL);
 
   free_string(lex.current_file);
   lex=save_lex;
diff --git a/src/threads.c b/src/threads.c
index c1f3db6f7d..9bbe58862c 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -1,5 +1,5 @@
 #include "global.h"
-RCSID("$Id: threads.c,v 1.74 1998/07/09 21:50:37 grubba Exp $");
+RCSID("$Id: threads.c,v 1.75 1998/07/10 15:52:06 grubba Exp $");
 
 int num_threads = 1;
 int threads_disabled = 0;
@@ -142,7 +142,7 @@ struct object *thread_id;
 static struct callback *threads_evaluator_callback=0;
 int thread_id_result_variable;
 
-MUTEX_T interpreter_lock, thread_table_lock;
+MUTEX_T interpreter_lock, thread_table_lock, interleave_lock;
 struct program *mutex_key = 0;
 struct program *thread_id_prog = 0;
 #ifdef POSIX_THREADS
@@ -156,13 +156,86 @@ struct thread_starter
   struct array *args;
 };
 
+static volatile IMUTEX_T *interleave_list = NULL;
+
+void init_threads_disable(struct object *o)
+{
+  /* Serious black magic to avoid dead-locks */
+
+  if (!threads_disabled) {
+    THREADS_FPRINTF(0, (stderr, "init_threads_disable(): Locking IM's...\n"));
+
+    if (thread_id) {
+      IMUTEX_T *im;
+
+      THREADS_ALLOW();
+
+      /* Keep this the entire session. */
+      mt_lock(&interleave_lock);
+
+      im = (IMUTEX_T *)interleave_list;
+
+      while(im) {
+	mt_lock(&(im->lock));
+
+	im = im->next;
+      }
+
+      THREADS_DISALLOW();
+    } else {
+      IMUTEX_T *im;
+
+      /* Keep this the entire session. */
+      mt_lock(&interleave_lock);
+
+      im = (IMUTEX_T *)interleave_list;
+
+      while(im) {
+	mt_lock(&(im->lock));
+
+	im = im->next;
+      }
+    }
+
+    THREADS_FPRINTF(0,
+		    (stderr, "init_threads_disable(): Disabling threads.\n"));
+
+    threads_disabled = 1;
+  } else {
+    threads_disabled++;
+  }
+
+  THREADS_FPRINTF(0, (stderr, "init_threads_disable(): threads_disabled:%d\n",
+		      threads_disabled));
+  while (live_threads) {
+    THREADS_FPRINTF(0,
+		    (stderr,
+		     "_disable_threads(): Waiting for %d threads to finish\n",
+		     live_threads));
+    co_wait(&live_threads_change, &interpreter_lock);
+  }
+}
+
 void exit_threads_disable(struct object *o)
 {
-  THREADS_FPRINTF((stderr, "exit_threads_disable(): threads_disabled:%d\n",
-		   threads_disabled));
+  THREADS_FPRINTF(0, (stderr, "exit_threads_disable(): threads_disabled:%d\n",
+		      threads_disabled));
   if(threads_disabled) {
     if(!--threads_disabled) {
-      THREADS_FPRINTF((stderr, "_exit_threads_disable(): Wake up!\n"));
+      IMUTEX_T *im = (IMUTEX_T *)interleave_list;
+
+      /* Order shouldn't matter for unlock, so no need to do it backwards. */
+      while(im) {
+	THREADS_FPRINTF(0,
+			(stderr,
+			 "exit_threads_disable(): Unlocking IM 0x%08p\n", im));
+	mt_unlock(&(im->lock));
+	im = im->next;
+      }
+
+      mt_unlock(&interleave_lock);
+
+      THREADS_FPRINTF(0, (stderr, "_exit_threads_disable(): Wake up!\n"));
       co_broadcast(&threads_disabled_change);
     }
 #ifdef DEBUG
@@ -172,32 +245,51 @@ void exit_threads_disable(struct object *o)
   }
 }
 
-void init_threads_disable(struct object *o)
+void init_interleave_mutex(IMUTEX_T *im)
 {
-  /* Serious black magic to avoid dead-locks */
+  mt_init(&(im->lock));
 
-  if (!threads_disabled) {
-    extern MUTEX_T password_protection_mutex;
+  THREADS_FPRINTF(0, (stderr,
+		      "init_interleave_mutex(): init_threads_disable()\n"));
 
-    THREADS_ALLOW_UID();
-    mt_lock(&password_protection_mutex);
-    THREADS_DISALLOW_UID();
+  init_threads_disable(NULL);
 
-    threads_disabled = 1;
+  THREADS_FPRINTF(0, (stderr,
+		      "init_interleave_mutex(): Locking IM 0x%08p\n", im));
 
-    mt_unlock(&password_protection_mutex);
-  } else {
-    threads_disabled++;
+  /* Lock it so that it can be unlocked by exit_threads_disable() */
+  mt_lock(&(im->lock));
+
+  im->next = (IMUTEX_T *)interleave_list;
+  if (interleave_list) {
+    interleave_list->prev = im;
   }
+  interleave_list = im;
+  im->prev = NULL;
 
-  THREADS_FPRINTF((stderr, "init_threads_disable(): threads_disabled:%d\n",
-		   threads_disabled));
-  while (live_threads) {
-    THREADS_FPRINTF((stderr,
-		     "_disable_threads(): Waiting for %d threads to finish\n",
-		     live_threads));
-    co_wait(&live_threads_change, &interpreter_lock);
+  THREADS_FPRINTF(0, (stderr,
+		      "init_interleave_mutex(): exit_threads_disable()\n"));
+
+  exit_threads_disable(NULL);
+}
+
+void exit_interleave_mutex(IMUTEX_T *im)
+{
+  init_threads_disable(NULL);
+
+  if (im->prev) {
+    im->prev->next = im->next;
+  } else {
+    interleave_list = im->next;
+  }
+  if (im->next) {
+    im->next->prev = im->prev;
   }
+
+  /* Just to be nice... */
+  mt_unlock(&(im->lock));
+
+  exit_threads_disable(NULL);
 }
 
 /* Thread hashtable */
@@ -329,8 +421,8 @@ void *new_thread_func(void * data)
   JMP_BUF back;
   INT32 tmp;
 
-  THREADS_FPRINTF((stderr,"THREADS_DISALLOW() Thread %08x created...\n",
-		   (unsigned int)arg.id));
+  THREADS_FPRINTF(0, (stderr,"THREADS_DISALLOW() Thread %08x created...\n",
+		      (unsigned int)arg.id));
   
   if((tmp=mt_lock( & interpreter_lock)))
     fatal("Failed to lock interpreter, errno %d\n",tmp);
@@ -344,7 +436,7 @@ void *new_thread_func(void * data)
   }
 #endif /* THREAD_TRACE */
 
-  THREADS_FPRINTF((stderr,"THREAD %08x INITED\n",(unsigned int)thread_id));
+  THREADS_FPRINTF(0, (stderr,"THREAD %08x INITED\n",(unsigned int)thread_id));
   if(SETJMP(back))
   {
     if(throw_severity < THROW_EXIT)
@@ -380,8 +472,8 @@ void *new_thread_func(void * data)
   free((char *)data); /* Moved by per, to avoid some bugs.... */
   UNSETJMP(back);
 
-  THREADS_FPRINTF((stderr,"THREADS_ALLOW() Thread %08x done\n",
-		   (unsigned int)thread_id));
+  THREADS_FPRINTF(0, (stderr,"THREADS_ALLOW() Thread %08x done\n",
+		      (unsigned int)thread_id));
 
   thread_table_delete(thread_id);
   free_object(thread_id);
@@ -428,7 +520,8 @@ void f_thread_create(INT32 args)
 						 check_threads, 0,0);
     }
     ref_push_object(arg->id);
-    THREADS_FPRINTF((stderr,"THREAD_CREATE -> t:%08x\n",(unsigned int)arg->id));
+    THREADS_FPRINTF(0, (stderr, "THREAD_CREATE -> t:%08x\n",
+			(unsigned int)arg->id));
   } else {
     free_object(arg->id);
     free_array(arg->args);
@@ -493,7 +586,8 @@ void f_mutex_lock(INT32 args)
   {
     if(m->key && OB2KEY(m->key)->owner == thread_id)
     {
-      THREADS_FPRINTF((stderr, "Recursive LOCK k:%08x, m:%08x(%08x), t:%08x\n",
+      THREADS_FPRINTF(0,
+		      (stderr, "Recursive LOCK k:%08x, m:%08x(%08x), t:%08x\n",
 		       (unsigned int)OB2KEY(m->key),
 		       (unsigned int)m,
 		       (unsigned int)OB2KEY(m->key)->mut,
@@ -508,7 +602,7 @@ void f_mutex_lock(INT32 args)
     SWAP_OUT_CURRENT_THREAD();
     do
     {
-      THREADS_FPRINTF((stderr,"WAITING TO LOCK m:%08x\n",(unsigned int)m));
+      THREADS_FPRINTF(1, (stderr,"WAITING TO LOCK m:%08x\n",(unsigned int)m));
       co_wait(& m->condition, & interpreter_lock);
     }while(m->key);
     SWAP_IN_CURRENT_THREAD();
@@ -516,11 +610,11 @@ void f_mutex_lock(INT32 args)
   m->key=o;
   OB2KEY(o)->mut=m;
 
-  THREADS_FPRINTF((stderr, "LOCK k:%08x, m:%08x(%08x), t:%08x\n",
-		   (unsigned int)OB2KEY(o),
-		   (unsigned int)m,
-		   (unsigned int)OB2KEY(m->key)->mut,
-		   (unsigned int)thread_id));
+  THREADS_FPRINTF(1, (stderr, "LOCK k:%08x, m:%08x(%08x), t:%08x\n",
+		      (unsigned int)OB2KEY(o),
+		      (unsigned int)m,
+		      (unsigned int)OB2KEY(m->key)->mut,
+		      (unsigned int)thread_id));
   pop_n_elems(args);
   push_object(o);
 }
@@ -573,7 +667,8 @@ void init_mutex_obj(struct object *o)
 
 void exit_mutex_obj(struct object *o)
 {
-  THREADS_FPRINTF((stderr,"DESTROYING MUTEX m:%08x\n",(unsigned int)THIS_MUTEX));
+  THREADS_FPRINTF(1, (stderr, "DESTROYING MUTEX m:%08x\n",
+		      (unsigned int)THIS_MUTEX));
   if(THIS_MUTEX->key) destruct(THIS_MUTEX->key);
   THIS_MUTEX->key=0;
   co_destroy(& THIS_MUTEX->condition);
@@ -582,8 +677,8 @@ void exit_mutex_obj(struct object *o)
 #define THIS_KEY ((struct key_storage *)(fp->current_storage))
 void init_mutex_key_obj(struct object *o)
 {
-  THREADS_FPRINTF((stderr, "KEY k:%08x, o:%08x\n",
-		   (unsigned int)THIS_KEY, (unsigned int)thread_id));
+  THREADS_FPRINTF(1, (stderr, "KEY k:%08x, o:%08x\n",
+		      (unsigned int)THIS_KEY, (unsigned int)thread_id));
   THIS_KEY->mut=0;
   add_ref(THIS_KEY->owner=thread_id);
   THIS_KEY->initialized=1;
@@ -591,11 +686,11 @@ void init_mutex_key_obj(struct object *o)
 
 void exit_mutex_key_obj(struct object *o)
 {
-  THREADS_FPRINTF((stderr, "UNLOCK k:%08x m:(%08x) t:%08x o:%08x\n",
-		   (unsigned int)THIS_KEY,
-		   (unsigned int)THIS_KEY->mut,
-		   (unsigned int)thread_id,
-		   (unsigned int)THIS_KEY->owner));
+  THREADS_FPRINTF(1, (stderr, "UNLOCK k:%08x m:(%08x) t:%08x o:%08x\n",
+		      (unsigned int)THIS_KEY,
+		      (unsigned int)THIS_KEY->mut,
+		      (unsigned int)thread_id,
+		      (unsigned int)THIS_KEY->owner));
   if(THIS_KEY->mut)
   {
     struct mutex_storage *mut = THIS_KEY->mut;
@@ -741,17 +836,14 @@ static void thread_was_marked(struct object *o)
 }
 #endif
 
-void th_init(void)
+void low_th_init(void)
 {
-  struct program *tmp;
-  INT32 mutex_key_offset;
-
 #ifdef SGI_SPROC_THREADS
 #error /* Need to specify a filename */
   us_cookie = usinit("");
 #endif /* SGI_SPROC_THREADS */
 
-  THREADS_FPRINTF((stderr, "THREADS_DISALLOW() Initializing threads.\n"));
+  THREADS_FPRINTF(0, (stderr, "THREADS_DISALLOW() Initializing threads.\n"));
 
 #ifdef POSIX_THREADS
 #ifdef HAVE_PTHREAD_INIT
@@ -762,6 +854,7 @@ void th_init(void)
   mt_init( & interpreter_lock);
   mt_lock( & interpreter_lock);
   mt_init( & thread_table_lock);
+  mt_init( & interleave_lock);
   co_init( & live_threads_change);
   co_init( & threads_disabled_change);
   thread_table_init();
@@ -779,7 +872,13 @@ void th_init(void)
   pthread_attr_setdetachstate(&small_pattr, PTHREAD_CREATE_DETACHED);
 
 #endif
-  
+}
+
+void th_init(void)
+{
+  struct program *tmp;
+  INT32 mutex_key_offset;
+
   add_efun("thread_create",f_thread_create,"function(mixed ...:object)",
            OPT_SIDE_EFFECT);
 #ifdef UNIX_THREADS
diff --git a/src/threads.h b/src/threads.h
index 982adb1397..d5ed226e3f 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -1,5 +1,5 @@
 /*
- * $Id: threads.h,v 1.44 1998/07/05 13:48:58 grubba Exp $
+ * $Id: threads.h,v 1.45 1998/07/10 15:52:08 grubba Exp $
  */
 #ifndef THREADS_H
 #define THREADS_H
@@ -231,6 +231,37 @@ extern COND_T threads_disabled_change;		/* Used by _disable_threads */
 struct svalue;
 struct frame;
 
+extern MUTEX_T interleave_lock;
+
+struct interleave_mutex
+{
+  struct interleave_mutex *next;
+  struct interleave_mutex *prev;
+  MUTEX_T lock;
+};
+
+#define IMUTEX_T struct interleave_mutex
+
+#define DEFINE_IMUTEX(name) IMUTEX_T name
+
+/* If threads are disabled, we already hold the lock. */
+#define LOCK_IMUTEX(im) do { \
+    if (!threads_disabled) { \
+      THREADS_FPRINTF(0, (stderr, "Locking IMutex 0x%08p...\n", (im))); \
+      THREADS_ALLOW(); \
+      mt_lock(&((im)->lock)); \
+      THREADS_DISALLOW(); \
+    } \
+  } while(0)
+
+/* If threads are disabled, the lock will be released later. */
+#define UNLOCK_IMUTEX(im) do { \
+    if (!threads_disabled) { \
+      THREADS_FPRINTF(0, (stderr, "Unlocking IMutex 0x%08p...\n", (im))); \
+      mt_unlock(&((im)->lock)); \
+    } \
+  } while(0)
+
 #define THREAD_NOT_STARTED -1
 #define THREAD_RUNNING 0
 #define THREAD_EXITED 1
@@ -272,12 +303,15 @@ struct thread_state {
 #endif
 
 /* Define to get a debug-trace of some of the threads operations. */
-/* #define VERBOSE_THREADS_DEBUG */
+/* #define VERBOSE_THREADS_DEBUG	0 */ /* Some debug */
+/* #define VERBOSE_THREADS_DEBUG	1 */ /* Lots of debug */
 
 #ifndef VERBOSE_THREADS_DEBUG
-#define THREADS_FPRINTF(X)
+#define THREADS_FPRINTF(L,X)
 #else
-#define THREADS_FPRINTF(X)	fprintf X
+#define THREADS_FPRINTF(L,X)	do { \
+    if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) fprintf X; \
+  } while(0)
 #endif /* VERBOSE_THREADS_DEBUG */
 
 #ifdef THREAD_TRACE
@@ -320,12 +354,12 @@ struct thread_state {
   do {\
      struct thread_state *_tmp=(struct thread_state *)thread_id->storage; \
      SWAP_OUT_THREAD(_tmp); \
-     THREADS_FPRINTF((stderr, "SWAP_OUT_CURRENT_THREAD() %s:%d t:%08x\n", \
-			__FILE__, __LINE__, (unsigned int)_tmp->thread_id)) \
+     THREADS_FPRINTF(1, (stderr, "SWAP_OUT_CURRENT_THREAD() %s:%d t:%08x\n", \
+			 __FILE__, __LINE__, (unsigned int)_tmp->thread_id)) \
 
 #define SWAP_IN_CURRENT_THREAD() \
-   THREADS_FPRINTF((stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \
-		    __FILE__, __LINE__, (unsigned int)_tmp->thread_id)); \
+   THREADS_FPRINTF(1, (stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \
+		       __FILE__, __LINE__, (unsigned int)_tmp->thread_id)); \
    SWAP_IN_THREAD(_tmp);\
  } while(0)
 
@@ -341,7 +375,7 @@ struct thread_state {
    int recoveries = 0, thread_id = 0; \
    int error = 0, xalloc = 0, low_my_putchar = 0, low_my_binary_strcat = 0; \
    int low_make_buf_space = 0, pop_n_elems = 0; \
-   int push_sp_mark = 0, pop_sp_mark = 0
+   int push_sp_mark = 0, pop_sp_mark = 0, threads_disabled = 1
 
 /* Note that the semi-colon below is needed to add an empty statement
  * in case there is a label before the macro.
@@ -357,9 +391,9 @@ struct thread_state {
      struct thread_state *_tmp=(struct thread_state *)thread_id->storage; \
      if(num_threads > 1 && !threads_disabled) { \
        SWAP_OUT_THREAD(_tmp); \
-       THREADS_FPRINTF((stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \
-			__FILE__, __LINE__, \
-			(unsigned int)_tmp->thread_id, live_threads)); \
+       THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \
+			   __FILE__, __LINE__, \
+			   (unsigned int)_tmp->thread_id, live_threads)); \
        mt_unlock(& interpreter_lock); \
      } else {} \
      HIDE_GLOBAL_VARIABLES()
@@ -368,11 +402,12 @@ struct thread_state {
      REVEAL_GLOBAL_VARIABLES(); \
      if(_tmp->swapped) { \
        mt_lock(& interpreter_lock); \
-       THREADS_FPRINTF((stderr, "THREADS_DISALLOW() %s:%d t:%08x(#%d)\n", \
-			__FILE__, __LINE__, \
-                        (unsigned int)_tmp->thread_id, live_threads)); \
+       THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW() %s:%d t:%08x(#%d)\n", \
+			   __FILE__, __LINE__, \
+                           (unsigned int)_tmp->thread_id, live_threads)); \
        while (threads_disabled) { \
-         THREADS_FPRINTF((stderr, "THREADS_DISALLOW(): Threads disabled\n")); \
+         THREADS_FPRINTF(1, (stderr, \
+                             "THREADS_DISALLOW(): Threads disabled\n")); \
          co_wait(&threads_disabled_change, &interpreter_lock); \
        } \
        SWAP_IN_THREAD(_tmp);\
@@ -384,9 +419,9 @@ struct thread_state {
      if(num_threads > 1 && !threads_disabled) { \
        SWAP_OUT_THREAD(_tmp_uid); \
        live_threads++; \
-       THREADS_FPRINTF((stderr, "THREADS_ALLOW_UID() %s:%d t:%08x(#%d)\n", \
-			__FILE__, __LINE__, \
-			(unsigned int)_tmp_uid->thread_id, live_threads)); \
+       THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW_UID() %s:%d t:%08x(#%d)\n", \
+			   __FILE__, __LINE__, \
+			   (unsigned int)_tmp_uid->thread_id, live_threads)); \
        mt_unlock(& interpreter_lock); \
      } else {} \
      HIDE_GLOBAL_VARIABLES()
@@ -396,12 +431,13 @@ struct thread_state {
      if(_tmp_uid->swapped) { \
        mt_lock(& interpreter_lock); \
        live_threads--; \
-       THREADS_FPRINTF((stderr, "THREADS_DISALLOW_UID() %s:%d t:%08x(#%d)\n", \
-			__FILE__, __LINE__, \
-                        (unsigned int)_tmp_uid->thread_id, live_threads)); \
+       THREADS_FPRINTF(1, (stderr, \
+                           "THREADS_DISALLOW_UID() %s:%d t:%08x(#%d)\n", \
+			   __FILE__, __LINE__, \
+                           (unsigned int)_tmp_uid->thread_id, live_threads)); \
        co_broadcast(&live_threads_change); \
        while (threads_disabled) { \
-         THREADS_FPRINTF((stderr, "THREADS_DISALLOW_UID(): Wait...\n")); \
+         THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW_UID(): Wait...\n")); \
          co_wait(&threads_disabled_change, &interpreter_lock); \
        } \
        SWAP_IN_THREAD(_tmp_uid);\
@@ -433,6 +469,7 @@ void init_thread_obj(struct object *o);
 void exit_thread_obj(struct object *o);
 void th_farm(void (*fun)(void *), void *);
 void th_init(void);
+void low_th_init(void);
 void th_cleanup(void);
 void thread_table_insert(struct object *o);
 void thread_table_delete(struct object *o);
@@ -443,11 +480,18 @@ void f_all_threads(INT32 args);
 void init_threads_disable(struct object *o);
 void exit_threads_disable(struct object *o);
 
+void init_interleave_mutex(IMUTEX_T *im);
+void exit_interleave_mutex(IMUTEX_T *im);
+
 /* Prototypes end here */
 
 #else
 #define th_setconcurrency(X)
 #define DEFINE_MUTEX(X)
+#define DEFINE_IMUTEX(X)
+#define init_interleave_mutex(X)
+#define LOCK_IMUTEX(X)
+#define UNLOCK_IMUTEX(X)
 #define mt_init(X)
 #define mt_lock(X)
 #define mt_unlock(X)
@@ -459,6 +503,7 @@ void exit_threads_disable(struct object *o);
 #define HIDE_GLOBAL_VARIABLES()
 #define REVEAL_GLOBAL_VARIABLES()
 #define th_init()
+#define low_th_init()
 #define th_cleanup()
 #define th_init_programs()
 #define th_self() ((void*)0)
-- 
GitLab