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.207 2003/02/16 15:05:07 mast Exp $ + || $Id: threads.c,v 1.208 2003/02/20 11:55:32 grubba Exp $   */      #ifndef CONFIGURE_TEST   #include "global.h" - RCSID("$Id: threads.c,v 1.207 2003/02/16 15:05:07 mast Exp $"); + RCSID("$Id: threads.c,v 1.208 2003/02/20 11:55:32 grubba Exp $");      PMOD_EXPORT int num_threads = 1;   PMOD_EXPORT int threads_disabled = 0;   #endif /* !CONFIGURE_TEST */      #ifdef _REENTRANT      #ifndef CONFIGURE_TEST      #include "threads.h"
pike.git/src/threads.c:245:   PMOD_EXPORT MUTEX_T interpreter_lock;   MUTEX_T thread_table_lock, interleave_lock;   struct program *mutex_key = 0;   PMOD_EXPORT struct program *thread_id_prog = 0;   struct program *thread_local_prog = 0;   PMOD_EXPORT ptrdiff_t thread_storage_offset;   #ifdef USE_CLOCK_FOR_SLICES   PMOD_EXPORT clock_t thread_start_clock = 0;   #endif    - struct thread_starter - { -  struct object *thread_obj; /* Object holding the thread_state. */ -  struct thread_state *thread_state; /* State of the thread. */ -  struct array *args; /* Arguments passed to the thread. */ - #ifdef HAVE_BROKEN_LINUX_THREAD_EUID -  int euid, egid; - #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ - }; -  +    struct thread_local   {    INT32 id;   };      static volatile IMUTEX_T *interleave_list = NULL;      /* 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. */
pike.git/src/threads.c:632: Inside #if defined(PIKE_DEBUG)
     #ifdef PIKE_DEBUG   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 obj: %p\n",Pike_interpreter.thread_obj); +     fprintf(stderr,"Current thread state: %p\n",Pike_interpreter.thread_state); -  +  fprintf(stderr,"Current thread obj: %p\n", +  Pike_interpreter.thread_state? +  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]: %p (stackbase=%p)",x,o,s->state.stack_top);    dumpmem(" ",&s->id, sizeof(s->id));    }    }
pike.git/src/threads.c:692: Inside #if defined(USE_CLOCK_FOR_SLICES)
     #ifdef USE_CLOCK_FOR_SLICES    /* Must set the base time for the slice here since clock() returns    * thread local time. */    thread_start_clock = clock();   #endif       DEBUG_CHECK_THREAD();   }    + struct thread_starter + { +  struct thread_state *thread_state; /* State of the thread. */ +  struct array *args; /* Arguments passed to the thread. */ + #ifdef HAVE_BROKEN_LINUX_THREAD_EUID +  int euid, egid; + #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */ + }; +  + /* Thread func starting new Pike-level threads. */   TH_RETURN_TYPE new_thread_func(void *data)   {    struct thread_starter arg = *(struct thread_starter *)data; -  +  struct object *thread_obj; +  struct thread_state *thread_state;    JMP_BUF back;    INT32 tmp;       THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p created...\n",    arg.thread_state));      #ifdef HAVE_BROKEN_LINUX_THREAD_EUID    /* Work-around for Linux's pthreads not propagating the    * effective uid & gid.    */
pike.git/src/threads.c:739:    arg.thread_state->swapped = 0;    Pike_interpreter = arg.thread_state->state;    init_interpreter();      #ifdef PROFILING    Pike_interpreter.stack_bottom=((char *)&data);   #endif    Pike_interpreter.stack_top=((char *)&data)+ (thread_stack_size-16384) * STACK_DIRECTION;    Pike_interpreter.recoveries = NULL;    -  add_ref(Pike_interpreter.thread_obj = arg.thread_obj); -  INIT_THREAD_STATE(arg.thread_state); -  co_broadcast(& arg.thread_state->status_change); +  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); +     DEBUG_CHECK_THREAD();       Pike_interpreter.trace_level = default_t_flag;       THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p inited\n",    arg.thread_state));       if(SETJMP(back))    {    if(throw_severity < THROW_EXIT)    call_handle_error();    if(throw_severity == THROW_EXIT)    { -  free((char *) data); +     pike_do_exit(throw_value.u.integer);    }    } else {    INT32 args=arg.args->size;    back.severity=THROW_EXIT;    push_array_items(arg.args);    arg.args=0;    f_call_function(args);       /* copy return value to the arg.thread_state here */    assign_svalue(&arg.thread_state->result, Pike_sp-1);    pop_stack();    }    -  +  UNSETJMP(back); +     DEBUG_CHECK_THREAD();    -  if(arg.thread_state->thread_local != NULL) { -  free_mapping(arg.thread_state->thread_local); -  arg.thread_state->thread_local = NULL; +  if(thread_state->thread_local != NULL) { +  free_mapping(thread_state->thread_local); +  thread_state->thread_local = NULL;    }    -  arg.thread_state->status = THREAD_EXITED; -  co_broadcast(& arg.thread_state->status_change); +  thread_state->status = THREAD_EXITED; +  co_broadcast(&thread_state->status_change);    -  free((char *)data); /* Moved by per, to avoid some bugs.... */ -  UNSETJMP(back); -  +     THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p done\n",    arg.thread_state));    -  +  /* This thread is now officially dead. */ +     cleanup_interpret(); -  thread_table_delete(arg.thread_state); -  EXIT_THREAD_STATE(arg.thread_state); -  Pike_interpreter.thread_obj = NULL; -  Pike_interpreter.thread_state = NULL; +  +  thread_table_delete(thread_state); +  EXIT_THREAD_STATE(thread_state); +  Pike_interpreter.thread_state = thread_state = NULL; +  +  /* Free ourselves. +  * NB: This really ought to run in some other thread... +  */ +  /* free_object(thread_obj); */ +  thread_obj = NULL; +     num_threads--;    if(!num_threads && threads_evaluator_callback)    {    remove_callback(threads_evaluator_callback);    threads_evaluator_callback=0;    } -  free_object(arg.thread_obj); +       #ifdef INTERNAL_PROFILING    fprintf (stderr, "Thread usage summary:\n");    debug_print_rusage (stderr);   #endif       /* FIXME: What about threads_disable? */    mt_unlock_interpreter();    th_exit(0);    /* NOT_REACHED, but removes a warning */
pike.git/src/threads.c:843:    *!    *! @note    *! This function is only available on systems with POSIX or UNIX or WIN32    *! threads support.    *!    *! @seealso    *! @[Mutex], @[Condition], @[this_thread()]    */   void f_thread_create(INT32 args)   { -  struct thread_starter *arg; +  struct thread_starter arg;    struct thread_state *thread_state =    (struct thread_state *)Pike_fp->current_storage;    ONERROR err;    int tmp;       if (thread_state->status != THREAD_NOT_STARTED) {    Pike_error("Threads can not be restarted.\n");    }    -  arg = ALLOC_STRUCT(thread_starter); -  SET_ONERROR(err, free, arg); +  arg.args = aggregate_array(args); +  arg.thread_state = thread_state;    -  arg->args = aggregate_array(args); -  arg->thread_obj = Pike_fp->current_object; -  arg->thread_state = thread_state; -  +    #ifdef HAVE_BROKEN_LINUX_THREAD_EUID -  arg->euid = geteuid(); -  arg->egid = getegid(); +  arg.euid = geteuid(); +  arg.egid = getegid();   #endif /* HAVE_BROKEN_LINUX_THREAD_EUID */       do { -  tmp = th_create(&arg->thread_state->id, +  tmp = th_create(&thread_state->id,    new_thread_func, -  arg); +  &arg);    if (tmp == EINTR) check_threads_etc();    } while( tmp == EINTR );       if(!tmp)    {    num_threads++; -  thread_table_insert(arg->thread_state); +  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);    } -  UNSET_ONERROR(err); -  +     /* 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, "THREAD_CREATE waiting...\n"));    low_co_wait_interpreter(&thread_state->status_change);    }    SWAP_IN_CURRENT_THREAD(); -  +  } else { +  free_array(arg.args); +  Pike_error("Failed to create thread (errno = %d).\n", tmp); +  }       THREADS_FPRINTF(0, (stderr, "THREAD_CREATE -> t:%08x\n", -  (unsigned int)arg->thread_obj)); +  (unsigned int)thread_state));    push_int(0); -  } else { -  free_array(arg->args); -  CALL_AND_UNSET_ONERROR(err); -  Pike_error("Failed to create thread (errno = %d).\n", tmp); +    } - } +       /*! @endclass    */      #ifdef UNIX_THREADS   /*! @decl void thread_set_concurrency(int concurrency)    *!    *! @fixme    *! Document this function    */
pike.git/src/threads.c:937:   /*! @decl Thread.Thread this_thread()    *!    *! This function returns the object that identifies this thread.    *!    *! @seealso    *! @[Thread()]    */   PMOD_EXPORT void f_this_thread(INT32 args)   {    pop_n_elems(args); -  ref_push_object(Pike_interpreter.thread_obj); +  if (Pike_interpreter.thread_state) { +  ref_push_object(Pike_interpreter.thread_state->thread_obj); +  } else { +  /* Threads not enabled yet/anylonger */ +  push_undefined();    } -  + }      #define THIS_MUTEX ((struct mutex_storage *)(CURRENT_STORAGE))         /* Note:    * No reference is kept to the key object, it is destructed if the    * mutex is destructed. The key pointer is set to zero by the    * key object when the key is destructed.    */      struct mutex_storage   {    COND_T condition;    struct object *key;   };      struct key_storage   {    struct mutex_storage *mut;    struct object *mutex_obj; -  struct object *owner; +  struct thread_state *owner; +  struct object *owner_obj;    int initialized;   };      #define OB2KEY(X) ((struct key_storage *)((X)->storage))      /*! @class Mutex    *!    *! @[Mutex] is a class that implements mutual exclusion locks.    *! Mutex locks are used to prevent multiple threads from simultaneously    *! execute sections of code which access or change shared data. The basic
pike.git/src/threads.c:1032:       switch(type)    {    default:    bad_arg_error("mutex->lock", Pike_sp-args, args, 2, "int(0..2)", Pike_sp+1-args,    "Unknown mutex locking style: %"PRINTPIKEINT"d\n",type);          case 0:    case 2: -  if(m->key && OB2KEY(m->key)->owner == Pike_interpreter.thread_obj) +  if(m->key && OB2KEY(m->key)->owner == Pike_interpreter.thread_state)    {    THREADS_FPRINTF(0,    (stderr, "Recursive LOCK k:%p, m:%p(%p), t:%p\n",    OB2KEY(m->key), m, OB2KEY(m->key)->mut,    Pike_interpreter.thread_state));       if(type==0) Pike_error("Recursive mutex locks!\n");       pop_n_elems(args);    push_int(0);
pike.git/src/threads.c:1120:    else    get_all_args("mutex->trylock",args,"%i",&type);       switch(type)    {    default:    bad_arg_error("mutex->trylock", Pike_sp-args, args, 2, "int(0..2)", Pike_sp+1-args,    "Unknown mutex locking style: %"PRINTPIKEINT"d\n",type);       case 0: -  if(m->key && OB2KEY(m->key)->owner == Pike_interpreter.thread_obj) +  if(m->key && OB2KEY(m->key)->owner == Pike_interpreter.thread_state)    {    Pike_error("Recursive mutex locks!\n");    }       case 2:    case 1:    break;    }       o=clone_object(mutex_key,0);
pike.git/src/threads.c:1166:    *! @seealso    *! @[Thread()]    */   PMOD_EXPORT void f_mutex_locking_thread(INT32 args)   {    struct mutex_storage *m = THIS_MUTEX;       pop_n_elems(args);       if (m->key && OB2KEY(m->key)->owner) -  ref_push_object(OB2KEY(m->key)->owner); +  ref_push_object(OB2KEY(m->key)->owner->thread_obj);    else    push_int(0);   }      /*! @decl Thread.MutexKey current_locking_key()    *!    *! This mutex method returns the key object currently governing    *! the lock on this mutex. 0 is returned if the mutex isn't locked.    *!    *! @seealso
pike.git/src/threads.c:1215:   /*! @endclass    */      #define THIS_KEY ((struct key_storage *)(CURRENT_STORAGE))   void init_mutex_key_obj(struct object *o)   {    THREADS_FPRINTF(1, (stderr, "KEY k:%p, o:%p\n",    THIS_KEY, Pike_interpreter.thread_state));    THIS_KEY->mut=0;    THIS_KEY->mutex_obj = NULL; -  add_ref(THIS_KEY->owner=Pike_interpreter.thread_obj); +  THIS_KEY->owner = Pike_interpreter.thread_state; +  add_ref(THIS_KEY->owner_obj = Pike_interpreter.thread_state->thread_obj);    THIS_KEY->initialized=1;   }      void exit_mutex_key_obj(struct object *o)   {    THREADS_FPRINTF(1, (stderr, "UNLOCK k:%p m:(%p) t:%p o:%p\n",    THIS_KEY, THIS_KEY->mut,    Pike_interpreter.thread_state, THIS_KEY->owner));    if(THIS_KEY->mut)    {    struct mutex_storage *mut = THIS_KEY->mut;      #ifdef PIKE_DEBUG    if(mut->key != o)    Pike_fatal("Mutex unlock from wrong key %p != %p!\n",THIS_KEY->mut->key,o);   #endif    mut->key=0;    if (THIS_KEY->owner) { -  free_object(THIS_KEY->owner); -  THIS_KEY->owner=0; +  THIS_KEY->owner = NULL;    } -  +  if (THIS_KEY->owner_obj) { +  free_object(THIS_KEY->owner_obj); +  THIS_KEY->owner_obj=0; +  }    free_object (THIS_KEY->mutex_obj);    THIS_KEY->mut=0;    THIS_KEY->mutex_obj = NULL;    THIS_KEY->initialized=0;    co_signal(& mut->condition);    }   }      #define THIS_COND ((COND_T *)(CURRENT_STORAGE))   
pike.git/src/threads.c:1377:    *! @seealso    *! @[predef::backtrace()]    */   void f_thread_backtrace(INT32 args)   {    void low_backtrace(struct Pike_interpreter *);    struct thread_state *foo = THIS_THREAD;       pop_n_elems(args);    -  if(foo->state.thread_obj == Pike_interpreter.thread_obj) +  if(foo == Pike_interpreter.thread_state)    {    f_backtrace(0);    }    else if(foo->state.stack_pointer)    {    low_backtrace(& foo->state);    }    else    {    push_int(0);
pike.git/src/threads.c:1460:    check_threads_etc();    }       assign_svalue_no_free(Pike_sp, &th->result);    Pike_sp++;   }      void init_thread_obj(struct object *o)   {    MEMSET(&THIS_THREAD->state, 0, sizeof(struct Pike_interpreter)); -  THIS_THREAD->state.thread_obj = Pike_fp->current_object; +  THIS_THREAD->thread_obj = Pike_fp->current_object;    THIS_THREAD->swapped = 0;    THIS_THREAD->status=THREAD_NOT_STARTED;    THIS_THREAD->result.type = T_INT;    THIS_THREAD->result.subtype = NUMBER_UNDEFINED;    THIS_THREAD->result.u.integer = 0;    co_init(& THIS_THREAD->status_change);    THIS_THREAD->thread_local=NULL;   #if CPU_TIME_IS_THREAD_LOCAL == PIKE_YES    THIS_THREAD->auto_gc_time = 0;   #endif
pike.git/src/threads.c:1482:         void exit_thread_obj(struct object *o)   {    if(THIS_THREAD->thread_local != NULL) {    free_mapping(THIS_THREAD->thread_local);    THIS_THREAD->thread_local = NULL;    }    co_destroy(& THIS_THREAD->status_change);    th_destroy(& THIS_THREAD->id); +  THIS_THREAD->thread_obj = NULL;   }      /*! @endclass    */      static void thread_was_recursed(struct object *o)   {    struct thread_state *tmp=THIS_THREAD;    if(tmp->thread_local != NULL)    gc_recurse_mapping(tmp->thread_local);
pike.git/src/threads.c:1611:    struct svalue key;    struct mapping *m;    key.u.integer = ((struct thread_local *)CURRENT_STORAGE)->id;    key.type = T_INT;    key.subtype = NUMBER_NUMBER;    if(args>1)    pop_n_elems(args-1);    else if(args<1)    SIMPLE_TOO_FEW_ARGS_ERROR("Thread.Local.set", 1);    -  if(Pike_interpreter.thread_obj == NULL) +  if(Pike_interpreter.thread_state == NULL)    Pike_error("Trying to set Thread.Local without thread!\n");       if((m = Pike_interpreter.thread_state->thread_local) == NULL)    m = Pike_interpreter.thread_state->thread_local =    allocate_mapping(4);       mapping_insert(m, &key, &Pike_sp[-1]);   }      #ifdef PIKE_DEBUG
pike.git/src/threads.c:1793:    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       ADD_EFUN("thread_set_concurrency",f_thread_set_concurrency,tFunc(tInt,tVoid), OPT_SIDE_EFFECT);   #endif       START_NEW_PROGRAM_ID(THREAD_MUTEX_KEY);    mutex_key_offset = ADD_STORAGE(struct key_storage);    /* This is needed to allow the gc to find the possible circular reference.    * It also allows a thread to take over ownership of a key.    */ -  PIKE_MAP_VARIABLE("_owner", mutex_key_offset + OFFSETOF(key_storage, owner), +  PIKE_MAP_VARIABLE("_owner", +  mutex_key_offset + OFFSETOF(key_storage, owner_obj),    tObjIs_THREAD_ID, T_OBJECT, 0);    PIKE_MAP_VARIABLE("_mutex", mutex_key_offset + OFFSETOF(key_storage, mutex_obj),    tObjIs_THREAD_MUTEX, T_OBJECT, ID_STATIC|ID_PRIVATE);    set_init_callback(init_mutex_key_obj);    set_exit_callback(exit_mutex_key_obj);    mutex_key=Pike_compiler->new_program;    add_ref(mutex_key);    end_class("mutex_key", 0);    mutex_key->flags|=PROGRAM_DESTRUCT_IMMEDIATE;   #ifdef PIKE_DEBUG
pike.git/src/threads.c:1917:    OPT_EXTERNAL_DEPEND);       /* Some constants... */    add_integer_constant("THREAD_NOT_STARTED", THREAD_NOT_STARTED, 0);    add_integer_constant("THREAD_RUNNING", THREAD_RUNNING, 0);    add_integer_constant("THREAD_EXITED", THREAD_EXITED, 0);       if(!mutex_key)    Pike_fatal("Failed to initialize thread program!\n");    -  Pike_interpreter.thread_obj = fast_clone_object(thread_id_prog); -  INIT_THREAD_STATE((struct thread_state *)(Pike_interpreter.thread_obj->storage + +  backend_thread_obj = fast_clone_object(thread_id_prog); +  INIT_THREAD_STATE((struct thread_state *)(backend_thread_obj->storage +    thread_storage_offset));    thread_table_insert(Pike_interpreter.thread_state);   }      void th_cleanup(void)   {    th_running = 0;       if (Pike_interpreter.thread_state) {    thread_table_delete(Pike_interpreter.thread_state);    Pike_interpreter.thread_state = NULL;    }    -  if(Pike_interpreter.thread_obj) +  if(backend_thread_obj)    { -  destruct(Pike_interpreter.thread_obj); -  free_object(Pike_interpreter.thread_obj); -  Pike_interpreter.thread_obj = NULL; +  destruct(backend_thread_obj); +  free_object(backend_thread_obj); +  backend_thread_obj = NULL;    destruct_objects_to_destruct_cb();    }       if(mutex_key)    {    free_program(mutex_key);    mutex_key=0;    }       if(thread_local_prog)