pike.git / src / threads.c

version» Context lines:

pike.git/src/threads.c:1:   #include "global.h" - RCSID("$Id: threads.c,v 1.74 1998/07/09 21:50:37 grubba Exp $"); + RCSID("$Id: threads.c,v 1.75 1998/07/10 15:52:06 grubba Exp $");      int num_threads = 1;   int threads_disabled = 0;      #ifdef _REENTRANT   #include "threads.h"   #include "array.h"   #include "object.h"   #include "pike_macros.h"   #include "callback.h"
pike.git/src/threads.c:135:      #endif         #define THIS_THREAD ((struct thread_state *)fp->current_storage)      struct object *thread_id;   static struct callback *threads_evaluator_callback=0;   int thread_id_result_variable;    - MUTEX_T interpreter_lock, thread_table_lock; + MUTEX_T interpreter_lock, thread_table_lock, interleave_lock;   struct program *mutex_key = 0;   struct program *thread_id_prog = 0;   #ifdef POSIX_THREADS   pthread_attr_t pattr;   pthread_attr_t small_pattr;   #endif      struct thread_starter   {    struct object *id;    struct array *args;   };    -  + static volatile IMUTEX_T *interleave_list = NULL; +  + void init_threads_disable(struct object *o) + { +  /* Serious black magic to avoid dead-locks */ +  +  if (!threads_disabled) { +  THREADS_FPRINTF(0, (stderr, "init_threads_disable(): Locking IM's...\n")); +  +  if (thread_id) { +  IMUTEX_T *im; +  +  THREADS_ALLOW(); +  +  /* Keep this the entire session. */ +  mt_lock(&interleave_lock); +  +  im = (IMUTEX_T *)interleave_list; +  +  while(im) { +  mt_lock(&(im->lock)); +  +  im = im->next; +  } +  +  THREADS_DISALLOW(); +  } else { +  IMUTEX_T *im; +  +  /* Keep this the entire session. */ +  mt_lock(&interleave_lock); +  +  im = (IMUTEX_T *)interleave_list; +  +  while(im) { +  mt_lock(&(im->lock)); +  +  im = im->next; +  } +  } +  +  THREADS_FPRINTF(0, +  (stderr, "init_threads_disable(): Disabling threads.\n")); +  +  threads_disabled = 1; +  } else { +  threads_disabled++; +  } +  +  THREADS_FPRINTF(0, (stderr, "init_threads_disable(): threads_disabled:%d\n", +  threads_disabled)); +  while (live_threads) { +  THREADS_FPRINTF(0, +  (stderr, +  "_disable_threads(): Waiting for %d threads to finish\n", +  live_threads)); +  co_wait(&live_threads_change, &interpreter_lock); +  } + } +    void exit_threads_disable(struct object *o)   { -  THREADS_FPRINTF((stderr, "exit_threads_disable(): threads_disabled:%d\n", +  THREADS_FPRINTF(0, (stderr, "exit_threads_disable(): threads_disabled:%d\n",    threads_disabled));    if(threads_disabled) {    if(!--threads_disabled) { -  THREADS_FPRINTF((stderr, "_exit_threads_disable(): Wake up!\n")); +  IMUTEX_T *im = (IMUTEX_T *)interleave_list; +  +  /* Order shouldn't matter for unlock, so no need to do it backwards. */ +  while(im) { +  THREADS_FPRINTF(0, +  (stderr, +  "exit_threads_disable(): Unlocking IM 0x%08p\n", im)); +  mt_unlock(&(im->lock)); +  im = im->next; +  } +  +  mt_unlock(&interleave_lock); +  +  THREADS_FPRINTF(0, (stderr, "_exit_threads_disable(): Wake up!\n"));    co_broadcast(&threads_disabled_change);    }   #ifdef DEBUG    } else {    fatal("exit_threads_disable() called too many times!\n");   #endif /* DEBUG */    }   }    - void init_threads_disable(struct object *o) + void init_interleave_mutex(IMUTEX_T *im)   { -  /* Serious black magic to avoid dead-locks */ +  mt_init(&(im->lock));    -  if (!threads_disabled) { -  extern MUTEX_T password_protection_mutex; +  THREADS_FPRINTF(0, (stderr, +  "init_interleave_mutex(): init_threads_disable()\n"));    -  THREADS_ALLOW_UID(); -  mt_lock(&password_protection_mutex); -  THREADS_DISALLOW_UID(); +  init_threads_disable(NULL);    -  threads_disabled = 1; +  THREADS_FPRINTF(0, (stderr, +  "init_interleave_mutex(): Locking IM 0x%08p\n", im));    -  mt_unlock(&password_protection_mutex); -  } else { -  threads_disabled++; +  /* Lock it so that it can be unlocked by exit_threads_disable() */ +  mt_lock(&(im->lock)); +  +  im->next = (IMUTEX_T *)interleave_list; +  if (interleave_list) { +  interleave_list->prev = im;    } -  +  interleave_list = im; +  im->prev = NULL;    -  THREADS_FPRINTF((stderr, "init_threads_disable(): threads_disabled:%d\n", -  threads_disabled)); -  while (live_threads) { -  THREADS_FPRINTF((stderr, -  "_disable_threads(): Waiting for %d threads to finish\n", -  live_threads)); -  co_wait(&live_threads_change, &interpreter_lock); +  THREADS_FPRINTF(0, (stderr, +  "init_interleave_mutex(): exit_threads_disable()\n")); +  +  exit_threads_disable(NULL);   } -  +  + void exit_interleave_mutex(IMUTEX_T *im) + { +  init_threads_disable(NULL); +  +  if (im->prev) { +  im->prev->next = im->next; +  } else { +  interleave_list = im->next;    } -  +  if (im->next) { +  im->next->prev = im->prev; +  }    -  +  /* Just to be nice... */ +  mt_unlock(&(im->lock)); +  +  exit_threads_disable(NULL); + } +    /* Thread hashtable */      #define THREAD_TABLE_SIZE 127 /* Totally arbitrary prime */      static struct thread_state *thread_table_chains[THREAD_TABLE_SIZE];      void thread_table_init(void)   {    INT32 x;    for(x=0; x<THREAD_TABLE_SIZE; x++)
pike.git/src/threads.c:322:    /* Allow other threads to run */    THREADS_DISALLOW();   }      void *new_thread_func(void * data)   {    struct thread_starter arg = *(struct thread_starter *)data;    JMP_BUF back;    INT32 tmp;    -  THREADS_FPRINTF((stderr,"THREADS_DISALLOW() Thread %08x created...\n", +  THREADS_FPRINTF(0, (stderr,"THREADS_DISALLOW() Thread %08x created...\n",    (unsigned int)arg.id));       if((tmp=mt_lock( & interpreter_lock)))    fatal("Failed to lock interpreter, errno %d\n",tmp);    init_interpreter();    thread_id=arg.id;    SWAP_OUT_THREAD((struct thread_state *)thread_id->storage); /* Init struct */    ((struct thread_state *)thread_id->storage)->swapped=0;   #ifdef THREAD_TRACE    {    t_flag = default_t_flag;    }   #endif /* THREAD_TRACE */    -  THREADS_FPRINTF((stderr,"THREAD %08x INITED\n",(unsigned int)thread_id)); +  THREADS_FPRINTF(0, (stderr,"THREAD %08x INITED\n",(unsigned int)thread_id));    if(SETJMP(back))    {    if(throw_severity < THROW_EXIT)    {    ONERROR tmp;    SET_ONERROR(tmp,exit_on_error,"Error in handle_error in master object!");    assign_svalue_no_free(sp++, & throw_value);    APPLY_MASTER("handle_error", 1);    pop_stack();    UNSET_ONERROR(tmp);
pike.git/src/threads.c:373:    sp-1);    pop_stack();    }       ((struct thread_state *)(thread_id->storage))->status=THREAD_EXITED;    co_signal(& ((struct thread_state *)(thread_id->storage))->status_change);       free((char *)data); /* Moved by per, to avoid some bugs.... */    UNSETJMP(back);    -  THREADS_FPRINTF((stderr,"THREADS_ALLOW() Thread %08x done\n", +  THREADS_FPRINTF(0, (stderr,"THREADS_ALLOW() Thread %08x done\n",    (unsigned int)thread_id));       thread_table_delete(thread_id);    free_object(thread_id);    thread_id=0;    cleanup_interpret();    num_threads--;    if(!num_threads && threads_evaluator_callback)    {    remove_callback(threads_evaluator_callback);
pike.git/src/threads.c:421:    {    num_threads++;    thread_table_insert(arg->id);       if(!threads_evaluator_callback)    {    threads_evaluator_callback=add_to_callback(&evaluator_callbacks,    check_threads, 0,0);    }    ref_push_object(arg->id); -  THREADS_FPRINTF((stderr,"THREAD_CREATE -> t:%08x\n",(unsigned int)arg->id)); +  THREADS_FPRINTF(0, (stderr, "THREAD_CREATE -> t:%08x\n", +  (unsigned int)arg->id));    } else {    free_object(arg->id);    free_array(arg->args);    free((char *)arg);    error("Failed to create thread (errno = %d).\n",tmp);    }   }      #ifdef UNIX_THREADS   void f_thread_set_concurrency(INT32 args)
pike.git/src/threads.c:486:       m=THIS_MUTEX;    /* Needs to be cloned here, since create()    * might use threads.    */    o=clone_object(mutex_key,0);    if(!args || IS_ZERO(sp-args))    {    if(m->key && OB2KEY(m->key)->owner == thread_id)    { -  THREADS_FPRINTF((stderr, "Recursive LOCK k:%08x, m:%08x(%08x), t:%08x\n", +  THREADS_FPRINTF(0, +  (stderr, "Recursive LOCK k:%08x, m:%08x(%08x), t:%08x\n",    (unsigned int)OB2KEY(m->key),    (unsigned int)m,    (unsigned int)OB2KEY(m->key)->mut,    (unsigned int) thread_id));    free_object(o);    error("Recursive mutex locks!\n");    }    }       if(m->key)    {    SWAP_OUT_CURRENT_THREAD();    do    { -  THREADS_FPRINTF((stderr,"WAITING TO LOCK m:%08x\n",(unsigned int)m)); +  THREADS_FPRINTF(1, (stderr,"WAITING TO LOCK m:%08x\n",(unsigned int)m));    co_wait(& m->condition, & interpreter_lock);    }while(m->key);    SWAP_IN_CURRENT_THREAD();    }    m->key=o;    OB2KEY(o)->mut=m;    -  THREADS_FPRINTF((stderr, "LOCK k:%08x, m:%08x(%08x), t:%08x\n", +  THREADS_FPRINTF(1, (stderr, "LOCK k:%08x, m:%08x(%08x), t:%08x\n",    (unsigned int)OB2KEY(o),    (unsigned int)m,    (unsigned int)OB2KEY(m->key)->mut,    (unsigned int)thread_id));    pop_n_elems(args);    push_object(o);   }      void f_mutex_trylock(INT32 args)   {
pike.git/src/threads.c:566:   }      void init_mutex_obj(struct object *o)   {    co_init(& THIS_MUTEX->condition);    THIS_MUTEX->key=0;   }      void exit_mutex_obj(struct object *o)   { -  THREADS_FPRINTF((stderr,"DESTROYING MUTEX m:%08x\n",(unsigned int)THIS_MUTEX)); +  THREADS_FPRINTF(1, (stderr, "DESTROYING MUTEX m:%08x\n", +  (unsigned int)THIS_MUTEX));    if(THIS_MUTEX->key) destruct(THIS_MUTEX->key);    THIS_MUTEX->key=0;    co_destroy(& THIS_MUTEX->condition);   }      #define THIS_KEY ((struct key_storage *)(fp->current_storage))   void init_mutex_key_obj(struct object *o)   { -  THREADS_FPRINTF((stderr, "KEY k:%08x, o:%08x\n", +  THREADS_FPRINTF(1, (stderr, "KEY k:%08x, o:%08x\n",    (unsigned int)THIS_KEY, (unsigned int)thread_id));    THIS_KEY->mut=0;    add_ref(THIS_KEY->owner=thread_id);    THIS_KEY->initialized=1;   }      void exit_mutex_key_obj(struct object *o)   { -  THREADS_FPRINTF((stderr, "UNLOCK k:%08x m:(%08x) t:%08x o:%08x\n", +  THREADS_FPRINTF(1, (stderr, "UNLOCK k:%08x m:(%08x) t:%08x o:%08x\n",    (unsigned int)THIS_KEY,    (unsigned int)THIS_KEY->mut,    (unsigned int)thread_id,    (unsigned int)THIS_KEY->owner));    if(THIS_KEY->mut)    {    struct mutex_storage *mut = THIS_KEY->mut;      #ifdef DEBUG    if(mut->key != o)
pike.git/src/threads.c:734: Inside #if defined(DEBUG)
  static void thread_was_marked(struct object *o)   {    struct thread_state *tmp=(struct thread_state *)(o->storage);    if(tmp->swapped)    {    debug_gc_xmark_svalues(tmp->evaluator_stack,tmp->sp-tmp->evaluator_stack-1,"idle thread stack");    }   }   #endif    - void th_init(void) + void low_th_init(void)   { -  struct program *tmp; -  INT32 mutex_key_offset; -  +    #ifdef SGI_SPROC_THREADS   #error /* Need to specify a filename */    us_cookie = usinit("");   #endif /* SGI_SPROC_THREADS */    -  THREADS_FPRINTF((stderr, "THREADS_DISALLOW() Initializing threads.\n")); +  THREADS_FPRINTF(0, (stderr, "THREADS_DISALLOW() Initializing threads.\n"));      #ifdef POSIX_THREADS   #ifdef HAVE_PTHREAD_INIT    pthread_init();   #endif /* HAVE_PTHREAD_INIT */   #endif /* POSIX_THREADS */       mt_init( & interpreter_lock);    mt_lock( & interpreter_lock);    mt_init( & thread_table_lock); -  +  mt_init( & interleave_lock);    co_init( & live_threads_change);    co_init( & threads_disabled_change);    thread_table_init();   #ifdef POSIX_THREADS    pthread_attr_init(&pattr);   #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE    pthread_attr_setstacksize(&pattr, 1024 * 1204);   #endif    pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);       pthread_attr_init(&small_pattr);   #ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE    pthread_attr_setstacksize(&small_pattr, 32768);   #endif    pthread_attr_setdetachstate(&small_pattr, PTHREAD_CREATE_DETACHED);      #endif -  + }    -  + void th_init(void) + { +  struct program *tmp; +  INT32 mutex_key_offset; +     add_efun("thread_create",f_thread_create,"function(mixed ...:object)",    OPT_SIDE_EFFECT);   #ifdef UNIX_THREADS    add_efun("thread_set_concurrency",f_thread_set_concurrency,    "function(int:void)", OPT_SIDE_EFFECT);   #endif    add_efun("this_thread",f_this_thread,"function(:object)",    OPT_EXTERNAL_DEPEND);    add_efun("all_threads",f_all_threads,"function(:array(object))",    OPT_EXTERNAL_DEPEND);