diff --git a/src/add-ons/kernel/file_systems/udf/UdfDebug.cpp b/src/add-ons/kernel/file_systems/udf/UdfDebug.cpp index 4ac3f5f3a2..6aa90adde2 100644 --- a/src/add-ons/kernel/file_systems/udf/UdfDebug.cpp +++ b/src/add-ons/kernel/file_systems/udf/UdfDebug.cpp @@ -1,18 +1,115 @@ -/* Debug - debug stuff -** -** UDF modifications by Tyler Dauwalder, tyler@dauwalder.net -** Initial version by Axel Dörfler, axeld@pinc-software.de -** Some code is based on work previously done by Marcus Overhagen -** -** This file may be used under the terms of the OpenBeOS License. +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// UDF version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +// Initial version copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de +//---------------------------------------------------------------------- + +/*! \file UdfDebug.cpp + + Support code for handy debugging macros. */ -#include "Debug.h" -//#include "BPlusTree.h" +#include "UdfDebug.h" #include +#include -#include +//---------------------------------------------------------------------- +// declarations +//---------------------------------------------------------------------- -#define Print __out +static void indent(); +static void unindent(); +static int32 get_tls_handle(); + +//! Used to keep the tls handle from being allocated more than once. +vint32 tls_spinlock = 0; + +/*! \brief Used to flag whether the tls handle has been allocated yet. + + Not sure if this really needs to be \c volatile or not... +*/ +volatile bool tls_handle_initialized = false; + +//! The tls handle of the tls var used to store indentation info. +int32 tls_handle = 0; + +//---------------------------------------------------------------------- +// public functions +//---------------------------------------------------------------------- + +/*! \brief Returns the current debug indentation level for the + current thread. +*/ +int32 +_get_debug_indent_level() +{ + return (int32)tls_get(get_tls_handle()); +} + +//---------------------------------------------------------------------- +// static functions +//---------------------------------------------------------------------- + +/*! \brief Increases the current debug indentation level for + the current thread by 1. +*/ +void +indent() +{ + tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()+1)); +} + +/*! \brief Decreases the current debug indentation level for + the current thread by 1. +*/ +void +unindent() +{ + tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()-1)); +} + +/*! \brief Returns the thread local storage handle used to store + indentation information, allocating the handle first if + necessary. +*/ +int32 +get_tls_handle() +{ + // Init the tls handle if this is the first call. + if (!tls_handle_initialized) { + if (atomic_or(&tls_spinlock, 1) == 0) { + // First one in gets to init + tls_handle = tls_allocate(); + tls_handle_initialized = true; + atomic_and(&tls_spinlock, 0); + } else { + // All others must wait patiently + while (!tls_handle_initialized) { + snooze(1); + } + } + } + return tls_handle; +} + +//---------------------------------------------------------------------- +// _DebugHelper +//---------------------------------------------------------------------- + +/*! \brief Increases the current indentation level. +*/ +_DebugHelper::_DebugHelper() +{ + indent(); +} + +/*! \brief Decreases the current indentation level. +*/ +_DebugHelper::~_DebugHelper() +{ + unindent(); +} diff --git a/src/add-ons/kernel/file_systems/udf/UdfDebug.h b/src/add-ons/kernel/file_systems/udf/UdfDebug.h index bf1d8f9fcc..5efb0b39a3 100644 --- a/src/add-ons/kernel/file_systems/udf/UdfDebug.h +++ b/src/add-ons/kernel/file_systems/udf/UdfDebug.h @@ -1,14 +1,21 @@ -#ifndef DEBUG_H -#define DEBUG_H -/* Debug - debug stuff -** -** UDF modifications by Tyler Dauwalder, tyler@dauwalder.net -** Initial version by Axel Dörfler, axeld@pinc-software.de -** This file may be used under the terms of the OpenBeOS License. +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// UDF version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +// Initial version copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de +//---------------------------------------------------------------------- +#ifndef UDF_DEBUG_H +#define UDF_DEBUG_H + +/*! \file UdfDebug.h + + Handy debugging macros. */ #include +#include #ifdef DEBUG # include #endif @@ -21,81 +28,226 @@ # define __out dprintf #endif -// Which debugger should be used when? -// The DEBUGGER() macro actually has no effect if DEBUG is not defined, -// use the DIE() macro if you really want to die. -#ifdef DEBUG -# ifdef USER -# define DEBUGGER(x) debugger x -# else -# define DEBUGGER(x) kernel_debugger x -# endif -#else -# define DEBUGGER(x) ; -#endif +/*! \def DIE(x) + \brief Drops the user into the appropriate debugger (user or kernel) + after printing out the handy message bundled in the parenthesee + enclosed printf-style format string found in \a x. + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); +*/ #ifdef USER # define DIE(x) debugger x #else # define DIE(x) kernel_debugger x #endif -// Short overview over the debug output macros: -// PRINT() -// is for general messages that very unlikely should appear in a release build -// FATAL() -// this is for fatal messages, when something has really gone wrong -// INFORM() -// general information, as disk size, etc. -// REPORT_ERROR(status_t) -// prints out error information -// RETURN_ERROR(status_t) -// calls REPORT_ERROR() and return the value -// D() -// the statements in D() are only included if DEBUG is defined +int32 _get_debug_indent_level(); +/*! \brief Helper class that is allocated on the stack by + the \c DEBUG_INIT() macro. On creation, it increases the + current indentation level by 1; on destruction, it decreases + it by 1. +*/ +class _DebugHelper +{ +public: + _DebugHelper(); + ~_DebugHelper(); +}; + +//---------------------------------------------------------------------- +// Long-winded overview of the debug output macros: +//---------------------------------------------------------------------- +/*! \def DEBUG_INIT() + \brief Increases the indentation level, prints out the enclosing function's + name, and creates a \c _DebugHelper object on the stack to automatically + decrease the indentation level upon function exit. + + This macro should be called at the very beginning of any function in + which you wish to use any of the other debugging macros. + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def PRINT(x) + \brief Prints out the enclosing function's name followed by the contents + of \a x at the current indentation level. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def LPRINT(x) + \brief Identical to \c PRINT(x), except that the line number in the source + file at which the macro is invoked is also printed. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def SIMPLE_PRINT(x) + \brief Directly prints the contents of \a x with no extra formatting or + information included (just like a straight \c printf() call). + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def PRINT_INDENT() + \brief Prints out enough indentation characters to indent the current line + to the current indentation level (assuming the cursor was flush left to + begin with...). + + This function is called by the other \c *PRINT* macros, and isn't really + intended for general consumption, but you might find it useful. + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def REPORT_ERROR(err) + \brief Calls \c LPRINT(x) with a format string listing the error + code in \c err (assumed to be a \c status_t value) and the + corresponding text error code returned by a call to \c strerror(). + + This function is called by the \c RETURN* macros, and isn't really + intended for general consumption, but you might find it useful. + + \param err A \c status_t error code to report. + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def RETURN_ERROR(err) + \brief Calls \c REPORT_ERROR(err) if err is a an error code (i.e. + negative), otherwise remains silent. In either case, the enclosing + function is then exited with a call to \c "return err;". + + \param err A \c status_t error code to report (if negative) and return. + + If DEBUG is undefined, silently returns the value in \c err. +*/ +//---------------------------------------------------------------------- +/*! \def RETURN(err) + \brief Prints out a description of the error code being returned + (which, in this case, may be either "erroneous" or "successful") + and then exits the enclosing function with a call to \c "return err;". + + \param err A \c status_t error code to report and return. + + If DEBUG is undefined, silently returns the value in \c err. +*/ +//---------------------------------------------------------------------- +/*! \def FATAL(x) + \brief Prints out a fatal error message. + + This one's still a work in progress... + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + If DEBUG is undefined, does nothing. +*/ +//---------------------------------------------------------------------- +/*! \def INFORM(x) + \brief Directly prints the contents of \a x with no extra formatting or + information included (just like a straight \c printf() call). Does so + whether \c DEBUG is defined or not. + + \param x A printf-style format string enclosed in an extra set of parenteses, + e.g. PRINT(("%d\n", 0)); + + I'll say it again: Prints its output regardless to DEBUG being defined or + undefined. +*/ +//---------------------------------------------------------------------- +/*! \def DBG(x) + \brief If debug is defined, \a x is passed along to the code and + executed unmodified. If \c DEBUG is undefined, the contents of + \a x disappear into the ether. + + \param x Damn near anything resembling valid C\C++. +*/ + +//---------------------------------------------------------------------- +// DEBUG-independent macros +//---------------------------------------------------------------------- +#define INFORM(x) { __out("udf: "); __out x; } + +//---------------------------------------------------------------------- +// DEBUG-dependent macros +//---------------------------------------------------------------------- #ifdef DEBUG - #define PRINT(x) { __out("udf: "); __out x; } - #define REPORT_ERROR(status) \ - __out("udf: %s:%d: %s\n", __FUNCTION__, __LINE__, strerror(status)); - #define RETURN_ERROR(err) { status_t _status = err; if (_status < B_OK) REPORT_ERROR(_status); return _status;} - #define FATAL(x) { __out("udf: "); __out x; } - #define INFORM(x) { __out("udf: "); __out x; } - #define FUNCTION() __out("udf: %s()\n",__FUNCTION__); - #define FUNCTION_START(x) { __out("udf: %s() ",__FUNCTION__); __out x; } -// #define FUNCTION() ; -// #define FUNCTION_START(x) ; - #define D(x) {x;}; - #define ASSERT(x) { if (!(x)) DEBUGGER(("udf: assert failed: " #x "\n")); } -#else + #define DEBUG_INIT() \ + _DebugHelper _debug_helper_object; \ + PRINT(("\n")); + + #define PRINT(x) { \ + PRINT_INDENT(); \ + __out("udf(%ld): %s(): ", find_thread(NULL), __FUNCTION__); \ + __out x; \ + } + + #define LPRINT(x) { \ + PRINT_INDENT(); \ + __out("udf(%ld): %s(): line %d: ", find_thread(NULL), __FUNCTION__, __LINE__); \ + __out x; \ + } + + #define SIMPLE_PRINT(x) { __out x; } + + #define PRINT_INDENT() { \ + int32 _level = _get_debug_indent_level(); \ + for (int32 i = 0; i < _level-1; i++) \ + __out(" "); \ + } + + #define REPORT_ERROR(err) { \ + LPRINT(("returning error 0x%lx, `%s'\n", err, strerror(err))); \ + } + + #define RETURN_ERROR(err) { \ + status_t _status = err; \ + if (_status < (status_t)B_OK) \ + REPORT_ERROR(_status); \ + return _status; \ + } + + #define RETURN(err) { \ + status_t _status = err; \ + if (_status < (status_t)B_OK) { \ + REPORT_ERROR(_status); \ + } else if (_status == (status_t)B_OK) { \ + LPRINT(("returning B_OK\n")); \ + } else { \ + LPRINT(("returning 0x%lx = %ld\n", _status, _status)); \ + } \ + return _status; \ + } + + #define FATAL(x) { \ + PRINT(("fatal error: ")); SIMPLE_PRINT(x); \ + } + + #define DBG(x) x ; + +#else // ifdef DEBUG + #define DEBUG_INIT() ; #define PRINT(x) ; + #define LPRINT(x) ; + #define SIMPLE_PRINT(x) ; + #define PRINT_INDENT(x) ; #define REPORT_ERROR(status) ; #define RETURN_ERROR(status) return status; - #define FATAL(x) { __out("udf: "); __out x; } - #define INFORM(x) { __out("udf: "); __out x; } - #define FUNCTION() ; - #define FUNCTION_START(x) ; - #define D(x) ; - #define ASSERT(x) ; -#endif + #define RETURN(status) return status; + #define FATAL(x) { __out("udf: fatal error: "); __out x; } + #define DBG(x) ; +#endif // ifdef DEBUG else -#ifdef DEBUG -// struct block_run; -// struct bplustree_header; -// struct bplustree_node; -// struct data_stream; -// struct udf_inode; -// struct disk_super_block; -// class Volume; - - // some structure dump functions -// extern void dump_block_run(const char *prefix, block_run &run); -// extern void dump_super_block(disk_super_block *superBlock); -// extern void dump_data_stream(data_stream *stream); -// extern void dump_inode(bfs_inode *inode); -// extern void dump_bplustree_header(bplustree_header *header); -// extern void dump_bplustree_node(bplustree_node *node,bplustree_header *header = NULL,Volume *volume = NULL); -// extern void dump_block(const char *buffer, int size); -#endif - -#endif /* DEBUG_H */ +#endif // DEBUG_H