pike.git / src / threads.c

version» Context lines:

pike.git/src/threads.c:52: Inside #if defined(HAVE_TIME_H)
  #endif   #ifdef HAVE_TIME_H   #include <time.h>   #endif      /* This is used for strapping the interpreter before the threads    * are loaded, and when there's no support for threads.    */   static struct Pike_interpreter_struct static_pike_interpreter;    + static cpu_time_t thread_quanta = 0; +    PMOD_EXPORT struct Pike_interpreter_struct *   #if defined(__GNUC__) && __GNUC__ >= 3    __restrict   #endif   Pike_interpreter_pointer = &static_pike_interpreter;      PMOD_EXPORT struct Pike_interpreter_struct * pike_get_interpreter_pointer(void)   {    return Pike_interpreter_pointer;   }
pike.git/src/threads.c:565:    /* NB: Assumes that there's a temporary Pike_interpreter_struct    * in Pike_interpreter_pointer, which we copy, and replace    * with ourselves.    */    Pike_interpreter.thread_state = ts;    ts->state = Pike_interpreter;    Pike_interpreter_pointer = &ts->state;    ts->id = th_self();    ts->status = THREAD_RUNNING;    ts->swapped = 0; +  ts->interval_start = get_real_time();   #ifdef PIKE_DEBUG    ts->debug_flags = 0;    thread_swaps++;   #endif   #ifdef USE_CLOCK_FOR_SLICES    /* Initialize thread_start_clock to zero instead of clock() since we    * don't know for how long the thread already has run. */    thread_start_clock = 0;    last_clocked_thread = ts->id;   #ifdef RDTSC
pike.git/src/threads.c:704: Inside #if defined(PIKE_DEBUG)
   "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 */    + /*! @class MasterObject +  */ +  + /*! @decl void thread_quanta_exceeded(Thread.Thread thread, int ns) +  *! +  *! Function called when a thread has exceeded the thread quanta. +  *! +  *! @param thread +  *! Thread that exceeded the thread quanta. +  *! +  *! @param ns +  *! Number of nanoseconds that the thread executed before allowing +  *! other threads to run. +  *! +  *! The default master prints a diagnostic and the thread backtrace +  *! to @[Stdio.stderr]. +  *! +  *! @note +  *! This function runs in a signal handler context, and should thus +  *! avoid handling of mutexes, etc. +  *! +  *! @seealso +  *! @[get_thread_quanta()], @[set_thread_quanta()] +  */ +  + /*! @endclass +  */ +    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    -  +  if (UNLIKELY(thread_quanta > 0)) { +  cpu_time_t now = get_real_time(); +  +  if (UNLIKELY((now - ts->interval_start) > thread_quanta) && +  LIKELY(ts->thread_obj)) { +  ref_push_object(ts->thread_obj); +  push_int64(now - ts->interval_start); +  ts->interval_start = now; + #ifndef LONG_CPU_TIME +  push_int(1000000000 / CPU_TIME_TICKS); +  o_multiply(); + #endif +  SAFE_APPLY_MASTER("thread_quanta_exceeded", 2); +  pop_stack(); +  } +  } +    #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
pike.git/src/threads.c:751: Inside #if defined(DO_PIKE_CLEANUP)
  {   #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);    }    +  if (UNLIKELY(thread_quanta)) { +  ts->interval_start = get_real_time(); +  } +    #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    -  +  if (UNLIKELY(thread_quanta > 0)) { +  cpu_time_t now = get_real_time(); +  +  if (UNLIKELY((now - ts->interval_start) > thread_quanta) && +  LIKELY(ts->thread_obj)) { +  ref_push_object(ts->thread_obj); +  push_int64(now - ts->interval_start); +  ts->interval_start = now; + #ifndef LONG_CPU_TIME +  push_int(1000000000 / CPU_TIME_TICKS); +  o_multiply(); + #endif +  SAFE_APPLY_MASTER("thread_quanta_exceeded", 2); +  pop_stack(); +  } +  } +    #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
pike.git/src/threads.c:814:    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);    }    +  if (UNLIKELY(thread_quanta)) { +  ts->interval_start = get_real_time(); +  } +    #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;   
pike.git/src/threads.c:2018:    pop_n_elems(args);    if (Pike_interpreter.thread_state &&    Pike_interpreter.thread_state->thread_obj) {    ref_push_object(Pike_interpreter.thread_state->thread_obj);    } else {    /* Threads not enabled yet/anylonger */    push_undefined();    }   }    + /*! @decl int(0..) get_thread_quanta() +  *! +  *! @returns +  *! Returns the current thread quanta in nanoseconds. +  *! +  *! @seealso +  *! @[set_thread_quanta()], @[gethrtime()] +  */ + static void f_get_thread_quanta(INT32 args) + { +  pop_n_elems(args); +  push_int64(thread_quanta); + #ifndef LONG_CPU_TIME_T +  /* Convert from ticks. */ +  push_int(1000000000 / CPU_TIME_TICKS); +  o_multiply(); + #endif + } +  + /*! @decl int(0..) set_thread_quanta(int(0..) ns) +  *! +  *! Set the thread quanta. +  *! +  *! @param ns +  *! New thread quanta in nanoseconds. +  *! A value of zero (default) disables the thread quanta checks. +  *! +  *! When enabled @[MasterObject.thread_quanta_exceeded()] will +  *! be called when a thread has spent more time than the quanta +  *! without allowing another thread to run. +  *! +  *! @note +  *! Setting a non-zero value that is too small to allow for +  *! @[MasterObject.thread_quanta_exceeded()] to run is NOT a +  *! good idea. +  *! +  *! @returns +  *! Returns the previous thread quanta in nanoseconds. +  *! +  *! @seealso +  *! @[set_thread_quanta()], @[gethrtime()] +  */ + static void f_set_thread_quanta(INT32 args) + { +  LONGEST ns = 0; +  + #ifndef LONG_CPU_TIME_T +  /* Convert to ticks. */ +  push_int(1000000000 / CPU_TIME_TICKS); +  o_divide(); + #endif +  get_all_args("set_thread_quanta", args, "%l", &ns); +  pop_n_elems(args); +  +  push_int64(thread_quanta); + #ifndef LONG_CPU_TIME_T +  /* Convert from ticks. */ +  push_int(1000000000 / CPU_TIME_TICKS); +  o_multiply(); + #endif +  +  if (ns <= 0) ns = 0; +  +  thread_quanta = ns; +  +  if (Pike_interpreter.thread_state) { +  Pike_interpreter.thread_state->interval_start = get_real_time(); +  } + } +    #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
pike.git/src/threads.c:3377:    add_global_program("thread_create", thread_id_prog);       ADD_EFUN("this_thread",f_this_thread,    tFunc(tNone,tObjIs_THREAD_ID),    OPT_EXTERNAL_DEPEND);       ADD_EFUN("all_threads",f_all_threads,    tFunc(tNone,tArr(tObjIs_THREAD_ID)),    OPT_EXTERNAL_DEPEND);    +  ADD_EFUN("get_thread_quanta", f_get_thread_quanta, +  tFunc(tNone, tInt), +  OPT_EXTERNAL_DEPEND); +  +  ADD_EFUN("set_thread_quanta", f_set_thread_quanta, +  tFunc(tInt, tInt), +  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);    add_integer_constant("THREAD_ABORTED", THREAD_ABORTED, 0);       original_interpreter = Pike_interpreter_pointer;    backend_thread_obj = fast_clone_object(thread_id_prog);    INIT_THREAD_STATE((struct thread_state *)(backend_thread_obj->storage +    thread_storage_offset));