#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
#define private public
#if (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
#include <bits/stl_alloc.h>
#else
#include <cstdlib>
#include <ext/pool_allocator.h>
#endif
#undef private
#endif
#include <cerrno>
#include <iostream>
#include <algorithm>
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include <cstdlib>
#include <new>
#include "cwd_debug.h"
#include "macros.h"
#include "private_debug_stack.inl"
#include <libcwd/class_location.inl>
extern "C" int raise(int);
#if LIBCWD_THREAD_SAFE
using libcwd::_private_::rwlock_tct;
using libcwd::_private_::debug_objects_instance;
using libcwd::_private_::debug_channels_instance;
#define DEBUG_OBJECTS_ACQUIRE_WRITE_LOCK rwlock_tct<libcwd::_private_::debug_objects_instance>::wrlock()
#define DEBUG_OBJECTS_RELEASE_WRITE_LOCK rwlock_tct<libcwd::_private_::debug_objects_instance>::wrunlock()
#define DEBUG_OBJECTS_ACQUIRE_READ_LOCK rwlock_tct<libcwd::_private_::debug_objects_instance>::rdlock()
#define DEBUG_OBJECTS_RELEASE_READ_LOCK rwlock_tct<libcwd::_private_::debug_objects_instance>::rdunlock()
#define DEBUG_OBJECTS_ACQUIRE_READ2WRITE_LOCK rwlock_tct<libcwd::_private_::debug_objects_instance>::rd2wrlock()
#define DEBUG_OBJECTS_ACQUIRE_WRITE2READ_LOCK rwlock_tct<libcwd::_private_::debug_objects_instance>::wr2rdlock()
#define DEBUG_CHANNELS_ACQUIRE_WRITE_LOCK rwlock_tct<libcwd::_private_::debug_channels_instance>::wrlock()
#define DEBUG_CHANNELS_RELEASE_WRITE_LOCK rwlock_tct<libcwd::_private_::debug_channels_instance>::wrunlock()
#define DEBUG_CHANNELS_ACQUIRE_READ_LOCK rwlock_tct<libcwd::_private_::debug_channels_instance>::rdlock()
#define DEBUG_CHANNELS_RELEASE_READ_LOCK rwlock_tct<libcwd::_private_::debug_channels_instance>::rdunlock()
#define DEBUG_CHANNELS_ACQUIRE_READ2WRITE_LOCK rwlock_tct<libcwd::_private_::debug_channels_instance>::rd2wrlock()
#define DEBUG_CHANNELS_ACQUIRE_WRITE2READ_LOCK rwlock_tct<libcwd::_private_::debug_channels_instance>::wr2rdlock()
#define COMMA_IFTHREADS(x) ,x
#else
#define DEBUG_OBJECTS_ACQUIRE_WRITE_LOCK
#define DEBUG_OBJECTS_RELEASE_WRITE_LOCK
#define DEBUG_OBJECTS_ACQUIRE_READ_LOCK
#define DEBUG_OBJECTS_RELEASE_READ_LOCK
#define DEBUG_OBJECTS_ACQUIRE_READ2WRITE_LOCK
#define DEBUG_OBJECTS_ACQUIRE_WRITE2READ_LOCK
#define DEBUG_CHANNELS_ACQUIRE_WRITE_LOCK
#define DEBUG_CHANNELS_RELEASE_WRITE_LOCK
#define DEBUG_CHANNELS_ACQUIRE_READ_LOCK
#define DEBUG_CHANNELS_RELEASE_READ_LOCK
#define DEBUG_CHANNELS_ACQUIRE_READ2WRITE_LOCK
#define DEBUG_CHANNELS_ACQUIRE_WRITE2READ_LOCK
#define COMMA_IFTHREADS(x)
#endif
#define NEED_SUPRESSION_OF_MALLOC_AND_BFD (__GNUC__ == 3 && \
((__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ == 0) || \
(__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 1) || \
(__GNUC_MINOR__ == 0)))
namespace _private_ {
#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
#if (__GNUC_MINOR__ == 4)
#if (__GNUC_PATCHLEVEL__ <= 1)
__gnu_cxx::_STL_mutex_lock* pool_allocator_lock_symbol_ptr;
#else
__gthread_mutex_t* pool_allocator_lock_symbol_ptr;
#endif
#endif
inline
bool allocator_trylock()
{
#if (__GNUC_MINOR__ < 4)
#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
if (!std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_init_flag)
std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_initialize();
#endif
return (__gthread_mutex_trylock(&std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_lock) == 0);
#else
if (!pool_allocator_lock_symbol_ptr)
return false;
#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
#if (__GNUC_PATCHLEVEL__ <= 1)
if (!pool_allocator_lock_symbol_ptr->_M_init_flag)
pool_allocator_lock_symbol_ptr->_M_initialize();
#else
#error "Sorry, not implemented yet."
#endif
#endif
#if (__GNUC_PATCHLEVEL__ <= 1)
return (__gthread_mutex_trylock(&pool_allocator_lock_symbol_ptr->_M_lock) == 0);
#else
return (__gthread_mutex_trylock(pool_allocator_lock_symbol_ptr) == 0);
#endif
#endif
}
inline
void allocator_unlock()
{
#if (__GNUC_MINOR__ < 4)
#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
if (!std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_init_flag)
std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_initialize();
#endif
__gthread_mutex_unlock(&std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_lock);
#else
#if (__GNUC_PATCHLEVEL__ <= 1)
__gthread_mutex_unlock(&pool_allocator_lock_symbol_ptr->_M_lock);
#else
__gthread_mutex_unlock(pool_allocator_lock_symbol_ptr);
#endif
#endif
}
#endif
}
using _private_::set_alloc_checking_on;
using _private_::set_alloc_checking_off;
#if CWDEBUG_ALLOC
using _private_::debug_message_st;
#endif
class buffer_ct : public _private_::auto_internal_stringbuf {
private:
typedef pos_type streampos_t;
streampos_t position;
#if LIBCWD_THREAD_SAFE
bool unfinished_already_printed;
bool continued_needed;
#endif
public:
#if LIBCWD_THREAD_SAFE
buffer_ct() : unfinished_already_printed(false), continued_needed(false) { }
#endif
void writeto(std::ostream* os LIBCWD_COMMA_TSD_PARAM, debug_ct& debug_object,
bool request_unfinished, bool do_flush COMMA_IFTHREADS(bool ends_on_newline)
COMMA_IFTHREADS(bool possible_nonewline_cf));
void store_position() {
position = this->pubseekoff(0, std::ios_base::cur, std::ios_base::out);
}
void restore_position() {
this->pubseekpos(position, std::ios_base::out);
this->pubseekpos(0, std::ios_base::in);
#if LIBCWD_THREAD_SAFE
continued_needed = false;
#endif
}
void write_prefix_to(std::ostream* os)
{
streampos_t old_in_pos = this->pubseekoff(0, std::ios_base::cur, std::ios_base::in);
this->pubseekpos(0, std::ios_base::in);
os->put(this->sgetc());
int size = position - std::streampos(0);
for (int c = 1; c < size; ++c)
os->put(this->snextc());
this->pubseekpos(old_in_pos, std::ios_base::in);
}
};
void buffer_ct::writeto(std::ostream* os LIBCWD_COMMA_TSD_PARAM,
#if LIBCWD_THREAD_SAFE
debug_ct& debug_object,
#else
debug_ct&,
#endif
bool request_unfinished, bool do_flush COMMA_IFTHREADS(bool ends_on_newline)
COMMA_IFTHREADS(bool possible_nonewline_cf))
{
#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
typedef debug_message_st* msgbuf_t;
msgbuf_t msgbuf;
bool const queue_msg = __libcwd_tsd.inside_malloc_or_free && !_private_::allocator_trylock();
if (__libcwd_tsd.inside_malloc_or_free && !queue_msg)
_private_::allocator_unlock();
int const extra_size = sizeof(debug_message_st) - sizeof(msgbuf->buf);
#else
typedef char* msgbuf_t;
msgbuf_t msgbuf;
bool const queue_msg = false;
int const extra_size = 0;
#endif
int curlen;
curlen = this->pubseekoff(0, std::ios_base::cur, std::ios_base::out) - this->pubseekoff(0, std::ios_base::cur, std::ios_base::in);
bool free_msgbuf = false;
if (queue_msg)
msgbuf = (msgbuf_t)
malloc(curlen + extra_size);
else if (curlen > 512 || !(msgbuf = (msgbuf_t)__builtin_alloca(curlen + extra_size)))
{
msgbuf = (msgbuf_t)
malloc(curlen + extra_size);
free_msgbuf = true;
}
#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
this->sgetn(msgbuf->buf, curlen);
#else
this->sgetn(msgbuf, curlen);
#endif
#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
if (queue_msg)
{
msgbuf->curlen = curlen;
msgbuf->prev = NULL;
msgbuf->next = debug_object.queue;
if (debug_object.queue)
debug_object.queue->prev = msgbuf;
else
debug_object.queue_top = msgbuf;
debug_object.queue = msgbuf;
}
else
{
#endif
#if CWDEBUG_ALLOC
int saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
#endif
#if LIBCWD_THREAD_SAFE
LIBCWD_DISABLE_CANCEL;
_private_::mutex_tct<_private_::set_ostream_instance>::lock();
bool got_lock = debug_object.M_mutex;
if (got_lock)
{
debug_object.M_mutex->lock();
__libcwd_tsd.pthread_lock_interface_is_locked = true;
}
std::ostream* locked_os = os;
_private_::mutex_tct<_private_::set_ostream_instance>::unlock();
if (!got_lock && _private_::WST_multi_threaded)
{
static bool WST_second_time = false;
if (!WST_second_time)
{
WST_second_time = true;
DoutFatal(
dc::core,
"When using multiple threads, you must provide a locking mechanism for the debug output stream. "
"You can pass a pointer to a mutex with `debug_ct::set_ostream' (see documentation/reference-manual/group__group__destination.html).");
}
}
#endif
#if LIBCWD_THREAD_SAFE
if (debug_object.newlineless_tsd && debug_object.newlineless_tsd != &__libcwd_tsd)
{
if (debug_object.unfinished_oss)
{
if (debug_object.unfinished_oss != this)
{
locked_os->write("<unfinished>\n", 13);
debug_object.unfinished_oss->unfinished_already_printed = true;
debug_object.unfinished_oss->continued_needed = true;
}
}
else
locked_os->write("<no newline>\n", 13);
}
if (continued_needed && curlen > 0)
{
continued_needed = false;
write_prefix_to(locked_os);
locked_os->write("<continued> ", 12);
}
#endif
#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
debug_message_st* message = debug_object.queue_top;
if (message)
{
debug_message_st* next_message;
do
{
next_message = message->prev;
locked_os->write(message->buf, message->curlen);
__libcwd_tsd.internal = 1;
free(message);
__libcwd_tsd.internal = 0;
}
while ((message = next_message));
debug_object.queue_top = debug_object.queue = NULL;
}
locked_os->write(msgbuf->buf, curlen);
#else
#if LIBCWD_THREAD_SAFE
locked_os->write(msgbuf, curlen);
#else
os->write(msgbuf, curlen);
#endif
#endif
#if LIBCWD_THREAD_SAFE
if (request_unfinished && !unfinished_already_printed)
locked_os->write("<unfinished>\n", 13);
#else
if (request_unfinished)
os->write("<unfinished>\n", 13);
#endif
if (do_flush)
#if LIBCWD_THREAD_SAFE
locked_os->flush();
#else
os->flush();
#endif
#if LIBCWD_THREAD_SAFE
unfinished_already_printed = ends_on_newline;
if (ends_on_newline)
{
debug_object.unfinished_oss = NULL;
debug_object.newlineless_tsd = NULL;
}
else if (curlen > 0)
{
debug_object.newlineless_tsd = &__libcwd_tsd;
if (possible_nonewline_cf)
debug_object.unfinished_oss = NULL;
else
debug_object.unfinished_oss = this;
}
if (got_lock)
{
__libcwd_tsd.pthread_lock_interface_is_locked = false;
debug_object.M_mutex->unlock();
}
LIBCWD_ENABLE_CANCEL;
#endif
#if CWDEBUG_ALLOC
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
#endif
#if LIBCWD_THREAD_SAFE && CWDEBUG_ALLOC && __GNUC__ == 3
}
#endif
if (free_msgbuf)
free(msgbuf);
}
unsigned long const config_signature_lib_c = config_signature_header_c;
unsigned long get_config_signature_lib_c()
{
return config_signature_lib_c;
}
void conf_check_failed()
{
DoutFatal(
dc::fatal,
"check_configuration: This version of libcwd was compiled with a different configuration than is currently used in libcwd/config.h!");
}
void version_check_failed()
{
DoutFatal(
dc::fatal,
"check_configuration: This version of libcwd does not match the version of libcwd/config.h! Are your paths correct? Did you recently upgrade libcwd and forgot to recompile this application?");
}
namespace {
unsigned short int WST_max_len = 8;
}
namespace channels {
namespace dc {
#ifndef HIDE_FROM_DOXYGEN
("DEBUG")
#endif
;
#ifndef HIDE_FROM_DOXYGEN
("NOTICE")
#endif
;
#ifndef HIDE_FROM_DOXYGEN
("SYSTEM")
#endif
;
#ifndef HIDE_FROM_DOXYGEN
("MALLOC")
#endif
;
#ifndef HIDE_FROM_DOXYGEN
("WARNING")
#endif
;
#ifndef HIDE_FROM_DOXYGEN
(continued_maskbit)
#endif
;
#ifndef HIDE_FROM_DOXYGEN
(finish_maskbit)
#endif
;
#ifndef HIDE_FROM_DOXYGEN
("FATAL", fatal_maskbit)
#endif
;
#ifndef HIDE_FROM_DOXYGEN
("COREDUMP", coredump_maskbit)
#endif
;
}
}
channel_ct const channel_ct::off_channel
#ifndef HIDE_FROM_DOXYGEN
("!NEVER!", false)
#endif
;
#if CWDEBUG_LOCATION
namespace cwbfd {
extern bool ST_init(LIBCWD_TSD_PARAM);
}
#endif
void ST_initialize_globals(LIBCWD_TSD_PARAM)
{
static bool ST_already_called;
if (ST_already_called)
return;
ST_already_called = true;
#if CWDEBUG_ALLOC
init_debugmalloc();
#endif
#if LIBCWD_THREAD_SAFE
_private_::initialize_global_mutexes();
#endif
_private_::process_environment_variables();
#if CWDEBUG_LOCATION
#endif
DoutFatal(
dc::core,
"Calling debug_ct::NS_init recursively from ST_initialize_globals");
#ifdef RLIMIT_CORE
struct rlimit corelim;
if (getrlimit(RLIMIT_CORE, &corelim))
corelim.rlim_cur = corelim.rlim_max;
if (corelim.rlim_max != RLIM_INFINITY && !_private_::suppress_startup_msgs)
{
debug_ct::OnOffState state;
Dout(
dc::warning,
"core size is limited (hard limit: " << (
unsigned long)(corelim.rlim_max / 1024) <<
" kb). Core dumps might be truncated!");
}
if (setrlimit(RLIMIT_CORE, &corelim))
#else
if (!_private_::suppress_startup_msgs)
{
debug_ct::OnOffState state;
}
#endif
#if CWDEBUG_LOCATION
cwbfd::ST_init(LIBCWD_TSD);
#endif
#if CWDEBUG_DEBUG && !CWDEBUG_DEBUGOUTPUT
(void)std::uncaught_exceptions();
#endif
}
namespace _private_ {
#if !LIBCWD_THREAD_SAFE
TSD_st __libcwd_tsd;
#endif
#if LIBCWD_THREAD_SAFE
extern bool WST_is_NPTL;
#endif
debug_channels_ct debug_channels;
debug_objects_ct debug_objects;
void debug_channels_ct::init(LIBCWD_TSD_PARAM)
{
#if LIBCWD_THREAD_SAFE
_private_::rwlock_tct<libcwd::_private_::debug_channels_instance>::initialize();
#endif
DEBUG_CHANNELS_ACQUIRE_READ_LOCK;
if (!WNS_debug_channels)
{
DEBUG_CHANNELS_ACQUIRE_READ2WRITE_LOCK;
set_alloc_checking_off(LIBCWD_TSD);
WNS_debug_channels = new debug_channels_ct::container_type;
set_alloc_checking_on(LIBCWD_TSD);
DEBUG_CHANNELS_RELEASE_WRITE_LOCK;
}
#if LIBCWD_THREAD_SAFE
else
DEBUG_CHANNELS_RELEASE_READ_LOCK;
#endif
}
#if LIBCWD_THREAD_SAFE
void debug_channels_ct::init_and_rdlock()
{
_private_::rwlock_tct<libcwd::_private_::debug_channels_instance>::initialize();
DEBUG_CHANNELS_ACQUIRE_READ_LOCK;
if (!WNS_debug_channels)
{
LIBCWD_TSD_DECLARATION;
set_alloc_checking_off(LIBCWD_TSD);
DEBUG_CHANNELS_ACQUIRE_READ2WRITE_LOCK;
WNS_debug_channels = new debug_channels_ct::container_type;
DEBUG_CHANNELS_ACQUIRE_WRITE2READ_LOCK;
set_alloc_checking_on(LIBCWD_TSD);
}
}
#endif
void debug_objects_ct::init(LIBCWD_TSD_PARAM)
{
#if LIBCWD_THREAD_SAFE
_private_::rwlock_tct<libcwd::_private_::debug_objects_instance>::initialize();
#endif
DEBUG_OBJECTS_ACQUIRE_READ_LOCK;
if (!WNS_debug_objects)
{
DEBUGDEBUG_CERR( (char const*)"_debug_objects == NULL; initializing it" );
#if CWDEBUG_ALLOC
init_debugmalloc();
#endif
DEBUG_OBJECTS_ACQUIRE_READ2WRITE_LOCK;
set_alloc_checking_off(LIBCWD_TSD);
WNS_debug_objects = new debug_objects_ct::container_type;
set_alloc_checking_on(LIBCWD_TSD);
DEBUG_OBJECTS_RELEASE_WRITE_LOCK;
}
#if LIBCWD_THREAD_SAFE
else
DEBUG_OBJECTS_RELEASE_READ_LOCK;
#endif
}
#if LIBCWD_THREAD_SAFE
void debug_objects_ct::init_and_rdlock()
{
_private_::rwlock_tct<libcwd::_private_::debug_objects_instance>::initialize();
DEBUG_OBJECTS_ACQUIRE_READ_LOCK;
if (!WNS_debug_objects)
{
DEBUGDEBUG_CERR( "_debug_objects == NULL; initializing it" );
#if CWDEBUG_ALLOC
init_debugmalloc();
#endif
LIBCWD_TSD_DECLARATION;
set_alloc_checking_off(LIBCWD_TSD);
DEBUG_OBJECTS_ACQUIRE_READ2WRITE_LOCK;
WNS_debug_objects = new debug_objects_ct::container_type;
DEBUG_OBJECTS_ACQUIRE_WRITE2READ_LOCK;
set_alloc_checking_on(LIBCWD_TSD);
}
}
#endif
void debug_objects_ct::ST_uninit()
{
if (WNS_debug_objects)
{
LIBCWD_TSD_DECLARATION;
set_alloc_checking_off(LIBCWD_TSD);
delete WNS_debug_objects;
set_alloc_checking_on(LIBCWD_TSD);
WNS_debug_objects = NULL;
}
}
}
#if CWDEBUG_DEBUG
static long WST_debug_object_init_magic = 0;
static void init_debug_object_init_magic()
{
struct timeval rn;
gettimeofday(&rn, NULL);
WST_debug_object_init_magic = rn.tv_usec;
if (!WST_debug_object_init_magic)
WST_debug_object_init_magic = 1;
DEBUGDEBUG_CERR( "Set WST_debug_object_init_magic to " << WST_debug_object_init_magic );
}
#endif
class laf_ct {
public:
buffer_ct buffer;
_private_::bufferstream_ct bufferstream;
char const* label;
int err;
public:
laf_ct(
control_flag_t m,
char const* l,
int e) : bufferstream(&buffer), mask(m), label(l), err(e) { }
};
static inline void write_whitespace_to(std::ostream& os, unsigned int size)
{
for (unsigned int i = size; i > 0; --i)
os.put(' ');
}
namespace _private_ {
static char WST_dummy_laf[sizeof(laf_ct)] __attribute__((__aligned__));
}
{
#if LIBCWD_THREAD_SAFE
#if CWDEBUG_DEBUGT || CWDEBUG_ALLOC
LIBCWD_TSD_DECLARATION;
#endif
LIBCWD_DISABLE_CANCEL;
if (!_private_::mutex_tct<_private_::kill_threads_instance>::try_lock())
{
#if CWDEBUG_ALLOC
__libcwd_tsd.internal = 0;
++__libcwd_tsd.library_call;;
#endif
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_exit(PTHREAD_CANCELED);
}
#endif
#if LIBCWD_THREAD_SAFE && CWDEBUG_DEBUG && defined(__linux)
if (!_private_::WST_is_NPTL && pthread_self() == (pthread_t)2049)
{
::write(1, "WARNING: Thread manager core dumped. Going into infinite loop. Please detach process with gdb.\n", 97);
while(1) ;
}
#endif
raise(6);
#if LIBCWD_THREAD_SAFE
LIBCWD_ENABLE_CANCEL;
#endif
_Exit(6);
}
size_t debug_string_ct::calculate_capacity(size_t size)
{
size_t capacity_plus_one = M_default_capacity + 1;
while(
size >= capacity_plus_one)
capacity_plus_one *= 2;
return capacity_plus_one - 1;
}
void debug_string_ct::NS_internal_init(char const* str, size_t len)
{
M_default_capacity = min_capacity_c;
M_str = (
char*)
malloc((M_default_capacity = M_capacity = calculate_capacity(len)) + 1);
strncpy(M_str, str, len);
M_size = len;
M_str[M_size] = 0;
}
void debug_string_ct::deinitialize()
{
free(M_str);
M_str = NULL;
}
debug_string_ct::~debug_string_ct()
{
#if CWDEBUG_DEBUG && LIBCWD_THREAD_SAFE
LIBCWD_ASSERT(M_str == NULL);
#endif
}
void debug_string_ct::internal_assign(char const* str, size_t len)
{
if (len > M_capacity || (M_capacity > M_default_capacity && len < M_default_capacity))
M_str = (char*)realloc(M_str, (M_capacity = calculate_capacity(len)) + 1);
strncpy(M_str, str, len);
M_size = len;
M_str[M_size] = 0;
}
void debug_string_ct::internal_append(char const* str, size_t len)
{
if (M_size + len > M_capacity || (M_capacity > M_default_capacity && M_size + len < M_default_capacity))
M_str = (char*)realloc(M_str, (M_capacity = calculate_capacity(M_size + len)) + 1);
strncpy(M_str + M_size, str, len);
M_size += len;
M_str[M_size] = 0;
}
void debug_string_ct::internal_prepend(char const* str, size_t len)
{
if (M_size + len > M_capacity || (M_capacity > M_default_capacity && M_size + len < M_default_capacity))
M_str = (char*)realloc(M_str, (M_capacity = calculate_capacity(M_size + len)) + 1);
memmove(M_str + len, M_str, M_size + 1);
strncpy(M_str, str, len);
M_size += len;
}
{
return;
LIBCWD_TSD_DECLARATION;
set_alloc_checking_off(LIBCWD_TSD);
M_default_capacity = min_capacity_c;
M_str = (
char*)realloc(M_str, (M_default_capacity = M_capacity = calculate_capacity(
size)) + 1);
set_alloc_checking_on(LIBCWD_TSD);
}
void debug_string_ct::internal_swallow(debug_string_ct const& ds)
{
free(M_str);
M_str = ds.M_str;
M_size = ds.M_size;
M_capacity = ds.M_capacity;
M_default_capacity = ds.M_default_capacity;
}
{
LIBCWD_TSD_DECLARATION;
debug_string_stack_element_ct* current_margin_stack = LIBCWD_TSD_MEMBER(M_margin_stack);
set_alloc_checking_off(LIBCWD_TSD);
void* new_debug_string =
malloc(
sizeof(debug_string_stack_element_ct));
LIBCWD_TSD_MEMBER(M_margin_stack) =
new (new_debug_string) debug_string_stack_element_ct(LIBCWD_TSD_MEMBER(
margin));
set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_TSD_MEMBER(M_margin_stack)->next = current_margin_stack;
}
{
LIBCWD_TSD_DECLARATION;
if (!LIBCWD_TSD_MEMBER(M_margin_stack))
DoutFatal(
dc::core,
"Calling `debug_ct::pop_margin' more often than `debug_ct::push_margin'.");
debug_string_stack_element_ct* next = LIBCWD_TSD_MEMBER(M_margin_stack)->next;
set_alloc_checking_off(LIBCWD_TSD);
LIBCWD_TSD_MEMBER(
margin).internal_swallow(LIBCWD_TSD_MEMBER(M_margin_stack)->debug_string);
free(LIBCWD_TSD_MEMBER(M_margin_stack));
set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_TSD_MEMBER(M_margin_stack) = next;
}
{
LIBCWD_TSD_DECLARATION;
debug_string_stack_element_ct* current_marker_stack = LIBCWD_TSD_MEMBER(M_marker_stack);
set_alloc_checking_off(LIBCWD_TSD);
void* new_debug_string =
malloc(
sizeof(debug_string_stack_element_ct));
LIBCWD_TSD_MEMBER(M_marker_stack) =
new (new_debug_string) debug_string_stack_element_ct(LIBCWD_TSD_MEMBER(
marker));
set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_TSD_MEMBER(M_marker_stack)->next = current_marker_stack;
}
{
LIBCWD_TSD_DECLARATION;
if (!LIBCWD_TSD_MEMBER(M_marker_stack))
DoutFatal(
dc::core,
"Calling `debug_ct::pop_marker' more often than `debug_ct::push_marker'.");
debug_string_stack_element_ct* next = LIBCWD_TSD_MEMBER(M_marker_stack)->next;
set_alloc_checking_off(LIBCWD_TSD);
LIBCWD_TSD_MEMBER(
marker).internal_swallow(LIBCWD_TSD_MEMBER(M_marker_stack)->debug_string);
free(LIBCWD_TSD_MEMBER(M_marker_stack));
set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_TSD_MEMBER(M_marker_stack) = next;
}
void debug_tsd_st::start(debug_ct& debug_object, channel_set_data_st& channel_set LIBCWD_COMMA_TSD_PARAM)
{
#if CWDEBUG_DEBUG || CWDEBUG_DEBUGT
#if LIBCWD_THREAD_SAFE
LIBCWD_ASSERT( tsd_initialized );
#else
if (!tsd_initialized)
init();
#endif
#endif
if (NEED_SUPRESSION_OF_MALLOC_AND_BFD)
{
#if CWDEBUG_LOCATION
#endif
}
if ((channel_set.mask & (continued_maskbit|finish_maskbit)))
{
current->err = errno;
if (!(current->mask & continued_expected_maskbit))
{
std::ostream* target_os = (channel_set.mask &
cerr_cf) ? &std::cerr : debug_object.real_os;
#if LIBCWD_THREAD_SAFE
int res;
struct timespec const t = { 0, 5000000 };
int count = 0;
do
{
if (!(res = debug_object.M_mutex->try_lock()))
break;
nanosleep(&t, NULL);
}
while(++count < 40);
#endif
target_os->put('\n');
#if LIBCWD_THREAD_SAFE
if (res == 0)
debug_object.M_mutex->unlock();
#endif
char const* channame = (channel_set.mask & finish_maskbit) ? "finish" : "continued";
#if CWDEBUG_LOCATION
" without (first using) a matching `continued_cf'.");
#else
"' without (first using) a matching `continued_cf'.");
#endif
}
#if CWDEBUG_DEBUG
LIBCWD_ASSERT( current != reinterpret_cast<laf_ct*>(_private_::WST_dummy_laf) );
#endif
current->mask = channel_set.mask;
if ((current->mask & finish_maskbit))
current->mask &= ~continued_expected_maskbit;
return;
}
set_alloc_checking_off(LIBCWD_TSD);
++LIBCWD_DO_TSD_MEMBER_OFF(debug_object);
DEBUGDEBUG_CERR( "Entering debug_ct::start(), _off became " << LIBCWD_DO_TSD_MEMBER_OFF(debug_object) );
if ((current->mask & continued_cf_maskbit) && unfinished_expected)
{
#if CWDEBUG_DEBUG
LIBCWD_ASSERT( current != reinterpret_cast<laf_ct*>(_private_::WST_dummy_laf) );
#endif
int saved_errno = errno;
std::ostream* target_os = (channel_set.mask &
cerr_cf) ? &std::cerr : debug_object.real_os;
current->buffer.writeto(target_os LIBCWD_COMMA_TSD, debug_object,
true,
false
COMMA_IFTHREADS(true)
COMMA_IFTHREADS(false));
current->buffer.restore_position();
current_bufferstream->write("<continued> ", 12);
errno = saved_errno;
}
if (!start_expected)
{
laf_stack.push(current);
indent += 4;
channel_set.mask |= (current->mask &
cerr_cf);
}
DEBUGDEBUG_CERR( "creating new laf_ct" );
int saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
_private_::set_invisible_on(LIBCWD_TSD);
current = new laf_ct(channel_set.mask, channel_set.label, errno);
_private_::set_invisible_off(LIBCWD_TSD);
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
DEBUGDEBUG_CERR( "current = " << (void*)current );
current_bufferstream = ¤t->bufferstream;
DEBUGDEBUG_CERR( "laf_ct created" );
start_expected = false;
unfinished_expected = true;
{
current_bufferstream->write(margin.c_str(), margin.size());
current_bufferstream->write(channel_set.label, WST_max_len);
current_bufferstream->write(marker.c_str(), marker.size());
write_whitespace_to(*current_bufferstream, indent);
}
{
write_whitespace_to(*current_bufferstream, margin.size());
else
current_bufferstream->write(margin.c_str(), margin.size());
#if !CWDEBUG_DEBUGOUTPUT
#endif
{
write_whitespace_to(*current_bufferstream, WST_max_len);
else
current_bufferstream->write(channel_set.label, WST_max_len);
write_whitespace_to(*current_bufferstream, marker.size());
else
current_bufferstream->write(marker.c_str(), marker.size());
write_whitespace_to(*current_bufferstream, indent);
}
}
if ((channel_set.mask & continued_cf_maskbit))
{
current->buffer.store_position();
}
--LIBCWD_DO_TSD_MEMBER_OFF(debug_object);
DEBUGDEBUG_CERR( "Leaving debug_ct::start(), _off became " << LIBCWD_DO_TSD_MEMBER_OFF(debug_object) );
set_alloc_checking_on(LIBCWD_TSD);
}
{
#if CWDEBUG_DEBUG
LIBCWD_ASSERT( current != reinterpret_cast<laf_ct*>(_private_::WST_dummy_laf) );
#endif
std::ostream* target_os = (current->mask &
cerr_cf) ? &std::cerr : debug_object.real_os;
set_alloc_checking_off(LIBCWD_TSD);
if (NEED_SUPRESSION_OF_MALLOC_AND_BFD)
{
#if CWDEBUG_LOCATION
#endif
}
if ((current->mask & continued_cf_maskbit) && !(current->mask & finish_maskbit))
{
current->mask |= continued_expected_maskbit;
if ((current->mask & continued_maskbit))
unfinished_expected = true;
{
current->buffer.writeto(target_os LIBCWD_COMMA_TSD, debug_object,
false,
true
COMMA_IFTHREADS(false)
COMMA_IFTHREADS(false));
}
set_alloc_checking_on(LIBCWD_TSD);
return;
}
++LIBCWD_DO_TSD_MEMBER_OFF(debug_object);
DEBUGDEBUG_CERR( "Entering debug_ct::finish(), _off became " << LIBCWD_DO_TSD_MEMBER_OFF(debug_object) );
{
#if CWDEBUG_ALLOC
int saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
#endif
#if !LIBCWD_THREAD_SAFE
char const* error_text = strerror(current->err);
#else
char error_text_buf[512];
char const* error_text;
#ifdef _GNU_SOURCE
error_text = strerror_r(current->err, error_text_buf, sizeof(error_text_buf));
#else
if (strerror_r(current->err, error_text_buf, sizeof(error_text_buf)) == -1)
{
if (errno == ERANGE)
error_text = "<libcwd: Oops, error text longer than 512 characters>";
else
error_text = "Unknown Error";
}
else
error_text = error_text_buf;
#endif
#endif
#if CWDEBUG_ALLOC
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
#endif
*current_bufferstream << ": " << strerrno(current->err) << " (" << error_text << ')';
}
current_bufferstream->put('\n');
if (current->mask != 0)
{
if ((current->mask & (coredump_maskbit|fatal_maskbit)))
{
current->buffer.writeto(target_os LIBCWD_COMMA_TSD, debug_object,
false,
!__libcwd_tsd.recursive_fatal
COMMA_IFTHREADS(true));
__libcwd_tsd.recursive_fatal = true;
if ((current->mask & coredump_maskbit))
DEBUGDEBUG_CERR( "Deleting `current' " << (void*)current );
int saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
_private_::set_invisible_on(LIBCWD_TSD);
delete current;
_private_::set_invisible_off(LIBCWD_TSD);
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
DEBUGDEBUG_CERR( "Done deleting `current'" );
set_alloc_checking_on(LIBCWD_TSD);
#if CWDEBUG_ALLOC
if (__libcwd_tsd.internal)
_private_::set_library_call_on(LIBCWD_TSD);
#endif
#if LIBCWD_THREAD_SAFE
LIBCWD_DISABLE_CANCEL;
if (!_private_::mutex_tct<_private_::kill_threads_instance>::try_lock())
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_exit(PTHREAD_CANCELED);
}
_private_::rwlock_tct<_private_::threadlist_instance>::rdlock(true);
for(_private_::threadlist_t::iterator thread_iter = _private_::threadlist->begin(); thread_iter != _private_::threadlist->end(); ++thread_iter)
if (!pthread_equal((*thread_iter).tid, pthread_self())
#ifdef __linux
&& (_private_::WST_is_NPTL || (*thread_iter).tid != (pthread_t)1024)
#endif
)
pthread_cancel((*thread_iter).tid);
_private_::rwlock_tct<_private_::threadlist_instance>::rdunlock();
LIBCWD_ENABLE_CANCEL;
#endif
_Exit(254);
}
{
current->buffer.writeto(target_os LIBCWD_COMMA_TSD, debug_object,
false, debug_object.interactive COMMA_IFTHREADS(!(current->mask &
nonewline_cf))
COMMA_IFTHREADS(true));
#if LIBCWD_THREAD_SAFE
debug_object.M_mutex->lock();
#endif
*target_os << "(type return)";
if (debug_object.interactive)
{
*target_os << std::flush;
while(std::cin.get() != '\n') ;
}
#if LIBCWD_THREAD_SAFE
debug_object.M_mutex->unlock();
#endif
}
else
current->buffer.writeto(target_os LIBCWD_COMMA_TSD, debug_object,
COMMA_IFTHREADS(true));
}
else
current->buffer.writeto(target_os LIBCWD_COMMA_TSD, debug_object,
false,
false COMMA_IFTHREADS(!(current->mask &
nonewline_cf)) COMMA_IFTHREADS(
true));
DEBUGDEBUG_CERR( "Deleting `current' " << (void*)current );
int saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
_private_::set_invisible_on(LIBCWD_TSD);
delete current;
_private_::set_invisible_off(LIBCWD_TSD);
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
DEBUGDEBUG_CERR( "Done deleting `current'" );
if (start_expected)
{
indent -= 4;
laf_stack.pop();
}
if (laf_stack.size())
{
current = laf_stack.top();
DEBUGDEBUG_CERR( "current = " << (void*)current );
current_bufferstream = ¤t->bufferstream;
}
else
{
current = reinterpret_cast<laf_ct*>(_private_::WST_dummy_laf);
DEBUGDEBUG_CERR( "current = " << (void*)current );
current_bufferstream = NULL;
}
start_expected = true;
unfinished_expected = false;
--LIBCWD_DO_TSD_MEMBER_OFF(debug_object);
DEBUGDEBUG_CERR( "Leaving debug_ct::finish(), _off became " << LIBCWD_DO_TSD_MEMBER_OFF(debug_object) );
set_alloc_checking_on(LIBCWD_TSD);
}
PRAGMA_DIAGNOSTIC_PUSH_IGNORE_infinite_recursion
void debug_tsd_st::fatal_finish(debug_ct& debug_object, channel_set_data_st& channel_set LIBCWD_COMMA_TSD_PARAM)
{
finish(debug_object, channel_set LIBCWD_COMMA_TSD);
DoutFatal(
dc::core,
"Don't use `DoutFatal' together with `continued_cf', use `Dout' instead. (This message can also occur when using DoutFatal correctly but from the constructor of a global object)." );
_Exit(1);
}
PRAGMA_DIAGNOSTIC_POP
#if LIBCWD_THREAD_SAFE
int debug_ct::S_index_count = 0;
#endif
bool debug_ct::NS_init(LIBCWD_TSD_PARAM)
{
if (NS_being_initialized)
return false;
ST_initialize_globals(LIBCWD_TSD);
if (WNS_initialized)
return true;
NS_being_initialized = true;
#if LIBCWD_THREAD_SAFE
M_mutex = NULL;
unfinished_oss = NULL;
#endif
#if CWDEBUG_DEBUG
if (!WST_debug_object_init_magic)
init_debug_object_init_magic();
init_magic = WST_debug_object_init_magic;
DEBUGDEBUG_CERR( "Set init_magic to " << init_magic );
DEBUGDEBUG_CERR( "Setting WNS_initialized to true" );
#endif
LIBCWD_DEFER_CANCEL;
_private_::debug_objects.init(LIBCWD_TSD);
set_alloc_checking_off(LIBCWD_TSD);
DEBUG_OBJECTS_ACQUIRE_WRITE_LOCK;
if (find(_private_::debug_objects.write_locked().begin(),
_private_::debug_objects.write_locked().end(), this)
== _private_::debug_objects.write_locked().end())
_private_::debug_objects.write_locked().push_back(this);
DEBUG_OBJECTS_RELEASE_WRITE_LOCK;
#if LIBCWD_THREAD_SAFE
set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_RESTORE_CANCEL;
set_alloc_checking_off(LIBCWD_TSD);
#endif
int saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
_private_::set_invisible_on(LIBCWD_TSD);
_private_::set_invisible_off(LIBCWD_TSD);
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
#if LIBCWD_THREAD_SAFE
WNS_index = S_index_count++;
#if CWDEBUG_DEBUGT
LIBCWD_ASSERT( !_private_::WST_multi_threaded );
#endif
LIBCWD_ASSERT( __libcwd_tsd.do_array[WNS_index] == NULL );
debug_tsd_st& tsd(*(__libcwd_tsd.do_array[WNS_index] = new debug_tsd_st));
#endif
tsd.init();
set_alloc_checking_on(LIBCWD_TSD);
#if CWDEBUG_DEBUGOUTPUT
LIBCWD_TSD_MEMBER_OFF = -1;
#else
LIBCWD_TSD_MEMBER_OFF = 0;
#endif
DEBUGDEBUG_CERR( "debug_ct::NS_init(), _off set to " << LIBCWD_TSD_MEMBER_OFF );
set_ostream(&std::cerr);
interactive = true;
NS_being_initialized = false;
WNS_initialized = true;
return true;
}
void debug_tsd_st::init()
{
DEBUGDEBUG_CERR( "Entering debug_tsd_st::init (this == " << (void*)this << ")");
#if CWDEBUG_DEBUGM
LIBCWD_TSD_DECLARATION;
LIBCWD_ASSERT( __libcwd_tsd.internal );
#endif
start_expected = true;
unfinished_expected = false;
current = reinterpret_cast<laf_ct*>(_private_::WST_dummy_laf);
DEBUGDEBUG_CERR( "current = " << (void*)current );
current_bufferstream = NULL;
laf_stack.init();
continued_stack.init();
margin.NS_internal_init("", 0);
marker.NS_internal_init(": ", 2);
#if CWDEBUG_DEBUGOUTPUT
first_time = true;
#endif
off_count = 0;
M_margin_stack = NULL;
M_marker_stack = NULL;
indent = 0;
tsd_initialized = true;
DEBUGDEBUG_CERR( "Leaving debug_tsd_st::init (this == " << (void*)this <<
"); &tsd_initialized == " << (void*)&tsd_initialized );
}
#if LIBCWD_THREAD_SAFE
namespace _private_ {
#if CWDEBUG_DEBUGT
void debug_tsd_init(LIBCWD_TSD_PARAM_UNUSED)
#else
void debug_tsd_init(LIBCWD_TSD_PARAM)
#endif
{
set_alloc_checking_off(LIBCWD_TSD);
LIBCWD_ASSERT( __libcwd_tsd.do_array[(debugObject).WNS_index] == NULL );
debug_tsd_st& tsd(*(__libcwd_tsd.do_array[(debugObject).WNS_index] = new debug_tsd_st));
tsd.init();
set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_DO_TSD_MEMBER_OFF(debugObject) = 0;
);
}
}
#endif
debug_tsd_st::~debug_tsd_st()
{
#if LIBCWD_THREAD_SAFE
margin.deinitialize();
marker.deinitialize();
#endif
if (!tsd_initialized)
return;
if (continued_stack.size())
if (laf_stack.size())
}
{
channel_ct* tmp = NULL;
LIBCWD_TSD_DECLARATION;
LIBCWD_DEFER_CANCEL;
_private_::debug_channels.init(LIBCWD_TSD);
DEBUG_CHANNELS_ACQUIRE_READ_LOCK;
for(_private_::debug_channels_ct::container_type::const_iterator i(_private_::debug_channels.read_locked().begin());
i != _private_::debug_channels.read_locked().end(); ++i)
{
if (!strncasecmp(label, (*i)->get_label(), strlen(label)))
tmp = (*i);
}
DEBUG_CHANNELS_RELEASE_READ_LOCK;
LIBCWD_RESTORE_CANCEL;
return tmp;
}
{
LIBCWD_TSD_DECLARATION;
if (LIBCWD_DO_TSD_MEMBER_OFF(debug_object) < 0)
{
LIBCWD_DEFER_CANCEL;
_private_::debug_channels.init(LIBCWD_TSD);
LIBCWD_RESTORE_CANCEL;
LIBCWD_DEFER_CLEANUP_PUSH(&rwlock_tct<libcwd::_private_::debug_channels_instance>::cleanup, NULL);
DEBUG_CHANNELS_ACQUIRE_READ_LOCK;
for(_private_::debug_channels_ct::container_type::const_iterator i(_private_::debug_channels.read_locked().begin());
i != _private_::debug_channels.read_locked().end(); ++i)
{
if (NEED_SUPRESSION_OF_MALLOC_AND_BFD)
{
#if CWDEBUG_LOCATION
#endif
}
LibcwDoutStream.write(LIBCWD_DO_TSD_MEMBER(debug_object, margin).c_str(), LIBCWD_DO_TSD_MEMBER(debug_object, margin).size());
LibcwDoutStream.write((*i)->get_label(), WST_max_len);
if ((*i)->is_on(LIBCWD_TSD))
LibcwDoutStream.write(": Enabled", 9);
else
LibcwDoutStream.write(": Disabled", 10);
if (NEED_SUPRESSION_OF_MALLOC_AND_BFD)
{
#if CWDEBUG_LOCATION
#endif
}
LibcwDoutScopeEnd;
}
DEBUG_CHANNELS_RELEASE_READ_LOCK;
LIBCWD_CLEANUP_POP_RESTORE(false);
}
}
void channel_ct::NS_initialize(char const* label LIBCWD_COMMA_TSD_PARAM, bool add_to_channel_list)
{
if (WNS_initialized)
return;
DEBUGDEBUG_CERR( "Entering `channel_ct::NS_initialize(\"" << label << "\")'" );
size_t label_len = strlen(label);
LIBCWD_DEFER_CANCEL;
_private_::debug_channels.init(LIBCWD_TSD);
static _private_::debug_channels_ct hidden_channels;
hidden_channels.init(LIBCWD_TSD);
DEBUG_CHANNELS_ACQUIRE_WRITE_LOCK;
set_alloc_checking_off(LIBCWD_TSD);
_private_::debug_channels_ct::container_type& channels(_private_::debug_channels.write_locked());
for(_private_::debug_channels_ct::container_type::iterator i(channels.begin()); i != channels.end(); ++i)
const_cast<char*>((*i)->get_label())[WST_max_len] = ' ';
_private_::debug_channels_ct::container_type& channels_not_listed(hidden_channels.write_locked());
for(_private_::debug_channels_ct::container_type::iterator i(channels_not_listed.begin());
i != channels_not_listed.end(); ++i)
const_cast<char*>((*i)->get_label())[WST_max_len] = ' ';
if (label_len > WST_max_len)
WST_max_len = label_len;
for(_private_::debug_channels_ct::container_type::iterator i(channels.begin()); i != channels.end(); ++i)
const_cast<char*>((*i)->get_label())[WST_max_len] = '\0';
for(_private_::debug_channels_ct::container_type::iterator i(channels_not_listed.begin());
i != channels_not_listed.end(); ++i)
const_cast<char*>((*i)->get_label())[WST_max_len] = '\0';
set_alloc_checking_on(LIBCWD_TSD);
#if LIBCWD_THREAD_SAFE
static int next_index;
WNS_index = ++next_index;
__libcwd_tsd.off_cnt_array[WNS_index] = 0;
#else
off_cnt = 0;
#endif
PRAGMA_DIAGNOSTIC_PUSH_IGNORE_stringop_overflow
strncpy(WNS_label, label, label_len);
PRAGMA_DIAGNOSTIC_POP
WNS_label[WST_max_len] = '\0';
set_alloc_checking_off(LIBCWD_TSD);
if (add_to_channel_list)
{
_private_::debug_channels_ct::container_type::iterator i(channels.begin());
for(; i != channels.end(); ++i)
if (strncmp((*i)->get_label(), WNS_label, WST_max_len) > 0)
break;
channels.insert(i, this);
}
else
channels_not_listed.push_back(this);
set_alloc_checking_on(LIBCWD_TSD);
DEBUG_CHANNELS_RELEASE_WRITE_LOCK;
LIBCWD_RESTORE_CANCEL;
if (strncmp(WNS_label, "WARNING", label_len) == 0)
#if LIBCWD_THREAD_SAFE
__libcwd_tsd.off_cnt_array[WNS_index] = -1;
#else
off_cnt = -1;
#endif
DEBUGDEBUG_CERR( "Leaving `channel_ct::NS_initialize(\"" << label << "\")" );
WNS_initialized = true;
}
void fatal_channel_ct::NS_initialize(
char const* label,
control_flag_t maskbit LIBCWD_COMMA_TSD_PARAM)
{
if (WNS_maskbit)
return;
WNS_maskbit = maskbit;
DEBUGDEBUG_CERR( "Entering `fatal_channel_ct::NS_initialize(\"" << label << "\")'" );
size_t label_len = strlen(label);
LIBCWD_DEFER_CANCEL;
_private_::debug_channels.init(LIBCWD_TSD);
DEBUG_CHANNELS_ACQUIRE_WRITE_LOCK;
set_alloc_checking_off(LIBCWD_TSD);
_private_::debug_channels_ct::container_type& channels(_private_::debug_channels.write_locked());
for(_private_::debug_channels_ct::container_type::iterator i(channels.begin()); i != channels.end(); ++i)
const_cast<char*>((*i)->get_label())[WST_max_len] = ' ';
if (label_len > WST_max_len)
WST_max_len = label_len;
for(_private_::debug_channels_ct::container_type::iterator i(channels.begin()); i != channels.end(); ++i)
const_cast<char*>((*i)->get_label())[WST_max_len] = '\0';
set_alloc_checking_on(LIBCWD_TSD);
PRAGMA_DIAGNOSTIC_PUSH_IGNORE_stringop_overflow
strncpy(WNS_label, label, label_len);
PRAGMA_DIAGNOSTIC_POP
WNS_label[WST_max_len] = '\0';
DEBUG_CHANNELS_RELEASE_WRITE_LOCK;
LIBCWD_RESTORE_CANCEL;
DEBUGDEBUG_CERR( "Leaving `fatal_channel_ct::NS_initialize(\"" << label << "\")" );
}
{
if (!WNS_maskbit)
WNS_maskbit = maskbit;
}
char const always_channel_ct::label[
max_label_len_c + 1] = {
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>',
'>', 0 };
void channel_ct::off()
{
#if LIBCWD_THREAD_SAFE
LIBCWD_TSD_DECLARATION;
__libcwd_tsd.off_cnt_array[WNS_index] += 1;
#else
++off_cnt;
#endif
}
void channel_ct::on()
{
#if LIBCWD_THREAD_SAFE
LIBCWD_TSD_DECLARATION;
if (__libcwd_tsd.off_cnt_array[WNS_index] == -1)
#else
if (off_cnt == -1)
#endif
#if LIBCWD_THREAD_SAFE
__libcwd_tsd.off_cnt_array[WNS_index] -= 1;
#else
--off_cnt;
#endif
}
namespace _private_ {
void print_pop_error() {
DoutFatal(
dc::core,
"Using \"dc::finish\" without corresponding \"continued_cf\" or "
"calling the Dout(dc::finish, ...) more often than its corresponding "
"Dout(dc::channel|continued_cf, ...). Note that the wrong \"dc::finish\" doesn't "
"have to be the one that we core dumped on, if two or more are nested.");
}
}
{
#if CWDEBUG_DEBUG
DEBUGDEBUG_CERR( "continued_cf detected" );
if (!do_tsd_ptr || !do_tsd_ptr->tsd_initialized)
{
if (do_tsd_ptr)
DEBUGDEBUG_CERR( "&do_tsd_ptr->tsd_initialized == " << (void*)&do_tsd_ptr->tsd_initialized );
FATALDEBUGDEBUG_CERR( "Don't use DoutFatal together with continued_cf, use Dout instead." );
}
#endif
mask |= continued_cf_maskbit;
if (!on)
{
++(do_tsd_ptr->off_count);
DEBUGDEBUG_CERR( "Channel is switched off. Increased off_count to " << do_tsd_ptr->off_count );
}
else
{
do_tsd_ptr->continued_stack.push(do_tsd_ptr->off_count);
DEBUGDEBUG_CERR( "Channel is switched on. Pushed off_count (" << do_tsd_ptr->off_count << ") to stack (size now " <<
do_tsd_ptr->continued_stack.size() << ") and set off_count to 0" );
do_tsd_ptr->off_count = 0;
}
return *(reinterpret_cast<continued_channel_set_st*>(this));
}
continued_channel_set_st& channel_set_bootstrap_st::operator|(continued_channel_ct const& cdc)
{
#if CWDEBUG_DEBUG
if ((cdc.get_maskbit() & continued_maskbit))
DEBUGDEBUG_CERR( "dc::continued detected" );
else
DEBUGDEBUG_CERR( "dc::finish detected" );
#endif
if ((on = !do_tsd_ptr->off_count))
{
DEBUGDEBUG_CERR( "Channel is switched on (off_count is 0)" );
do_tsd_ptr->current->mask |= cdc.get_maskbit();
mask = do_tsd_ptr->current->mask;
label = do_tsd_ptr->current->label;
if (cdc.get_maskbit() == finish_maskbit)
{
do_tsd_ptr->off_count = do_tsd_ptr->continued_stack.top();
do_tsd_ptr->continued_stack.pop();
DEBUGDEBUG_CERR( "Restoring off_count to " << do_tsd_ptr->off_count << ". Stack size now " << do_tsd_ptr->continued_stack.size() );
}
}
else
{
DEBUGDEBUG_CERR( "Channel is switched off (off_count is " << do_tsd_ptr->off_count << ')' );
if (cdc.get_maskbit() == finish_maskbit)
{
DEBUGDEBUG_CERR( "` decrementing off_count with 1" );
--(do_tsd_ptr->off_count);
}
}
return *reinterpret_cast<continued_channel_set_st*>(this);
}
namespace _private_ {
void assert_fail(char const* expr, char const* file, int line, char const* function)
{
#if CWDEBUG_DEBUG
LIBCWD_TSD_DECLARATION;
if (__libcwd_tsd.recursive_assert
#if CWDEBUG_DEBUGM
|| __libcwd_tsd.inside_malloc_or_free
#endif
)
{
if (!__libcwd_tsd.recursive_assert
#if CWDEBUG_ALLOC
&& __libcwd_tsd.library_call < 6
#endif
)
{
#if CWDEBUG_ALLOC
int saved_internal = 0;
bool is_internal = __libcwd_tsd.internal;
if (is_internal)
saved_internal = _private_::set_library_call_on(LIBCWD_TSD);
else
++__libcwd_tsd.library_call;
#endif
#if CWDEBUG_ALLOC
if (is_internal)
_private_::set_library_call_off(saved_internal LIBCWD_COMMA_TSD);
else
--__libcwd_tsd.library_call;
#endif
}
set_alloc_checking_off(LIBCWD_TSD);
FATALDEBUGDEBUG_CERR(file << ':' << line << ": " << function << ": Assertion `" << expr << "' failed.\n");
set_alloc_checking_on(LIBCWD_TSD);
}
__libcwd_tsd.recursive_assert = true;
#if CWDEBUG_DEBUGT
__libcwd_tsd.internal_debugging_code = true;
#endif
#endif
DoutFatal(
dc::core, file <<
':' << line <<
": " <<
function <<
": Assertion `" << expr <<
"' failed.\n");
}
}
void debug_ct::force_on(debug_ct::OnOffState& state)
{
LIBCWD_TSD_DECLARATION;
#if CWDEBUG_DEBUG
if (!NS_init(LIBCWD_TSD))
DoutFatal(
dc::core,
"Calling debug_ct::NS_init recursively from debug_ct::force_on");
#else
(void)NS_init(LIBCWD_TSD);
#endif
state._off = LIBCWD_TSD_MEMBER_OFF;
#if CWDEBUG_DEBUGOUTPUT
state.first_time = LIBCWD_TSD_MEMBER(first_time);
#endif
LIBCWD_TSD_MEMBER_OFF = -1;
}
void debug_ct::restore(debug_ct::OnOffState const& state)
{
LIBCWD_TSD_DECLARATION;
#if CWDEBUG_DEBUGOUTPUT
if (state.first_time != LIBCWD_TSD_MEMBER(first_time))
#endif
if (LIBCWD_TSD_MEMBER_OFF != -1)
LIBCWD_TSD_MEMBER_OFF = state._off;
}
void channel_ct::force_on(channel_ct::OnOffState& state, char const* label)
{
LIBCWD_TSD_DECLARATION;
NS_initialize(label LIBCWD_COMMA_TSD, true);
#if LIBCWD_THREAD_SAFE
int& off_cnt(__libcwd_tsd.off_cnt_array[WNS_index]);
#endif
state.off_cnt = off_cnt;
off_cnt = -1;
}
void channel_ct::restore(channel_ct::OnOffState const& state)
{
#if LIBCWD_THREAD_SAFE
LIBCWD_TSD_DECLARATION;
int& off_cnt(__libcwd_tsd.off_cnt_array[WNS_index]);
#endif
if (off_cnt != -1)
off_cnt = state.off_cnt;
}
#if LIBCWD_THREAD_SAFE
template<>
void debug_ct::set_ostream(std::ostream* os, pthread_mutex_t* mutex)
{
LIBCWD_TSD_DECLARATION;
_private_::set_alloc_checking_off(LIBCWD_TSD);
_private_::lock_interface_base_ct* new_mutex = new _private_::pthread_lock_interface_ct(mutex);
_private_::set_alloc_checking_on(LIBCWD_TSD);
LIBCWD_DEFER_CANCEL;
_private_::mutex_tct<_private_::set_ostream_instance>::lock();
_private_::lock_interface_base_ct* old_mutex = M_mutex;
if (old_mutex)
old_mutex->lock();
M_mutex = new_mutex;
if (old_mutex)
{
old_mutex->unlock();
_private_::set_alloc_checking_off(LIBCWD_TSD);
delete old_mutex;
_private_::set_alloc_checking_on(LIBCWD_TSD);
}
private_set_ostream(os);
_private_::mutex_tct<_private_::set_ostream_instance>::unlock();
LIBCWD_RESTORE_CANCEL;
}
#endif
void debug_ct::set_ostream(std::ostream* os)
{
#if LIBCWD_THREAD_SAFE
if (_private_::WST_multi_threaded)
#if CWDEBUG_LOCATION
Dout(
dc::warning, location_ct((
char*)__builtin_return_address(0) +
builtin_return_address_offset) <<
": You should passing a locking mechanism to `set_ostream' for the ostream (see documentation/reference-manual/group__group__destination.html)");
#else
DoutFatal(
dc::core,
"You must pass a locking mechanism to `set_ostream' for the ostream (see documentation/reference-manual/group__group__destination.html)");
#endif
#if CWDEBUG_DEBUGT
LIBCWD_TSD_DECLARATION;
#endif
LIBCWD_DEFER_CANCEL;
_private_::mutex_tct<_private_::set_ostream_instance>::lock();
#endif
private_set_ostream(os);
#if LIBCWD_THREAD_SAFE
_private_::mutex_tct<_private_::set_ostream_instance>::unlock();
LIBCWD_RESTORE_CANCEL;
#endif
}
}
extern "C" char const* const __libcwd_version = VERSION;
namespace _private_ {
extern void demangle_symbol(
char const* in, _private_::internal_string& out);
}
}
void off()
Turn this channel off.
Definition: debug.cc:1780
void on()
Cancel one call to ‘off()’.
Definition: debug.cc:1795
size_t size() const
The size of the string.
Definition: class_debug_string.inl:89
void reserve(size_t)
Reserve memory for the string in advance.
Definition: debug.cc:905
This is the main header file of libcwd.
#define Dout(cntrl, data)
Macro for writing debug output.
Definition: debug.h:154
#define Debug(STATEMENTS...)
Encapsulation macro for general debugging code.
Definition: debug.h:124
void core_dump()
Dump core of current thread.
Definition: debug.cc:806
control_flag_t const blank_marker_cf
Replace marker by white space.
Definition: control_flag.h:50
control_flag_t const noprefix_cf
Omit margin, label, marker and indentation.
Definition: control_flag.h:38
control_flag_t const nolabel_cf
Omit label, marker and indentation.
Definition: control_flag.h:41
unsigned int control_flag_t
Definition: control_flag.h:31
control_flag_t const nonewline_cf
Omit the default new line at the end.
Definition: control_flag.h:35
control_flag_t const blank_margin_cf
Replace margin by white space.
Definition: control_flag.h:44
continued_cf_nt
continued_cf has its own type for overloading purposes.
Definition: control_flag.h:75
control_flag_t const error_cf
Append error string according to errno.
Definition: control_flag.h:62
control_flag_t const cerr_cf
Force output to be written to cerr.
Definition: control_flag.h:53
control_flag_t const blank_label_cf
Replace label by white space.
Definition: control_flag.h:47
control_flag_t const wait_cf
If interactive, wait till return is pressed.
Definition: control_flag.h:59
control_flag_t const flush_cf
Flush ostream after writing this output.
Definition: control_flag.h:56
channel_ct system
Definition: debug.cc:467
channel_ct malloc
Definition: debug.cc:474
channel_ct bfd
Definition: bfd.cc:92
continued_channel_ct finish
Definition: debug.cc:517
fatal_channel_ct fatal
Definition: debug.cc:527
channel_ct notice
Definition: debug.cc:460
continued_channel_ct continued
Definition: debug.cc:506
channel_ct debug
Definition: debug.cc:453
always_channel_ct always
Definition: debug.cc:495
fatal_channel_ct core
Definition: debug.cc:537
channel_ct warning
Definition: debug.cc:485
void demangle_symbol(char const *input, std::string &output)
Demangle mangled symbol name input and write the result to string output.
Definition: demangle3.cc:825
std::ostream * get_ostream() const
Get the ostream device as set with set_ostream().
Definition: class_debug.inl:128
#define DoutFatal(cntrl, data)
Macro for writing fatal debug output to the default debug object libcw_do .
Definition: debug.h:164
channel_ct * find_channel(char const *label)
Find debug channel with label label.
Definition: debug.cc:1528
#define ForAllDebugObjects(STATEMENT...)
Looping over all debug objects.
Definition: debug.h:209
void list_channels_on(debug_ct &debug_object)
List all debug channels to a given debug object.
Definition: debug.cc:1575
namespace for libcwd.
Definition: debug.cc:87
debug_ct libcw_do
The default debug object.
Definition: debug.cc:429
int const builtin_return_address_offset
Offset to __builtin_return_address() needed to get the correct line number from location_ct.
Definition: sys.h:39
unsigned short const max_label_len_c
The maximum number of characters that are allowed in a debug channel label.
Definition: max_label_len.h:24
«