21#include <sys/sysinfo.h>
24#include <mach/mach_init.h>
36#include "Gaudi/Property.h"
37#include "GaudiKernel/IAlgorithm.h"
38#include "GaudiKernel/IIncidentSvc.h"
39#include "GaudiKernel/IAlgContextSvc.h"
40#include "GaudiKernel/IAlgExecStateSvc.h"
41#include "GaudiKernel/IAlgManager.h"
42#include "GaudiKernel/ServiceHandle.h"
43#include "GaudiKernel/System.h"
44#include "GaudiKernel/ConcurrencyFlags.h"
45#include "GaudiKernel/EventContext.h"
58 const char*
const horizLine =
"-------------------------------------------------------------------------------------\n";
60 void ExitOnInt(
int sig,
siginfo_t*,
void* ) {
61 if ( sig == SIGINT ) {
64 std::println (std::cerr,
"Athena CRITICAL stopped by user interrupt");
89 std::ostream* ostr(&std::cout);
104 const int maxcalls = 64;
105 static std::atomic<int> ncalls (0);
106 if (++ncalls >= maxcalls) _exit (98);
108 static std::mutex tidlist_mutex;
112 pthread_t self = pthread_self();
113 std::lock_guard<std::mutex>
lock (tidlist_mutex);
114 for (
size_t i = 0; i < ntids; i++) {
115 if (pthread_equal (self, tids[i]))
return;
117 if (ntids == maxcalls) _exit (98);
118 tids[ntids++] = self;
122 static std::atomic<int> inThreads = 0;
125 const unsigned int timeoutSeconds =
static_cast<unsigned int>(round(
coreDumpSvc->m_timeout * 1e-9));
127 if ( sig == SIGALRM) {
129 std::println (log(),
"Received SIGALRM. Aborting job...");
135 std::println (log(),
"Received SIGALRM. Terminating job...");
146 static std::mutex threadMutex;
147 const timespec one_second { 1, 0 };
149 unsigned int waits = 0;
150 while (!threadMutex.try_lock()) {
151 nanosleep (&one_second,
nullptr);
152 if (++waits > timeoutSeconds) _exit (97);
157 if ( timeoutSeconds > 0 && (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT) ) {
159 alarm(timeoutSeconds);
165 write (1, horizLine, strlen(horizLine));
166 const char*
msg =
"Producing (fast) stack trace...\n";
167 write (1,
msg, strlen (
msg));
168 write (1, horizLine, strlen(horizLine));
169 Athena::Signal::fatalDump (sig, info, extra,
170 Athena::DebugAids::stacktraceFd(),
186 std::print (log(),
"{}Producing stack trace (can be slow, check gdb process)...\n{}",
187 horizLine, horizLine);
189 gSystem->StackTrace();
190 std::println (log());
197 std::print (log(),
"{}Invoking previous signal handler (can be slow, check gdb process)...\n{}",
198 horizLine, horizLine);
200 if ( oact.sa_flags & SA_SIGINFO ) {
201 oact.sa_sigaction(sig, info, extra);
203 else if (oact.sa_handler != SIG_DFL && oact.sa_handler != SIG_IGN ) {
204 oact.sa_handler(sig);
207 std::println (log(),
"Could not invoke previous signal handler");
212 threadMutex.unlock();
215 if (
coreDumpSvc && (sig == SIGSEGV || sig == SIGBUS || sig == SIGABRT) ) {
218 unsigned int waits = 0;
219 while (inThreads > 0 && waits < timeoutSeconds) {
220 nanosleep (&one_second,
nullptr);
224 std::println (log(),
"Aborting job... ");
241 base_class( name, pSvcLocator )
247 m_dumpCoreFile.declareUpdateHandler(&CoreDumpSvc::propertyHandler,
this);
248 m_stackTrace.declareUpdateHandler(&CoreDumpSvc::propertyHandler,
this);
252 m_killOnSigInt.declareUpdateHandler(&CoreDumpSvc::propertyHandler,
this);
263void CoreDumpSvc::propertyHandler(Gaudi::Details::PropertyBase& p)
271 const std::string val = p.toString();
272 if ( val==
"stdout" ) {
273 CoreDumpSvcHandler::ostr = &std::cout;
275 else if ( val==
"stderr" ) {
276 CoreDumpSvcHandler::ostr = &std::cerr;
290 ATH_MSG_INFO(
"could not convert [{}] to integer",
p.toString());
322 if ( installSignalHandler().isFailure() ) {
324 return StatusCode::FAILURE;
328 ServiceHandle<IIncidentSvc> incSvc(
"IncidentSvc",
name());
329 if ( !incSvc.retrieve().isSuccess() ) {
333 incSvc->addListener(
this, IncidentType::BeginRun);
334 incSvc->addListener(
this, IncidentType::BeginEvent);
335 incSvc->addListener(
this, IncidentType::EndRun);
336 incSvc->addListener(
this, IncidentType::EndEvent);
337 incSvc->addListener(
this,
"StoreCleared");
340 return StatusCode::SUCCESS;
345 auto numSlots = std::max<size_t>(1, Gaudi::Concurrency::ConcurrencyFlags::numConcurrentEvents());
348 return StatusCode::SUCCESS;
351StatusCode CoreDumpSvc::finalize()
355 if ( uninstallSignalHandler().isFailure() ) {
357 return StatusCode::FAILURE;
360 return StatusCode::SUCCESS;
377 auto slot = ctx.valid() ? ctx.slot() : 0;
387 std::println (CoreDumpSvcHandler::log(),
388 "{} FATAL Caught fatal signal. Printing details to {}{}",
389 name(), m_coreDumpStream.value(),
390 (m_dumpCoreFile ?
". Will try to produce a core dump file on exit." :
"."));
392 CoreDumpSvcHandler::log() <<
dump() << std::flush;
400 std::ostringstream os;
402 const time_t now = time(
nullptr);
404#define PR(FMT, ...) std::println(os, FMT __VA_OPT__(,) __VA_ARGS__)
406 PR(
"-------------------------------------------------------------------------------------");
407 std::print (os,
"Core dump from {} on {} at {}",
408 name(), System::hostName(), ctime_r(&now, buf));
415 PR (
"Caught signal {}({}). Details: ", signo, strsignal(signo));
417 PR (
" errno = {}, code = {} ({})",
429 const long pagesz = sysconf(_SC_PAGESIZE);
430 PR (
" vmem = {} MB\n"
432 s.vm_pages*pagesz/1024./1024., s.rss_pages*pagesz/1024./1024.);
440 if ( 0 == sysinfo(&sys) ) {
442 const float mem_units = sys.mem_unit/(1024.*1024.);
443 PR (
" total-ram = {} MB\n"
444 " free-ram = {} MB\n"
445 " buffer-ram= {} MB\n"
446 " total-swap= {} MB\n"
447 " free-swap = {} MB",
448 sys.totalram * mem_units,
449 sys.freeram * mem_units,
450 sys.bufferram* mem_units,
451 sys.totalswap* mem_units,
452 sys.freeswap * mem_units);
458 if (signo == SIGILL || signo == SIGFPE || signo == SIGSEGV || signo == SIGBUS)
466 SmartIF<IAlgManager> algMgr{serviceLocator()->as<IAlgManager>()};
467 SmartIF<IAlgContextSvc> algContextSvc;
471 if (Gaudi::Concurrency::ConcurrencyFlags::numConcurrentEvents() == 0) {
472 algContextSvc = service(
"AlgContextSvc",
false);
479 std::string currentAlg;
482 if (Gaudi::Concurrency::ConcurrencyFlags::numConcurrentEvents() > 0) {
483 const EventContext ctx(0,t);
484 ATH_MSG_DEBUG(
"Using AlgExecStateSvc to determine current algorithm(s)");
486 for (
const IAlgorithm* alg : algMgr->getAlgorithms()) {
487 auto aes = alg->execState(ctx);
488 if (aes.state()==AlgExecState::State::Executing)
489 currentAlg += (alg->name() +
" ");
492 catch (
const GaudiException&) {
493 ATH_MSG_INFO(
"No information from AlgExecStateSvc because no algorithm was executed yet.");
496 else if (algContextSvc) {
497 ATH_MSG_DEBUG(
"Using AlgContextSvc to determine current algorithm");
498 IAlgorithm* alg = algContextSvc->currentAlg();
499 if (alg) currentAlg = alg->name();
502 ATH_MSG_WARNING(
"AlgExecStateSvc or AlgContextSvc not available. Cannot determine current algorithm.");
505 if (currentAlg.empty()) currentAlg =
"<NONE>";
506 PR (
"Slot {:3} : Current algorithm = {}", t, currentAlg);
510 if (!sys.LastInc.empty()) {
511 PR (
" : Last Incident = {}\n"
513 sys.LastInc, sys.EvId);
519 for (
auto &s : usr) {
520 PR (
" : (usr) {} = {}", s.first, s.second);
526 std::print (os,
"Algorithm stack: ");
527 if ( algContextSvc->algorithms().empty() )
531 for (
auto alg : algContextSvc->algorithms()) {
532 if (alg)
PR (
" {}", alg->name());
538 "| AtlasBaseDir : {:66} |\n"
539 "| AtlasVersion : {:66} |\n"
540 "| BINARY_TAG : {:66} |\n"
542 " Note: to see line numbers in below stacktrace you might consider running following :\n"
543 " atlasAddress2Line --file <logfile>",
545 getenv(
"AtlasBaseDir"),
546 getenv(
"AtlasVersion"),
547 getenv(
"BINARY_TAG"),
550 SmartIF<IAthenaSummarySvc> iass{service(
"AthenaSummarySvc",
false)};
552 iass->addSummary(
"CoreDumpSvc",os.str());
554 iass->createSummary().ignore();
568 auto slot = incident.context().valid() ? incident.context().slot() : 0;
571 currRec.LastInc = incident.source() +
":" + incident.type();
573 std::ostringstream oss;
574 oss << incident.context().eventID();
575 currRec.EvId = oss.str();
577 if (incident.type()==IncidentType::BeginEvent) {
581 }
else if (incident.type() ==
"StoreCleared") {
583 auto newstr = currRec.EvId;
586 newstr[0] = newstr[0];
587 currRec.EvId = std::move(newstr);
602 std::ostringstream oss;
604 for (
auto sig : m_signals) {
606 if (sig<1 || sig>SIGRTMAX) {
611 std::print (oss,
"{}({}) ", sig, strsignal(sig));
617 struct sigaction sigact;
618 memset (&sigact, 0,
sizeof(sigact));
619 sigact.sa_sigaction = CoreDumpSvcHandler::action;
621 sigact.sa_flags = SA_SIGINFO + SA_ONSTACK;
624 ATH_MSG_ERROR (
"Error on installing handler for signal {}: {}",
625 sig, strerror(errno));
626 return StatusCode::FAILURE;
631 return StatusCode::SUCCESS;
644 int ret = sigaction(kv.first, &(kv.second),
nullptr);
646 sc = StatusCode::FAILURE;
648 kv.first, strerror(errno));
662 std::vector<uint8_t>& stack =
s_stack;
664 stack.resize (std::max (SIGSTKSZ, MINSIGSTKSZ) + 2*1024*1024);
666 ss.ss_sp = stack.data();
668 ss.ss_size = stack.size();
669 int ret = sigaltstack (&
ss,
nullptr);
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
void CoreDumpSvc::print ATLAS_NOT_THREAD_SAFE()
Install fatal handler with default options.
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
Collecting a few shared bits and pieces from SEAL headers.
#define IOFD_INVALID
Invalid channel descriptor constant.
This are the SEAL debug aids, adapted to build in Atlas, after the drop of that project.
This is the signal handler from SEAL, adapted to build in Atlas, after the drop of that project.
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
static const int FATAL_DUMP_CONTEXT
Option to make fataldump(int, siginfo_t *, void *) (invoked by fatal(int, siginfo_t *,...
static const char * describe(int sig, int code)
Return the description for signal info code code for signal number sig.
static void revert(int sig)
Revert the signal number sig back to its default behaviour.
static const int FATAL_DUMP_SIG
Option to make fataldump(int, siginfo_t *, void *) (invoked by fatal(int, siginfo_t *,...
static HandlerType handle(int sig, HandlerType handler, const sigset_t *blockMask=0)
Install a new signal handler handler for signal number sig and returns the old handler.
static const int FATAL_DUMP_STACK
Option to make fataldump(int, siginfo_t *, void *) (invoked by fatal(int, siginfo_t *,...
Service to print additional information before a crash.
siginfo_t * m_siginfo
Pointer to siginfo_t struct (set by signal handler).
void setAltStack()
Set up an alternate stack for the current thread.
static std::vector< uint8_t > s_stack
virtual StatusCode start() override
Gaudi::Property< int > m_fatalHandlerFlags
std::vector< UserCore_t > m_usrCoreDumps
User defined core dump info.
Gaudi::Property< bool > m_callOldHandler
Gaudi::Property< bool > m_stackTrace
virtual std::string dump() const override
Print all core dump records.
virtual void handle(const Incident &incident) override
Incident listener.
virtual ~CoreDumpSvc() ATLAS_CTORDTOR_NOT_THREAD_SAFE
Destructor.
virtual void setCoreDumpInfo(const std::string &name, const std::string &value) override
Set a name/value pair in the core dump record.
Gaudi::Property< bool > m_dumpCoreFile
Gaudi::Property< bool > m_killOnSigInt
CoreDumpSvc()
Default constructor (do not use).
Gaudi::Property< std::string > m_coreDumpStream
std::vector< sysDumpRec > m_sysCoreDumps
Core dump info collected by this service.
std::atomic< EventID::event_number_t > m_eventCounter
Event counter.
Gaudi::Property< bool > m_fastStackTrace
Signal handler for CoreDumpSvc.
CoreDumpSvc * coreDumpSvc(nullptr)
pointer to CoreDumpSvc
SigHandler_t oldSigHandler
old signal handlers
std::map< int, struct sigaction > SigHandler_t
std::ostream &log ATLAS_NOT_THREAD_SAFE()
convenience method for logging
bool dumpCoreFile(false)
dump core file on exit?
bool callOldHandler(true)
forward calls to old handlers?
bool stackTrace(false)
produce stack trace?
bool fastStackTrace(false)
produce fast stack trace using CxxUtils/Seal
::StatusCode StatusCode
StatusCode definition for legacy code.
void raise(const std::string &msg)
struct athena_statm read_athena_statm()