• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

signals.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /**************************************************************************
00025   Signal functions and handlers.
00026 
00027 **************************************************************************/
00028 
00029 #include "libts.h"
00030 #include "signals.h"
00031 #include "ProxyConfig.h"
00032 #include "P_EventSystem.h"
00033 #include "StatSystem.h"
00034 #include "proxy/Main.h"
00035 
00036 // For backtraces on crash
00037 #include "ink_stack_trace.h"
00038 
00039 #if TS_HAS_PROFILER
00040 #include <google/profiler.h>
00041 #endif
00042 
00043 #if !defined(linux) && !defined(freebsd)
00044 typedef void (*SigActionFunc_t) (int sig, siginfo_t * t, void *f);
00045 #else
00046 typedef void (*SigActionFunc_t) (int sig);
00047 #endif
00048 
00049 int exited_children = 0;
00050 
00051 static volatile int sigusr1_received = 0;
00052 extern int fastmemtotal;
00053 
00054 class SignalContinuation:public Continuation
00055 {
00056 public:
00057   char *end;
00058   char *snap;
00059   int fastmemsnap;
00060     SignalContinuation()
00061   : Continuation(new_ProxyMutex())
00062   {
00063     end = snap = 0;
00064     fastmemsnap = 0;
00065     SET_HANDLER(&SignalContinuation::periodic);
00066   }
00067 
00068   int periodic(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
00069   {
00070     if (sigusr1_received) {
00071       sigusr1_received = 0;
00072       // TODO: TS-567 Integrate with debugging allocators "dump" features?
00073       ink_freelists_dump(stderr);
00074       if (!end)
00075         end = (char *) sbrk(0);
00076       if (!snap)
00077         snap = (char *) sbrk(0);
00078       char *now = (char *) sbrk(0);
00079       // TODO: Use logging instead directly writing to stderr
00080       //       This is not error condition at the first place
00081       //       so why stderr?
00082       //
00083       fprintf(stderr, "sbrk 0x%" PRIu64 "x from first %" PRIu64 " from last %" PRIu64 "\n",
00084               (uint64_t) ((ptrdiff_t) now), (uint64_t) ((ptrdiff_t) (now - end)),
00085               (uint64_t) ((ptrdiff_t) (now - snap)));
00086 #ifdef DEBUG
00087       int fmdelta = fastmemtotal - fastmemsnap;
00088       fprintf(stderr, "fastmem %" PRId64 " from last %" PRId64 "\n", (int64_t) fastmemtotal, (int64_t) fmdelta);
00089       fastmemsnap += fmdelta;
00090 #endif
00091       snap = now;
00092     }
00093 
00094     return EVENT_CONT;
00095   }
00096 };
00097 
00098 class TrackerContinuation:public Continuation
00099 {
00100 public:
00101   int baseline_taken;
00102   int use_baseline;
00103   TrackerContinuation()
00104     : Continuation(new_ProxyMutex())
00105   {
00106     SET_HANDLER(&TrackerContinuation::periodic);
00107     use_baseline = 0;
00108     // TODO: ATS prefix all those environment struff or
00109     //       even better use config since env can be
00110     //       different for parent and child process users.
00111     //
00112     if (getenv("MEMTRACK_BASELINE"))
00113     {
00114       use_baseline = 1;
00115     }
00116     baseline_taken = 0;
00117   }
00118 
00119   int periodic(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
00120   {
00121     if (use_baseline) {
00122       // TODO: TS-567 Integrate with debugging allocators "dump" features?
00123       ink_freelists_dump_baselinerel(stderr);
00124     } else {
00125       // TODO: TS-567 Integrate with debugging allocators "dump" features?
00126       ink_freelists_dump(stderr);
00127     }
00128     if (!baseline_taken && use_baseline) {
00129       ink_freelists_snap_baseline();
00130       // TODO: TS-567 Integrate with debugging allocators "dump" features?
00131       baseline_taken = 1;
00132     }
00133     return EVENT_CONT;
00134   }
00135 };
00136 
00137 
00138 static void
00139 interrupt_handler(int sig)
00140 {
00141   (void) sig;
00142   fprintf(stderr, "interrupt caught...exit\n");
00143   shutdown_system();
00144   _exit(1);
00145 }
00146 
00147 #if defined(linux)
00148 static void
00149 signal_handler(int sig)
00150 #else
00151 static void
00152 signal_handler(int sig, siginfo_t * t, void *c)
00153 #endif
00154 {
00155   if (sig == SIGUSR1) {
00156     sigusr1_received = 1;
00157     return;
00158   }
00159 
00160   char sig_msg[2048];
00161 #if !defined(linux) && !defined(freebsd)
00162   // Print out information about where the signal came from
00163   //  so that we can debug signal related problems
00164   //
00165   //  I'm avoiding use of the Diags stuff since it is more
00166   //    likely to deadlock from a signal handler.  The syslog
00167   //    if questionable and probably should be eventually be
00168   //    turned off but should be helpful through Rator alpha
00169   //
00170   //    lomew adds on May 03, 2002: don't call syslog here because it
00171   //    calls malloc and can deadlock you if the SEGV happened in free after
00172   //    the heap-mutex has been taken, like if free was called with garbage.
00173   //
00174   if (t) {
00175     if (t->si_code <= 0) {
00176       // TODO: Use UID_FMT_T instead duplicating code
00177 #if defined(solaris)
00178       snprintf(sig_msg, sizeof(sig_msg), "NOTE: Traffic Server received User Sig %d from pid: %d uid: %d\n",
00179                sig, (int)t->si_pid, (int)t->si_uid);
00180 #else
00181       snprintf(sig_msg, sizeof(sig_msg), "NOTE: Traffic Server received User Sig %d from pid: %d uid: %d\n",
00182                sig, t->si_pid, t->si_uid);
00183 #endif
00184     } else {
00185       snprintf(sig_msg, sizeof(sig_msg), "NOTE: Traffic Server received Kernel Sig %d, Reason: %d\n", sig, t->si_code);
00186     }
00187 
00188     write(2, sig_msg, strlen(sig_msg));
00189     //syslog(LOG_ERR, sig_msg);
00190   }
00191 #else
00192   snprintf(sig_msg, sizeof(sig_msg), "NOTE: Traffic Server received Sig %d: %s\n", sig, strsignal(sig));
00193   ATS_UNUSED_RETURN(write(2, sig_msg, strlen(sig_msg)));
00194   //syslog(LOG_ERR, sig_msg);
00195 #endif
00196 
00197 #if TS_HAS_PROFILER
00198   ProfilerStop();
00199 #endif
00200   shutdown_system();
00201 
00202   // Make sure to drop a core for signals that normally
00203   // would do so.
00204   switch (sig) {
00205   case SIGQUIT:
00206   case SIGILL:
00207   case SIGTRAP:
00208 #if !defined(linux)
00209   case SIGEMT:
00210   case SIGSYS:
00211 #endif
00212   case SIGFPE:
00213   case SIGBUS:
00214   case SIGXCPU:
00215   case SIGXFSZ:
00216   case SIGSEGV:
00217     ink_stack_trace_dump();
00218     signal(sig, SIG_DFL);
00219     return;
00220   case SIGUSR2:
00221     ink_stack_trace_dump();
00222     return;
00223   case SIGABRT:
00224   case SIGUSR1:
00225   default:
00226     _exit(sig);
00227   }
00228 }
00229 
00230 static void
00231 child_signal_handler(int sig)
00232 {
00233   (void) sig;
00234   int pid;
00235   int saved_errno = errno;
00236   while ((pid = waitpid(-1, 0, WNOHANG)) > 0) {
00237     fprintf(stderr, "child %d exited\n", pid);
00238     ++exited_children;
00239   }
00240   errno = saved_errno;
00241 }
00242 
00243 static void
00244 set_signal(int signal, SigActionFunc_t action_func)
00245 {
00246   struct sigaction action;
00247   struct sigaction o_action;
00248 
00249 #if !defined(linux) && !defined(freebsd)
00250   action.sa_handler = NULL;
00251   action.sa_sigaction = action_func;
00252 #else
00253   action.sa_handler = action_func;
00254 #endif
00255   // action.sa_mask = 0;                // changed 10/17/97 to make portable
00256   sigemptyset(&(action.sa_mask));       // changed 10/17/97 to make portable
00257   action.sa_flags = 0;
00258 
00259   int res = sigaction(signal, &action, &o_action);
00260   ink_release_assert(res == 0);
00261 }
00262 
00263 static void
00264 check_signal(int signal, SigActionFunc_t action_func)
00265 {
00266   struct sigaction action;
00267   struct sigaction o_action;
00268 
00269 #if !defined(linux) && !defined(freebsd)
00270   action.sa_handler = NULL;
00271   action.sa_sigaction = action_func;
00272   action.sa_flags = SA_SIGINFO;
00273 #else
00274   action.sa_handler = action_func;
00275   action.sa_flags = 0;
00276 #endif
00277   // action.sa_mask = 0;                // changed 10/17/97 to make portable
00278   sigemptyset(&(action.sa_mask));       // changed 10/17/97 to make portable
00279 
00280   int res = sigaction(signal, &action, &o_action);
00281   ink_release_assert(res == 0);
00282 
00283 #if !defined(linux) && !defined(freebsd)
00284   if (o_action.sa_sigaction != action_func) {
00285     fprintf(stderr, "Handler for signal %d was %p, not %p as expected\n", signal, o_action.sa_sigaction, action_func);
00286   }
00287 #endif
00288 }
00289 
00290 //
00291 // This is used during debugging to insure that the signals
00292 // don't change from under us, as they did on the DEC alpha
00293 // with a specific version of pthreads.
00294 //
00295 
00296 void
00297 check_signals()
00298 {
00299   check_signal(SIGPIPE, (SigActionFunc_t) SIG_IGN);
00300   check_signal(SIGQUIT, (SigActionFunc_t) signal_handler);
00301   check_signal(SIGHUP, (SigActionFunc_t) interrupt_handler);
00302   check_signal(SIGTERM, (SigActionFunc_t) signal_handler);
00303   check_signal(SIGINT, (SigActionFunc_t) signal_handler);
00304   check_signal(SIGUSR1, (SigActionFunc_t) signal_handler);
00305 }
00306 
00307 
00308 //
00309 // This thread checks the signals every 2 seconds to make
00310 // certain the DEC pthreads SIGPIPE bug isn't back..
00311 //
00312 #if !defined(linux) && !defined(freebsd) && defined(DEBUG)
00313 static void *
00314 check_signal_thread(void *)
00315 {
00316   for (;;) {
00317     check_signals();
00318     sleep(2);
00319   }
00320   return NULL;
00321 }
00322 #endif
00323 
00324 void
00325 init_signals(bool do_stackdump)
00326 {
00327   sigset_t sigsToBlock;
00328 
00329   sigemptyset(&sigsToBlock);
00330   ink_thread_sigsetmask(SIG_SETMASK, &sigsToBlock, NULL);
00331 
00332   set_signal(SIGPIPE, (SigActionFunc_t) SIG_IGN);
00333   set_signal(SIGQUIT, (SigActionFunc_t) signal_handler);
00334   set_signal(SIGTERM, (SigActionFunc_t) signal_handler);
00335   set_signal(SIGINT, (SigActionFunc_t) signal_handler);
00336   set_signal(SIGHUP, (SigActionFunc_t) interrupt_handler);
00337   set_signal(SIGILL, (SigActionFunc_t) signal_handler);
00338   if(do_stackdump) {
00339     set_signal(SIGBUS, (SigActionFunc_t) signal_handler);
00340     set_signal(SIGSEGV, (SigActionFunc_t) signal_handler);
00341   }
00342 
00343 //
00344 //    Presviously the following lines were #if 0
00345 //
00346 //  set_signal(SIGILL,(SigActionFunc_t)signal_handler);
00347 //  set_signal(SIGBUS,(SigActionFunc_t)signal_handler);
00348 //  set_signal(SIGSEGV,(SigActionFunc_t)signal_handler);
00349 //
00350 //  There was an an addtional #if 0 w/ a note about SIGABRT
00351 //   // Do not catch, results in recursive
00352 //   //  SIGABRT loop on solaris assert() failures
00353 //  set_signal(SIGABRT,(SigActionFunc_t)signal_handler);
00354 //
00355 #if !defined(freebsd)
00356   set_signal(SIGUSR1, (SigActionFunc_t) signal_handler);
00357 #endif
00358 
00359 #if defined(linux)
00360   set_signal(SIGUSR2, (SigActionFunc_t) signal_handler);
00361 #endif
00362 
00363 #if !defined(linux) && !defined(freebsd) && defined(DEBUG)
00364   ink_thread_create(check_signal_thread, NULL);
00365 #endif
00366 
00367   // do not handle these
00368   // ink_assert(signal(SIGINT,(SigActionFunc_t)interrupt_handler) != SIG_ERR);
00369 }
00370 
00371 
00372 int
00373 init_tracker(const char *config_var, RecDataT /* type ATS_UNUSED */, RecData data, void * /* cookie ATS_UNUSED */)
00374 {
00375   static Event *tracker_event = NULL;
00376   int dump_mem_info_frequency = 0;
00377 
00378   if (config_var)
00379     dump_mem_info_frequency = data.rec_int;
00380   else
00381     dump_mem_info_frequency = REC_ConfigReadInteger("proxy.config.dump_mem_info_frequency");
00382   Debug("tracker", "init_tracker called [%d]\n", dump_mem_info_frequency);
00383   if (tracker_event) {
00384     tracker_event->cancel();
00385     tracker_event = NULL;
00386   }
00387   if (dump_mem_info_frequency > 0) {
00388     tracker_event = eventProcessor.schedule_every(new TrackerContinuation,
00389                                                   HRTIME_SECONDS(dump_mem_info_frequency), ET_CALL);
00390   }
00391   return 1;
00392 }
00393 
00394 void
00395 init_signals2()
00396 {
00397   eventProcessor.schedule_every(new SignalContinuation, HRTIME_MSECOND * 500, ET_CALL);
00398   REC_RegisterConfigUpdateFunc("proxy.config.dump_mem_info_frequency", init_tracker, NULL);
00399   RecData data;
00400   data.rec_int = 0; // Shouldn't be used now anyways
00401   init_tracker(NULL, RECD_INT, data, NULL);
00402 }
00403 
00404 
00405 void
00406 init_daemon_signals()
00407 {
00408   struct sigaction act;
00409   ink_assert(signal(SIGCHLD, (VI_PFN) child_signal_handler) != SIG_ERR);
00410   act.sa_handler = (VI_PFN) child_signal_handler;
00411   ink_assert(!sigemptyset(&act.sa_mask));
00412   act.sa_flags = SA_NOCLDSTOP;
00413   ink_assert(!sigaction(SIGCHLD, &act, NULL));
00414 }

Generated by  doxygen 1.7.1