Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:1:   // This file is part of Roxen WebServer.   // Copyright © 1996 - 2004, Roxen IS.   //   // The Roxen WebServer main program.   //   // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.   // ABS and suicide systems contributed freely by Francesco Chemolli    - constant cvs_version="$Id: roxen.pike,v 1.986 2008/09/19 22:17:53 mast Exp $"; + constant cvs_version="$Id: roxen.pike,v 1.987 2008/09/22 12:07:59 mast Exp $";      //! @appears roxen   //!   //! The Roxen WebServer main program.      // The argument cache. Used by the image cache.   ArgCache argcache;      // Some headerfiles   #define IN_ROXEN
Roxen.git/server/base_server/roxen.pike:599: Inside #if defined(THREADS)
   {    buffer=buffer[r_ptr..]+allocate(8);    w_ptr-=r_ptr;    r_ptr=0;    }    buffer[w_ptr++]=v;    r_cond::signal();    }   }    + #ifndef NO_SLOW_REQ_BT + // This is a system to dump all threads whenever a request takes + // longer than a configurable timeout. +  + protected Pike.Backend slow_req_monitor; // Set iff slow req bt is enabled. + protected int slow_req_timeout; +  + protected void slow_req_monitor_thread (Pike.Backend my_monitor) + { +  // my_monitor is just a safeguard to ensure we don't get multiple +  // monitor threads. +  while (slow_req_monitor == my_monitor) +  slow_req_monitor (3600); + } +  + void set_slow_req_timeout (int secs) + { + #ifdef DEBUG +  if (secs < 0) error ("Invalid timeout.\n"); + #endif +  +  Pike.Backend monitor = slow_req_monitor; +  slow_req_timeout = secs; +  +  if (secs && monitor) { +  // Just a change of timeout - nothing more to do. +  } +  +  else if (secs) { // Start. +  monitor = slow_req_monitor = Pike.SmallBackend(); +  Thread.thread_create (slow_req_monitor_thread, monitor); +  monitor->call_out (lambda () {}, 0); // Safeguard if there's a race. +  } +  +  else if (monitor) { // Stop. +  slow_req_monitor = 0; +  monitor->call_out (lambda () {}, 0); // To wake up the thread. +  } + } +  + protected void dump_slow_req (Thread.Thread thread, int timeout) + { +  report_debug ("### Thread 0x%x has been busy for more than %d seconds.\n", +  thread->id_number(), timeout); +  describe_all_threads(); + } +  + #endif // !NO_SLOW_REQ_BT +    // // This is easier than when there are no threads.   // // See the discussion below. :-)   //   // // But there is extra functionality below we really want, though,   // // so let's use that one instead...   // function async_sig_start( function f, int really )   // {   // return lambda( mixed ... args ) {   // thread_create( f, @args );   // };
Roxen.git/server/base_server/roxen.pike:641: Inside #if defined(THREADS) and #if defined(TEST_EUID_CHANGE)
   Stdio.File f = Stdio.File();    if (f->open ("rootonly", "r") && f->read())    werror ("Handler thread %d can read rootonly\n", id);    else    werror ("Handler thread %d can't read rootonly\n", id);    }   #endif    while(1)    {    int thread_flagged_as_busy; + #ifndef NO_SLOW_REQ_BT +  mixed slow_req_call_out; + #endif    if(q=catch {    do {   // if (!busy_threads) werror ("GC: %d\n", gc());    cache_clear_deltas();    THREAD_WERR("Handle thread ["+id+"] waiting for next event");    if(arrayp(h=handle_queue->read()) && h[0]) {    THREAD_WERR(sprintf("Handle thread [%O] calling %O(%{%O, %})",    id, h[0], h[1] / 1));    set_locale();    busy_threads++;    thread_flagged_as_busy = 1; -  +  + #ifndef NO_SLOW_REQ_BT +  if (Pike.Backend monitor = +  // Leave out bg_process_queue. It makes a timeout on +  // every individual job instead. +  h[0] != bg_process_queue && +  slow_req_monitor) { +  slow_req_call_out = +  monitor->call_out (dump_slow_req, slow_req_timeout, +  this_thread(), slow_req_timeout);    h[0](@h[1]); -  +  monitor->remove_call_out (slow_req_call_out); +  } +  else + #endif +  h[0](@h[1]); +     h=0;    busy_threads--;    thread_flagged_as_busy = 0;    } else if(!h) {    // Roxen is shutting down.    report_debug("Handle thread ["+id+"] stopped.\n");    thread_reap_cnt--;   #ifdef NSERIOUS    if(!thread_reap_cnt) report_debug("+++ATH\n");   #endif
Roxen.git/server/base_server/roxen.pike:689: Inside #if defined(THREADS)
   Thread.Mutex m = Thread.Mutex();    cond->wait (m->lock());    }    threads_on_hold--;    THREAD_WERR("Handle thread [" + id + "] released");    }    } while(1);    }) {    if (thread_flagged_as_busy)    busy_threads--; + #ifndef NO_SLOW_REQ_BT +  if (Pike.Backend monitor = slow_req_call_out && slow_req_monitor) +  monitor->remove_call_out (slow_req_call_out); + #endif    if (h = catch {    report_error(/*LOCALE("", "Uncaught error in handler thread: %s"    "Client will not get any response from Roxen.\n"),*/    describe_backtrace(q));    if (q = catch {h = 0;}) {    report_error(LOC_M(5, "Uncaught error in handler thread: %sClient "    "will not get any response from Roxen.")+"\n",    describe_backtrace(q));    catch (q = 0);    }
Roxen.git/server/base_server/roxen.pike:982: Inside #if defined(THREADS)
     protected void bg_process_queue()   {    if (bg_process_running) return;    // Relying on the interpreter lock here.    bg_process_running = 1;       int maxbeats =    min (time() - bg_last_busy, bg_time_buffer_max) * (int) (1 / 0.04);    + #ifndef NO_SLOW_REQ_BT +  mixed slow_req_call_out; + #endif +     if (mixed err = catch {    while (bg_queue->size()) {    // Not a race here since only one thread is reading the queue.    array task = bg_queue->read();       // Wait a while if another thread is busy already.    if (busy_threads > 1) {    for (maxbeats = max (maxbeats, (int) (bg_time_buffer_min / 0.04));    busy_threads > 1 && maxbeats > 0;    maxbeats--)
Roxen.git/server/base_server/roxen.pike:1010: Inside #if defined(THREADS) and #if defined(DEBUG_BACKGROUND_RUN)
   sprintf ("%s: %s", Function.defined (task[0]),    master()->describe_function (task[0])) :    programp (task[0]) ?    sprintf ("%s: %s", Program.defined (task[0]),    master()->describe_program (task[0])) :    sprintf ("%O", task[0]),    map (task[1], lambda (mixed arg)    {return sprintf ("%O", arg);}) * ", ",    bg_queue->size());   #endif +  +  float task_vtime, task_rtime; +  + #ifndef NO_SLOW_REQ_BT +  if (Pike.Backend monitor = slow_req_monitor) { +  slow_req_call_out = +  monitor->call_out (dump_slow_req, slow_req_timeout, +  this_thread(), slow_req_timeout); + #endif    int start_hrtime = gethrtime (1); -  float task_vtime = gauge { -  if (task[0]) // Ignore things that have become destructed. +  task_vtime = gauge { +  if (task[0]) // Ignore things that have become destructed.    // Note: BackgroundProcess.repeat assumes that there are    // exactly two refs to task[0] during the call below.    task[0] (@task[1]);    }; -  float task_rtime = (gethrtime (1) - start_hrtime) / 1e9; +  task_rtime = (gethrtime (1) - start_hrtime) / 1e9; + #ifndef NO_SLOW_REQ_BT +  monitor->remove_call_out (slow_req_call_out); +  } + #endif       if (task_rtime > 60.0)    report_warning ("Warning: Background job took more than one minute "    "(%g s real time and %g s cpu time):\n"    " %s (%s)\n%s",    task_rtime, task_vtime,    functionp (task[0]) ?    sprintf ("%s: %s", Function.defined (task[0]),    master()->describe_function (task[0])) :    programp (task[0]) ?
Roxen.git/server/base_server/roxen.pike:1049: Inside #if defined(THREADS) and #if defined(DEBUG_BACKGROUND_RUN)
  #ifdef DEBUG_BACKGROUND_RUN    else    report_debug ("background_run done, "    "took %g ms cpu time and %g ms real time\n",    task_vtime * 1000, task_rtime * 1000);   #endif       if (busy_threads > 1) bg_last_busy = time();    }    }) { + #ifndef NO_SLOW_REQ_BT +  if (Pike.Backend monitor = slow_req_call_out && slow_req_monitor) +  monitor->remove_call_out (slow_req_call_out); + #endif    bg_process_running = 0;    handle (bg_process_queue);    throw (err);    }    bg_process_running = 0;   }   #endif      mixed background_run (int|float delay, function func, mixed... args)   //! Enqueue a task to run in the background in a way that makes as
Roxen.git/server/base_server/roxen.pike:4884: Inside #if constant (thread_create)
  {   #if constant (thread_create)    // Disable all threads to avoid potential locking problems while we    // have the backtraces. It also gives an atomic view of the state.    object threads_disabled = _disable_threads();       report_debug("### Describing all Pike threads:\n\n");       array(Thread.Thread) threads = all_threads();    -  mapping(Thread.Thread:string|int) thread_ids = ([]); -  foreach (threads, Thread.Thread thread) { -  string desc = sprintf ("%O", thread); -  if (sscanf (desc, "Thread.Thread(%d)", int i)) thread_ids[thread] = i; -  else thread_ids[thread] = desc; -  } -  +     threads = Array.sort_array (    threads,    lambda (Thread.Thread a, Thread.Thread b) {    // Backend thread first, otherwise in id order.    if (a == backend_thread)    return 0;    else if (b == backend_thread)    return 1;    else -  return thread_ids[a] > thread_ids[b]; +  return a->id_number() > b->id_number();    });       int i;    for(i=0; i < sizeof(threads); i++) { -  string|int thread_id = thread_ids[threads[i]]; -  if (intp (thread_id)) thread_id = sprintf ("%x", thread_id); -  report_debug("### Thread %s%s:\n", -  thread_id, +  report_debug("### Thread 0x%x%s:\n", +  threads[i]->id_number(),   #ifdef THREADS    threads[i] == backend_thread ? " (backend thread)" : ""   #else    ""   #endif    );    report_debug(describe_backtrace(threads[i]->backtrace()) + "\n");    }       report_debug ("### Total %d Pike threads\n\n", sizeof (threads));
Roxen.git/server/base_server/roxen.pike:5020: Inside #if defined(TIMERS)
   reverse(a);    reverse(b);    report_notice("Timers:\n");    for( int i = 0; i<sizeof(b); i++ )    report_notice( " %-30s : %10.1fms\n", b[i], a[i]/1000.0 );    report_notice("\n\n");   }   #endif       - class GCTimestamp + protected class GCTimestamp   {    array self_ref;    protected void create() {self_ref = ({this_object()});}    protected void destroy() {    werror ("GC runs at %s", ctime(time()));    GCTimestamp();    }   }      
Roxen.git/server/base_server/roxen.pike:5253:    {    array(string) splitdir = roxen_path ("$LOGFILE") / "/";    cdt_filename = splitdir[-1];    cdt_directory = splitdir[..sizeof (splitdir) - 2] * "/";    if (has_suffix (cdt_filename, ".1"))    cdt_filename = cdt_filename[..sizeof (cdt_filename) - 3];    cdt_filename += ".dump_threads";    cdt_changed (getvar ("dump_threads_by_file"));    }    + #ifndef NO_SLOW_REQ_BT +  if (int timeout = query ("slow_req_bt")) +  if (timeout > 0) +  set_slow_req_timeout (timeout); + #endif +    #ifdef ROXEN_DEBUG_MEMORY_TRACE    restart_roxen_debug_memory_trace();   #endif      #ifndef __NT__    restart_if_stuck( 0 );   #endif   #ifdef __RUN_TRACE    trace(1);   #endif