LDMX Software
fire.cxx
1
2//----------------//
3// C++ StdLib //
4//----------------//
5#include <signal.h>
6#include <stdio.h>
7#include <string.h>
8#include <unistd.h>
9
10#include <iostream>
11
12//-------------//
13// ldmx-sw //
14//-------------//
15#include "Framework/Configure/Python.h"
16#include "Framework/Process.h"
17
22// using namespace framework;
23
24// This code allows ldmx-app to exit gracefully when receiving preemption
25// signals from the SDF (SIGUSR2) or Ctrl-c (SIGINT). It finishes the current
26// event and closes ROOT files properly instead of losing work.
27// NOTE: This seems to be container dependent. It has been tested and works
28// with apptainer v1.2 (at SDF) while does not work with podman.
29// NOLINTNEXTLINE(readability-identifier-naming)
30extern volatile std::sig_atomic_t preemption_received_;
31
32static void softFinish(int sig, siginfo_t* siginfo, void* context) {
33 preemption_received_ = 1;
34}
35
41void printUsage();
42
52int main(int argc, char* argv[]) try {
53 if (argc < 2) {
54 printUsage();
55 return 2;
56 }
57
58 int ptrpy = 1;
59 for (ptrpy = 1; ptrpy < argc; ptrpy++) {
60 if (strstr(argv[ptrpy], ".py")) break;
61 }
62
63 if (ptrpy == argc) {
64 printUsage();
65 std::cout << " ** No python configuration script provided (must end in "
66 "'.py'). ** "
67 << std::endl;
68 return 3;
69 }
70
71 std::cout << "---- LDMXSW: Loading configuration --------" << std::endl;
72
74 try {
76 framework::config::run("ldmxcfg.Process.lastProcess", argv[ptrpy],
77 argv + ptrpy + 1, argc - ptrpy - 1)};
78 p = std::make_unique<framework::Process>(config);
79 } catch (const framework::exception::Exception& e) {
80 // Error message currently printed twice since the stack trace code
81 // sometimes crashes. Once this is fixed, the output above the stack trace
82 // can be removed
83 // https://github.com/LDMX-Software/Framework/issues/50
84 std::cerr << "Configuration Error [" << e.name() << "] : " << e.message()
85 << std::endl;
86 std::cerr << " at " << e.module() << ":" << e.line() << " in "
87 << e.function() << std::endl;
88 return 4;
89 }
90
91 std::cout << "---- LDMXSW: Configuration load complete --------"
92 << std::endl;
93
94 // Setup signal handlers for graceful shutdown
95 struct sigaction act;
96 memset(&act, '\0', sizeof(act));
97 act.sa_sigaction = &softFinish;
98 act.sa_flags = SA_SIGINFO;
99
100 // Handle SIGUSR2 (SDF preemption signal)
101 if (sigaction(SIGUSR2, &act, NULL) < 0) {
102 std::cerr << "Error setting up SIGUSR2 handler: " << strerror(errno)
103 << std::endl;
104 return 5;
105 }
106
107 // Also handle SIGINT (Ctrl-C)
108 if (sigaction(SIGINT, &act, NULL) < 0) {
109 std::cerr << "Error setting up SIGINT handler: " << strerror(errno)
110 << std::endl;
111 return 5;
112 }
113
114 std::cout << "---- LDMXSW: Starting event processing --------" << std::endl;
115
116 try {
117 p->run();
118 } catch (const framework::exception::Exception& e) {
119 // Process::run opens up the logging using the parameters passed to it from
120 // python
121 // if an Exception is thrown, we haven't gotten to the end of Process::run
122 // where logging is closed, so we can do one more error message and then
123 // close it.
124 // ldmx_log macro needs this variable to be named 'the_log_'
125 // NOLINTNEXTLINE(readability-identifier-naming)
126 auto the_log_{framework::logging::makeLogger("fire")};
127 ldmx_log(fatal) << "[" << e.name() << "] : " << e.message() << "\n"
128 << " at " << e.module() << ":" << e.line() << " in "
129 << e.function();
130 ldmx_log(debug) << e.stackTrace();
131 framework::logging::close();
132 return 6; // return non-zero error-status
133 }
134
135 std::cout << "---- LDMXSW: Event processing complete --------" << std::endl;
136 return 0;
137} catch (const std::exception& e) {
138 std::cerr << "Unrecognized Exception: " << e.what() << std::endl;
139 return 127;
140}
141
142void printUsage() {
143 std::cout << "Usage: fire {configuration_script.py} [arguments to "
144 "configuration script]"
145 << std::endl;
146 std::cout << " configuration_script.py (required) python script to "
147 "configure the processing"
148 << std::endl;
149 std::cout << " arguments (optional) passed to "
150 "configuration script when run in python"
151 << std::endl;
152}
Class which represents the process under execution.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
Standard base exception class with some useful output information.
Definition Exception.h:20
const std::string & function() const
Get the function name where the exception occurred.
Definition Exception.h:74
int line() const
Get the source line number where the exception occurred.
Definition Exception.h:80
const std::string & message() const
Get the message of the exception.
Definition Exception.h:62
const std::string & name() const
Get the name of the exception.
Definition Exception.h:56
const std::string & stackTrace() const
Get the full stack trace.
Definition Exception.h:91
const std::string & module() const
Get the source filename where the exception occurred.
Definition Exception.h:68
Parameters run(const std::string &root_object, const std::string &pythonScript, char *args[], int nargs)
run the python script and extract the parameters
Definition Python.cxx:300
std::unique_ptr< Process > ProcessHandle
A handle to the current process Used to pass a process from ConfigurePython to fire....
Definition Process.h:234