pike.git / src / threads.c

version» Context lines:

pike.git/src/threads.c:1:   /*   || 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"    -  + /* Define to get a debug trace of thread operations. Debug levels can be 0-2. */ + /* #define VERBOSE_THREADS_DEBUG 1 */ +    #ifndef CONFIGURE_TEST    - /* #define VERBOSE_THREADS_DEBUG */ -  +    #include "threads.h"   #include "array.h"   #include "mapping.h"   #include "object.h"   #include "pike_macros.h"   #include "callback.h"   #include "builtin_functions.h"   #include "constants.h"   #include "program.h"   #include "program_id.h"   #include "gc.h"   #include "main.h"   #include "module_support.h"   #include "pike_types.h"   #include "operators.h"   #include "bignum.h"   #include "signal_handler.h"   #include "backend.h"   #include "pike_rusage.h"    -  + #include <assert.h>   #include <errno.h>      #ifdef HAVE_SYS_PRCTL_H   #include <sys/prctl.h>   #endif /* HAVE_SYS_PRCTL_H */      #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)   #endif      PMOD_EXPORT size_t thread_stack_size=PIKE_THREAD_C_STACK_SIZE;      PMOD_EXPORT void thread_low_error (int errcode, const char *cmd,    const char *fname, int lineno)   {   #ifdef CONFIGURE_TEST    fprintf (stderr, "%s:%d: %s\n"    "Unexpected error from thread function: %d\n",    fname, lineno, cmd, errcode);    abort();   #else -  Pike_fatal ("%s:%d: %s\n" +  debug_fatal ("%s:%d: Fatal error: %s\n"    "Unexpected error from thread function: %d\n",    fname, lineno, cmd, errcode);   #endif   }      /* SCO magic... */   int __thread_sys_behavior = 1;      #ifndef CONFIGURE_TEST   
pike.git/src/threads.c:114:   void th_atfork_child(void)   {    call_callback(& atfork_child_callback, 0);   }   #endif      #endif /* !CONFIGURE_TEST */      #ifdef __NT__    - int low_nt_create_thread(unsigned Pike_stack_size, + 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)    {    CloseHandle(h);    return 0;    }
pike.git/src/threads.c:165: Inside #if defined(SIMULATE_COND_WITH_EVENT)
   /* Cancellation point?? */      #ifdef PIKE_DEBUG    if(me.next)    Pike_fatal("Wait on event return prematurely!!\n");   #endif       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);    me.next=0;    mt_lock(& c->lock);       if(c->tail)    {    c->tail->next=&me;    c->tail=&me;
pike.git/src/threads.c:256: Inside #if defined(SIMULATE_COND_WITH_EVENT)
   t=c->head;    mt_unlock(& c->lock);    if(t) return -1;    mt_destroy(& c->lock);    return 0;   }      #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;   #ifdef HAVE_PTHREAD_COND_RELTIMEDWAIT_NP    /* Solaris extension: relative timeout. */    timeout.tv_sec = s;    timeout.tv_nsec = nanos;    return pthread_cond_reltimedwait_np(c, m, &timeout);   #else /* !HAVE_PTHREAD_COND_RELTIMEDWAIT_NP */    /* Absolute timeout. */
pike.git/src/threads.c:319: Inside #if defined(POSIX_THREADS)
   pthread_attr_setstacksize(&small_pattr, 4096*sizeof(char *));   #endif    pthread_attr_setdetachstate(&small_pattr, PTHREAD_CREATE_DETACHED);   #endif   }      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 " +  Pike_sp = (struct svalue *) (ptrdiff_t) -1; +  Pike_fp = (struct pike_frame *) (ptrdiff_t) -1; + #endif +  +  /* 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) + { +  THREADS_FPRINTF (2, (stderr, "Swap in thread %p" DLOC_PF(" @ ",) "\n", +  ts COMMA_DLOC_ARGS_OPT)); +  + #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"; - PMOD_EXPORT const char msg_global_dynbuf_in_use[] = -  "Threads allowed while the global dynamic buffer is in use.\n"; +  "(self: %"PRINTSIZET"x, disabler: %"PRINTSIZET"x)\n", +  (size_t) self, (size_t) threads_disabled_thread); +  }   #endif -  + }    - struct thread_local + PMOD_EXPORT void pike_threads_disallow (struct thread_state *ts COMMA_DLOC_DECL)   { -  INT32 id; - }; + #ifdef DO_PIKE_CLEANUP +  if (!ts) return; + #endif    - static volatile IMUTEX_T *interleave_list = NULL; +  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    * THREADS_ALLOW_UID threads. */   void low_init_threads_disable(void)   {    /* Serious black magic to avoid dead-locks */       if (!threads_disabled) {    THREADS_FPRINTF(0,    (stderr, "low_init_threads_disable(): Locking IM's...\n"));
pike.git/src/threads.c:468:    *! gc. (This advice applies to mutex locks in general, for that    *! matter.)    */   void init_threads_disable(struct object *o)   {    low_init_threads_disable();       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();    }   }      void exit_threads_disable(struct object *o)   {    THREADS_FPRINTF(0, (stderr, "exit_threads_disable(): threads_disabled:%d\n",    threads_disabled));
pike.git/src/threads.c:497:    /* Order shouldn't matter for unlock, so no need to do it backwards. */    while(im) {    THREADS_FPRINTF(0, (stderr,    "exit_threads_disable(): Unlocking IM %p\n", im));    mt_unlock(&(im->lock));    im = im->next;    }       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;   #endif    }   #ifdef PIKE_DEBUG    } else {    Pike_fatal("exit_threads_disable() called too many times!\n");   #endif /* PIKE_DEBUG */    }
pike.git/src/threads.c:573:    INT32 x;    for(x=0; x<THREAD_TABLE_SIZE; x++)    thread_table_chains[x] = NULL;   }      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);   #ifdef PIKE_DEBUG    if(h>=THREAD_TABLE_SIZE)    Pike_fatal("thread_table_hash failed miserably!\n");    if(thread_state_for_id(s->id))    {    if(thread_state_for_id(s->id) == s)    Pike_fatal("Registring thread twice!\n");    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++;    if((s->hashlink = thread_table_chains[h]) != NULL)    s->hashlink->backlink = &s->hashlink;    thread_table_chains[h] = s;    s->backlink = &thread_table_chains[h];    mt_unlock( & thread_table_lock );   }      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)    s->hashlink->backlink = s->backlink;    *(s->backlink) = s->hashlink;    mt_unlock( & thread_table_lock );   }      PMOD_EXPORT struct thread_state *thread_state_for_id(THREAD_T tid)   {    unsigned INT32 h = thread_table_hash(&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)    Pike_fatal("thread_table_hash failed miserably!\n");   #endif    mt_lock( & thread_table_lock );    if(thread_table_chains[h] == NULL)    {    /* NULL result */    }
pike.git/src/threads.c:665:    /* And relink at the head of the chain */    if((s->hashlink = thread_table_chains[h]) != NULL)    s->hashlink->backlink = &s->hashlink;    thread_table_chains[h] = s;    s->backlink = &thread_table_chains[h];    }    }    mt_unlock( & thread_table_lock );   #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    as you have the interpreter lock, unless tid == th_self() */   }      struct thread_state *gdb_thread_state_for_id(THREAD_T tid)   /* Should only be used from a debugger session. */   {    unsigned INT32 h = thread_table_hash(&tid);
pike.git/src/threads.c:815:   }      #ifdef PIKE_DEBUG   PMOD_EXPORT void debug_list_all_threads(void)   {    INT32 x;    struct thread_state *s;    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 ?    " (swapped)" : "");    fprintf(stderr,"Current thread state according to thread_state_for_id(): %p\n",    thread_state_for_id (self));    fprintf(stderr,"Current thread obj: %p\n",    (Pike_interpreter.thread_state &&    Pike_interpreter.thread_state != (struct thread_state *) (ptrdiff_t) -1) ?    Pike_interpreter.thread_state->thread_obj : NULL);    fprintf(stderr,"Current thread hash: %d\n",thread_table_hash(&self));    fprintf(stderr,"Current stack pointer: %p\n",&self);    for(x=0; x<THREAD_TABLE_SIZE; x++)    {    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");   }   #endif      PMOD_EXPORT int count_pike_threads(void)   {    return num_pike_threads;   }
pike.git/src/threads.c:1078:    add_ref(thread_obj = arg.thread_state->thread_obj);    INIT_THREAD_STATE(thread_state = arg.thread_state);       /* Inform the spawning thread that we are now running. */    co_broadcast(&thread_state->status_change);       /* After signalling the status change to the spawning thread we may    * now wait if threads are disabled. */    if (threads_disabled) {    SWAP_OUT_CURRENT_THREAD(); -  threads_disabled_wait(); +  threads_disabled_wait (DLOC);    SWAP_IN_CURRENT_THREAD();    }       DEBUG_CHECK_THREAD();       Pike_interpreter.trace_level = default_t_flag;       THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p inited\n",    arg.thread_state));   
pike.git/src/threads.c:1245:    {    num_threads++;    thread_table_insert(thread_state);       if(!threads_evaluator_callback)    {    threads_evaluator_callback=add_to_callback(&evaluator_callbacks,    check_threads, 0,0);    dmalloc_accept_leak(threads_evaluator_callback);    } +     /* Wait for the thread to start properly.    * so that we can avoid races.    *    * The main race is the one on current_object,    * since it at this point only has one reference.    *    * We also want the stuff in arg to be copied properly    * 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); -  } +  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 {    low_cleanup_interpret(&thread_state->state);    free_array(arg.args);    Pike_error("Failed to create thread (errno = %d).\n", tmp);    }       THREADS_FPRINTF(0, (stderr, "f_thread_create %p done\n", thread_state));    push_int(0);
pike.git/src/threads.c:2497:       mt_init( & interpreter_lock);    low_mt_lock_interpreter();    mt_init( & thread_table_lock);    mt_init( & interleave_lock);    mt_init( & rosie);    co_init( & live_threads_change);    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;      void th_init(void)   {    ptrdiff_t mutex_key_offset;      #ifdef UNIX_THREADS