A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
fatal-impl.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010 NICTA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Quincy Tse <quincy.tse@nicta.com.au>
7 */
8#include "fatal-impl.h"
9
10#include "log.h"
11
12#include <csignal>
13#include <cstdio>
14#include <cstdlib>
15#include <iostream>
16#include <list>
17
18#ifdef __WIN32__
19struct sigaction
20{
21 void (*sa_handler)(int);
22 int sa_flags;
23 int sa_mask;
24};
25
26int
27sigaction(int sig, struct sigaction* action, struct sigaction* old)
28{
29 if (sig == -1)
30 {
31 return 0;
32 }
33 if (old == nullptr)
34 {
35 if (signal(sig, SIG_DFL) == SIG_ERR)
36 {
37 return -1;
38 }
39 }
40 else
41 {
42 if (signal(sig, action->sa_handler) == SIG_ERR)
43 {
44 return -1;
45 }
46 }
47 return 0;
48}
49#endif
50
51/**
52 * \file
53 * \ingroup fatalimpl
54 * \brief ns3::FatalImpl::RegisterStream(), ns3::FatalImpl::UnregisterStream(),
55 * and ns3::FatalImpl::FlushStreams() implementations;
56 * see Implementation note!
57 *
58 * \note Implementation.
59 *
60 * The singleton pattern we use here is tricky because we have to ensure:
61 *
62 * - RegisterStream() succeeds, even if called before \c main() enters and
63 * before any constructor run in this file.
64 *
65 * - UnregisterStream() succeeds, whether or not FlushStreams() has
66 * been called.
67 *
68 * - All memory allocated with \c new is deleted properly before program exit.
69 *
70 * This is why we go through all the painful hoops below.
71 */
72
73namespace ns3
74{
75
76NS_LOG_COMPONENT_DEFINE("FatalImpl");
77
78namespace FatalImpl
79{
80
81/**
82 * \ingroup fatalimpl
83 * Unnamed namespace for fatal streams memory implementation
84 * and signal handler.
85 */
86namespace
87{
88
89/**
90 * \ingroup fatalimpl
91 * \brief Static variable pointing to the list of output streams
92 * to be flushed on fatal errors.
93 *
94 * \returns The address of the static pointer.
95 */
96std::list<std::ostream*>**
98{
100 static std::list<std::ostream*>* streams = nullptr;
101 return &streams;
102}
103
104/**
105 * \ingroup fatalimpl
106 * \brief Get the stream list, initializing it if necessary.
107 *
108 * \returns The stream list.
109 */
110std::list<std::ostream*>*
112{
114 std::list<std::ostream*>** pstreams = PeekStreamList();
115 if (*pstreams == nullptr)
116 {
117 *pstreams = new std::list<std::ostream*>();
118 }
119 return *pstreams;
120}
121
122} // unnamed namespace
123
124void
125RegisterStream(std::ostream* stream)
126{
127 NS_LOG_FUNCTION(stream);
128 GetStreamList()->push_back(stream);
129}
130
131void
132UnregisterStream(std::ostream* stream)
133{
134 NS_LOG_FUNCTION(stream);
135 std::list<std::ostream*>** pl = PeekStreamList();
136 if (*pl == nullptr)
137 {
138 return;
139 }
140 (*pl)->remove(stream);
141 if ((*pl)->empty())
142 {
143 delete *pl;
144 *pl = nullptr;
145 }
146}
147
148/**
149 * \ingroup fatalimpl
150 * Unnamed namespace for fatal streams signal handler.
151 *
152 * This is private to the fatal implementation.
153 */
154namespace
155{
156
157/**
158 * \ingroup fatalimpl
159 * \brief Overrides normal SIGSEGV handler once the HandleTerminate
160 * function is run.
161 *
162 * This is private to the fatal implementation.
163 *
164 * \param [in] sig The signal condition.
165 */
166void
168{
169 NS_LOG_FUNCTION(sig);
170 FlushStreams();
171 std::abort();
172}
173} // unnamed namespace
174
175void
177{
179 std::list<std::ostream*>** pl = PeekStreamList();
180 if (*pl == nullptr)
181 {
182 return;
183 }
184
185 /* Override default SIGSEGV handler - will flush subsequent
186 * streams even if one of the stream pointers is bad.
187 * The SIGSEGV override should only be active for the
188 * duration of this function. */
189 struct sigaction hdl;
190 hdl.sa_handler = sigHandler;
191 sigaction(SIGSEGV, &hdl, nullptr);
192
193 std::list<std::ostream*>* l = *pl;
194
195 /* Need to do it this way in case any of the ostream* causes SIGSEGV */
196 while (!l->empty())
197 {
198 std::ostream* s(l->front());
199 l->pop_front();
200 s->flush();
201 }
202
203 /* Restore default SIGSEGV handler (Not that it matters anyway) */
204 hdl.sa_handler = SIG_DFL;
205 sigaction(SIGSEGV, &hdl, nullptr);
206
207 /* Flush all opened FILE* */
208 std::fflush(nullptr);
209
210 /* Flush stdandard streams - shouldn't be required (except for clog) */
211 std::cout.flush();
212 std::cerr.flush();
213 std::clog.flush();
214
215 delete l;
216 *pl = nullptr;
217}
218
219} // namespace FatalImpl
220
221} // namespace ns3
ns3::FatalImpl::RegisterStream(), ns3::FatalImpl::UnregisterStream(), and ns3::FatalImpl::FlushStream...
void UnregisterStream(std::ostream *stream)
Unregister a stream for flushing on abnormal exit.
std::list< std::ostream * > ** PeekStreamList()
Static variable pointing to the list of output streams to be flushed on fatal errors.
Definition fatal-impl.cc:97
void sigHandler(int sig)
Overrides normal SIGSEGV handler once the HandleTerminate function is run.
std::list< std::ostream * > * GetStreamList()
Get the stream list, initializing it if necessary.
void RegisterStream(std::ostream *stream)
Register a stream to be flushed on abnormal exit.
void FlushStreams()
Flush all currently registered streams.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.