aboutsummaryrefslogtreecommitdiff
path: root/libbutl/diagnostics.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbutl/diagnostics.cxx')
-rw-r--r--libbutl/diagnostics.cxx80
1 files changed, 80 insertions, 0 deletions
diff --git a/libbutl/diagnostics.cxx b/libbutl/diagnostics.cxx
new file mode 100644
index 0000000..e73412b
--- /dev/null
+++ b/libbutl/diagnostics.cxx
@@ -0,0 +1,80 @@
+// file : libbutl/diagnostics.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <libbutl/diagnostics.hxx>
+
+#include <mutex>
+#include <iostream> // cerr
+
+using namespace std;
+
+namespace butl
+{
+ ostream* diag_stream = &cerr;
+
+ static mutex diag_mutex;
+
+ diag_lock::diag_lock ()
+ {
+ diag_mutex.lock ();
+ }
+
+ diag_lock::~diag_lock ()
+ {
+ diag_mutex.unlock ();
+ }
+
+ void diag_record::
+ flush () const
+ {
+ if (!empty_)
+ {
+ if (epilogue_ == nullptr)
+ {
+ os.put ('\n');
+
+ {
+ diag_lock l;
+ *diag_stream << os.str ();
+ }
+
+ // We can endup flushing the result of several writes. The last one may
+ // possibly be incomplete, but that's not a problem as it will also be
+ // followed by the flush() call.
+ //
+ diag_stream->flush ();
+
+ empty_ = true;
+ }
+ else
+ {
+ // Clear the epilogue in case it calls us back.
+ //
+ auto e (epilogue_);
+ epilogue_ = nullptr;
+ e (*this); // Can throw.
+ flush (); // Call ourselves to write the data in case it returns.
+ }
+ }
+ }
+
+ diag_record::
+ ~diag_record () noexcept (false)
+ {
+ // Don't flush the record if this destructor was called as part of the
+ // stack unwinding.
+ //
+#ifdef __cpp_lib_uncaught_exceptions
+ if (uncaught_ == std::uncaught_exceptions ())
+ flush ();
+#else
+ // Fallback implementation. Right now this means we cannot use this
+ // mechanism in destructors, which is not a big deal, except for one
+ // place: exception_guard. Thus the ugly special check.
+ //
+ if (!std::uncaught_exception () || exception_unwinding_dtor ())
+ flush ();
+#endif
+ }
+}