diff --git a/.gitattributes b/.gitattributes
index 9facb0f5db1634cd74485745c3762c76956c1a39..4268ddbcc6bcfbbc0dcd524a7a1e4c21672508e2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -581,6 +581,7 @@ testfont binary
 /src/pike_macros.h foreign_ident
 /src/pike_memory.c foreign_ident
 /src/pike_memory.h foreign_ident
+/src/pike_threadlib.h foreign_ident
 /src/pike_types.c foreign_ident
 /src/pike_types.h foreign_ident
 /src/port.c foreign_ident
diff --git a/src/array.c b/src/array.c
index 5e3812ad5ff95e3665f1216ed8c0814c9a892a78..4e74241155b9b80f9671d94a63d7262ed948e9a4 100644
--- a/src/array.c
+++ b/src/array.c
@@ -23,13 +23,16 @@
 #include "stuff.h"
 #include "bignum.h"
 
-RCSID("$Id: array.c,v 1.102 2001/02/03 01:04:48 mast Exp $");
+RCSID("$Id: array.c,v 1.103 2001/04/07 07:38:23 hubbe Exp $");
 
 PMOD_EXPORT struct array empty_array=
 {
   1,                     /* Never free */
 #ifdef PIKE_SECURITY
   0,
+#endif
+#ifdef USE_LOCAL_MUTEX
+  PTHREAD_MUTEX_INITIALIZER,
 #endif
   &empty_array,          /* Next */
   &empty_array,          /* previous (circular) */
@@ -73,11 +76,9 @@ PMOD_EXPORT struct array *low_allocate_array(ptrdiff_t size, ptrdiff_t extra_spa
 
   v->malloced_size = DO_NOT_WARN((INT32)(size + extra_space));
   v->size = DO_NOT_WARN((INT32)size);
-  v->refs=1;
+  INIT_PIKE_MEMOBJ(v);
   LINK_ARRAY(v);
 
-  INITIALIZE_PROT(v);
-
   for(e=0;e<v->size;e++)
   {
     ITEM(v)[e].type=T_INT;
@@ -115,7 +116,7 @@ PMOD_EXPORT void really_free_array(struct array *v)
 #endif
 
   add_ref(v);
-  FREE_PROT(v);
+  EXIT_PIKE_MEMOBJ(v);
   free_svalues(ITEM(v), v->size, v->type_field);
   v->refs--;
   array_free_no_free(v);
diff --git a/src/array.h b/src/array.h
index 5a278bac1205ada46c16c6146c6ea3150bc7f942..b92ab74e93456358989d398603fc3a47a4583b61 100644
--- a/src/array.h
+++ b/src/array.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: array.h,v 1.32 2001/03/23 03:14:39 hubbe Exp $
+ * $Id: array.h,v 1.33 2001/04/07 07:38:23 hubbe Exp $
  */
 #ifndef ARRAY_H
 #define ARRAY_H
@@ -14,10 +14,8 @@
 
 struct array
 {
-  INT32 refs;		/* Reference count */
-#ifdef PIKE_SECURITY
-  struct object *prot;
-#endif
+  PIKE_MEMORY_OBJECT_MEMBERS;
+
   struct array *next;	/* we need to keep track of all arrays */
   struct array *prev;	/* Another pointer, so we don't have to search
 			 * when freeing arrays */
diff --git a/src/constants.c b/src/constants.c
index 4a1c77fdc978968ae90d83490737530240635428..136a53ce15941ad3a1b81287ccc96c2a8a3cf514 100644
--- a/src/constants.c
+++ b/src/constants.c
@@ -16,7 +16,7 @@
 #include "pike_error.h"
 #include "block_alloc.h"
 
-RCSID("$Id: constants.c,v 1.28 2001/03/03 00:23:45 grubba Exp $");
+RCSID("$Id: constants.c,v 1.29 2001/04/07 07:38:24 hubbe Exp $");
 
 struct mapping *builtin_constants = 0;
 
@@ -68,6 +68,7 @@ PMOD_EXPORT void add_global_program(char *name, struct program *p)
 #define EXIT_BLOCK(X) do {		\
   free_type(X->type);			\
   free_string(X->name);			\
+  EXIT_PIKE_MEMOBJ(X);                  \
 }while(0)
 BLOCK_ALLOC(callable,128)
 
@@ -80,7 +81,7 @@ PMOD_EXPORT struct callable *low_make_callable(c_fun fun,
 				   docode_fun docode)
 {
   struct callable *f=alloc_callable();
-  f->refs=1;
+  INIT_PIKE_MEMOBJ(f);
   f->function=fun;
   f->name=name;
   f->type=type;
diff --git a/src/constants.h b/src/constants.h
index 6c3bc74241f4c6f67fed4faee0aa35798e3e7d06..5bae6091a2ff09bcee4a1169b9c77edb3cda6406 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: constants.h,v 1.16 2001/02/19 23:49:59 grubba Exp $
+ * $Id: constants.h,v 1.17 2001/04/07 07:38:24 hubbe Exp $
  */
 #ifndef ADD_EFUN_H
 #define ADD_EFUN_H
@@ -20,10 +20,7 @@ typedef node *(*optimize_fun)(node *n);
 
 struct callable
 {
-  INT32 refs;
-#ifdef PIKE_SECURITY
-  struct object *prot;
-#endif
+  PIKE_MEMORY_OBJECT_MEMBERS;
   c_fun function;
   struct pike_type *type;
   struct pike_string *name;
diff --git a/src/mapping.h b/src/mapping.h
index d25b987509ccb677e106f207a3115105c8b32007..564c231b8b633c1dd72524dabca4e1f2b5c84b8a 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: mapping.h,v 1.35 2001/03/23 03:14:40 hubbe Exp $
+ * $Id: mapping.h,v 1.36 2001/04/07 07:38:24 hubbe Exp $
  */
 #ifndef MAPPING_H
 #define MAPPING_H
@@ -24,7 +24,7 @@ struct keypair
 
 struct mapping_data
 {
-  INT32 refs;
+  PIKE_MEMORY_OBJECT_MEMBERS;
   INT32 valrefs; /* lock values too */
   INT32 hardlinks;
   INT32 size, hashsize;
@@ -41,10 +41,7 @@ struct mapping_data
 
 struct mapping
 {
-  INT32 refs;
-#ifdef PIKE_SECURITY
-  struct object *prot;
-#endif
+  PIKE_MEMORY_OBJECT_MEMBERS;
 #ifdef MAPPING_SIZE_DEBUG
   INT32 debug_size;
 #endif
@@ -75,7 +72,7 @@ extern struct mapping *gc_internal_mapping;
 #define free_mapping_data(M) do{ \
  struct mapping_data *md_=(M); \
  debug_malloc_touch(md_); \
- if(!--md_->refs) really_free_mapping_data(md_); \
+ if(!sub_ref(md_)) really_free_mapping_data(md_); \
  /* FIXME: What about valrefs & hardlinks? */ \
 }while(0)
 
diff --git a/src/multiset.c b/src/multiset.c
index 1d24a3c9818fad54eac414cbdc1bdc26bf4af7dc..06c1120391e4e7382adb3b13f4a49e454a22d8c5 100644
--- a/src/multiset.c
+++ b/src/multiset.c
@@ -17,7 +17,7 @@
 #include "gc.h"
 #include "security.h"
 
-RCSID("$Id: multiset.c,v 1.32 2001/01/31 13:19:01 grubba Exp $");
+RCSID("$Id: multiset.c,v 1.33 2001/04/07 07:38:24 hubbe Exp $");
 
 struct multiset *first_multiset;
 
@@ -41,12 +41,10 @@ PMOD_EXPORT struct multiset *allocate_multiset(struct array *ind)
   struct multiset *l;
   l=ALLOC_STRUCT(multiset);
   GC_ALLOC(l);
-  l->refs = 1;
+  INIT_PIKE_MEMOBJ(l);
   l->ind=ind;
   DOUBLELINK(first_multiset, l);
 
-  INITIALIZE_PROT(l);
-
   return l;
 }
 
@@ -61,7 +59,7 @@ PMOD_EXPORT void really_free_multiset(struct multiset *l)
 #endif
 
   free_array(l->ind);
-  FREE_PROT(l);
+  EXIT_PIKE_MEMOBJ(l);
 
   DOUBLEUNLINK(first_multiset, l);
 
diff --git a/src/multiset.h b/src/multiset.h
index ae0a6e67a9ac43e4facdb6d7e7d759387f550595..42ce9f6a82a6a0d64224ed691acc27820cb1afc0 100644
--- a/src/multiset.h
+++ b/src/multiset.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: multiset.h,v 1.17 2001/03/23 03:14:40 hubbe Exp $
+ * $Id: multiset.h,v 1.18 2001/04/07 07:38:24 hubbe Exp $
  */
 #ifndef MULTISET_H
 #define MULTISET_H
@@ -14,10 +14,8 @@
 
 struct multiset
 {
-  INT32 refs;
-#ifdef PIKE_SECURITY
-  struct object *prot;
-#endif
+  PIKE_MEMORY_OBJECT_MEMBERS;  /* Must be first */
+
   struct multiset *next,*prev;
   struct array *ind;
 };
diff --git a/src/object.c b/src/object.c
index e28fd5013597302b97ea7becf5d15ca861a53cd0..7787cd6c460eb5e456603aaf9effe23b89861815 100644
--- a/src/object.c
+++ b/src/object.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: object.c,v 1.166 2001/03/22 02:21:15 hubbe Exp $");
+RCSID("$Id: object.c,v 1.167 2001/04/07 07:38:24 hubbe Exp $");
 #include "object.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
@@ -135,13 +135,12 @@ PMOD_EXPORT struct object *low_clone(struct program *p)
   o->parent_identifier=0;
 
   DOUBLELINK(first_object,o);
-  o->refs=1;
+  INIT_PIKE_MEMOBJ(o);
 
 #ifdef PIKE_DEBUG
   o->program_id=p->id;
 #endif
 
-  INITIALIZE_PROT(o);
   return o;
 }
 
@@ -769,7 +768,7 @@ PMOD_EXPORT void schedule_really_free_object(struct object *o)
       /* As far as the gc is concerned, the fake objects doesn't exist. */
       GC_FREE(o);
 
-    FREE_PROT(o);
+    EXIT_PIKE_MEMOBJ(o);
 
     if(o->storage)
     {
diff --git a/src/object.h b/src/object.h
index 4b9737cb778e9111fb3391d15ac1278d354741a3..64f51a6e6738d2921bd7f013051d94998a6a1de6 100644
--- a/src/object.h
+++ b/src/object.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: object.h,v 1.60 2001/03/23 03:14:40 hubbe Exp $
+ * $Id: object.h,v 1.61 2001/04/07 07:38:24 hubbe Exp $
  */
 #ifndef OBJECT_H
 #define OBJECT_H
@@ -20,10 +20,7 @@
 #endif
 struct object
 {
-  INT32 refs;                    /* Reference count, must be first. */
-#ifdef PIKE_SECURITY
-  struct object *prot;
-#endif
+  PIKE_MEMORY_OBJECT_MEMBERS; /* Must be first */
   struct program *prog;
   struct object *parent;
   INT16 parent_identifier;
diff --git a/src/pike_cpulib.c b/src/pike_cpulib.c
index 58ae97fe1ecf1d77e5d6bae410583e4c2ced62e7..4708358d4f2441f4b7c9683e425fbb1c835c7f6e 100644
--- a/src/pike_cpulib.c
+++ b/src/pike_cpulib.c
@@ -8,10 +8,11 @@
 #define PIKE_MEM_HASH 17903
 PIKE_MUTEX_T pike_memory_locks[PIKE_MEM_HASH];
 
-void init_cpulib(void)
+void init_pike_cpulib(void)
 {
   int e;
-  for(e=0;e<PIKE_MEM_HASH;e++) mt_init(pike_memory_locks+e);
+  for(e=0;e<PIKE_MEM_HASH;e++)
+    mt_init_recursive(pike_memory_locks+e);
 }
 
 #endif
diff --git a/src/pike_cpulib.h b/src/pike_cpulib.h
index b09ebf0e92e95c8eefd9a891d5d490c5237ad7c9..b4e9ed4530993d42be0dc8ed464d2f6249352a3f 100644
--- a/src/pike_cpulib.h
+++ b/src/pike_cpulib.h
@@ -26,8 +26,19 @@
     mt_unlock(pike_mem_mutex);  \
   }while(0)
 
+#define pike_memlock(ADDR) do{				\
+    PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+	\
+        ((unsigned long)(ADDR))%PIKE_MEM_HASH;		\
+    mt_lock(pike_mem_mutex)				\
+}while(0)
+
+#define pike_unmemlock(ADDR) do{			\
+    PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+	\
+        ((unsigned long)(ADDR))%PIKE_MEM_HASH;		\
+    mt_unlock(pike_mem_mutex)				\
+}while(0)
 
-
+#define PIKE_NEED_MEMLOCK
 
 /* Autoconf this? */
 #if defined(__i386__) && defined(__GNUC__)
@@ -76,6 +87,7 @@ pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
 }
 
 
+/* NOT USED */
 #define PIKE_HAS_COMPARE_AND_SWAP64
 static inline int
 pike_atomic_compare_and_swap64 (INT64 *p, INT64 oldval, INT64 newval)
diff --git a/src/pike_threadlib.h b/src/pike_threadlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d2ffb2845a978141aa8555b10d7ac161d8a8e00
--- /dev/null
+++ b/src/pike_threadlib.h
@@ -0,0 +1,615 @@
+/*
+ * $Id: pike_threadlib.h,v 1.1 2001/04/07 07:38:25 hubbe Exp $
+ */
+#ifndef PIKE_THREADLIB_H
+#define PIKE_THREADLIB_H
+
+/*
+ * This file is for the low-level thread interface functions
+ * 'threads.h' is for anything that concerns the object interface
+ * for pike threads.
+ */
+
+
+#include "machine.h"
+
+/* Needed for the sigset_t typedef, which is needed for
+ * the pthread_sigsetmask() prototype on Solaris 2.x.
+ */
+#include <signal.h>
+
+#ifdef HAVE_SYS_TYPES_H
+/* Needed for pthread_t on OSF/1 */
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef PIKE_THREADS
+
+/* The fp macro conflicts with Solaris's <pthread.h>. */
+#ifdef fp
+#undef fp
+#define FRAMEPOINTER_WAS_DEFINED
+#endif /* fp */
+
+/*
+ * Decide which type of threads to use
+ *
+ * UNIX_THREADS      : Unix international threads
+ * POSIX_THREADS     : POSIX standard threads
+ * SGI_SPROC_THREADS : SGI sproc() based threads
+ * NT_THREADS        : NT threads
+ */
+
+#ifdef _UNIX_THREADS
+#ifdef HAVE_THREAD_H
+#define UNIX_THREADS
+#include <thread.h>
+#undef HAVE_PTHREAD_H
+#undef HAVE_THREAD_H
+#endif
+#endif /* _UNIX_THREADS */
+
+#ifdef _MIT_POSIX_THREADS
+#define POSIX_THREADS
+#include <pthread.h>
+
+/* AIX is *STUPID* - Hubbe */
+#undef func_data
+
+#undef HAVE_PTHREAD_H
+#endif /* _MIT_POSIX_THREADS */
+
+#ifdef _SGI_SPROC_THREADS
+/* Not supported yet */
+#undef SGI_SPROC_THREADS
+#undef HAVE_SPROC
+#endif /* _SGI_SPROC_THREADS */
+
+
+
+/* Restore the fp macro. */
+#ifdef FRAMEPOINTER_WAS_DEFINED
+#define fp Pike_fp
+#undef FRAMEPOINTER_WAS_DEFINED
+#endif /* FRAMEPOINTER_WAS_DEFINED */
+
+
+extern int num_threads;
+PMOD_EXPORT extern int live_threads;
+struct object;
+PMOD_EXPORT extern size_t thread_stack_size;
+
+#define DEFINE_MUTEX(X) PIKE_MUTEX_T X
+
+
+#ifdef POSIX_THREADS
+
+#ifdef HAVE_PTHREAD_ATFORK
+#define th_atfork(X,Y,Z) pthread_atfork((X),(Y),(Z))
+#define th_atfork_prepare()
+#define th_atfork_parent()
+#define th_atfork_child()
+#else
+int th_atfork(void (*)(void),void (*)(void),void (*)(void));
+void th_atfork_prepare(void);
+void th_atfork_parent(void);
+void th_atfork_child(void);
+#endif
+
+#define THREAD_T pthread_t
+#define PIKE_MUTEX_T pthread_mutex_t
+#define mt_init(X) pthread_mutex_init((X),0)
+
+#if !defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
+#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
+#define HAVE_PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+
+#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP
+#define mt_init_recursive(X)						\
+    do{ \
+      pthread_mutexattr_t attr;					\
+      pthread_mutexattr_init(&attr);					\
+      pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);	\
+      pthread_mutex_init((X), &attr);					\
+    }while(0)
+#endif
+
+#define mt_lock(X) pthread_mutex_lock(X)
+#define mt_trylock(X) pthread_mutex_trylock(X)
+#define mt_unlock(X) pthread_mutex_unlock(X)
+#define mt_destroy(X) pthread_mutex_destroy(X)
+
+/* SIGH! No setconcurrency in posix threads. This is more or less
+ * needed to make usable multi-threaded programs on solaris machines
+ * with only one CPU. Otherwise, only systemcalls are actually
+ * threaded.
+ */
+#define th_setconcurrency(X) 
+#ifdef HAVE_PTHREAD_YIELD
+#define th_yield()	pthread_yield()
+#else
+#define th_yield()
+#endif /* HAVE_PTHREAD_YIELD */
+extern pthread_attr_t pattr;
+extern pthread_attr_t small_pattr;
+
+#define th_create(ID,fun,arg) pthread_create(ID,&pattr,fun,arg)
+#define th_create_small(ID,fun,arg) pthread_create(ID,&small_pattr,fun,arg)
+#define th_exit(foo) pthread_exit(foo)
+#define th_self() pthread_self()
+
+#define TH_KEY_T pthread_key_t
+#define th_key_create pthread_key_create
+#define th_setspecific pthread_setspecific
+#define th_getspecific pthread_getspecific
+
+
+#ifdef HAVE_PTHREAD_KILL
+#define th_kill(ID,sig) pthread_kill((ID),(sig))
+#else /* !HAVE_PTHREAD_KILL */
+/* MacOS X (aka Darwin) doesn't have pthread_kill. */
+#define th_kill(ID,sig)
+#endif /* HAVE_PTHREAD_KILL */
+#define th_join(ID,res) pthread_join((ID),(res))
+#ifdef HAVE_PTHREAD_COND_INIT
+#define COND_T pthread_cond_t
+
+#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX
+/* AIX wants the & ... */
+#define co_init(X) pthread_cond_init((X), &pthread_condattr_default)
+#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */
+#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT
+/* ... while FreeBSD doesn't. */
+#define co_init(X) pthread_cond_init((X), pthread_condattr_default)
+#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT */
+#define co_init(X) pthread_cond_init((X), 0)
+#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT */
+#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */
+
+#define co_wait(COND, MUTEX) pthread_cond_wait((COND), (MUTEX))
+#define co_signal(X) pthread_cond_signal(X)
+#define co_broadcast(X) pthread_cond_broadcast(X)
+#define co_destroy(X) pthread_cond_destroy(X)
+#else
+#error No way to make cond-vars
+#endif /* HAVE_PTHREAD_COND_INIT */
+
+#endif /* POSIX_THREADS */
+
+
+
+
+#ifdef UNIX_THREADS
+#define THREAD_T thread_t
+#define PTHREAD_MUTEX_INITIALIZER DEFAULTMUTEX
+#define PIKE_MUTEX_T mutex_t
+#define mt_init(X) mutex_init((X),USYNC_THREAD,0)
+#define mt_lock(X) mutex_lock(X)
+#define mt_trylock(X) mutex_trylock(X)
+#define mt_unlock(X) mutex_unlock(X)
+#define mt_destroy(X) mutex_destroy(X)
+
+#define th_setconcurrency(X) thr_setconcurrency(X)
+
+#define th_create(ID,fun,arg) thr_create(NULL,thread_stack_size,fun,arg,THR_DAEMON|THR_DETACHED,ID)
+#define th_create_small(ID,fun,arg) thr_create(NULL,8192*sizeof(char *),fun,arg,THR_DAEMON|THR_DETACHED,ID)
+#define th_exit(foo) thr_exit(foo)
+#define th_self() thr_self()
+#define th_kill(ID,sig) thr_kill((ID),(sig))
+#define th_yield() thr_yield()
+#define th_join(ID,res) thr_join((ID), NULL, (res))
+
+#define COND_T cond_t
+#define co_init(X) cond_init((X),USYNC_THREAD,0)
+#define co_wait(COND, MUTEX) cond_wait((COND), (MUTEX))
+#define co_signal(X) cond_signal(X)
+#define co_broadcast(X) cond_broadcast(X)
+#define co_destroy(X) cond_destroy(X)
+
+
+#endif /* UNIX_THREADS */
+
+#ifdef SGI_SPROC_THREADS
+
+/*
+ * Not fully supported yet
+ */
+#define THREAD_T	int
+
+#define PIKE_MUTEX_T		ulock_t
+#define mt_init(X)	(usinitlock(((*X) = usnewlock(/*********/))))
+#define mt_lock(X)	ussetlock(*X)
+#define mt_unlock(X)	usunsetlock(*X)
+#define mt_destroy(X)	usfreelock((*X), /*******/)
+
+#define th_setconcurrency(X)	/*******/
+
+#define PIKE_SPROC_FLAGS	(PR_SADDR|PR_SFDS|PR_SDIR|PS_SETEXITSIG)
+#define th_create(ID, fun, arg)	(((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1)
+#define th_create_small(ID, fun, arg)	(((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1)
+#define th_exit(X)	exit(X)
+#define th_self()	getpid()
+#define th_yield()	sginap(0)
+#define th_join(ID,res)	/*********/
+#define th_equal(X,Y) ((X)==(Y))
+#define th_hash(X) ((unsigned INT32)(X))
+
+/*
+ * No cond_vars yet
+ */
+
+#endif /* SGI_SPROC_THREADS */
+
+
+#ifdef NT_THREADS
+#include <process.h>
+#include <windows.h>
+
+#define THREAD_T unsigned
+#define th_setconcurrency(X)
+#define th_create(ID,fun,arg) low_nt_create_thread(2*1024*1024,fun, arg,ID)
+#define th_create_small(ID,fun,arg) low_nt_create_thread(8192*sizeof(char *), fun,arg,ID)
+#define TH_RETURN_TYPE unsigned __stdcall
+#define TH_STDCALL __stdcall
+#define th_exit(foo) _endthreadex(foo)
+#define th_join(ID,res)	/******************* FIXME! ****************/
+#define th_self() GetCurrentThreadId()
+#define th_destroy(X)
+#define th_yield() Sleep(0)
+#define th_equal(X,Y) ((X)==(Y))
+#define th_hash(X) (X)
+
+#define PIKE_MUTEX_T HANDLE
+#define mt_init(X) CheckValidHandle((*(X)=CreateMutex(NULL, 0, NULL)))
+#define mt_lock(X) WaitForSingleObject(CheckValidHandle(*(X)), INFINITE)
+#define mt_trylock(X) WaitForSingleObject(CheckValidHandle(*(X)), 0)
+#define mt_unlock(X) ReleaseMutex(CheckValidHandle(*(X)))
+#define mt_destroy(X) CloseHandle(CheckValidHandle(*(X)))
+
+#define EVENT_T HANDLE
+#define event_init(X) CheckValidHandle(*(X)=CreateEvent(NULL, 1, 0, NULL))
+#define event_signal(X) SetEvent(CheckValidHandle(*(X)))
+#define event_destroy(X) CloseHandle(CheckValidHandle(*(X)))
+#define event_wait(X) WaitForSingleObject(CheckValidHandle(*(X)), INFINITE)
+
+#endif
+
+
+#if !defined(COND_T) && defined(EVENT_T) && defined(PIKE_MUTEX_T)
+
+#define SIMULATE_COND_WITH_EVENT
+
+struct cond_t_queue
+{
+  struct cond_t_queue *next;
+  EVENT_T event;
+};
+
+typedef struct cond_t_s
+{
+  PIKE_MUTEX_T lock;
+  struct cond_t_queue *head, *tail;
+} COND_T;
+
+#define COND_T struct cond_t_s
+
+#define co_init(X) do { mt_init(& (X)->lock), (X)->head=(X)->tail=0; }while(0)
+
+PMOD_EXPORT int co_wait(COND_T *c, PIKE_MUTEX_T *m);
+PMOD_EXPORT int co_signal(COND_T *c);
+PMOD_EXPORT int co_broadcast(COND_T *c);
+PMOD_EXPORT int co_destroy(COND_T *c);
+
+#endif
+
+extern int th_running;
+
+PMOD_EXPORT extern PIKE_MUTEX_T interpreter_lock;
+
+#if defined(PIKE_DEBUG) && !defined(__NT__)
+
+/* This is a debug wrapper to enable checks that the interpreter lock
+ * is hold by the current thread. */
+
+extern THREAD_T debug_locking_thread;
+#define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0)
+
+#define mt_lock_interpreter() (mt_lock(&interpreter_lock) || SET_LOCKING_THREAD)
+#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD)
+#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock))
+#define co_wait_interpreter(COND) \
+  do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0)
+
+#define CHECK_INTERPRETER_LOCK() do {					\
+  if (th_running) {							\
+    THREAD_T self;							\
+    if (!mt_trylock(&interpreter_lock))					\
+      fatal("Interpreter is not locked.\n");				\
+    self = th_self();							\
+    if (!th_equal(debug_locking_thread, self))				\
+      fatal("Interpreter is not locked by this thread.\n");		\
+  }									\
+} while (0)
+
+#else
+
+#define mt_lock_interpreter() (mt_lock(&interpreter_lock))
+#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock))
+#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock))
+#define co_wait_interpreter(COND) do {co_wait((COND), &interpreter_lock);} while (0)
+
+#endif
+
+#ifndef TH_RETURN_TYPE
+#define TH_RETURN_TYPE void *
+#endif
+
+#ifndef TH_STDCALL
+#define TH_STDCALL
+#endif
+
+#ifndef th_destroy
+#define th_destroy(X)
+#endif
+
+#ifndef th_yield
+#define th_yield()
+#endif
+
+#ifndef th_equal
+#define th_equal(X,Y) (!MEMCMP(&(X),&(Y),sizeof(THREAD_T)))
+#endif
+
+#ifndef th_hash
+#define th_hash(X) hashmem((unsigned char *)&(X),sizeof(THREAD_T), 16)
+#endif
+
+/* Define to get a debug-trace of some of the threads operations. */
+/* #define VERBOSE_THREADS_DEBUG	0 */ /* Some debug */
+/* #define VERBOSE_THREADS_DEBUG	1 */ /* Lots of debug */
+
+#ifndef VERBOSE_THREADS_DEBUG
+#define THREADS_FPRINTF(L,X)
+#else
+#define THREADS_FPRINTF(L,X)	do { \
+    if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) fprintf X; \
+  } while(0)
+#endif /* VERBOSE_THREADS_DEBUG */
+
+#ifdef THREAD_TRACE
+PMOD_EXPORT extern int t_flag;
+#define SWAP_OUT_TRACE(_tmp)	do { (_tmp)->status.t_flag = t_flag; } while(0)
+#define SWAP_IN_TRACE(_tmp)	do { t_flag = (_tmp)->status.t_flag; } while(0)
+#else /* !THREAD_TRACE */
+#define SWAP_OUT_TRACE(_tmp)
+#define SWAP_IN_TRACE(_tmp)
+#endif /* THREAD_TRACE */
+
+#if defined(PROFILING) && defined(HAVE_GETHRTIME)
+#define DO_IF_PROFILING(X) X
+#else
+#define DO_IF_PROFILING(X)
+#endif
+
+#define SWAP_OUT_THREAD(_tmp) do {				\
+       (_tmp)->state=Pike_interpreter;				\
+       (_tmp)->swapped=1;					\
+       DO_IF_PROFILING( (_tmp)->time_base += gethrtime() ; )	\
+      } while(0)
+
+#define SWAP_IN_THREAD(_tmp) do {					\
+       (_tmp)->swapped=0;						\
+       Pike_interpreter=(_tmp)->state;					\
+       DO_IF_PROFILING(  Pike_interpreter.time_base -=  gethrtime();)	\
+     } while(0)
+
+#define SWAP_OUT_CURRENT_THREAD() \
+  do {\
+     struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \
+     SWAP_OUT_THREAD(_tmp); \
+     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(1, (stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \
+		       __FILE__, __LINE__, (unsigned int)_tmp->thread_id)); \
+   SWAP_IN_THREAD(_tmp);\
+ } while(0)
+
+#if defined(PIKE_DEBUG) && ! defined(DONT_HIDE_GLOBALS)
+/* Note that scalar types are used in place of pointers and vice versa
+ * below. This is intended to cause compiler warnings/errors if
+ * there is an attempt to use the global variables in an unsafe
+ * environment.
+ */
+#define HIDE_GLOBAL_VARIABLES() do { \
+   int Pike_interpreter =0; \
+   int pop_n_elems = 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.
+ */
+#define REVEAL_GLOBAL_VARIABLES() ; } while(0)
+#else /* PIKE_DEBUG */
+#define HIDE_GLOBAL_VARIABLES()
+#define REVEAL_GLOBAL_VARIABLES()
+#endif /* PIKE_DEBUG */
+
+#define	OBJ2THREAD(X) \
+  ((struct thread_state *)((X)->storage+thread_storage_offset))
+
+#define THREADSTATE2OBJ(X) ((X)->state.thread_id)
+
+PMOD_EXPORT extern int Pike_in_gc;
+#define THREADS_ALLOW() do { \
+     struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \
+     DO_IF_DEBUG({ \
+       if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \
+	 fatal("thread_for_id() (or Pike_interpreter.thread_id) failed!" \
+               " %p != %p\n", \
+               thread_for_id(th_self()), Pike_interpreter.thread_id); \
+       if (Pike_in_gc > 50 && Pike_in_gc < 300) \
+	 fatal("Threads allowed during garbage collection.\n"); \
+     }) \
+     if(num_threads > 1 && !threads_disabled) { \
+       SWAP_OUT_THREAD(_tmp); \
+       THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \
+			   __FILE__, __LINE__, \
+			   (unsigned int)_tmp->thread_id, live_threads)); \
+       mt_unlock_interpreter(); \
+     } else {} \
+     HIDE_GLOBAL_VARIABLES()
+
+#define THREADS_DISALLOW() \
+     REVEAL_GLOBAL_VARIABLES(); \
+     if(_tmp->swapped) { \
+       mt_lock_interpreter(); \
+       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(1, (stderr, \
+                             "THREADS_DISALLOW(): Threads disabled\n")); \
+         co_wait_interpreter(&threads_disabled_change); \
+       } \
+       SWAP_IN_THREAD(_tmp);\
+     } \
+     DO_IF_DEBUG( if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \
+        fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n",thread_for_id(th_self()),Pike_interpreter.thread_id) ; ) \
+   } while(0)
+
+#define THREADS_ALLOW_UID() do { \
+     struct thread_state *_tmp_uid=OBJ2THREAD(Pike_interpreter.thread_id); \
+     DO_IF_DEBUG({ \
+       if(thread_for_id(th_self()) != Pike_interpreter.thread_id) { \
+	 fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n", \
+               thread_for_id(th_self()),Pike_interpreter.thread_id); \
+       } \
+       if ((Pike_in_gc > 50) && (Pike_in_gc < 300)) { \
+         fprintf(stderr, __FILE__ ":" DEFINETOSTR(__LINE__) ": Fatal error:\n"); \
+	 debug_fatal("Threads allowed during garbage collection (%d).\n", \
+                     Pike_in_gc); \
+       } \
+     }) \
+     if(num_threads > 1 && !threads_disabled) { \
+       SWAP_OUT_THREAD(_tmp_uid); \
+       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(); \
+     } else {} \
+     HIDE_GLOBAL_VARIABLES()
+
+#define THREADS_DISALLOW_UID() \
+     REVEAL_GLOBAL_VARIABLES(); \
+     if(_tmp_uid->swapped) { \
+       mt_lock_interpreter(); \
+       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(1, (stderr, "THREADS_DISALLOW_UID(): Wait...\n")); \
+         co_wait_interpreter(&threads_disabled_change); \
+       } \
+       SWAP_IN_THREAD(_tmp_uid);\
+     } \
+   } while(0)
+
+#define SWAP_IN_THREAD_IF_REQUIRED() do { 			\
+  struct thread_state *_tmp=thread_state_for_id(th_self());	\
+  HIDE_GLOBAL_VARIABLES();					\
+  THREADS_DISALLOW()
+
+#ifdef PIKE_DEBUG
+#define ASSERT_THREAD_SWAPPED_IN() do {				\
+    struct thread_state *_tmp=thread_state_for_id(th_self());	\
+    if(_tmp->swapped) fatal("Thread is not swapped in!\n");	\
+  }while(0)
+
+#else
+#define ASSERT_THREAD_SWAPPED_IN()
+#endif
+
+#endif /* PIKE_THREADS */
+
+#ifndef PIKE_THREADS
+
+#define th_atfork(X,Y,Z)
+#define th_atfork_prepare()
+#define th_atfork_parent()
+#define th_atfork_child()
+
+#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)
+#define mt_destroy(X)
+#define THREADS_ALLOW()
+#define THREADS_DISALLOW()
+#define THREADS_ALLOW_UID()
+#define THREADS_DISALLOW_UID()
+#define HIDE_GLOBAL_VARIABLES()
+#define REVEAL_GLOBAL_VARIABLES()
+#define ASSERT_THREAD_SWAPPED_IN()
+#define SWAP_IN_THREAD_IF_REQUIRED()
+#define th_init()
+#define low_th_init()
+#define th_cleanup()
+#define th_init_programs()
+#define th_self() ((void*)0)
+#define co_signal(X)
+#define co_broadcast(X)
+
+#define low_init_threads_disable()
+#define init_threads_disable(X)
+#define exit_threads_disable(X)
+
+
+#endif /* PIKE_THREADS */
+
+#ifndef CHECK_INTERPRETER_LOCK
+#define CHECK_INTERPRETER_LOCK() do {} while (0)
+#endif
+
+#ifdef __NT__
+#ifndef PIKE_DEBUG
+#define CheckValidHandle(X) (X)
+#else
+PMOD_EXPORT HANDLE CheckValidHandle(HANDLE h);
+#endif
+#endif
+
+extern int threads_disabled;
+PMOD_EXPORT extern ptrdiff_t thread_storage_offset;
+PMOD_EXPORT extern struct program *thread_id_prog;
+
+#ifndef NO_PIKE_SHORTHAND
+#define MUTEX_T PIKE_MUTEX_T
+#endif
+
+
+/* Initializer macros for static mutex and condition variables */
+#ifdef PTHREAD_MUTEX_INITIALIZER
+#define STATIC_MUTEX_INIT  = PTHREAD_MUTEX_INITIALIZER
+#else
+#define STATIC_MUTEX_INIT
+#endif
+#ifdef PTHREAD_COND_INITIALIZER
+#define STATIC_COND_INIT   = PTHREAD_COND_INITIALIZER
+#else
+#define STATIC_COND_INIT
+#endif
+
+
+#endif /* PIKE_THREADLIB_H */
+
diff --git a/src/program.c b/src/program.c
index 38367f10216fc06bd5dcf5a6422ee781591e5ecb..63967500a3a7dd075ef62c9d86a42256d2ea631a 100644
--- a/src/program.c
+++ b/src/program.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: program.c,v 1.308 2001/04/01 15:40:21 grubba Exp $");
+RCSID("$Id: program.c,v 1.309 2001/04/07 07:38:25 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -1108,12 +1108,11 @@ struct program *low_allocate_program(void)
   p->alignment_needed=1;
 
   GC_ALLOC(p);
-  p->refs=1;
   p->id=++current_program_id;
+  INIT_PIKE_MEMOBJ(p);
 
   DOUBLELINK(first_program, p);
   GETTIMEOFDAY(& p->timestamp);
-  INITIALIZE_PROT(p);
   return p;
 }
 
@@ -1395,7 +1394,7 @@ PMOD_EXPORT void really_free_program(struct program *p)
 #include "program_areas.h"
   }
 
-  FREE_PROT(p);
+  EXIT_PIKE_MEMOBJ(p);
   dmfree((char *)p);
 
   GC_FREE(p);
diff --git a/src/program.h b/src/program.h
index 515c9093f2e93be3e59238c47f7176f217d6060a..b612b29ca510ac28ba5a635efe538cd0edc998d0 100644
--- a/src/program.h
+++ b/src/program.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: program.h,v 1.122 2001/03/29 02:54:10 per Exp $
+ * $Id: program.h,v 1.123 2001/04/07 07:38:25 hubbe Exp $
  */
 #ifndef PROGRAM_H
 #define PROGRAM_H
@@ -269,10 +269,8 @@ enum pike_program_event
 
 struct program
 {
-  INT32 refs;
-#ifdef PIKE_SECURITY
-  struct object *prot;
-#endif
+  PIKE_MEMORY_OBJECT_MEMBERS; /* Must be first */
+
   INT32 id;             /* used to identify program in caches */
   INT32 parent_program_id;
   /* storage_needed - storage needed in object struct
diff --git a/src/svalue.h b/src/svalue.h
index fa38ad84bf1b4e1fdc00a6fc64160c0a4d49853f..bdcff2f28d752f628f396f8b6570f304c43604ed 100644
--- a/src/svalue.h
+++ b/src/svalue.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: svalue.h,v 1.86 2001/03/30 02:52:26 hubbe Exp $
+ * $Id: svalue.h,v 1.87 2001/04/07 07:38:25 hubbe Exp $
  */
 #ifndef SVALUE_H
 #define SVALUE_H
@@ -52,11 +52,8 @@ struct processing
   struct processing *next;
   void *pointer_a, *pointer_b;
 };
-
-struct ref_dummy
-{
-  INT32 refs;
-};
+   
+struct ref_dummy;
 
 union anything
 {
@@ -274,9 +271,24 @@ do{ \
 #ifdef PIKE_RUN_UNLOCKED
 #define add_ref(X) pike_atomic_inc32(&(X)->refs)
 #define sub_ref(X) pike_atomic_dec_and_test32(&(X)->refs)
+
+#if 0
+#define IF_LOCAL_MUTEX(X) X
+#define USE_LOCAL_MUTEX
+#define pike_lock_data(X) mt_lock(&(X)->mutex)
+#define pike_unlock_data(X) mt_unlock(&(X)->mutex)
 #else
+#define IF_LOCAL_MUTEX(X)
+#define pike_lock_data(X) pike_lockmem((X))
+#define pike_unlock_data(X) pike_unlockmem((X))
+#endif
+
+#else
+#define IF_LOCAL_MUTEX(X)
 #define add_ref(X) (void)((X)->refs++)
 #define sub_ref(X) (--(X)->refs)
+#define pike_lock_data(X) (void)(X)
+#define pike_unlock_data(X) (void)(X)
 #endif
 
 
@@ -621,6 +633,40 @@ static inline void assign_svalue(struct svalue *to, struct svalue *from)
 #define assign_svalue assign_svalue_unlocked
 #endif /* FOO_PIKE_RUN_UNLOCKED */
 
+#ifdef PIKE_RUN_UNLOCKED
+#include "pike_threadlib.h"
+#endif
+
+/* 
+ * Note to self:
+ * It might be better to use a static array of mutexes instead
+ * and just lock mutex ptr % array_size instead.
+ * That way I wouldn't need a mutex in each memory object,
+ * but it would cost a couple of cycles in every lock/unlock
+ * operation instead.
+ */
+#define PIKE_MEMORY_OBJECT_MEMBERS \
+  INT32 refs \
+  DO_IF_SECURITY(; struct object *prot) \
+  IF_LOCAL_MUTEX(; PIKE_MUTEX_T mutex)
+
+#define INIT_PIKE_MEMOBJ(X) do {			\
+  struct ref_dummy *v_=(struct ref_dummy *)(X);		\
+  v_->refs=1;						\
+  DO_IF_SECURITY( INITIALIZE_PROT(v_) );		\
+  IF_LOCAL_MUTEX(mt_init_recursive(&(v_->mutex)));	\
+}while(0)
+
+#define EXIT_PIKE_MEMOBJ(X) do {		\
+  struct ref_dummy *v_=(struct ref_dummy *)(X);		\
+  DO_IF_SECURITY( FREE_PROT(v_) );		\
+  IF_LOCAL_MUTEX(mt_destroy(&(v_->mutex)));	\
+}while(0)
+
 
+struct ref_dummy
+{
+  PIKE_MEMORY_OBJECT_MEMBERS;
+};
 
 #endif /* !SVALUE_H */
diff --git a/src/threads.h b/src/threads.h
index 19086f0045a5cdafd6e15ccd6dbf0d1d5fd89df8..d4e6848f82254c6a61fa87003a0de745b5e6ac89 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -1,5 +1,5 @@
 /*
- * $Id: threads.h,v 1.112 2001/02/28 04:21:53 hubbe Exp $
+ * $Id: threads.h,v 1.113 2001/04/07 07:38:26 hubbe Exp $
  */
 #ifndef THREADS_H
 #define THREADS_H
@@ -8,333 +8,8 @@
 #include "object.h"
 #include "pike_error.h"
 #include "interpret.h"
+#include "pike_threadlib.h"
 
-/* Needed for the sigset_t typedef, which is needed for
- * the pthread_sigsetmask() prototype on Solaris 2.x.
- */
-#include <signal.h>
-
-#ifdef HAVE_SYS_TYPES_H
-/* Needed for pthread_t on OSF/1 */
-#include <sys/types.h>
-#endif /* HAVE_SYS_TYPES_H */
-#ifdef PIKE_THREADS
-
-/* The fp macro conflicts with Solaris's <pthread.h>. */
-#ifdef fp
-#undef fp
-#define FRAMEPOINTER_WAS_DEFINED
-#endif /* fp */
-
-/*
- * Decide which type of threads to use
- *
- * UNIX_THREADS      : Unix international threads
- * POSIX_THREADS     : POSIX standard threads
- * SGI_SPROC_THREADS : SGI sproc() based threads
- * NT_THREADS        : NT threads
- */
-
-#ifdef _UNIX_THREADS
-#ifdef HAVE_THREAD_H
-#define UNIX_THREADS
-#include <thread.h>
-#undef HAVE_PTHREAD_H
-#undef HAVE_THREAD_H
-#endif
-#endif /* _UNIX_THREADS */
-
-#ifdef _MIT_POSIX_THREADS
-#define POSIX_THREADS
-#include <pthread.h>
-
-/* AIX is *STUPID* - Hubbe */
-#undef func_data
-
-#undef HAVE_PTHREAD_H
-#endif /* _MIT_POSIX_THREADS */
-
-#ifdef _SGI_SPROC_THREADS
-/* Not supported yet */
-#undef SGI_SPROC_THREADS
-#undef HAVE_SPROC
-#endif /* _SGI_SPROC_THREADS */
-
-
-
-/* Restore the fp macro. */
-#ifdef FRAMEPOINTER_WAS_DEFINED
-#define fp Pike_fp
-#undef FRAMEPOINTER_WAS_DEFINED
-#endif /* FRAMEPOINTER_WAS_DEFINED */
-
-
-extern int num_threads;
-PMOD_EXPORT extern int live_threads;
-struct object;
-PMOD_EXPORT extern size_t thread_stack_size;
-
-#define DEFINE_MUTEX(X) PIKE_MUTEX_T X
-
-
-#ifdef POSIX_THREADS
-
-#ifdef HAVE_PTHREAD_ATFORK
-#define th_atfork(X,Y,Z) pthread_atfork((X),(Y),(Z))
-#define th_atfork_prepare()
-#define th_atfork_parent()
-#define th_atfork_child()
-#else
-int th_atfork(void (*)(void),void (*)(void),void (*)(void));
-void th_atfork_prepare(void);
-void th_atfork_parent(void);
-void th_atfork_child(void);
-#endif
-
-#define THREAD_T pthread_t
-#define PIKE_MUTEX_T pthread_mutex_t
-#define mt_init(X) pthread_mutex_init((X),0)
-
-#if !defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
-#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
-#define HAVE_PTHREAD_MUTEX_RECURSIVE_NP
-#endif
-
-#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP
-#define mt_init_recursive(X)						\
-    do{ \
-      pthread_mutexattr_t attr;					\
-      pthread_mutexattr_init(&attr);					\
-      pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);	\
-      pthread_mutex_init((X), &attr);					\
-    }while(0)
-#endif
-
-#define mt_lock(X) pthread_mutex_lock(X)
-#define mt_trylock(X) pthread_mutex_trylock(X)
-#define mt_unlock(X) pthread_mutex_unlock(X)
-#define mt_destroy(X) pthread_mutex_destroy(X)
-
-/* SIGH! No setconcurrency in posix threads. This is more or less
- * needed to make usable multi-threaded programs on solaris machines
- * with only one CPU. Otherwise, only systemcalls are actually
- * threaded.
- */
-#define th_setconcurrency(X) 
-#ifdef HAVE_PTHREAD_YIELD
-#define th_yield()	pthread_yield()
-#else
-#define th_yield()
-#endif /* HAVE_PTHREAD_YIELD */
-extern pthread_attr_t pattr;
-extern pthread_attr_t small_pattr;
-
-#define th_create(ID,fun,arg) pthread_create(ID,&pattr,fun,arg)
-#define th_create_small(ID,fun,arg) pthread_create(ID,&small_pattr,fun,arg)
-#define th_exit(foo) pthread_exit(foo)
-#define th_self() pthread_self()
-
-#define TH_KEY_T pthread_key_t
-#define th_key_create pthread_key_create
-#define th_setspecific pthread_setspecific
-#define th_getspecific pthread_getspecific
-
-
-#ifdef HAVE_PTHREAD_KILL
-#define th_kill(ID,sig) pthread_kill((ID),(sig))
-#else /* !HAVE_PTHREAD_KILL */
-/* MacOS X (aka Darwin) doesn't have pthread_kill. */
-#define th_kill(ID,sig)
-#endif /* HAVE_PTHREAD_KILL */
-#define th_join(ID,res) pthread_join((ID),(res))
-#ifdef HAVE_PTHREAD_COND_INIT
-#define COND_T pthread_cond_t
-
-#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT_AIX
-/* AIX wants the & ... */
-#define co_init(X) pthread_cond_init((X), &pthread_condattr_default)
-#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */
-#ifdef HAVE_PTHREAD_CONDATTR_DEFAULT
-/* ... while FreeBSD doesn't. */
-#define co_init(X) pthread_cond_init((X), pthread_condattr_default)
-#else /* !HAVE_PTHREAD_CONDATTR_DEFAULT */
-#define co_init(X) pthread_cond_init((X), 0)
-#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT */
-#endif /* HAVE_PTHREAD_CONDATTR_DEFAULT_AIX */
-
-#define co_wait(COND, MUTEX) pthread_cond_wait((COND), (MUTEX))
-#define co_signal(X) pthread_cond_signal(X)
-#define co_broadcast(X) pthread_cond_broadcast(X)
-#define co_destroy(X) pthread_cond_destroy(X)
-#else
-#error No way to make cond-vars
-#endif /* HAVE_PTHREAD_COND_INIT */
-
-#endif /* POSIX_THREADS */
-
-
-
-
-#ifdef UNIX_THREADS
-#define THREAD_T thread_t
-#define PTHREAD_MUTEX_INITIALIZER DEFAULTMUTEX
-#define PIKE_MUTEX_T mutex_t
-#define mt_init(X) mutex_init((X),USYNC_THREAD,0)
-#define mt_lock(X) mutex_lock(X)
-#define mt_trylock(X) mutex_trylock(X)
-#define mt_unlock(X) mutex_unlock(X)
-#define mt_destroy(X) mutex_destroy(X)
-
-#define th_setconcurrency(X) thr_setconcurrency(X)
-
-#define th_create(ID,fun,arg) thr_create(NULL,thread_stack_size,fun,arg,THR_DAEMON|THR_DETACHED,ID)
-#define th_create_small(ID,fun,arg) thr_create(NULL,8192*sizeof(char *),fun,arg,THR_DAEMON|THR_DETACHED,ID)
-#define th_exit(foo) thr_exit(foo)
-#define th_self() thr_self()
-#define th_kill(ID,sig) thr_kill((ID),(sig))
-#define th_yield() thr_yield()
-#define th_join(ID,res) thr_join((ID), NULL, (res))
-
-#define COND_T cond_t
-#define co_init(X) cond_init((X),USYNC_THREAD,0)
-#define co_wait(COND, MUTEX) cond_wait((COND), (MUTEX))
-#define co_signal(X) cond_signal(X)
-#define co_broadcast(X) cond_broadcast(X)
-#define co_destroy(X) cond_destroy(X)
-
-
-#endif /* UNIX_THREADS */
-
-#ifdef SGI_SPROC_THREADS
-
-/*
- * Not fully supported yet
- */
-#define THREAD_T	int
-
-#define PIKE_MUTEX_T		ulock_t
-#define mt_init(X)	(usinitlock(((*X) = usnewlock(/*********/))))
-#define mt_lock(X)	ussetlock(*X)
-#define mt_unlock(X)	usunsetlock(*X)
-#define mt_destroy(X)	usfreelock((*X), /*******/)
-
-#define th_setconcurrency(X)	/*******/
-
-#define PIKE_SPROC_FLAGS	(PR_SADDR|PR_SFDS|PR_SDIR|PS_SETEXITSIG)
-#define th_create(ID, fun, arg)	(((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1)
-#define th_create_small(ID, fun, arg)	(((*(ID)) = sproc(fun, PIKE_SPROC_FLAGS, arg)) == -1)
-#define th_exit(X)	exit(X)
-#define th_self()	getpid()
-#define th_yield()	sginap(0)
-#define th_join(ID,res)	/*********/
-#define th_equal(X,Y) ((X)==(Y))
-#define th_hash(X) ((unsigned INT32)(X))
-
-/*
- * No cond_vars yet
- */
-
-#endif /* SGI_SPROC_THREADS */
-
-
-#ifdef NT_THREADS
-#include <process.h>
-#include <windows.h>
-
-#define THREAD_T unsigned
-#define th_setconcurrency(X)
-#define th_create(ID,fun,arg) low_nt_create_thread(2*1024*1024,fun, arg,ID)
-#define th_create_small(ID,fun,arg) low_nt_create_thread(8192*sizeof(char *), fun,arg,ID)
-#define TH_RETURN_TYPE unsigned __stdcall
-#define TH_STDCALL __stdcall
-#define th_exit(foo) _endthreadex(foo)
-#define th_join(ID,res)	/******************* FIXME! ****************/
-#define th_self() GetCurrentThreadId()
-#define th_destroy(X)
-#define th_yield() Sleep(0)
-#define th_equal(X,Y) ((X)==(Y))
-#define th_hash(X) (X)
-
-#define PIKE_MUTEX_T HANDLE
-#define mt_init(X) CheckValidHandle((*(X)=CreateMutex(NULL, 0, NULL)))
-#define mt_lock(X) WaitForSingleObject(CheckValidHandle(*(X)), INFINITE)
-#define mt_trylock(X) WaitForSingleObject(CheckValidHandle(*(X)), 0)
-#define mt_unlock(X) ReleaseMutex(CheckValidHandle(*(X)))
-#define mt_destroy(X) CloseHandle(CheckValidHandle(*(X)))
-
-#define EVENT_T HANDLE
-#define event_init(X) CheckValidHandle(*(X)=CreateEvent(NULL, 1, 0, NULL))
-#define event_signal(X) SetEvent(CheckValidHandle(*(X)))
-#define event_destroy(X) CloseHandle(CheckValidHandle(*(X)))
-#define event_wait(X) WaitForSingleObject(CheckValidHandle(*(X)), INFINITE)
-
-#endif
-
-
-#if !defined(COND_T) && defined(EVENT_T) && defined(PIKE_MUTEX_T)
-
-#define SIMULATE_COND_WITH_EVENT
-
-struct cond_t_queue
-{
-  struct cond_t_queue *next;
-  EVENT_T event;
-};
-
-typedef struct cond_t_s
-{
-  PIKE_MUTEX_T lock;
-  struct cond_t_queue *head, *tail;
-} COND_T;
-
-#define COND_T struct cond_t_s
-
-#define co_init(X) do { mt_init(& (X)->lock), (X)->head=(X)->tail=0; }while(0)
-
-PMOD_EXPORT int co_wait(COND_T *c, PIKE_MUTEX_T *m);
-PMOD_EXPORT int co_signal(COND_T *c);
-PMOD_EXPORT int co_broadcast(COND_T *c);
-PMOD_EXPORT int co_destroy(COND_T *c);
-
-#endif
-
-extern int th_running;
-
-PMOD_EXPORT extern PIKE_MUTEX_T interpreter_lock;
-
-#if defined(PIKE_DEBUG) && !defined(__NT__)
-
-/* This is a debug wrapper to enable checks that the interpreter lock
- * is hold by the current thread. */
-
-extern THREAD_T debug_locking_thread;
-#define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0)
-
-#define mt_lock_interpreter() (mt_lock(&interpreter_lock) || SET_LOCKING_THREAD)
-#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD)
-#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock))
-#define co_wait_interpreter(COND) \
-  do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0)
-
-#define CHECK_INTERPRETER_LOCK() do {					\
-  if (th_running) {							\
-    THREAD_T self;							\
-    if (!mt_trylock(&interpreter_lock))					\
-      fatal("Interpreter is not locked.\n");				\
-    self = th_self();							\
-    if (!th_equal(debug_locking_thread, self))				\
-      fatal("Interpreter is not locked by this thread.\n");		\
-  }									\
-} while (0)
-
-#else
-
-#define mt_lock_interpreter() (mt_lock(&interpreter_lock))
-#define mt_trylock_interpreter() (mt_trylock(&interpreter_lock))
-#define mt_unlock_interpreter() (mt_unlock(&interpreter_lock))
-#define co_wait_interpreter(COND) do {co_wait((COND), &interpreter_lock);} while (0)
-
-#endif
 
 PMOD_EXPORT extern COND_T live_threads_change;		/* Used by _disable_threads */
 PMOD_EXPORT extern COND_T threads_disabled_change;		/* Used by _disable_threads */
@@ -390,201 +65,7 @@ struct thread_state {
 #endif /* PROFILING */
 };
 
-
-#ifndef TH_RETURN_TYPE
-#define TH_RETURN_TYPE void *
-#endif
-
-#ifndef TH_STDCALL
-#define TH_STDCALL
-#endif
-
-#ifndef th_destroy
-#define th_destroy(X)
-#endif
-
-#ifndef th_yield
-#define th_yield()
-#endif
-
-#ifndef th_equal
-#define th_equal(X,Y) (!MEMCMP(&(X),&(Y),sizeof(THREAD_T)))
-#endif
-
-#ifndef th_hash
-#define th_hash(X) hashmem((unsigned char *)&(X),sizeof(THREAD_T), 16)
-#endif
-
-/* Define to get a debug-trace of some of the threads operations. */
-/* #define VERBOSE_THREADS_DEBUG	0 */ /* Some debug */
-/* #define VERBOSE_THREADS_DEBUG	1 */ /* Lots of debug */
-
-#ifndef VERBOSE_THREADS_DEBUG
-#define THREADS_FPRINTF(L,X)
-#else
-#define THREADS_FPRINTF(L,X)	do { \
-    if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) fprintf X; \
-  } while(0)
-#endif /* VERBOSE_THREADS_DEBUG */
-
-#ifdef THREAD_TRACE
-PMOD_EXPORT extern int t_flag;
-#define SWAP_OUT_TRACE(_tmp)	do { (_tmp)->status.t_flag = t_flag; } while(0)
-#define SWAP_IN_TRACE(_tmp)	do { t_flag = (_tmp)->status.t_flag; } while(0)
-#else /* !THREAD_TRACE */
-#define SWAP_OUT_TRACE(_tmp)
-#define SWAP_IN_TRACE(_tmp)
-#endif /* THREAD_TRACE */
-
-#if defined(PROFILING) && defined(HAVE_GETHRTIME)
-#define DO_IF_PROFILING(X) X
-#else
-#define DO_IF_PROFILING(X)
-#endif
-
-#define SWAP_OUT_THREAD(_tmp) do {				\
-       (_tmp)->state=Pike_interpreter;				\
-       (_tmp)->swapped=1;					\
-       DO_IF_PROFILING( (_tmp)->time_base += gethrtime() ; )	\
-      } while(0)
-
-#define SWAP_IN_THREAD(_tmp) do {					\
-       (_tmp)->swapped=0;						\
-       Pike_interpreter=(_tmp)->state;					\
-       DO_IF_PROFILING(  Pike_interpreter.time_base -=  gethrtime();)	\
-     } while(0)
-
-#define SWAP_OUT_CURRENT_THREAD() \
-  do {\
-     struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \
-     SWAP_OUT_THREAD(_tmp); \
-     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(1, (stderr, "SWAP_IN_CURRENT_THREAD() %s:%d ... t:%08x\n", \
-		       __FILE__, __LINE__, (unsigned int)_tmp->thread_id)); \
-   SWAP_IN_THREAD(_tmp);\
- } while(0)
-
-#if defined(PIKE_DEBUG) && ! defined(DONT_HIDE_GLOBALS)
-/* Note that scalar types are used in place of pointers and vice versa
- * below. This is intended to cause compiler warnings/errors if
- * there is an attempt to use the global variables in an unsafe
- * environment.
- */
-#define HIDE_GLOBAL_VARIABLES() do { \
-   int Pike_interpreter =0; \
-   int pop_n_elems = 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.
- */
-#define REVEAL_GLOBAL_VARIABLES() ; } while(0)
-#else /* PIKE_DEBUG */
-#define HIDE_GLOBAL_VARIABLES()
-#define REVEAL_GLOBAL_VARIABLES()
-#endif /* PIKE_DEBUG */
-
-#define	OBJ2THREAD(X) \
-  ((struct thread_state *)((X)->storage+thread_storage_offset))
-
-#define THREADSTATE2OBJ(X) ((X)->state.thread_id)
-
-PMOD_EXPORT extern int Pike_in_gc;
-#define THREADS_ALLOW() do { \
-     struct thread_state *_tmp=OBJ2THREAD(Pike_interpreter.thread_id); \
-     DO_IF_DEBUG({ \
-       if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \
-	 fatal("thread_for_id() (or Pike_interpreter.thread_id) failed!" \
-               " %p != %p\n", \
-               thread_for_id(th_self()), Pike_interpreter.thread_id); \
-       if (Pike_in_gc > 50 && Pike_in_gc < 300) \
-	 fatal("Threads allowed during garbage collection.\n"); \
-     }) \
-     if(num_threads > 1 && !threads_disabled) { \
-       SWAP_OUT_THREAD(_tmp); \
-       THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() %s:%d t:%08x(#%d)\n", \
-			   __FILE__, __LINE__, \
-			   (unsigned int)_tmp->thread_id, live_threads)); \
-       mt_unlock_interpreter(); \
-     } else {} \
-     HIDE_GLOBAL_VARIABLES()
-
-#define THREADS_DISALLOW() \
-     REVEAL_GLOBAL_VARIABLES(); \
-     if(_tmp->swapped) { \
-       mt_lock_interpreter(); \
-       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(1, (stderr, \
-                             "THREADS_DISALLOW(): Threads disabled\n")); \
-         co_wait_interpreter(&threads_disabled_change); \
-       } \
-       SWAP_IN_THREAD(_tmp);\
-     } \
-     DO_IF_DEBUG( if(thread_for_id(th_self()) != Pike_interpreter.thread_id) \
-        fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n",thread_for_id(th_self()),Pike_interpreter.thread_id) ; ) \
-   } while(0)
-
-#define THREADS_ALLOW_UID() do { \
-     struct thread_state *_tmp_uid=OBJ2THREAD(Pike_interpreter.thread_id); \
-     DO_IF_DEBUG({ \
-       if(thread_for_id(th_self()) != Pike_interpreter.thread_id) { \
-	 fatal("thread_for_id() (or Pike_interpreter.thread_id) failed! %p != %p\n", \
-               thread_for_id(th_self()),Pike_interpreter.thread_id); \
-       } \
-       if ((Pike_in_gc > 50) && (Pike_in_gc < 300)) { \
-         fprintf(stderr, __FILE__ ":" DEFINETOSTR(__LINE__) ": Fatal error:\n"); \
-	 debug_fatal("Threads allowed during garbage collection (%d).\n", \
-                     Pike_in_gc); \
-       } \
-     }) \
-     if(num_threads > 1 && !threads_disabled) { \
-       SWAP_OUT_THREAD(_tmp_uid); \
-       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(); \
-     } else {} \
-     HIDE_GLOBAL_VARIABLES()
-
-#define THREADS_DISALLOW_UID() \
-     REVEAL_GLOBAL_VARIABLES(); \
-     if(_tmp_uid->swapped) { \
-       mt_lock_interpreter(); \
-       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(1, (stderr, "THREADS_DISALLOW_UID(): Wait...\n")); \
-         co_wait_interpreter(&threads_disabled_change); \
-       } \
-       SWAP_IN_THREAD(_tmp_uid);\
-     } \
-   } while(0)
-
-#define SWAP_IN_THREAD_IF_REQUIRED() do { 			\
-  struct thread_state *_tmp=thread_state_for_id(th_self());	\
-  HIDE_GLOBAL_VARIABLES();					\
-  THREADS_DISALLOW()
-
-#ifdef PIKE_DEBUG
-#define ASSERT_THREAD_SWAPPED_IN() do {				\
-    struct thread_state *_tmp=thread_state_for_id(th_self());	\
-    if(_tmp->swapped) fatal("Thread is not swapped in!\n");	\
-  }while(0)
-
-#else
-#define ASSERT_THREAD_SWAPPED_IN()
-#endif
+#ifdef PIKE_THREADS
 
 /* Prototypes begin here */
 int low_nt_create_thread(unsigned Pike_stack_size,
@@ -638,77 +119,6 @@ int th_num_farmers(void);
 PMOD_EXPORT void th_farm(void (*fun)(void *), void *here);
 /* Prototypes end here */
 
-#else
-
-#define th_atfork(X,Y,Z)
-#define th_atfork_prepare()
-#define th_atfork_parent()
-#define th_atfork_child()
-
-#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)
-#define mt_destroy(X)
-#define THREADS_ALLOW()
-#define THREADS_DISALLOW()
-#define THREADS_ALLOW_UID()
-#define THREADS_DISALLOW_UID()
-#define HIDE_GLOBAL_VARIABLES()
-#define REVEAL_GLOBAL_VARIABLES()
-#define ASSERT_THREAD_SWAPPED_IN()
-#define SWAP_IN_THREAD_IF_REQUIRED()
-#define th_init()
-#define low_th_init()
-#define th_cleanup()
-#define th_init_programs()
-#define th_self() ((void*)0)
-#define co_signal(X)
-#define co_broadcast(X)
-
-#define low_init_threads_disable()
-#define init_threads_disable(X)
-#define exit_threads_disable(X)
-
-
-#endif /* PIKE_THREADS */
-
-#ifndef CHECK_INTERPRETER_LOCK
-#define CHECK_INTERPRETER_LOCK() do {} while (0)
-#endif
-
-#ifdef __NT__
-#ifndef PIKE_DEBUG
-#define CheckValidHandle(X) (X)
-#else
-PMOD_EXPORT HANDLE CheckValidHandle(HANDLE h);
-#endif
-#endif
-
-extern int threads_disabled;
-PMOD_EXPORT extern ptrdiff_t thread_storage_offset;
-PMOD_EXPORT extern struct program *thread_id_prog;
-
-#ifndef NO_PIKE_SHORTHAND
-#define MUTEX_T PIKE_MUTEX_T
-#endif
-
-
-/* Initializer macros for static mutex and condition variables */
-#ifdef PTHREAD_MUTEX_INITIALIZER
-#define STATIC_MUTEX_INIT  = PTHREAD_MUTEX_INITIALIZER
-#else
-#define STATIC_MUTEX_INIT
-#endif
-#ifdef PTHREAD_COND_INITIALIZER
-#define STATIC_COND_INIT   = PTHREAD_COND_INITIALIZER
-#else
-#define STATIC_COND_INIT
 #endif