diff --git a/.gitattributes b/.gitattributes
index 9070bc6c7e59bc551dee116cb41159ceee7b1176..6d5fc39814929230d55673624e12381d0ac6411d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -798,7 +798,6 @@ testfont binary
 /src/pike_search_engine.c foreign_ident
 /src/pike_search_engine2.c foreign_ident
 /src/pike_security.h foreign_ident
-/src/pike_threadlib.h foreign_ident
 /src/pike_types.c foreign_ident
 /src/pike_types.h foreign_ident
 /src/pikecode.c foreign_ident
@@ -922,8 +921,6 @@ testfont binary
 /src/svalue.h foreign_ident
 /src/test_co.pike foreign_ident
 /src/testsuite.in foreign_ident
-/src/threads.c foreign_ident
-/src/threads.h foreign_ident
 /src/time_stuff.h foreign_ident
 /src/tmodule.c foreign_ident
 /src/treeopt.in foreign_ident
diff --git a/src/pike_threadlib.h b/src/pike_threadlib.h
index cde85120bb585896786d88a2bd4295391fdd1811..8e8112f6b9304ed5acb82c29c761a3e893739ef4 100644
--- a/src/pike_threadlib.h
+++ b/src/pike_threadlib.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: pike_threadlib.h,v 1.73 2010/09/28 16:13:32 grubba Exp $
+|| $Id$
 */
 
 #ifndef PIKE_THREADLIB_H
@@ -14,7 +14,6 @@
  * for pike threads.
  */
 
-
 #include "global.h"
 #include "pike_embed.h"
 #include "pike_rusage.h"
@@ -29,10 +28,6 @@
 #include <sys/types.h>
 #endif /* HAVE_SYS_TYPES_H */
 
-PMOD_EXPORT extern int threads_disabled;
-PMOD_EXPORT extern ptrdiff_t thread_storage_offset;
-PMOD_EXPORT extern struct program *thread_id_prog;
-
 #ifdef PIKE_THREADS
 
 /* The fp macro conflicts with Solaris's <pthread.h>. */
@@ -98,17 +93,16 @@ PMOD_EXPORT extern struct program *thread_id_prog;
 #include <mach/mach_init.h>
 #endif
 
-
 /* Restore the fp macro. */
 #ifdef FRAMEPOINTER_WAS_DEFINED
 #define fp Pike_fp
 #undef FRAMEPOINTER_WAS_DEFINED
 #endif /* FRAMEPOINTER_WAS_DEFINED */
 
-
+PMOD_EXPORT extern int threads_disabled;
+PMOD_EXPORT extern ptrdiff_t thread_storage_offset;
+PMOD_EXPORT extern struct program *thread_id_prog;
 PMOD_EXPORT extern int num_threads;
-PMOD_EXPORT extern int live_threads;
-struct object;
 PMOD_EXPORT extern size_t thread_stack_size;
 
 PMOD_EXPORT void thread_low_error (int errcode, const char *cmd,
@@ -209,7 +203,6 @@ extern pthread_attr_t small_pattr;
 #define th_setspecific pthread_setspecific
 #define th_getspecific pthread_getspecific
 
-
 #ifdef HAVE_PTHREAD_KILL
 #define th_kill(ID,sig) LOW_THREAD_CHECK_NONZERO_ERROR (pthread_kill((ID),(sig)))
 #else /* !HAVE_PTHREAD_KILL */
@@ -242,9 +235,8 @@ extern pthread_attr_t small_pattr;
 #endif /* POSIX_THREADS */
 
 
-
-
 #ifdef UNIX_THREADS
+
 #define THREAD_T thread_t
 #define PTHREAD_MUTEX_INITIALIZER DEFAULTMUTEX
 #define PIKE_MUTEX_T mutex_t
@@ -270,9 +262,9 @@ extern pthread_attr_t small_pattr;
 #define co_broadcast(X) cond_broadcast(X)
 #define co_destroy(X) cond_destroy(X)
 
-
 #endif /* UNIX_THREADS */
 
+
 #ifdef SGI_SPROC_THREADS
 
 /*
@@ -305,6 +297,7 @@ extern pthread_attr_t small_pattr;
 
 
 #ifdef NT_THREADS
+
 #include <process.h>
 #include <windows.h>
 
@@ -353,7 +346,7 @@ extern pthread_attr_t small_pattr;
 #define th_atfork_parent()
 #define th_atfork_child()
 
-#endif
+#endif	/* NT_THREADS */
 
 
 #if !defined(COND_T) && defined(EVENT_T) && defined(PIKE_MUTEX_T)
@@ -381,7 +374,7 @@ 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
+#endif	/* !COND_T && EVENT_T && PIKE_MUTEX_T */
 
 #ifndef TH_RETURN_TYPE
 #define TH_RETURN_TYPE void *
@@ -412,7 +405,7 @@ PMOD_EXPORT int co_destroy(COND_T *c);
 #define th_hash(X) hashmem((unsigned char *)&(X),sizeof(THREAD_T), 16)
 #endif
 
-PMOD_EXPORT int co_wait_timeout(COND_T *c, PIKE_MUTEX_T *m, int s, int nanos);
+PMOD_EXPORT int co_wait_timeout(COND_T *c, PIKE_MUTEX_T *m, long s, long nanos);
 
 #ifndef CONFIGURE_TEST
 
@@ -427,37 +420,14 @@ struct interleave_mutex
 
 #define DEFINE_IMUTEX(name) IMUTEX_T name
 
-/* If threads are disabled, we already hold the lock.
- *
- * NOTE: Threads are enabled during the locking operation.
- */
-#define LOCK_IMUTEX(im) do { \
-    if (!threads_disabled) { \
-      THREADS_FPRINTF(0, (stderr, "Locking IMutex %p...\n", (im))); \
-      THREADS_ALLOW(); \
-      mt_lock(&((im)->lock)); \
-      THREADS_DISALLOW(); \
-      THREADS_FPRINTF(0, (stderr, "Locked IMutex %p\n", (im))); \
-    } \
-  } while(0)
-
-/* If threads are disabled, the lock will be released later.
- *
- * NOTE: MUST be called in a THREADS_DISALLOW() context.
- */
-#define UNLOCK_IMUTEX(im) do { \
-    if (!threads_disabled) { \
-      THREADS_FPRINTF(0, (stderr, "Unlocking IMutex %p\n", (im))); \
-      mt_unlock(&((im)->lock)); \
-    } \
-  } while(0)
-
-extern int th_running;
+PMOD_EXPORT void pike_lock_imutex (IMUTEX_T *im COMMA_DLOC_DECL);
+PMOD_EXPORT void pike_unlock_imutex (IMUTEX_T *im COMMA_DLOC_DECL);
 
-PMOD_EXPORT extern PIKE_MUTEX_T interpreter_lock;
+/* NOTE: Threads are enabled during the locking operation. */
+#define LOCK_IMUTEX(IM) pike_lock_imutex ((IM) COMMA_DLOC)
 
-PMOD_EXPORT extern COND_T live_threads_change;		/* Used by _disable_threads */
-PMOD_EXPORT extern COND_T threads_disabled_change;		/* Used by _disable_threads */
+/* NOTE: MUST be called in a THREADS_DISALLOW() context. */
+#define UNLOCK_IMUTEX(IM) pike_unlock_imutex ((IM) COMMA_DLOC)
 
 #define THREAD_TABLE_SIZE 127  /* Totally arbitrary prime */
 
@@ -479,140 +449,34 @@ extern int num_pike_threads;
     mt_unlock( & thread_table_lock );					\
   } while (0)
 
-#if !defined(HAVE_GETHRTIME) && \
-    !(defined(HAVE_MACH_TASK_INFO_H) && defined(TASK_THREAD_TIMES_INFO)) && \
-    defined(HAVE_CLOCK) && \
-    !defined(HAVE_NO_YIELD)
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-PMOD_EXPORT extern clock_t thread_start_clock;
-PMOD_EXPORT extern THREAD_T last_clocked_thread;
-#define USE_CLOCK_FOR_SLICES
-#define DO_IF_USE_CLOCK_FOR_SLICES(X) X
-#else
-#define DO_IF_USE_CLOCK_FOR_SLICES(X)
-#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
-#include <errno.h>
-#define THREADS_FPRINTF(L,X)	do { \
-    if ((VERBOSE_THREADS_DEBUG + 0) >= (L)) {				\
-      /* E.g. THREADS_DISALLOW is used in numerous places where the */	\
-      /* value in errno must not be clobbered. */			\
-      int saved_errno__ = errno;					\
-      fprintf (stderr, "[%"PRINTSIZET"x] ", (size_t) th_self());	\
-      fprintf X;							\
-      errno = saved_errno__;						\
-    }									\
-  } while(0)
-#endif /* VERBOSE_THREADS_DEBUG */
-
-#if defined(PIKE_DEBUG)
-
-/* This is a debug wrapper to enable checks that the interpreter lock
- * is hold by the current thread. */
-
-PMOD_EXPORT extern THREAD_T debug_locking_thread;
-#define SET_LOCKING_THREAD (debug_locking_thread = th_self(), 0)
-
-#define _do_mt_lock_interpreter()					\
-  do {mt_lock(&interpreter_lock); SET_LOCKING_THREAD;} while (0)
-#define low_mt_trylock_interpreter()					\
-  (mt_trylock(&interpreter_lock) || SET_LOCKING_THREAD)
-#define _do_co_wait_interpreter(COND) \
-  do {co_wait((COND), &interpreter_lock); SET_LOCKING_THREAD;} while (0)
-#define _do_co_wait_interpreter_timeout(COND, SECS, NANOS) do {		\
-    co_wait_timeout((COND), &interpreter_lock, (SECS), (NANOS));	\
-    SET_LOCKING_THREAD;							\
-  } while (0)
-
-PMOD_EXPORT extern const char msg_ip_not_locked[];
-PMOD_EXPORT extern const char msg_ip_not_locked_this_thr[];
-
-#define CHECK_INTERPRETER_LOCK() do {					\
-  if (th_running) {							\
-    THREAD_T self;							\
-    if (!mt_trylock(&interpreter_lock))					\
-      Pike_fatal(msg_ip_not_locked);					\
-    self = th_self();							\
-    if (!th_equal(debug_locking_thread, self))				\
-      Pike_fatal(msg_ip_not_locked_this_thr);				\
-  }									\
-} while (0)
-
-#else
-
-#define _do_mt_lock_interpreter() do {mt_lock(&interpreter_lock);} while (0)
-#define low_mt_trylock_interpreter() (mt_trylock(&interpreter_lock))
-#define _do_co_wait_interpreter(COND) do {				\
-    co_wait((COND), &interpreter_lock);					\
-  } while (0)
-#define _do_co_wait_interpreter_timeout(COND, SECS, NANOS) do {		\
-    co_wait_timeout((COND), &interpreter_lock, (SECS), (NANOS));	\
-  } while (0)
-
-#endif
-
-#define _do_mt_unlock_interpreter() do {				\
-    mt_unlock(&interpreter_lock);					\
-  } while (0)
-
-#define low_mt_lock_interpreter() do {					\
-    _do_mt_lock_interpreter();						\
-    THREADS_FPRINTF (1, (stderr, "Got interpreter lock @ %s:%d\n",	\
-			 __FILE__, __LINE__));				\
-  } while (0)
-#define low_co_wait_interpreter(COND) do {				\
-    THREADS_FPRINTF (1, (stderr, "Waiting on %s @ %s:%d\n",		\
-			 #COND, __FILE__, __LINE__));			\
-    _do_co_wait_interpreter (COND);					\
-    THREADS_FPRINTF (1, (stderr, "Acquired %s @ %s:%d\n",		\
-			 #COND, __FILE__, __LINE__));			\
-  } while (0)
-#define low_co_wait_interpreter_timeout(COND, SECS, NANOS) do {		\
-    THREADS_FPRINTF (1, (stderr, "Timed wait on %s @ %s:%d\n",		\
-			 #COND, __FILE__, __LINE__));			\
-    _do_co_wait_interpreter_timeout (COND, SECS, NANOS);		\
-    THREADS_FPRINTF (1, (stderr, "Stopped waiting on %s @ %s:%d\n",	\
-			 #COND, __FILE__, __LINE__));			\
-  } while (0)
-
-static INLINE int threads_disabled_wait(void)
-{
-  do {
-    THREADS_FPRINTF(1, (stderr, "Wait on threads_disabled\n"));
-    _do_co_wait_interpreter(&threads_disabled_change);
-  } while (threads_disabled);
-  THREADS_FPRINTF(1, (stderr, "Continue after threads_disabled\n"));
-  return 0;
-}
-
-#define mt_lock_interpreter() do {					\
-    low_mt_lock_interpreter();						\
-    if (threads_disabled) threads_disabled_wait();			\
-  } while (0)
-#define mt_trylock_interpreter() \
-  (low_mt_trylock_interpreter() || (threads_disabled && threads_disabled_wait()))
-#define mt_unlock_interpreter() do {					\
-    THREADS_FPRINTF(1, (stderr, "Releasing interpreter lock @ %s:%d\n",	\
-			__FILE__, __LINE__));				\
-    _do_mt_unlock_interpreter();					\
-  } while (0)
-#define co_wait_interpreter(COND) do {					\
-    low_co_wait_interpreter(COND);					\
-    if (threads_disabled) threads_disabled_wait();			\
-  } while (0)
-#define co_wait_interpreter_timeout(COND, SECS, NANOS) do {		\
-    low_co_wait_interpreter_timeout(COND, SECS, NANOS);			\
-    if (threads_disabled) threads_disabled_wait();			\
-  } while (0)
+PMOD_EXPORT void pike_low_lock_interpreter (DLOC_DECL);
+PMOD_EXPORT int pike_low_trylock_interpreter (DLOC_DECL);
+PMOD_EXPORT void pike_low_wait_interpreter (COND_T *cond COMMA_DLOC_DECL);
+PMOD_EXPORT int pike_low_timedwait_interpreter (COND_T *cond,
+						long sec, long nsec
+						COMMA_DLOC_DECL);
+
+PMOD_EXPORT void pike_lock_interpreter (DLOC_DECL);
+PMOD_EXPORT int pike_trylock_interpreter (DLOC_DECL);
+PMOD_EXPORT void pike_unlock_interpreter (DLOC_DECL);
+PMOD_EXPORT void pike_wait_interpreter (COND_T *cond COMMA_DLOC_DECL);
+PMOD_EXPORT int pike_timedwait_interpreter (COND_T *cond,
+					    long sec, long nsec
+					    COMMA_DLOC_DECL);
+
+#define low_mt_lock_interpreter() pike_low_lock_interpreter (DLOC)
+#define low_mt_trylock_interpreter() pike_low_trylock_interpreter (DLOC)
+#define low_co_wait_interpreter(COND)					\
+  pike_low_wait_interpreter (COND COMMA_DLOC)
+#define low_co_wait_interpreter_timeout(COND, SEC, NSEC)		\
+  pike_low_timedwait_interpreter (COND, SEC, NSEC COMMA_DLOC)
+
+#define mt_lock_interpreter() pike_lock_interpreter (DLOC)
+#define mt_trylock_interpreter() pike_trylock_interpreter (DLOC)
+#define mt_unlock_interpreter() pike_unlock_interpreter (DLOC)
+#define co_wait_interpreter(COND) pike_wait_interpreter (COND COMMA_DLOC)
+#define co_wait_interpreter_timeout(COND, SEC, NSEC)			\
+  pike_timedwait_interpreter (COND, SEC, NSEC COMMA_DLOC)
 
 #ifdef INTERNAL_PROFILING
 PMOD_EXPORT extern unsigned long thread_yields;
@@ -621,120 +485,34 @@ PMOD_EXPORT extern unsigned long thread_yields;
 #define th_yield() low_th_yield()
 #endif
 
-#ifdef PIKE_DEBUG
-PMOD_EXPORT extern THREAD_T threads_disabled_thread;
-#endif
-
-#define INIT_THREAD_STATE(_tmp) do {					\
-    struct thread_state *_th_state = (_tmp);				\
-    Pike_interpreter.thread_state = _th_state;				\
-    _th_state->state = Pike_interpreter;				\
-    _th_state->id = th_self();						\
-    _th_state->status = THREAD_RUNNING;					\
-    _th_state->swapped = 0;						\
-    DO_IF_DEBUG(_th_state->debug_flags = 0;)				\
-    DO_IF_USE_CLOCK_FOR_SLICES (					\
-      thread_start_clock = 0;						\
-      last_clocked_thread = _th_state->id;				\
-    );									\
-  } while (0)
-
+PMOD_EXPORT void pike_init_thread_state (struct thread_state *ts);
+#define INIT_THREAD_STATE(TS) pike_init_thread_state (TS)
 #define EXIT_THREAD_STATE(_tmp) do {					\
     DO_IF_DEBUG (Pike_sp = (struct svalue *) (ptrdiff_t) -1);		\
   } while (0)
 
-#define SWAP_OUT_THREAD(_tmp) do {					\
-    struct thread_state *_th_state = (_tmp);				\
-    _th_state->state=Pike_interpreter;					\
-    DO_IF_PROFILING({							\
-	if (!_th_state->swapped) {					\
-	  cpu_time_t now = get_cpu_time();				\
-	  DO_IF_PROFILING_DEBUG({					\
-	      fprintf(stderr, "%p: Swap out at: %" PRINT_CPU_TIME	\
-		      " unlocked: %" PRINT_CPU_TIME "\n",		\
-		      _th_state, now, _th_state->state.unlocked_time);	\
-	    });								\
-	  _th_state->state.unlocked_time -= now;			\
-	}								\
-      });								\
-    _th_state->swapped=1;						\
-    DO_IF_DEBUG (							\
-      /* Yo! Yo run now, yo DIE! Hear! */				\
-      Pike_sp = (struct svalue *) (ptrdiff_t) -1;			\
-      Pike_fp = (struct pike_frame *) (ptrdiff_t) -1;			\
-    );									\
-    /* Do this one always to catch nested THREADS_ALLOW(), etc. */	\
-    Pike_interpreter.thread_state = 					\
-      (struct thread_state *) (ptrdiff_t) -1;				\
-  } while(0)
-
-PMOD_EXPORT extern const char msg_thr_swapped_over[];
-
-#define SWAP_IN_THREAD(_tmp) do {					\
-    struct thread_state *_th_state = (_tmp);				\
-    DO_IF_DEBUG (							\
-      if (Pike_sp != (struct svalue *) (ptrdiff_t) -1)			\
-	Pike_fatal (msg_thr_swapped_over,				\
-		    (size_t) _th_state->id,				\
-		    Pike_interpreter.thread_state ?			\
-		    (size_t) Pike_interpreter.thread_state->id : 0);	\
-    );									\
-    DO_IF_PROFILING({							\
-	if (_th_state->swapped) {					\
-	  cpu_time_t now = get_cpu_time();				\
-	  DO_IF_DEBUG({							\
-	      DO_IF_PROFILING_DEBUG({					\
-		  fprintf(stderr, "%p: Swap in at: %" PRINT_CPU_TIME	\
-			  " unlocked: %" PRINT_CPU_TIME "\n",		\
-			  _th_state, now, _th_state->state.unlocked_time); \
-		});							\
-	      if (now < -Pike_interpreter.unlocked_time) {		\
-		Pike_fatal("Time at swap in is before time at swap out."\
-			   " %" PRINT_CPU_TIME " < %" PRINT_CPU_TIME	\
-			   "\n", now, -Pike_interpreter.unlocked_time);	\
-	      }								\
-	    });								\
-	  _th_state->state.unlocked_time += now;			\
-	}								\
-      });								\
-    _th_state->swapped=0;						\
-    Pike_interpreter=_th_state->state;					\
-    DO_IF_USE_CLOCK_FOR_SLICES (					\
-      if (last_clocked_thread != _th_state->id) {			\
-	thread_start_clock = clock();					\
-	last_clocked_thread = _th_state->id;				\
-      }									\
-    );									\
-  } while(0)
-
-#define SWAP_OUT_CURRENT_THREAD() \
-  do {\
-     struct thread_state *_tmp = Pike_interpreter.thread_state; \
-     SWAP_OUT_THREAD(_tmp); \
-     THREADS_FPRINTF(1, (stderr, "SWAP_OUT_CURRENT_THREAD() @ %s:%d\n", \
-			 __FILE__, __LINE__))
-
-PMOD_EXPORT extern void debug_list_all_threads(void);
-extern void dumpmem(const char *desc, void *x, int size);
-
-PMOD_EXPORT extern const char msg_saved_thread_id[];
-PMOD_EXPORT extern const char msg_swap_in_cur_thr_failed[];
-
-#define SWAP_IN_CURRENT_THREAD()					      \
-   THREADS_FPRINTF(1, (stderr, "SWAP_IN_CURRENT_THREAD() @ %s:%d\n",	\
-		       __FILE__, __LINE__));				\
-   SWAP_IN_THREAD(_tmp);						      \
-   DO_IF_DEBUG(								      \
-   {									      \
-     THREAD_T self=th_self();						      \
-     if(MEMCMP( & _tmp->id, &self, sizeof(self)))		    	      \
-     {									      \
-       dumpmem(msg_saved_thread_id,&self,sizeof(self));			      \
-       debug_list_all_threads();					      \
-       Pike_fatal(msg_swap_in_cur_thr_failed);				      \
-     }									      \
-   })									      \
- } while(0)
+PMOD_EXPORT void pike_swap_out_thread (struct thread_state *ts COMMA_DLOC_DECL);
+PMOD_EXPORT void pike_swap_in_thread (struct thread_state *ts COMMA_DLOC_DECL);
+PMOD_EXPORT void pike_swap_in_current_thread (struct thread_state *ts
+					      COMMA_DLOC_DECL);
+
+#define SWAP_OUT_THREAD(TS) pike_swap_out_thread (TS COMMA_DLOC)
+#define SWAP_IN_THREAD(TS) pike_swap_in_thread (TS COMMA_DLOC)
+
+#define SWAP_OUT_CURRENT_THREAD()					\
+  do {									\
+    struct thread_state *cur_ts__ = Pike_interpreter.thread_state;	\
+    pike_swap_out_thread (cur_ts__ COMMA_DLOC);				\
+    {
+
+#define SWAP_IN_CURRENT_THREAD()					\
+    ;}									\
+    pike_swap_in_current_thread (cur_ts__ COMMA_DLOC);			\
+  } while (0)
+
+#ifdef PIKE_DEBUG
+PMOD_EXPORT void debug_list_all_threads(void);
+#endif
 
 #if defined(PIKE_DEBUG) && ! defined(DONT_HIDE_GLOBALS)
 /* Note that scalar types are used in place of pointers and vice versa
@@ -752,124 +530,49 @@ PMOD_EXPORT extern const char msg_swap_in_cur_thr_failed[];
  * very well sometimes anyways... -Hubbe
  */
 #define HIDE_PC								\
-  ;void *pc_=(((unsigned char **)__builtin_frame_address(0))[1]);	\
+  void *pc_=(((unsigned char **)__builtin_frame_address(0))[1]);	\
   (((unsigned char **)__builtin_frame_address(0))[1])=0
 #define REVEAL_PC \
   (((unsigned char **)__builtin_frame_address(0))[1])=pc_;
-#endif
-#endif
+
+#endif	/* __i386__ */
+#endif	/* __GCC__ */
 
 #ifndef HIDE_PC
 #define HIDE_PC
 #define REVEAL_PC
 #endif
 
-#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 \
-   HIDE_PC
+#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;	\
+    HIDE_PC;								\
+    {
 
 /* 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() ; REVEAL_PC } while(0)
+#define REVEAL_GLOBAL_VARIABLES()					\
+    ;}									\
+    REVEAL_PC;								\
+  } while (0)
+
 #else /* PIKE_DEBUG */
 #define HIDE_GLOBAL_VARIABLES()
 #define REVEAL_GLOBAL_VARIABLES()
 #endif /* PIKE_DEBUG */
 
 #ifdef PIKE_DEBUG
-
-PMOD_EXPORT extern const char msg_thr_not_swapped_in[];
-PMOD_EXPORT extern const char msg_cur_thr_not_bound[];
-PMOD_EXPORT extern const char msg_thr_states_mixed[];
-
-#define ASSERT_THREAD_SWAPPED_IN() do {					\
-    struct thread_state *_tmp=thread_state_for_id(th_self());		\
-    if(_tmp->swapped) Pike_fatal(msg_thr_not_swapped_in);		\
-    if (_tmp->debug_flags & THREAD_DEBUG_LOOSE) {			\
-      Pike_fatal(msg_cur_thr_not_bound);				\
-    }									\
-  }while(0)
-#define DEBUG_CHECK_THREAD() do {					\
-    struct thread_state *_tmp=thread_state_for_id(th_self());		\
-    if (_tmp->debug_flags & THREAD_DEBUG_LOOSE) {			\
-      Pike_fatal(msg_cur_thr_not_bound);				\
-    }									\
-    if(_tmp != Pike_interpreter.thread_state) {				\
-      debug_list_all_threads();						\
-      Pike_fatal(msg_thr_states_mixed);					\
-    }									\
-  } while (0)
+PMOD_EXPORT void pike_assert_thread_swapped_in (DLOC_DECL);
+PMOD_EXPORT void pike_debug_check_thread (DLOC_DECL);
+#define ASSERT_THREAD_SWAPPED_IN() pike_assert_thread_swapped_in (DLOC)
+#define DEBUG_CHECK_THREAD() pike_debug_check_thread (DLOC)
 #else
 #define ASSERT_THREAD_SWAPPED_IN() do { } while (0)
 #define DEBUG_CHECK_THREAD() do { } while (0)
 #endif
 
-#define THREADSTATE2OBJ(X) ((X)->thread_obj)
-
-#ifdef PIKE_DEBUG
-PMOD_EXPORT extern const char msg_thr_allow_in_gc[];
-PMOD_EXPORT extern const char msg_thr_allow_in_disabled[];
-PMOD_EXPORT extern const char msg_global_dynbuf_in_use[];
-PMOD_EXPORT extern dynamic_buffer pike_global_buffer;
-#if defined(__ia64) && defined(__xlc__)
-/* Workaround for a code generation bug in xlc 5.5.0.0/ia64 . */
-#define DO_IF_NOT_XLC_IA64(X)
-#else /* !ia64 || !xlc */
-#define DO_IF_NOT_XLC_IA64(X)	X
-#endif
-#endif
-
-PMOD_EXPORT extern int Pike_in_gc;
-#define THREADS_ALLOW() do { \
-     struct thread_state *_tmp = Pike_interpreter.thread_state; \
-     DO_IF_PIKE_CLEANUP (					\
-       /* Might get here after th_cleanup() when reporting leaks. */	\
-       if (_tmp) {)						\
-     DEBUG_CHECK_THREAD();					\
-     DO_IF_DEBUG({ \
-       if (Pike_in_gc > 50 && Pike_in_gc < 300) \
-	 Pike_fatal(msg_thr_allow_in_gc, Pike_in_gc);			\
-       if (pike_global_buffer.s.str)					\
-	 Pike_fatal(msg_global_dynbuf_in_use);				\
-     }) \
-     if(num_threads > 1 && !threads_disabled) { \
-       SWAP_OUT_THREAD(_tmp); \
-       THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW() @ %s:%d (%d live thr)\n", \
-			   __FILE__, __LINE__, live_threads));		\
-       _do_mt_unlock_interpreter();					\
-     } else {								\
-       DO_IF_DEBUG(							\
-	 THREAD_T self = th_self();					\
-	 if (threads_disabled &&					\
-	     !th_equal(threads_disabled_thread, self))			\
-	   DO_IF_NOT_XLC_IA64(Pike_fatal(msg_thr_allow_in_disabled,	\
-					 (size_t) self,			\
-					 (size_t) threads_disabled_thread)); \
-       );								\
-     }									\
-     DO_IF_DEBUG(_tmp->debug_flags |= THREAD_DEBUG_LOOSE;)		\
-     DO_IF_PIKE_CLEANUP (})						\
-     HIDE_GLOBAL_VARIABLES()
-
-#define THREADS_DISALLOW() \
-     REVEAL_GLOBAL_VARIABLES(); \
-     DO_IF_PIKE_CLEANUP (if (_tmp) {) \
-     if(_tmp->swapped) { \
-       _do_mt_lock_interpreter(); \
-       THREADS_FPRINTF(1, (stderr, "THREADS_DISALLOW() @ %s:%d "	\
-			   "(%d live thr)\n",				\
-			   __FILE__, __LINE__, live_threads));		\
-       if (threads_disabled) threads_disabled_wait(); \
-       SWAP_IN_THREAD(_tmp);\
-     } \
-     DO_IF_DEBUG(_tmp->debug_flags &= ~THREAD_DEBUG_LOOSE;) \
-     DEBUG_CHECK_THREAD(); \
-     DO_IF_PIKE_CLEANUP (}) \
-   } while(0)
-
 /* The difference between THREADS_ALLOW and THREADS_ALLOW_UID is that
  * _disable_threads waits for the latter to hold in
  * THREADS_DISALLOW_UID before returning. Otoh, THREADS_ALLOW sections
@@ -879,65 +582,44 @@ PMOD_EXPORT extern int Pike_in_gc;
  * necessary when doing any kind of I/O, calling nonreentrant
  * functions, or similar. */
 
-#define THREADS_ALLOW_UID() do { \
-     struct thread_state *_tmp_uid = Pike_interpreter.thread_state; \
-     DO_IF_PIKE_CLEANUP (					\
-       /* Might get here after th_cleanup() when reporting leaks. */	\
-       if (_tmp_uid) {)						\
-     DEBUG_CHECK_THREAD();					    \
-     DO_IF_DEBUG({ \
-       if ((Pike_in_gc > 50) && (Pike_in_gc < 300)) { \
-	 debug_fatal(msg_thr_allow_in_gc, Pike_in_gc); \
-       if (pike_global_buffer.s.str)					\
-	 Pike_fatal(msg_global_dynbuf_in_use);				\
-       } \
-     }) \
-     if(num_threads > 1 && !threads_disabled) { \
-       SWAP_OUT_THREAD(_tmp_uid); \
-       live_threads++; \
-       THREADS_FPRINTF(1, (stderr, "THREADS_ALLOW_UID() @ %s:%d "	\
-			   "(%d live thr)\n",				\
-			   __FILE__, __LINE__, live_threads));		\
-       _do_mt_unlock_interpreter();					\
-     } else {								\
-       DO_IF_DEBUG(							\
-	 THREAD_T self = th_self();					\
-	 if (threads_disabled &&					\
-	     !th_equal(threads_disabled_thread, self))			\
-	   DO_IF_NOT_XLC_IA64(Pike_fatal(msg_thr_allow_in_disabled,	\
-					 (size_t) self,			\
-					 (size_t) threads_disabled_thread)); \
-       );								\
-     }									\
-     DO_IF_DEBUG(_tmp_uid->debug_flags |= THREAD_DEBUG_LOOSE;)		\
-     DO_IF_PIKE_CLEANUP (})						\
-     HIDE_GLOBAL_VARIABLES()
-
-#define THREADS_DISALLOW_UID() \
-     REVEAL_GLOBAL_VARIABLES(); \
-     DO_IF_PIKE_CLEANUP (if (_tmp_uid) {) \
-     if(_tmp_uid->swapped) { \
-       _do_mt_lock_interpreter(); \
-       live_threads--; \
-       THREADS_FPRINTF(1, (stderr, \
-			   "THREADS_DISALLOW_UID() @ %s:%d (%d live thr)\n", \
-			   __FILE__, __LINE__, live_threads));	     \
-       co_broadcast(&live_threads_change); \
-       if (threads_disabled) threads_disabled_wait(); \
-       SWAP_IN_THREAD(_tmp_uid);\
-     } \
-     DO_IF_DEBUG(_tmp_uid->debug_flags &= ~THREAD_DEBUG_LOOSE;) \
-     DEBUG_CHECK_THREAD(); \
-     DO_IF_PIKE_CLEANUP (}) \
-   } while(0)
+PMOD_EXPORT void pike_threads_allow (struct thread_state *ts
+				     COMMA_DLOC_DECL);
+PMOD_EXPORT void pike_threads_disallow (struct thread_state *ts
+					COMMA_DLOC_DECL);
+PMOD_EXPORT void pike_threads_allow_ext (struct thread_state *ts
+					 COMMA_DLOC_DECL);
+PMOD_EXPORT void pike_threads_disallow_ext (struct thread_state *ts
+					    COMMA_DLOC_DECL);
+
+#define THREADS_ALLOW() do {						\
+    struct thread_state *cur_ts__ = Pike_interpreter.thread_state;	\
+    pike_threads_allow (cur_ts__ COMMA_DLOC);				\
+    HIDE_GLOBAL_VARIABLES();						\
+    {
+
+#define THREADS_DISALLOW()						\
+    ;}									\
+    REVEAL_GLOBAL_VARIABLES();						\
+    pike_threads_disallow (cur_ts__ COMMA_DLOC);			\
+  } while (0)
+
+#define THREADS_ALLOW_UID() do {					\
+    struct thread_state *cur_ts_ext__ = Pike_interpreter.thread_state;	\
+    pike_threads_allow_ext (cur_ts_ext__ COMMA_DLOC);			\
+    HIDE_GLOBAL_VARIABLES();						\
+    {
+
+#define THREADS_DISALLOW_UID()						\
+    ;}									\
+    REVEAL_GLOBAL_VARIABLES();						\
+    pike_threads_disallow_ext (cur_ts_ext__ COMMA_DLOC);		\
+  } while (0)
 
 /* FIXME! The macro below leaks live_threads!
  *        Avoid if possible!
  */
-#define SWAP_IN_THREAD_IF_REQUIRED() do { 			\
-  struct thread_state *_tmp=thread_state_for_id(th_self());	\
-  HIDE_GLOBAL_VARIABLES();					\
-  THREADS_DISALLOW()
+#define SWAP_IN_THREAD_IF_REQUIRED()					\
+  pike_threads_disallow (thread_state_for_id(th_self()) COMMA_DLOC)
 
 #endif	/* !CONFIGURE_TEST */
 
diff --git a/src/threads.c b/src/threads.c
index 1019eb206c525de5f86ac51a92f9686b069579f7..5766dcae3d9261a2cb8bc6648984f2bb5bf774d2 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -2,23 +2,21 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: threads.c,v 1.284 2010/09/28 16:20:57 grubba Exp $
+|| $Id$
 */
 
 #include "global.h"
 
-PMOD_EXPORT int num_threads = 1;
-PMOD_EXPORT int threads_disabled = 0;
-
 /* #define PICKY_MUTEX */
 
 #ifdef _REENTRANT
 
 #include "pike_error.h"
 
-#ifndef CONFIGURE_TEST
+/* Define to get a debug trace of thread operations. Debug levels can be 0-2. */
+/* #define VERBOSE_THREADS_DEBUG 1 */
 
-/* #define VERBOSE_THREADS_DEBUG */
+#ifndef CONFIGURE_TEST
 
 #include "threads.h"
 #include "array.h"
@@ -40,6 +38,7 @@ PMOD_EXPORT int threads_disabled = 0;
 #include "backend.h"
 #include "pike_rusage.h"
 
+#include <assert.h>
 #include <errno.h>
 
 #ifdef HAVE_SYS_PRCTL_H
@@ -49,14 +48,28 @@ PMOD_EXPORT int threads_disabled = 0;
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
 
-PMOD_EXPORT int live_threads = 0;
-PMOD_EXPORT COND_T live_threads_change;
-PMOD_EXPORT COND_T threads_disabled_change;
+#else  /* CONFIGURE_TEST */
+#include "pike_threadlib.h"
+#endif
 
+#ifndef VERBOSE_THREADS_DEBUG
+#define THREADS_FPRINTF(LEVEL,FPRINTF_ARGS)
 #else
-#include "pike_threadlib.h"
-#endif	/* !CONFIGURE_TEST */
+#define THREADS_FPRINTF(LEVEL,FPRINTF_ARGS) do {			\
+    if ((VERBOSE_THREADS_DEBUG + 0) >= (LEVEL)) {			\
+      /* E.g. THREADS_DISALLOW is used in numerous places where the */	\
+      /* value in errno must not be clobbered. */			\
+      int saved_errno = errno;						\
+      fprintf (stderr, "[%"PRINTSIZET"x] ", (size_t) th_self());	\
+      fprintf FPRINTF_ARGS;						\
+      errno = saved_errno;						\
+    }									\
+  } while(0)
+#endif /* VERBOSE_THREADS_DEBUG */
 
 #ifndef PIKE_THREAD_C_STACK_SIZE
 #define PIKE_THREAD_C_STACK_SIZE (256 * 1024)
@@ -73,9 +86,9 @@ PMOD_EXPORT void thread_low_error (int errcode, const char *cmd,
 	   fname, lineno, cmd, errcode);
   abort();
 #else
-  Pike_fatal ("%s:%d: %s\n"
-	      "Unexpected error from thread function: %d\n",
-	      fname, lineno, cmd, errcode);
+  debug_fatal ("%s:%d: Fatal error: %s\n"
+	       "Unexpected error from thread function: %d\n",
+	       fname, lineno, cmd, errcode);
 #endif
 }
 
@@ -121,10 +134,10 @@ void th_atfork_child(void)
 
 #ifdef __NT__
 
-int low_nt_create_thread(unsigned Pike_stack_size,
-			 unsigned (TH_STDCALL *fun)(void *),
-			 void *arg,
-			 unsigned *id)
+PMOD_EXPORT int low_nt_create_thread(unsigned Pike_stack_size,
+				     unsigned (TH_STDCALL *fun)(void *),
+				     void *arg,
+				     unsigned *id)
 {
   HANDLE h = (HANDLE)_beginthreadex(NULL, Pike_stack_size, fun, arg, 0, id);
   if(h)
@@ -172,7 +185,7 @@ PMOD_EXPORT int co_wait(COND_T *c, MUTEX_T *m)
   return 0;
 }
 
-PMOD_EXPORT int co_wait_timeout(COND_T *c, MUTEX_T *m, int s, int nanos)
+PMOD_EXPORT int co_wait_timeout(COND_T *c, MUTEX_T *m, long s, long nanos)
 {
   struct cond_t_queue me;
   event_init(&me.event);
@@ -263,7 +276,7 @@ PMOD_EXPORT int co_destroy(COND_T *c)
 #else /* !SIMULATE_COND_WITH_EVENT */
 
 #ifndef CONFIGURE_TEST
-PMOD_EXPORT int co_wait_timeout(COND_T *c, PIKE_MUTEX_T *m, int s, int nanos)
+PMOD_EXPORT int co_wait_timeout(COND_T *c, PIKE_MUTEX_T *m, long s, long nanos)
 {
 #ifdef POSIX_THREADS
   struct timespec timeout;
@@ -326,64 +339,447 @@ static void cleanup_thread_state (struct thread_state *th);
 
 #ifndef CONFIGURE_TEST
 
+#if !defined(HAVE_GETHRTIME) && \
+    !(defined(HAVE_MACH_TASK_INFO_H) && defined(TASK_THREAD_TIMES_INFO)) && \
+    defined(HAVE_CLOCK) && \
+    !defined(HAVE_NO_YIELD)
+static clock_t thread_start_clock = 0;
+static THREAD_T last_clocked_thread = 0;
+#define USE_CLOCK_FOR_SLICES
+#endif
+
 #define THIS_THREAD ((struct thread_state *)CURRENT_STORAGE)
 
 static struct callback *threads_evaluator_callback=0;
 
-int th_running = 0;
+PMOD_EXPORT int num_threads = 1;
+PMOD_EXPORT int threads_disabled = 0;
+
 #ifdef PIKE_DEBUG
-int debug_interpreter_is_locked = 0;
-THREAD_T debug_locking_thread;
-THREAD_T threads_disabled_thread = 0;
+static THREAD_T threads_disabled_thread = 0;
 #endif
 #ifdef INTERNAL_PROFILING
 PMOD_EXPORT unsigned long thread_yields = 0;
 #endif
-PMOD_EXPORT MUTEX_T interpreter_lock;
-MUTEX_T thread_table_lock, interleave_lock;
-struct program *mutex_key = 0;
+static int th_running = 0;
+static MUTEX_T interpreter_lock;
+MUTEX_T thread_table_lock;
+static MUTEX_T interleave_lock;
+static struct program *mutex_key = 0;
 PMOD_EXPORT struct program *thread_id_prog = 0;
-struct program *thread_local_prog = 0;
+static struct program *thread_local_prog = 0;
 PMOD_EXPORT ptrdiff_t thread_storage_offset;
+static int live_threads = 0;
+static COND_T live_threads_change;
+static COND_T threads_disabled_change;
+
+struct thread_local
+{
+  INT32 id;
+};
+
+static volatile IMUTEX_T *interleave_list = NULL;
+
+#define THREADSTATE2OBJ(X) ((X)->thread_obj)
+
+#if defined(PIKE_DEBUG)
+
+/* This is a debug wrapper to enable checks that the interpreter lock
+ * is hold by the current thread. */
+static THREAD_T debug_locking_thread;
+#define SET_LOCKING_THREAD (debug_locking_thread = th_self())
+static INLINE void check_interpreter_lock (DLOC_DECL)
+{
+  if (th_running) {
+    THREAD_T self;
+    if (!mt_trylock (&interpreter_lock))
+      pike_fatal_dloc ("Interpreter not locked.\n");
+    self = th_self();
+    if (!th_equal (debug_locking_thread, self))
+      pike_fatal_dloc ("Interpreter not locked by this thread.\n");
+  }
+}
+
+#else
+
+#define SET_LOCKING_THREAD 0
+static INLINE void check_interpreter_lock (DLOC_DECL) {}
+
+#endif
+
+PMOD_EXPORT INLINE void pike_low_lock_interpreter (DLOC_DECL)
+{
+  mt_lock (&interpreter_lock);
+  SET_LOCKING_THREAD;
+  THREADS_FPRINTF (1, (stderr, "Got iplock" DLOC_PF(" @ ",) "\n"
+		       COMMA_DLOC_ARGS_OPT));
+}
+
+PMOD_EXPORT INLINE int pike_low_trylock_interpreter (DLOC_DECL)
+{
+  int res = mt_trylock (&interpreter_lock);
+  if (!res) {
+    SET_LOCKING_THREAD;
+    THREADS_FPRINTF (1, (stderr, "Got iplock" DLOC_PF(" @ ",) "\n"
+			 COMMA_DLOC_ARGS_OPT));
+  }
+  return res;
+}
+
+PMOD_EXPORT INLINE void pike_low_wait_interpreter (COND_T *cond COMMA_DLOC_DECL)
+{
+  THREADS_FPRINTF (1, (stderr,
+		       "Waiting on cond %p without iplock" DLOC_PF(" @ ",) "\n",
+		       cond COMMA_DLOC_ARGS_OPT));
+  co_wait (cond, &interpreter_lock);
+  SET_LOCKING_THREAD;
+  THREADS_FPRINTF (1, (stderr,
+		       "Got signal on cond %p with iplock" DLOC_PF(" @ ",) "\n",
+		       cond COMMA_DLOC_ARGS_OPT));
+}
+
+PMOD_EXPORT INLINE int pike_low_timedwait_interpreter (COND_T *cond,
+						       long sec, long nsec
+						       COMMA_DLOC_DECL)
+{
+  int res;
+  THREADS_FPRINTF (1, (stderr,
+		       "Waiting on cond %p without iplock" DLOC_PF(" @ ",) "\n",
+		       cond COMMA_DLOC_ARGS_OPT));
+  res = co_wait_timeout (cond, &interpreter_lock, sec, nsec);
+  SET_LOCKING_THREAD;
+  THREADS_FPRINTF (1, (stderr,
+		       "Got signal on cond %p with iplock" DLOC_PF(" @ ",) "\n",
+		       cond COMMA_DLOC_ARGS_OPT));
+  return res;
+}
+
+static void threads_disabled_wait (DLOC_DECL)
+{
+  assert (threads_disabled);
+  do {
+    THREADS_FPRINTF (1, (stderr,
+			 "Waiting on threads_disabled" DLOC_PF(" @ ",) "\n"
+			 COMMA_DLOC_ARGS_OPT));
+    co_wait (&threads_disabled_change, &interpreter_lock);
+    SET_LOCKING_THREAD;
+  } while (threads_disabled);
+  THREADS_FPRINTF (1, (stderr,
+		       "Continue after threads_disabled" DLOC_PF(" @ ",) "\n"
+		       COMMA_DLOC_ARGS_OPT));
+}
+
+PMOD_EXPORT INLINE void pike_lock_interpreter (DLOC_DECL)
+{
+  pike_low_lock_interpreter (DLOC_ARGS_OPT);
+  if (threads_disabled) threads_disabled_wait (DLOC_ARGS_OPT);
+}
+
+PMOD_EXPORT INLINE int pike_trylock_interpreter (DLOC_DECL)
+{
+  int res = pike_low_trylock_interpreter (DLOC_ARGS_OPT);
+  if (!res && threads_disabled) threads_disabled_wait (DLOC_ARGS_OPT);
+  return res;
+}
+
+PMOD_EXPORT INLINE void pike_unlock_interpreter (DLOC_DECL)
+{
+  THREADS_FPRINTF (1, (stderr, "Releasing iplock" DLOC_PF(" @ ",) "\n"
+		       COMMA_DLOC_ARGS_OPT));
+  mt_unlock (&interpreter_lock);
+}
+
+PMOD_EXPORT INLINE void pike_wait_interpreter (COND_T *cond COMMA_DLOC_DECL)
+{
+  pike_low_wait_interpreter (cond COMMA_DLOC_ARGS_OPT);
+  if (threads_disabled) threads_disabled_wait (DLOC_ARGS_OPT);
+}
+
+PMOD_EXPORT INLINE int pike_timedwait_interpreter (COND_T *cond,
+						   long sec, long nsec
+						   COMMA_DLOC_DECL)
+{
+  int res = pike_low_timedwait_interpreter (cond, sec, nsec
+					    COMMA_DLOC_ARGS_OPT);
+  if (threads_disabled) threads_disabled_wait (DLOC_ARGS_OPT);
+  return res;
+}
+
+PMOD_EXPORT void pike_init_thread_state (struct thread_state *ts)
+{
+  Pike_interpreter.thread_state = ts;
+  ts->state = Pike_interpreter;
+  ts->id = th_self();
+  ts->status = THREAD_RUNNING;
+  ts->swapped = 0;
+#ifdef PIKE_DEBUG
+  ts->debug_flags = 0;
+#endif
 #ifdef USE_CLOCK_FOR_SLICES
-PMOD_EXPORT clock_t thread_start_clock = 0;
-PMOD_EXPORT THREAD_T last_clocked_thread = 0;
+  thread_start_clock = 0;
+  last_clocked_thread = ts->id;
 #endif
+}
+
+PMOD_EXPORT void pike_swap_out_thread (struct thread_state *ts
+				       COMMA_DLOC_DECL)
+{
+  THREADS_FPRINTF (2, (stderr, "Swap out %sthread %p" DLOC_PF(" @ ",) "\n",
+		       ts == Pike_interpreter.thread_state ? "current " : "",
+		       ts
+		       COMMA_DLOC_ARGS_OPT));
+
+  ts->state = Pike_interpreter;
+
+#ifdef PROFILING
+  if (!ts->swapped) {
+    cpu_time_t now = get_cpu_time();
+#ifdef PROFILING_DEBUG
+    fprintf(stderr, "%p: Swap out at: %" PRINT_CPU_TIME
+	    " unlocked: %" PRINT_CPU_TIME "\n",
+	    ts, now, ts->state.unlocked_time);
+#endif
+    ts->state.unlocked_time -= now;
+  }
+#endif
+
+  ts->swapped=1;
 
 #ifdef PIKE_DEBUG
-PMOD_EXPORT const char msg_ip_not_locked[] =
-  "Interpreter not locked.\n";
-PMOD_EXPORT const char msg_ip_not_locked_this_thr[] =
-  "Interpreter not locked by this thread.\n";
-PMOD_EXPORT const char msg_thr_swapped_over[] =
-  "Thread %"PRINTSIZET"x swapped in over existing thread %"PRINTSIZET"x.\n";
-PMOD_EXPORT const char msg_saved_thread_id[] =
-  "Saved thread id: ";
-PMOD_EXPORT const char msg_swap_in_cur_thr_failed[] =
-  "SWAP_IN_CURRENT_THREAD failed.\n";
-PMOD_EXPORT const char msg_thr_not_swapped_in[] =
-  "Thread is not swapped in.\n";
-PMOD_EXPORT const char msg_cur_thr_not_bound[] =
-  "Current thread is not bound to the interpreter. "
-  "Nested use of ALLOW_THREADS()?\n";
-PMOD_EXPORT const char msg_thr_states_mixed[] =
-  "Thread states mixed up between threads.\n";
-PMOD_EXPORT const char msg_thr_allow_in_gc[] =
-  "Threads allowed during garbage collection (pass %d).\n";
-PMOD_EXPORT const char msg_thr_allow_in_disabled[] =
-  "Threads allowed from a different thread "
-  "while threads are disabled. "
-  "(self: %"PRINTSIZET"x, disabler: %"PRINTSIZET"x)\n";
-PMOD_EXPORT const char msg_global_dynbuf_in_use[] =
-  "Threads allowed while the global dynamic buffer is in use.\n";
+  Pike_sp = (struct svalue *) (ptrdiff_t) -1;
+  Pike_fp = (struct pike_frame *) (ptrdiff_t) -1;
 #endif
 
-struct thread_local
+  /* Do this one always to catch nested THREADS_ALLOW(), etc. */
+  Pike_interpreter.thread_state =
+    (struct thread_state *) (ptrdiff_t) -1;
+}
+
+PMOD_EXPORT void pike_swap_in_thread (struct thread_state *ts
+				      COMMA_DLOC_DECL)
 {
-  INT32 id;
-};
+  THREADS_FPRINTF (2, (stderr, "Swap in thread %p" DLOC_PF(" @ ",) "\n",
+		       ts COMMA_DLOC_ARGS_OPT));
 
-static volatile IMUTEX_T *interleave_list = NULL;
+#ifdef PIKE_DEBUG
+  if (Pike_sp != (struct svalue *) (ptrdiff_t) -1)
+    pike_fatal_dloc ("Thread %"PRINTSIZET"x swapped in "
+		     "over existing thread %"PRINTSIZET"x.\n",
+		     (size_t) ts->id,
+		     (size_t) (Pike_interpreter.thread_state ?
+			       Pike_interpreter.thread_state->id : 0));
+#endif
+
+#ifdef PROFILING
+  if (ts->swapped) {
+    cpu_time_t now = get_cpu_time();
+#ifdef PROFILING_DEBUG
+    fprintf(stderr, "%p: Swap in at: %" PRINT_CPU_TIME
+	    " unlocked: %" PRINT_CPU_TIME "\n",
+	    ts, now, ts->state.unlocked_time);
+#endif
+#ifdef PIKE_DEBUG
+    if (now < -Pike_interpreter.unlocked_time) {
+      pike_fatal_dloc("Time at swap in is before time at swap out."
+		      " %" PRINT_CPU_TIME " < %" PRINT_CPU_TIME
+		      "\n", now, -Pike_interpreter.unlocked_time);
+    }
+#endif
+    ts->state.unlocked_time += now;
+  }
+#endif
+
+  ts->swapped=0;
+  Pike_interpreter=ts->state;
+
+#ifdef USE_CLOCK_FOR_SLICES
+  if (last_clocked_thread != ts->id) {
+    thread_start_clock = clock();
+    last_clocked_thread = ts->id;
+  }
+#endif
+}
+
+PMOD_EXPORT void pike_swap_in_current_thread (struct thread_state *ts
+					      COMMA_DLOC_DECL)
+{
+#ifdef PIKE_DEBUG
+  THREAD_T self = th_self();
+  if (!th_equal (ts->id, self))
+    pike_fatal_dloc ("Swapped in thread state %p into wrong thread "
+		     "%"PRINTSIZET"x - should be %"PRINTSIZET"x.\n",
+		     ts, th_self(), ts->id);
+#endif
+
+  pike_swap_in_thread (ts COMMA_DLOC_ARGS_OPT);
+}
+
+#ifdef PIKE_DEBUG
+
+PMOD_EXPORT void pike_assert_thread_swapped_in (DLOC_DECL)
+{
+  struct thread_state *ts=thread_state_for_id(th_self());
+  if(ts->swapped)
+    pike_fatal_dloc ("Thread is not swapped in.\n");
+  if (ts->debug_flags & THREAD_DEBUG_LOOSE)
+    pike_fatal_dloc ("Current thread is not bound to the interpreter. "
+		     "Nested use of ALLOW_THREADS()?\n");
+}
+
+PMOD_EXPORT void pike_debug_check_thread (DLOC_DECL)
+{
+  struct thread_state *ts=thread_state_for_id(th_self());
+  if (ts->debug_flags & THREAD_DEBUG_LOOSE)
+    pike_fatal_dloc ("Current thread is not bound to the interpreter. "
+		     "Nested use of ALLOW_THREADS()?\n");
+  if(ts != Pike_interpreter.thread_state) {
+    debug_list_all_threads();
+    Pike_fatal ("Thread states mixed up between threads.\n");
+  }
+  check_interpreter_lock (DLOC_ARGS_OPT);
+}
+
+#endif	/* PIKE_DEBUG */
+
+PMOD_EXPORT void pike_threads_allow (struct thread_state *ts COMMA_DLOC_DECL)
+{
+#ifdef DO_PIKE_CLEANUP
+  /* Might get here after th_cleanup() when reporting leaks. */
+  if (!ts) return;
+#endif
+
+#ifdef PIKE_DEBUG
+  pike_debug_check_thread (DLOC_ARGS_OPT);
+  if (Pike_in_gc > 50 && Pike_in_gc < 300)
+    pike_fatal_dloc ("Threads allowed during garbage collection (pass %d).\n",
+		     Pike_in_gc);
+  if (pike_global_buffer.s.str)
+    pike_fatal_dloc ("Threads allowed while the global dynamic buffer "
+		     "is in use.\n");
+  ts->debug_flags |= THREAD_DEBUG_LOOSE;
+#endif
+
+  if (num_threads > 1 && !threads_disabled) {
+    pike_swap_out_thread (ts COMMA_DLOC_ARGS_OPT);
+    pike_unlock_interpreter (DLOC_ARGS_OPT);
+  }
+
+#if defined (PIKE_DEBUG) && !(defined(__ia64) && defined(__xlc__))
+  else {
+    /* Disabled in xlc 5.5.0.0/ia64 due to a code generation bug. */
+    THREAD_T self = th_self();
+    if (threads_disabled && !th_equal(threads_disabled_thread, self))
+      pike_fatal_dloc ("Threads allowed from a different thread "
+		       "while threads are disabled. "
+		       "(self: %"PRINTSIZET"x, disabler: %"PRINTSIZET"x)\n",
+		       (size_t) self, (size_t) threads_disabled_thread);
+  }
+#endif
+}
+
+PMOD_EXPORT void pike_threads_disallow (struct thread_state *ts COMMA_DLOC_DECL)
+{
+#ifdef DO_PIKE_CLEANUP
+  if (!ts) return;
+#endif
+
+  if (ts->swapped) {
+    pike_lock_interpreter (DLOC_ARGS_OPT);
+    pike_swap_in_thread (ts COMMA_DLOC_ARGS_OPT);
+  }
+
+#ifdef PIKE_DEBUG
+  ts->debug_flags &= ~THREAD_DEBUG_LOOSE;
+  pike_debug_check_thread (DLOC_ARGS_OPT);
+#endif
+}
+
+PMOD_EXPORT void pike_threads_allow_ext (struct thread_state *ts
+					 COMMA_DLOC_DECL)
+{
+#ifdef DO_PIKE_CLEANUP
+  /* Might get here after th_cleanup() when reporting leaks. */
+  if (!ts) return;
+#endif
+
+#ifdef PIKE_DEBUG
+  pike_debug_check_thread (DLOC_ARGS_OPT);
+  if (Pike_in_gc > 50 && Pike_in_gc < 300)
+    pike_fatal_dloc ("Threads allowed during garbage collection (pass %d).\n",
+		     Pike_in_gc);
+  if (pike_global_buffer.s.str)
+    pike_fatal_dloc ("Threads allowed while the global dynamic buffer "
+		     "is in use.\n");
+  ts->debug_flags |= THREAD_DEBUG_LOOSE;
+#endif
+
+  if (num_threads > 1 && !threads_disabled) {
+    pike_swap_out_thread (ts COMMA_DLOC_ARGS_OPT);
+    live_threads++;
+    THREADS_FPRINTF (1, (stderr, "Increased live threads to %d\n",
+			 live_threads));
+    pike_unlock_interpreter (DLOC_ARGS_OPT);
+  }
+
+#if defined (PIKE_DEBUG) && !(defined(__ia64) && defined(__xlc__))
+  else {
+    /* Disabled in xlc 5.5.0.0/ia64 due to a code generation bug. */
+    THREAD_T self = th_self();
+    if (threads_disabled && !th_equal(threads_disabled_thread, self))
+      pike_fatal_dloc ("Threads allowed from a different thread "
+		       "while threads are disabled. "
+		       "(self: %"PRINTSIZET"x, disabler: %"PRINTSIZET"x)\n",
+		       (size_t) self, (size_t) threads_disabled_thread);
+  }
+#endif
+}
+
+PMOD_EXPORT void pike_threads_disallow_ext (struct thread_state *ts
+					    COMMA_DLOC_DECL)
+{
+#ifdef DO_PIKE_CLEANUP
+  if (!ts) return;
+#endif
+
+  if (ts->swapped) {
+    pike_low_lock_interpreter (DLOC_ARGS_OPT);
+    live_threads--;
+    THREADS_FPRINTF (1, (stderr, "Decreased live threads to %d\n",
+			 live_threads));
+    co_broadcast (&live_threads_change);
+    if (threads_disabled) threads_disabled_wait (DLOC_ARGS_OPT);
+    pike_swap_in_thread (ts COMMA_DLOC_ARGS_OPT);
+  }
+
+#ifdef PIKE_DEBUG
+  ts->debug_flags &= ~THREAD_DEBUG_LOOSE;
+  pike_debug_check_thread (DLOC_ARGS_OPT);
+#endif
+}
+
+PMOD_EXPORT void pike_lock_imutex (IMUTEX_T *im COMMA_DLOC_DECL)
+{
+  struct thread_state *ts = Pike_interpreter.thread_state;
+
+  /* If threads are disabled, we already hold the lock. */
+  if (threads_disabled) return;
+
+  THREADS_FPRINTF(0, (stderr, "Locking IMutex %p...\n", im));
+  pike_threads_allow (ts COMMA_DLOC_ARGS_OPT);
+  mt_lock(&((im)->lock));
+  pike_threads_disallow (ts COMMA_DLOC_ARGS_OPT);
+  THREADS_FPRINTF(1, (stderr, "Locked IMutex %p\n", im));
+}
+
+PMOD_EXPORT void pike_unlock_imutex (IMUTEX_T *im COMMA_DLOC_DECL)
+{
+  /* If threads are disabled, we already hold the lock. */
+  if (threads_disabled) return;
+
+  THREADS_FPRINTF(0, (stderr, "Unlocking IMutex %p" DLOC_PF(" @ ",) "\n",
+		      im COMMA_DLOC_ARGS_OPT));
+  mt_unlock(&(im->lock));
+}
 
 /* This is a variant of init_threads_disable that blocks all other
  * threads that might run pike code, but still doesn't block the
@@ -475,11 +871,11 @@ void init_threads_disable(struct object *o)
   if(live_threads) {
     SWAP_OUT_CURRENT_THREAD();
     while (live_threads) {
-      THREADS_FPRINTF(0,
+      THREADS_FPRINTF(1,
 		      (stderr,
 		       "_disable_threads(): Waiting for %d threads to finish\n",
 		       live_threads));
-      _do_co_wait_interpreter(&live_threads_change);
+      low_co_wait_interpreter (&live_threads_change);
     }
     THREADS_FPRINTF(0, (stderr, "_disable_threads(): threads now disabled\n"));
     SWAP_IN_CURRENT_THREAD();
@@ -504,7 +900,7 @@ void exit_threads_disable(struct object *o)
 
       mt_unlock(&interleave_lock);
 
-      THREADS_FPRINTF(0, (stderr, "_exit_threads_disable(): Wake up!\n"));
+      THREADS_FPRINTF(0, (stderr, "exit_threads_disable(): Wake up!\n"));
       co_broadcast(&threads_disabled_change);
 #ifdef PIKE_DEBUG
       threads_disabled_thread = 0;
@@ -580,19 +976,6 @@ unsigned INT32 thread_table_hash(THREAD_T *tid)
   return th_hash(*tid) % THREAD_TABLE_SIZE;
 }
 
-#ifdef PIKE_DEBUG
-void dumpmem(const char *desc, void *x, int size)
-{
-  int e;
-  unsigned char *tmp=(unsigned char *)x;
-  fprintf(stderr, "%s0x", desc);
-  for(e=0;e<size;e++)
-    fprintf(stderr,"%02x",tmp[e]);
-  fprintf(stderr,"\n");
-}
-#endif
-
-
 PMOD_EXPORT void thread_table_insert(struct thread_state *s)
 {
   unsigned INT32 h = thread_table_hash(&s->id);
@@ -606,7 +989,7 @@ PMOD_EXPORT void thread_table_insert(struct thread_state *s)
     else
       Pike_fatal("Forgot to unregister thread!\n");
   }
-/*  dumpmem("thread_table_insert: ",&s->id, sizeof(THREAD_T)); */
+/*  fprintf(stderr, "thread_table_insert: %"PRINTSIZET"x\n", (size_t) s->id); */
 #endif
   mt_lock( & thread_table_lock );
   num_pike_threads++;
@@ -619,7 +1002,7 @@ PMOD_EXPORT void thread_table_insert(struct thread_state *s)
 
 PMOD_EXPORT void thread_table_delete(struct thread_state *s)
 {
-/*  dumpmem("thread_table_delete: ",&s->id, sizeof(THREAD_T)); */
+/*  fprintf(stderr, "thread_table_delete: %"PRINTSIZET"x\n", (size_t) s->id); */
   mt_lock( & thread_table_lock );
   num_pike_threads--;
   if(s->hashlink != NULL)
@@ -634,7 +1017,7 @@ PMOD_EXPORT struct thread_state *thread_state_for_id(THREAD_T tid)
   struct thread_state *s = NULL;
 #if 0
   if(num_threads>1)
-    dumpmem("thread_state_for_id: ",&tid,sizeof(tid));
+    fprintf (stderr, "thread_state_for_id: %"PRINTSIZET"x\n", (size_t) tid);
 #endif
 #ifdef PIKE_DEBUG
   if(h>=THREAD_TABLE_SIZE)
@@ -672,7 +1055,8 @@ PMOD_EXPORT struct thread_state *thread_state_for_id(THREAD_T tid)
   mt_unlock( & thread_table_lock );
 #if 0
   if(num_threads>1 && s)
-    dumpmem("thread_state_for_id return value: ",&s->id,sizeof(tid));
+    fprintf (stderr, "thread_state_for_id return value: %"PRINTSIZET"x\n",
+	     (size_t) s->id);
 #endif
   return s;
   /* NOTEZ BIEN:  Return value only guaranteed to remain valid as long
@@ -822,7 +1206,7 @@ PMOD_EXPORT void debug_list_all_threads(void)
   THREAD_T self = th_self();
 
   fprintf(stderr,"--Listing all threads--\n");
-  dumpmem("Current thread: ",&self, sizeof(self));
+  fprintf (stderr, "Current thread: %"PRINTSIZET"x\n", (size_t) self);
   fprintf(stderr,"Current interpreter thread state: %p%s\n",
 	  Pike_interpreter.thread_state,
 	  Pike_interpreter.thread_state == (struct thread_state *) (ptrdiff_t) -1 ?
@@ -840,13 +1224,14 @@ PMOD_EXPORT void debug_list_all_threads(void)
     for(s=thread_table_chains[x]; s; s=s->hashlink) {
       struct object *o = THREADSTATE2OBJ(s);
       fprintf(stderr,"ThTab[%d]: state=%p, obj=%p, "
-	      "swapped=%d, sp=%p (%+"PRINTPTRDIFFT"d), fp=%p, stackbase=%p",
+	      "swapped=%d, sp=%p (%+"PRINTPTRDIFFT"d), fp=%p, stackbase=%p, "
+	      "id=%"PRINTSIZET"x\n",
 	      x, s, o, s->swapped,
 	      s->state.stack_pointer,
 	      s->state.stack_pointer - s->state.evaluator_stack,
 	      s->state.frame_pointer,
-	      s->state.stack_top);
-      dumpmem(", id=",&s->id, sizeof(s->id));
+	      s->state.stack_top,
+	      (size_t) s->id);
     }
   }
   fprintf(stderr,"-----------------------\n");
@@ -1085,7 +1470,7 @@ TH_RETURN_TYPE new_thread_func(void *data)
    * now wait if threads are disabled. */
   if (threads_disabled) {
     SWAP_OUT_CURRENT_THREAD();
-    threads_disabled_wait();
+    threads_disabled_wait (DLOC);
     SWAP_IN_CURRENT_THREAD();
   }
 
@@ -1252,6 +1637,7 @@ void f_thread_create(INT32 args)
 						 check_threads, 0,0);
       dmalloc_accept_leak(threads_evaluator_callback);
     }
+
     /* Wait for the thread to start properly.
      * so that we can avoid races.
      *
@@ -1262,11 +1648,10 @@ void f_thread_create(INT32 args)
      * before we exit the function...
      */
     SWAP_OUT_CURRENT_THREAD();
-    while (thread_state->status == THREAD_NOT_STARTED) {
-      THREADS_FPRINTF(0, (stderr, "f_thread_create %p waiting...\n",
-			  thread_state));
-      _do_co_wait_interpreter(&thread_state->status_change);
-    }
+    THREADS_FPRINTF(0, (stderr, "f_thread_create %p waiting...\n",
+			thread_state));
+    while (thread_state->status == THREAD_NOT_STARTED)
+      low_co_wait_interpreter (&thread_state->status_change);
     THREADS_FPRINTF(0, (stderr, "f_thread_create %p continue\n", thread_state));
     SWAP_IN_CURRENT_THREAD();
   } else {
@@ -2504,10 +2889,7 @@ void low_th_init(void)
   co_init( & threads_disabled_change);
   thread_table_init();
 
-#ifdef POSIX_THREADS
-  /* FIXME: Why set this only when POSIX_THREADS? /mast */
   th_running = 1;
-#endif
 }
 
 static struct object *backend_thread_obj = NULL;
diff --git a/src/threads.h b/src/threads.h
index e0fa3f1f6e5d8435df0a9b8828fef4fcc653dbf5..9c32650d06d965682b02e8a7b9486182db5eabee 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -2,7 +2,7 @@
 || This file is part of Pike. For copyright information see COPYRIGHT.
 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
 || for more information.
-|| $Id: threads.h,v 1.139 2010/09/29 12:48:22 grubba Exp $
+|| $Id$
 */
 
 #ifndef THREADS_H
@@ -20,8 +20,6 @@
 struct svalue;
 struct pike_frame;
 
-extern PIKE_MUTEX_T interleave_lock;
-
 /* Status values */
 #define THREAD_NOT_STARTED -1
 #define THREAD_RUNNING 0