Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4ios.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4ios implementation
27//
28// Authors: H.Yoshida, M.Nagamatu - November 1998
29// --------------------------------------------------------------------
30
31#include "G4ios.hh"
32
33#include "G4coutDestination.hh"
34#include "G4Threading.hh"
35#include "G4AutoLock.hh"
36
37#include <iostream>
38
39namespace
40{
41// We need a mutex to be able to syncronize writes to std::cout etc at shutdown
42#ifdef G4MULTITHREADED
43G4Mutex g_stream_finalization_mutex;
44#endif
45
46// Concrete streambuf redirecting output to G4coutDestination via G4cout etc
47// Templated on two policy types to determine:
48// - DestinationPolicy: which member member function of G4coutDestination to redirect to
49// - DefaultPolicy: what to do if G4coutDestination is default (nullptr)
50template <typename DestinationPolicy, typename DefaultPolicy>
51class G4strstreambuf : public std::basic_streambuf<char>
52{
53 public:
54 G4strstreambuf()
55 {
56 size = 4095;
57 buffer = new char[size + 1];
58 }
59
60 ~G4strstreambuf() override
61 {
62 delete[] buffer;
63 }
64
65 G4strstreambuf(const G4strstreambuf&) = delete;
66 G4strstreambuf& operator=(const G4strstreambuf&) = delete;
67
68 G4int overflow(G4int c = EOF) override
69 {
70 G4int result = 0;
71 if (count >= size) result = sync();
72
73 buffer[count] = (char)c;
74 count++;
75
76 return result;
77 }
78
79 G4int sync() override
80 {
81 buffer[count] = '\0';
82 count = 0;
83 return ReceiveString();
84 }
85
86#ifdef WIN32
87 virtual G4int underflow() { return 0; }
88#endif
89
90 void SetDestination(G4coutDestination* dest) { destination = dest; }
91
92 inline G4int ReceiveString()
93 {
94 G4String stringToSend(buffer);
95 if (destination != nullptr) {
96 return DestinationPolicy::PostMessage(destination, stringToSend);
97 }
98 return DefaultPolicy::PostMessage(stringToSend);
99 }
100
101 private:
102 char* buffer = nullptr;
103 G4int count = 0;
104 G4int size = 0;
105 G4coutDestination* destination = nullptr;
106};
107
108// Policies
109struct PostToG4debug
110{
111 static inline G4int PostMessage(G4coutDestination* d, const G4String& s)
112 {
113 return d->ReceiveG4debug_(s);
114 }
115};
116
117struct PostToG4cout
118{
119 static inline G4int PostMessage(G4coutDestination* d, const G4String& s)
120 {
121 return d->ReceiveG4cout_(s);
122 }
123};
124
125struct PostToG4cerr
126{
127 static inline G4int PostMessage(G4coutDestination* d, const G4String& s)
128 {
129 return d->ReceiveG4cerr_(s);
130 }
131};
132
133struct DefaultToCout
134{
135 static inline G4int PostMessage(const G4String& s)
136 {
137 std::cout << s << std::flush;
138 return 0;
139 }
140};
141
142struct DefaultToCerr
143{
144 static inline G4int PostMessage(const G4String& s)
145 {
146 std::cerr << s << std::flush;
147 return 0;
148 }
149};
150
151using G4debugstreambuf = G4strstreambuf<PostToG4debug, DefaultToCout>;
152using G4coutstreambuf = G4strstreambuf<PostToG4cout, DefaultToCout>;
153using G4cerrstreambuf = G4strstreambuf<PostToG4cerr, DefaultToCerr>;
154} // namespace
155
156#ifdef G4MULTITHREADED
157// --- StreamBuffers
158G4debugstreambuf*& _G4debugbuf_p()
159{
160 G4ThreadLocalStatic auto* _instance = new G4debugstreambuf;
161 return _instance;
162}
163
164G4coutstreambuf*& _G4coutbuf_p()
165{
166 G4ThreadLocalStatic auto* _instance = new G4coutstreambuf;
167 return _instance;
168}
169
170G4cerrstreambuf*& _G4cerrbuf_p()
171{
172 G4ThreadLocalStatic auto* _instance = new G4cerrstreambuf;
173 return _instance;
174}
175
176// --- Streams
177std::ostream*& _G4debug_p()
178{
179 G4ThreadLocalStatic auto* _instance = new std::ostream(_G4debugbuf_p());
180 return _instance;
181}
182
183std::ostream*& _G4cout_p()
184{
185 G4ThreadLocalStatic auto* _instance = new std::ostream(_G4coutbuf_p());
186 return _instance;
187}
188
189std::ostream*& _G4cerr_p()
190{
191 G4ThreadLocalStatic auto* _instance = new std::ostream(_G4cerrbuf_p());
192 return _instance;
193}
194
196{
197 // --- Stream Buffers
198 if (_G4debugbuf_p() == nullptr) {
199 _G4debugbuf_p() = new G4debugstreambuf;
200 }
201 if (_G4coutbuf_p() == nullptr) {
202 _G4coutbuf_p() = new G4coutstreambuf;
203 }
204 if (_G4cerrbuf_p() == nullptr) {
205 _G4cerrbuf_p() = new G4cerrstreambuf;
206 }
207
208 // --- Streams
209 if (_G4debug_p() == &std::cout || _G4debug_p() == nullptr) {
210 _G4debug_p() = new std::ostream(_G4debugbuf_p());
211 }
212 if (_G4cout_p() == &std::cout || _G4cout_p() == nullptr) {
213 _G4cout_p() = new std::ostream(_G4coutbuf_p());
214 }
215 if (_G4cerr_p() == &std::cerr || _G4cerr_p() == nullptr) {
216 _G4cerr_p() = new std::ostream(_G4cerrbuf_p());
217 }
218}
219
221{
222 G4AutoLock lock_(&g_stream_finalization_mutex);
223 // Reverse order
224 // --- Flush
225 _G4debug_p()->flush();
226 _G4cout_p()->flush();
227 _G4cerr_p()->flush();
228
229 // --- Streams
230 delete _G4debug_p();
231 _G4debug_p() = &std::cout;
232 delete _G4cout_p();
233 _G4cout_p() = &std::cout;
234 delete _G4cerr_p();
235 _G4cerr_p() = &std::cerr;
236
237 // --- Stream Buffers
238 delete _G4debugbuf_p();
239 _G4debugbuf_p() = nullptr;
240 delete _G4coutbuf_p();
241 _G4coutbuf_p() = nullptr;
242 delete _G4cerrbuf_p();
243 _G4cerrbuf_p() = nullptr;
244}
245
246# define G4debugbuf (*_G4debugbuf_p())
247# define G4coutbuf (*_G4coutbuf_p())
248# define G4cerrbuf (*_G4cerrbuf_p())
249
250// We want to trigger initialization at load time and
251// finalization at unloading time. Directly manipulating
252// the `.init/.fini` section using the `__attribute__((constructor))`
253// (beside that it does not work on Windows) does not work
254// where Geant4 is built with static libraries but a downstream
255// package is built with shared library and has also executable
256// that are linking against those shared library and directly
257// to the Geant4 static libraries (for example if the executable
258// code calls Geant4 directly in addition to indirectly through
259// the shared library).
260// In this example, the explicit `.init/.fini` manipulations are
261// added twice (because the linker is asked to link with this .o
262// file twice and each time needs to add the init and finalization)
263// This issue appear also for the initialization on an file static
264// including those declared as function static in anonymous namespace.
265// To get the behavior we need (where the G4iosFinalization
266// and G4iosFinalization are called exactly once), we need to
267// associate the initialization with a symbol and/or mechanism that
268// the linker is told to de-duplicate even in the example described
269// above. So we use an extern object that is guaranteed to be only
270// initialized once.
271namespace
272{
273struct RAII_G4iosSystem {
274 RAII_G4iosSystem() {
276 }
277 ~RAII_G4iosSystem() {
279 }
280};
281} // namespace
282// Extern but not user reachable (anonymous type)
283// We want the linker to only create one of those.
284extern "C" RAII_G4iosSystem RAII_G4iosSystemObj;
285
286#else // Sequential
287
288G4debugstreambuf G4debugbuf;
289G4coutstreambuf G4coutbuf;
290G4cerrstreambuf G4cerrbuf;
291
292std::ostream G4debug(&G4debugbuf);
293std::ostream G4cout(&G4coutbuf);
294std::ostream G4cerr(&G4cerrbuf);
295
298 G4debug.flush();
299 G4cout.flush();
300 G4cerr.flush();
301}
302
303#endif
304
306{
307 G4debugbuf.SetDestination(sink);
308 G4coutbuf.SetDestination(sink);
309 G4cerrbuf.SetDestination(sink);
310}
G4TemplateAutoLock< G4Mutex > G4AutoLock
G4PVDivision & operator=(const G4PVDivision &)=delete
std::mutex G4Mutex
int G4int
Definition G4Types.hh:85
G4debugstreambuf G4debugbuf
Definition G4ios.cc:288
void G4iosFinalization()
Definition G4ios.cc:297
void G4iosSetDestination(G4coutDestination *sink)
Definition G4ios.cc:305
G4coutstreambuf G4coutbuf
Definition G4ios.cc:289
G4cerrstreambuf G4cerrbuf
Definition G4ios.cc:290
void G4iosInitialization()
Definition G4ios.cc:296
G4GLOB_DLL std::ostream G4debug
void G4iosFinalization()
Definition G4ios.cc:297
G4GLOB_DLL std::ostream G4cerr
G4GLOB_DLL std::ostream G4cout
void G4iosInitialization()
Definition G4ios.cc:296
G4int ReceiveG4cout_(const G4String &msg)
G4int ReceiveG4debug_(const G4String &msg)
G4int ReceiveG4cerr_(const G4String &msg)
#define G4ThreadLocalStatic
Definition tls.hh:76