libcwdversion 2.0.0
The C++ Debugging Support Library
Loading...
Searching...
No Matches
DebugObject.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2000-2005, 2018-2021, 2023, 2026 Carlo Wood
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
9
10#ifndef LIBCWD_CLASS_DEBUG_H
11#define LIBCWD_CLASS_DEBUG_H
12
13#include "ChannelSet.h"
16#include "DebugObject_ThreadSpecificData.h"
17#include "libcwd/config.h"
18
19#include <atomic>
20#include <cstddef>
21#include <iosfwd>
22#include <mutex>
23
24namespace libcwd {
25
26class Buffer;
27
28#ifndef HIDE_FROM_DOXYGEN
29namespace _private_ {
30
31// Store the ostream destination together with the lock that protects writes to it.
32//
33struct OstreamState
34{
35 private:
36 mutable std::mutex state_mutex_; // Protects real_os_ and mutex_ as one pair.
37 std::ostream*
38 real_os_{}; // The destination selected with DebugObject::set_ostream. mutex points at the user-provided lock
39 LockInterfaceBase* mutex_{}; // User-provided lock adapter for that stream, or null while the debug object is still
40 // limited to single-threaded output.
41
42 public:
43 // Replace both the ostream and its lock adapter with os and new_mutex.
44 //
45 // Returns the old lock adapter after waiting until all writers that already selected the old pair have left
46 // the old stream critical area. The returned adapter is no longer reachable through this state object.
47 LockInterfaceBase* replace_with(std::ostream* os, LockInterfaceBase* new_mutex);
48
49 // Replace only the ostream with os while keeping the current lock adapter.
50 //
51 // If a lock adapter is present, this waits for old writers before returning so the previous ostream can be
52 // destroyed safely after DebugObject::set_ostream(std::ostream*) returns.
53 void set_ostream(std::ostream* os);
54
55 // Return the currently selected ostream without locking its stream mutex.
56 //
57 // This is a snapshot accessor for the legacy public API; callers must not use the returned pointer as a
58 // lifetime guarantee against concurrent set_ostream calls.
59 std::ostream* read_real_os() const;
60
61 // Return true when this state currently has a stream lock adapter.
62 bool has_mutex() const;
63
64 // Return os, or the stored ostream when os is null, after locking the current stream lock adapter.
65 //
66 // locked_mutex_out receives the adapter that was locked, or null when no adapter is installed.
67 // If a non-null adapter is returned then the caller must unlock it after finishing the write.
68 std::ostream* get_locked_os(std::ostream* os, LockInterfaceBase** locked_mutex_out) const;
69
70 // Try to select os, or the stored ostream when os is null, and lock the current stream lock adapter.
71 //
72 // Returns true after publishing locked_os_out and locked_mutex_out. If a lock adapter exists,
73 // it has been successfully locked before the pair is published. If no adapter exists,
74 // *locked_mutex_out is null and the ostream is returned unlocked.
75 //
76 // Returns false when a lock adapter exists but could not be locked immediately; in that case
77 // neither protected pointer is published.
78 bool try_lock_os(std::ostream* os, std::ostream** locked_os_out, LockInterfaceBase** locked_mutex_out) const;
79
80 // Write color_off followed by a newline to os, or to the stored ostream when os is null.
81 //
82 // This helper is used only for the legacy bounded-try-lock fallback path where output proceeds without
83 // holding the stream lock adapter; keeping the state access inside this call still protects pointer lifetime.
84 void write_color_off_newline(std::ostream* os, char const* color_off, std::size_t color_off_size) const;
85};
86
87} // namespace _private_
88#endif // HIDE_FROM_DOXYGEN
89
90//===================================================================================================
91// class DebugObject
92//
93// Note: Debug output is printed already *before* this object is constructed,
94// and is still printed when this object is already destructed.
95// This is why initialization is done with method init() *before* construction
96// and debug is turned off when this object is destructed.
97// I hope that this is no problem because libcwd::libcw_do is a global object.
98// It means however that this object can not contain any attributes that have
99// a constructor of their own!
100
110{
111 friend void DebugObject_ThreadSpecificData::start(DebugObject&, ChannelSetData&, LIBCWD_TSD_PARAM);
112 friend void DebugObject_ThreadSpecificData::finish(DebugObject&, ChannelSetData&, LIBCWD_TSD_PARAM);
113#ifdef LIBCWD_DOXYGEN
114 protected:
115#else
116 public: // Only public because macro LibcwDout needs acces, don't access this directly.
117#endif
118 int index_;
119 // Assigned during initialization before this debug object is made visible to other threads.
120 // Public only because LibcwDout needs direct access; do not access this directly.
121 static int s_index_count_;
122
123 protected:
124 //-------------------------------------------------------------------------------------------------
125 // Protected attributes.
126 //
127
128 friend class libcwd::Buffer; // Buffer::writeto() needs access.
129 _private_::OstreamState ostream_state_;
130 // Ostream destination and matching external lock, protected as one unit.
131
132 Buffer* unfinished_oss_;
133 void const* newlineless_tsd_;
134
135 private:
136 //-------------------------------------------------------------------------------------------------
137 // Private attributes:
138 //
139
140 bool initialized_;
141 // Written during initialization before this debug object is made visible to other threads.
142 // Set to true when this object is initialized (by a call to NS_init()).
143
144 bool being_initialized_;
145 // Only written during single-threaded initialization before concurrent access begins.
146 // Set to true when this object is being initialized (by a call to NS_init()).
147
148#if CWDEBUG_DEBUG
149 long init_magic_;
150 // Used to check if the trick with `initialized_' really works.
151#endif
152
153 bool interactive_;
154 // Set true if the last or current debug output is to cerr
155
156 std::atomic<int> always_flush_{0};
157 // Application-wide flush on/off counter for Debug Objects.
158
159 public:
162
170 DebugString const& color_on() const;
171
179 DebugString const& color_off() const;
180
191 DebugString const& margin() const;
192
203 DebugString const& marker() const;
204
206
207 public:
208 //-------------------------------------------------------------------------------------------------
209 // Manipulators and accessors for the "format" attributes:
210 //
211
212 void set_indent(unsigned short indentation);
213 void inc_indent(unsigned short indentation);
214 void dec_indent(unsigned short indentation);
215 unsigned short get_indent() const;
216
217 void push_margin();
218 void pop_margin();
219 void push_marker();
220 void pop_marker();
221
222 //-------------------------------------------------------------------------------------------------
223 // Other accessors
224 //
225
226 std::ostream* get_ostream() const; // The original ostream set with set_ostream.
227 bool has_mutex() const; // Returns true if a mutex was (already) set with set_ostream.
228
229 private:
230 //-------------------------------------------------------------------------------------------------
231 // Initialization function.
232 //
233
234 friend class Channel;
235 friend class FatalChannel;
236 friend void ST_initialize_globals(LIBCWD_TSD_PARAM);
237#if CWDEBUG_LOCATION
238 friend bool dwarf::ensure_initialization(LIBCWD_TSD_PARAM);
239#endif
240 bool NS_init(LIBCWD_TSD_PARAM);
241 // Initialize this object, needed because debug output can be written
242 // from the constructors of (other) global objects.
243 // This will return false when it is called recursively which can happen
244 // as part of initialization of libcwd via a call to malloc while creating
245 // OutputState -> Buffer --> basic_stringbuf. In that case the initialization
246 // failed thus. On success, it returns true.
247
248 public:
249 //-------------------------------------------------------------------------------------------------
250 // Constructors and destructors.
251 //
252
253 DebugObject();
254
255 public:
256 //-------------------------------------------------------------------------------------------------
257 // Manipulators:
258 //
259
260 void set_ostream(std::ostream* os);
261 template <class T>
262 void set_ostream(std::ostream* os, T* mutex);
263 void off();
264 void on();
265
266 void always_flush_on();
267 void always_flush_off();
268
269 struct OnOffState
270 {
271 int off_cnt;
272#if CWDEBUG_DEBUGOUTPUT
273 bool first_time;
274#endif
275 };
276
277 void force_on(OnOffState& state);
278 void restore(OnOffState const& state);
279 bool is_on(LIBCWD_TSD_PARAM) const;
280 bool always_flush_is_on() const;
281};
282
283} // namespace libcwd
284
285#include "set_ostream.inl.h"
286
287#endif // LIBCWD_CLASS_DEBUG_H
void always_flush_on()
Turn always-flush for this debug object on.
Definition DebugObject.inl.h:287
void on()
Cancel last call to off().
Definition DebugObject.inl.h:266
DebugObject()
Constructor.
Definition DebugObject.inl.h:223
void off()
Turn this debug object off.
Definition DebugObject.inl.h:237
void always_flush_off()
Cancel last call to always_flush_on().
Definition DebugObject.inl.h:306
A string class used for the debug output margin and marker.
Definition DebugString.h:34
void inc_indent(unsigned short indentation)
Increment number of spaces to indent.
Definition DebugObject.inl.h:84
void push_margin()
Push the current margin on a stack.
Definition debug.cxx:801
DebugString & marker()
The marker.
Definition DebugObject.inl.h:60
DebugString & color_off()
Turn colorization off.
Definition DebugObject.inl.h:36
void pop_marker()
Pop marker from the stack.
Definition debug.cxx:839
void pop_margin()
Pop margin from the stack.
Definition debug.cxx:813
DebugString & margin()
The margin.
Definition DebugObject.inl.h:48
unsigned short get_indent() const
Get the current indentation.
Definition DebugObject.inl.h:103
void set_indent(unsigned short indentation)
Set number of spaces to indent.
Definition DebugObject.inl.h:75
DebugString & color_on()
Colorization code.
Definition DebugObject.inl.h:24
void push_marker()
Push the current marker on a stack.
Definition debug.cxx:827
void dec_indent(unsigned short indentation)
Decrement number of spaces to indent.
Definition DebugObject.inl.h:93
void set_ostream(std::ostream *os)
Set output device (single threaded applications).
Definition debug.cxx:1601
std::ostream * get_ostream() const
Get the ostream device as set with set_ostream().
Definition DebugObject.inl.h:117
namespace for libcwd.