annotate win32-mingw/include/kj/debug.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents eccd51b72864
children
rev   line source
Chris@64 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
Chris@64 2 // Licensed under the MIT License:
Chris@64 3 //
Chris@64 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
Chris@64 5 // of this software and associated documentation files (the "Software"), to deal
Chris@64 6 // in the Software without restriction, including without limitation the rights
Chris@64 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Chris@64 8 // copies of the Software, and to permit persons to whom the Software is
Chris@64 9 // furnished to do so, subject to the following conditions:
Chris@64 10 //
Chris@64 11 // The above copyright notice and this permission notice shall be included in
Chris@64 12 // all copies or substantial portions of the Software.
Chris@64 13 //
Chris@64 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Chris@64 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Chris@64 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Chris@64 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Chris@64 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Chris@64 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Chris@64 20 // THE SOFTWARE.
Chris@64 21
Chris@64 22 // This file declares convenient macros for debug logging and error handling. The macros make
Chris@64 23 // it excessively easy to extract useful context information from code. Example:
Chris@64 24 //
Chris@64 25 // KJ_ASSERT(a == b, a, b, "a and b must be the same.");
Chris@64 26 //
Chris@64 27 // On failure, this will throw an exception whose description looks like:
Chris@64 28 //
Chris@64 29 // myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same.
Chris@64 30 //
Chris@64 31 // As you can see, all arguments after the first provide additional context.
Chris@64 32 //
Chris@64 33 // The macros available are:
Chris@64 34 //
Chris@64 35 // * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can
Chris@64 36 // intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`,
Chris@64 37 // `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the
Chris@64 38 // user should be able to pass a flag like `--verbose` to enable them. Other log levels are
Chris@64 39 // enabled by default. Log messages -- like exceptions -- can be intercepted by registering an
Chris@64 40 // ExceptionCallback.
Chris@64 41 //
Chris@64 42 // * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while
Chris@64 43 // debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing
Chris@64 44 // code. It is suggested that you set up a pre-commit hook that checks for this.
Chris@64 45 //
Chris@64 46 // * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if
Chris@64 47 // exceptions are disabled. This macro should be used to check for bugs in the surrounding code
Chris@64 48 // and its dependencies, but NOT to check for invalid input. The macro may be followed by a
Chris@64 49 // brace-delimited code block; if so, the block will be executed in the case where the assertion
Chris@64 50 // fails, before throwing the exception. If control jumps out of the block (e.g. with "break",
Chris@64 51 // "return", or "goto"), then the error is considered "recoverable" -- in this case, if
Chris@64 52 // exceptions are disabled, execution will continue normally rather than aborting (but if
Chris@64 53 // exceptions are enabled, an exception will still be thrown on exiting the block). A "break"
Chris@64 54 // statement in particular will jump to the code immediately after the block (it does not break
Chris@64 55 // any surrounding loop or switch). Example:
Chris@64 56 //
Chris@64 57 // KJ_ASSERT(value >= 0, "Value cannot be negative.", value) {
Chris@64 58 // // Assertion failed. Set value to zero to "recover".
Chris@64 59 // value = 0;
Chris@64 60 // // Don't abort if exceptions are disabled. Continue normally.
Chris@64 61 // // (Still throw an exception if they are enabled, though.)
Chris@64 62 // break;
Chris@64 63 // }
Chris@64 64 // // When exceptions are disabled, we'll get here even if the assertion fails.
Chris@64 65 // // Otherwise, we get here only if the assertion passes.
Chris@64 66 //
Chris@64 67 // * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to
Chris@64 68 // validate parameters passed from a caller. A failure indicates that the caller is buggy.
Chris@64 69 //
Chris@64 70 // * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result
Chris@64 71 // is considered an error, with error code reported via `errno`. EINTR is handled by retrying.
Chris@64 72 // Other errors are handled by throwing an exception. If you need to examine the return code,
Chris@64 73 // assign it to a variable like so:
Chris@64 74 //
Chris@64 75 // int fd;
Chris@64 76 // KJ_SYSCALL(fd = open(filename, O_RDONLY), filename);
Chris@64 77 //
Chris@64 78 // `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`.
Chris@64 79 //
Chris@64 80 // * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on
Chris@64 81 // EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it
Chris@64 82 // indicates an error; in this case, it can assume the error was EAGAIN because any other error
Chris@64 83 // would have caused an exception to be thrown.
Chris@64 84 //
Chris@64 85 // * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown
Chris@64 86 // from within the current scope. That is, until control exits the block in which KJ_CONTEXT()
Chris@64 87 // is used, if any exception is generated, it will contain the given information in its context
Chris@64 88 // chain. This is helpful because it can otherwise be very difficult to come up with error
Chris@64 89 // messages that make sense within low-level helper code. Note that the parameters to
Chris@64 90 // KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables
Chris@64 91 // used must remain valid until the end of the scope.
Chris@64 92 //
Chris@64 93 // Notes:
Chris@64 94 // * Do not write expressions with side-effects in the message content part of the macro, as the
Chris@64 95 // message will not necessarily be evaluated.
Chris@64 96 // * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report
Chris@64 97 // failures that already happened. For the macros that check a boolean condition, `FAIL_FOO`
Chris@64 98 // omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and
Chris@64 99 // `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters.
Chris@64 100 // The string should be the name of the failed system call.
Chris@64 101 // * For every macro `FOO` above, there is a `DFOO` version (or `RECOVERABLE_DFOO`) which is only
Chris@64 102 // executed in debug mode, i.e. when KJ_DEBUG is defined. KJ_DEBUG is defined automatically
Chris@64 103 // by common.h when compiling without optimization (unless NDEBUG is defined), but you can also
Chris@64 104 // define it explicitly (e.g. -DKJ_DEBUG). Generally, production builds should NOT use KJ_DEBUG
Chris@64 105 // as it may enable expensive checks that are unlikely to fail.
Chris@64 106
Chris@64 107 #ifndef KJ_DEBUG_H_
Chris@64 108 #define KJ_DEBUG_H_
Chris@64 109
Chris@64 110 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
Chris@64 111 #pragma GCC system_header
Chris@64 112 #endif
Chris@64 113
Chris@64 114 #include "string.h"
Chris@64 115 #include "exception.h"
Chris@64 116
Chris@64 117 #ifdef ERROR
Chris@64 118 // This is problematic because windows.h #defines ERROR, which we use in an enum here.
Chris@64 119 #error "Make sure to to undefine ERROR (or just #include <kj/windows-sanity.h>) before this file"
Chris@64 120 #endif
Chris@64 121
Chris@64 122 namespace kj {
Chris@64 123
Chris@64 124 #if _MSC_VER
Chris@64 125 // MSVC does __VA_ARGS__ differently from GCC:
Chris@64 126 // - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants
Chris@64 127 // you to request this behavior with "##__VA_ARGS__".
Chris@64 128 // - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a
Chris@64 129 // *single* argument rather than an argument list. This can be worked around by wrapping the
Chris@64 130 // outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before
Chris@64 131 // the macro is evaluated. I don't understand the C preprocessor.
Chris@64 132 // - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is
Chris@64 133 // empty, rather than expanding to an empty string literal. We can work around by concatenating
Chris@64 134 // with an empty string literal.
Chris@64 135
Chris@64 136 #define KJ_EXPAND(X) X
Chris@64 137
Chris@64 138 #define KJ_LOG(severity, ...) \
Chris@64 139 if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \
Chris@64 140 ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
Chris@64 141 "" #__VA_ARGS__, __VA_ARGS__)
Chris@64 142
Chris@64 143 #define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__))
Chris@64 144
Chris@64 145 #define KJ_REQUIRE(cond, ...) \
Chris@64 146 if (KJ_LIKELY(cond)) {} else \
Chris@64 147 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
Chris@64 148 #cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 149
Chris@64 150 #define KJ_FAIL_REQUIRE(...) \
Chris@64 151 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
Chris@64 152 nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 153
Chris@64 154 #define KJ_SYSCALL(call, ...) \
Chris@64 155 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
Chris@64 156 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 157 _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 158
Chris@64 159 #define KJ_NONBLOCKING_SYSCALL(call, ...) \
Chris@64 160 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
Chris@64 161 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 162 _kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 163
Chris@64 164 #define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
Chris@64 165 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 166 errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 167
Chris@64 168 #if _WIN32
Chris@64 169
Chris@64 170 #define KJ_WIN32(call, ...) \
Chris@64 171 if (::kj::_::Debug::isWin32Success(call)) {} else \
Chris@64 172 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 173 ::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 174
Chris@64 175 #define KJ_WINSOCK(call, ...) \
Chris@64 176 if ((call) != SOCKET_ERROR) {} else \
Chris@64 177 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 178 ::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 179
Chris@64 180 #define KJ_FAIL_WIN32(code, errorNumber, ...) \
Chris@64 181 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 182 ::kj::_::Debug::Win32Error(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 183
Chris@64 184 #endif
Chris@64 185
Chris@64 186 #define KJ_UNIMPLEMENTED(...) \
Chris@64 187 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
Chris@64 188 nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
Chris@64 189
Chris@64 190 // TODO(msvc): MSVC mis-deduces `ContextImpl<decltype(func)>` as `ContextImpl<int>` in some edge
Chris@64 191 // cases, such as inside nested lambdas inside member functions. Wrapping the type in
Chris@64 192 // `decltype(instance<...>())` helps it deduce the context function's type correctly.
Chris@64 193 #define KJ_CONTEXT(...) \
Chris@64 194 auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
Chris@64 195 return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
Chris@64 196 ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \
Chris@64 197 }; \
Chris@64 198 decltype(::kj::instance<::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))>>()) \
Chris@64 199 KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
Chris@64 200
Chris@64 201 #define KJ_REQUIRE_NONNULL(value, ...) \
Chris@64 202 (*[&] { \
Chris@64 203 auto _kj_result = ::kj::_::readMaybe(value); \
Chris@64 204 if (KJ_UNLIKELY(!_kj_result)) { \
Chris@64 205 ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
Chris@64 206 #value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \
Chris@64 207 } \
Chris@64 208 return _kj_result; \
Chris@64 209 }())
Chris@64 210
Chris@64 211 #define KJ_EXCEPTION(type, ...) \
Chris@64 212 ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
Chris@64 213 ::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__))
Chris@64 214
Chris@64 215 #else
Chris@64 216
Chris@64 217 #define KJ_LOG(severity, ...) \
Chris@64 218 if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \
Chris@64 219 ::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
Chris@64 220 #__VA_ARGS__, ##__VA_ARGS__)
Chris@64 221
Chris@64 222 #define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__)
Chris@64 223
Chris@64 224 #define KJ_REQUIRE(cond, ...) \
Chris@64 225 if (KJ_LIKELY(cond)) {} else \
Chris@64 226 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
Chris@64 227 #cond, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 228
Chris@64 229 #define KJ_FAIL_REQUIRE(...) \
Chris@64 230 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
Chris@64 231 nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 232
Chris@64 233 #define KJ_SYSCALL(call, ...) \
Chris@64 234 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
Chris@64 235 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 236 _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 237
Chris@64 238 #define KJ_NONBLOCKING_SYSCALL(call, ...) \
Chris@64 239 if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
Chris@64 240 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 241 _kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 242
Chris@64 243 #define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
Chris@64 244 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 245 errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 246
Chris@64 247 #if _WIN32
Chris@64 248
Chris@64 249 #define KJ_WIN32(call, ...) \
Chris@64 250 if (::kj::_::Debug::isWin32Success(call)) {} else \
Chris@64 251 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 252 ::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 253
Chris@64 254 #define KJ_WINSOCK(call, ...) \
Chris@64 255 if ((call) != SOCKET_ERROR) {} else \
Chris@64 256 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 257 ::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 258
Chris@64 259 #define KJ_FAIL_WIN32(code, errorNumber, ...) \
Chris@64 260 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
Chris@64 261 ::kj::_::Debug::Win32Error(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 262
Chris@64 263 #endif
Chris@64 264
Chris@64 265 #define KJ_UNIMPLEMENTED(...) \
Chris@64 266 for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
Chris@64 267 nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
Chris@64 268
Chris@64 269 #define KJ_CONTEXT(...) \
Chris@64 270 auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
Chris@64 271 return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
Chris@64 272 ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \
Chris@64 273 }; \
Chris@64 274 ::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
Chris@64 275 KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
Chris@64 276
Chris@64 277 #define KJ_REQUIRE_NONNULL(value, ...) \
Chris@64 278 (*({ \
Chris@64 279 auto _kj_result = ::kj::_::readMaybe(value); \
Chris@64 280 if (KJ_UNLIKELY(!_kj_result)) { \
Chris@64 281 ::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
Chris@64 282 #value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \
Chris@64 283 } \
Chris@64 284 kj::mv(_kj_result); \
Chris@64 285 }))
Chris@64 286
Chris@64 287 #define KJ_EXCEPTION(type, ...) \
Chris@64 288 ::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
Chris@64 289 ::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__))
Chris@64 290
Chris@64 291 #endif
Chris@64 292
Chris@64 293 #define KJ_SYSCALL_HANDLE_ERRORS(call) \
Chris@64 294 if (int _kjSyscallError = ::kj::_::Debug::syscallError([&](){return (call);}, false)) \
Chris@64 295 switch (int error = _kjSyscallError)
Chris@64 296 // Like KJ_SYSCALL, but doesn't throw. Instead, the block after the macro is a switch block on the
Chris@64 297 // error. Additionally, the int value `error` is defined within the block. So you can do:
Chris@64 298 //
Chris@64 299 // KJ_SYSCALL_HANDLE_ERRORS(foo()) {
Chris@64 300 // case ENOENT:
Chris@64 301 // handleNoSuchFile();
Chris@64 302 // break;
Chris@64 303 // case EEXIST:
Chris@64 304 // handleExists();
Chris@64 305 // break;
Chris@64 306 // default:
Chris@64 307 // KJ_FAIL_SYSCALL("foo()", error);
Chris@64 308 // } else {
Chris@64 309 // handleSuccessCase();
Chris@64 310 // }
Chris@64 311
Chris@64 312 #define KJ_ASSERT KJ_REQUIRE
Chris@64 313 #define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE
Chris@64 314 #define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL
Chris@64 315 // Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code.
Chris@64 316 // That is, if the assert ever fails, it indicates that the immediate surrounding code is broken.
Chris@64 317
Chris@64 318 #ifdef KJ_DEBUG
Chris@64 319 #define KJ_DLOG KJ_LOG
Chris@64 320 #define KJ_DASSERT KJ_ASSERT
Chris@64 321 #define KJ_DREQUIRE KJ_REQUIRE
Chris@64 322 #else
Chris@64 323 #define KJ_DLOG(...) do {} while (false)
Chris@64 324 #define KJ_DASSERT(...) do {} while (false)
Chris@64 325 #define KJ_DREQUIRE(...) do {} while (false)
Chris@64 326 #endif
Chris@64 327
Chris@64 328 namespace _ { // private
Chris@64 329
Chris@64 330 class Debug {
Chris@64 331 public:
Chris@64 332 Debug() = delete;
Chris@64 333
Chris@64 334 typedef LogSeverity Severity; // backwards-compatibility
Chris@64 335
Chris@64 336 #if _WIN32
Chris@64 337 struct Win32Error {
Chris@64 338 // Hack for overloading purposes.
Chris@64 339 uint number;
Chris@64 340 inline explicit Win32Error(uint number): number(number) {}
Chris@64 341 };
Chris@64 342 #endif
Chris@64 343
Chris@64 344 static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; }
Chris@64 345 // Returns whether messages of the given severity should be logged.
Chris@64 346
Chris@64 347 static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; }
Chris@64 348 // Set the minimum message severity which will be logged.
Chris@64 349 //
Chris@64 350 // TODO(someday): Expose publicly.
Chris@64 351
Chris@64 352 template <typename... Params>
Chris@64 353 static void log(const char* file, int line, LogSeverity severity, const char* macroArgs,
Chris@64 354 Params&&... params);
Chris@64 355
Chris@64 356 class Fault {
Chris@64 357 public:
Chris@64 358 template <typename Code, typename... Params>
Chris@64 359 Fault(const char* file, int line, Code code,
Chris@64 360 const char* condition, const char* macroArgs, Params&&... params);
Chris@64 361 Fault(const char* file, int line, Exception::Type type,
Chris@64 362 const char* condition, const char* macroArgs);
Chris@64 363 Fault(const char* file, int line, int osErrorNumber,
Chris@64 364 const char* condition, const char* macroArgs);
Chris@64 365 #if _WIN32
Chris@64 366 Fault(const char* file, int line, Win32Error osErrorNumber,
Chris@64 367 const char* condition, const char* macroArgs);
Chris@64 368 #endif
Chris@64 369 ~Fault() noexcept(false);
Chris@64 370
Chris@64 371 KJ_NOINLINE KJ_NORETURN(void fatal());
Chris@64 372 // Throw the exception.
Chris@64 373
Chris@64 374 private:
Chris@64 375 void init(const char* file, int line, Exception::Type type,
Chris@64 376 const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
Chris@64 377 void init(const char* file, int line, int osErrorNumber,
Chris@64 378 const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
Chris@64 379 #if _WIN32
Chris@64 380 void init(const char* file, int line, Win32Error osErrorNumber,
Chris@64 381 const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
Chris@64 382 #endif
Chris@64 383
Chris@64 384 Exception* exception;
Chris@64 385 };
Chris@64 386
Chris@64 387 class SyscallResult {
Chris@64 388 public:
Chris@64 389 inline SyscallResult(int errorNumber): errorNumber(errorNumber) {}
Chris@64 390 inline operator void*() { return errorNumber == 0 ? this : nullptr; }
Chris@64 391 inline int getErrorNumber() { return errorNumber; }
Chris@64 392
Chris@64 393 private:
Chris@64 394 int errorNumber;
Chris@64 395 };
Chris@64 396
Chris@64 397 template <typename Call>
Chris@64 398 static SyscallResult syscall(Call&& call, bool nonblocking);
Chris@64 399 template <typename Call>
Chris@64 400 static int syscallError(Call&& call, bool nonblocking);
Chris@64 401
Chris@64 402 #if _WIN32
Chris@64 403 static bool isWin32Success(int boolean);
Chris@64 404 static bool isWin32Success(void* handle);
Chris@64 405 static Win32Error getWin32Error();
Chris@64 406 #endif
Chris@64 407
Chris@64 408 class Context: public ExceptionCallback {
Chris@64 409 public:
Chris@64 410 Context();
Chris@64 411 KJ_DISALLOW_COPY(Context);
Chris@64 412 virtual ~Context() noexcept(false);
Chris@64 413
Chris@64 414 struct Value {
Chris@64 415 const char* file;
Chris@64 416 int line;
Chris@64 417 String description;
Chris@64 418
Chris@64 419 inline Value(const char* file, int line, String&& description)
Chris@64 420 : file(file), line(line), description(mv(description)) {}
Chris@64 421 };
Chris@64 422
Chris@64 423 virtual Value evaluate() = 0;
Chris@64 424
Chris@64 425 virtual void onRecoverableException(Exception&& exception) override;
Chris@64 426 virtual void onFatalException(Exception&& exception) override;
Chris@64 427 virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
Chris@64 428 String&& text) override;
Chris@64 429
Chris@64 430 private:
Chris@64 431 bool logged;
Chris@64 432 Maybe<Value> value;
Chris@64 433
Chris@64 434 Value ensureInitialized();
Chris@64 435 };
Chris@64 436
Chris@64 437 template <typename Func>
Chris@64 438 class ContextImpl: public Context {
Chris@64 439 public:
Chris@64 440 inline ContextImpl(Func& func): func(func) {}
Chris@64 441 KJ_DISALLOW_COPY(ContextImpl);
Chris@64 442
Chris@64 443 Value evaluate() override {
Chris@64 444 return func();
Chris@64 445 }
Chris@64 446 private:
Chris@64 447 Func& func;
Chris@64 448 };
Chris@64 449
Chris@64 450 template <typename... Params>
Chris@64 451 static String makeDescription(const char* macroArgs, Params&&... params);
Chris@64 452
Chris@64 453 private:
Chris@64 454 static LogSeverity minSeverity;
Chris@64 455
Chris@64 456 static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs,
Chris@64 457 ArrayPtr<String> argValues);
Chris@64 458 static String makeDescriptionInternal(const char* macroArgs, ArrayPtr<String> argValues);
Chris@64 459
Chris@64 460 static int getOsErrorNumber(bool nonblocking);
Chris@64 461 // Get the error code of the last error (e.g. from errno). Returns -1 on EINTR.
Chris@64 462 };
Chris@64 463
Chris@64 464 template <typename... Params>
Chris@64 465 void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs,
Chris@64 466 Params&&... params) {
Chris@64 467 String argValues[sizeof...(Params)] = {str(params)...};
Chris@64 468 logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
Chris@64 469 }
Chris@64 470
Chris@64 471 template <>
Chris@64 472 inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) {
Chris@64 473 logInternal(file, line, severity, macroArgs, nullptr);
Chris@64 474 }
Chris@64 475
Chris@64 476 template <typename Code, typename... Params>
Chris@64 477 Debug::Fault::Fault(const char* file, int line, Code code,
Chris@64 478 const char* condition, const char* macroArgs, Params&&... params)
Chris@64 479 : exception(nullptr) {
Chris@64 480 String argValues[sizeof...(Params)] = {str(params)...};
Chris@64 481 init(file, line, code, condition, macroArgs,
Chris@64 482 arrayPtr(argValues, sizeof...(Params)));
Chris@64 483 }
Chris@64 484
Chris@64 485 inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber,
Chris@64 486 const char* condition, const char* macroArgs)
Chris@64 487 : exception(nullptr) {
Chris@64 488 init(file, line, osErrorNumber, condition, macroArgs, nullptr);
Chris@64 489 }
Chris@64 490
Chris@64 491 inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type,
Chris@64 492 const char* condition, const char* macroArgs)
Chris@64 493 : exception(nullptr) {
Chris@64 494 init(file, line, type, condition, macroArgs, nullptr);
Chris@64 495 }
Chris@64 496
Chris@64 497 #if _WIN32
Chris@64 498 inline Debug::Fault::Fault(const char* file, int line, Win32Error osErrorNumber,
Chris@64 499 const char* condition, const char* macroArgs)
Chris@64 500 : exception(nullptr) {
Chris@64 501 init(file, line, osErrorNumber, condition, macroArgs, nullptr);
Chris@64 502 }
Chris@64 503
Chris@64 504 inline bool Debug::isWin32Success(int boolean) {
Chris@64 505 return boolean;
Chris@64 506 }
Chris@64 507 inline bool Debug::isWin32Success(void* handle) {
Chris@64 508 // Assume null and INVALID_HANDLE_VALUE mean failure.
Chris@64 509 return handle != nullptr && handle != (void*)-1;
Chris@64 510 }
Chris@64 511 #endif
Chris@64 512
Chris@64 513 template <typename Call>
Chris@64 514 Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
Chris@64 515 while (call() < 0) {
Chris@64 516 int errorNum = getOsErrorNumber(nonblocking);
Chris@64 517 // getOsErrorNumber() returns -1 to indicate EINTR.
Chris@64 518 // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
Chris@64 519 // non-error.
Chris@64 520 if (errorNum != -1) {
Chris@64 521 return SyscallResult(errorNum);
Chris@64 522 }
Chris@64 523 }
Chris@64 524 return SyscallResult(0);
Chris@64 525 }
Chris@64 526
Chris@64 527 template <typename Call>
Chris@64 528 int Debug::syscallError(Call&& call, bool nonblocking) {
Chris@64 529 while (call() < 0) {
Chris@64 530 int errorNum = getOsErrorNumber(nonblocking);
Chris@64 531 // getOsErrorNumber() returns -1 to indicate EINTR.
Chris@64 532 // Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
Chris@64 533 // non-error.
Chris@64 534 if (errorNum != -1) {
Chris@64 535 return errorNum;
Chris@64 536 }
Chris@64 537 }
Chris@64 538 return 0;
Chris@64 539 }
Chris@64 540
Chris@64 541 template <typename... Params>
Chris@64 542 String Debug::makeDescription(const char* macroArgs, Params&&... params) {
Chris@64 543 String argValues[sizeof...(Params)] = {str(params)...};
Chris@64 544 return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
Chris@64 545 }
Chris@64 546
Chris@64 547 template <>
Chris@64 548 inline String Debug::makeDescription<>(const char* macroArgs) {
Chris@64 549 return makeDescriptionInternal(macroArgs, nullptr);
Chris@64 550 }
Chris@64 551
Chris@64 552 } // namespace _ (private)
Chris@64 553 } // namespace kj
Chris@64 554
Chris@64 555 #endif // KJ_DEBUG_H_