diff options
Diffstat (limited to 'src/mongo/logger/console.cpp')
-rw-r--r-- | src/mongo/logger/console.cpp | 308 |
1 files changed, 151 insertions, 157 deletions
diff --git a/src/mongo/logger/console.cpp b/src/mongo/logger/console.cpp index 19ac32793e7..90945ad7f21 100644 --- a/src/mongo/logger/console.cpp +++ b/src/mongo/logger/console.cpp @@ -38,169 +38,163 @@ namespace mongo { namespace { - /* - * Theory of operation: - * - * At process start, the loader initializes "consoleMutex" to NULL. At some point during static - * initialization, the static initialization process, running in the one and only extant thread, - * allocates a new stdx::mutex on the heap and assigns consoleMutex to point to it. While - * consoleMutex is still NULL, we know that there is only one thread extant, so it is safe to - * skip locking the consoleMutex in the Console constructor. Once the mutex is initialized, - * users of Console can start acquiring it. - */ - - stdx::mutex *consoleMutex = new stdx::mutex; +/* + * Theory of operation: + * + * At process start, the loader initializes "consoleMutex" to NULL. At some point during static + * initialization, the static initialization process, running in the one and only extant thread, + * allocates a new stdx::mutex on the heap and assigns consoleMutex to point to it. While + * consoleMutex is still NULL, we know that there is only one thread extant, so it is safe to + * skip locking the consoleMutex in the Console constructor. Once the mutex is initialized, + * users of Console can start acquiring it. + */ + +stdx::mutex* consoleMutex = new stdx::mutex; #if defined(_WIN32) - /** - * Very basic implementation of a stream buffer backed by - * a fixed sized internal buffer that flushes - * to the console using WriteConsoleW(). - * - * Implementation notes: - * WriteConsoleW() vs std::wcout - * std::wcout produces garbage output for messages containing 2-byte sequences - * under all the terminal environments tested (Command Prompt, Power Shell, Cygwin). - * 3-byte sequences will cause std::wcout to go into a bad state (failbit=true). - * Also tried calling _setmode( _fileno(stdout), ...) with various modes (_O_U16TEXT, - * ...), all of which produces garbage results on the console. - */ - - class ConsoleStreamBuffer : public std::streambuf { - public: - - explicit ConsoleStreamBuffer(HANDLE consoleHandle) : _consoleHandle(consoleHandle) { - // leave room at end of buffer for overflow character - setp(&(_buffer[0]), &(_buffer[_bufferSize-1])); - } +/** + * Very basic implementation of a stream buffer backed by + * a fixed sized internal buffer that flushes + * to the console using WriteConsoleW(). + * + * Implementation notes: + * WriteConsoleW() vs std::wcout + * std::wcout produces garbage output for messages containing 2-byte sequences + * under all the terminal environments tested (Command Prompt, Power Shell, Cygwin). + * 3-byte sequences will cause std::wcout to go into a bad state (failbit=true). + * Also tried calling _setmode( _fileno(stdout), ...) with various modes (_O_U16TEXT, + * ...), all of which produces garbage results on the console. + */ - int_type overflow(int_type ch) { - if (ch == traits_type::eof()) { - return ch; - } +class ConsoleStreamBuffer : public std::streambuf { +public: + explicit ConsoleStreamBuffer(HANDLE consoleHandle) : _consoleHandle(consoleHandle) { + // leave room at end of buffer for overflow character + setp(&(_buffer[0]), &(_buffer[_bufferSize - 1])); + } - // push to end of buffer - *(pptr()) = ch; - pbump(1); - - // If the overflow byte is part of a UTF-8 multi-byte sequence, - // locate the beginning of the byte sequence and determine if - // the byte sequence represents a complete unicode code point. - // If the sequence is complete, proceed to flush the buffer. - // If the sequence is incomplete, flush the buffer up to but - // not including incomplete code point before re-inserting the - // bytes back into the internal buffer. - - if (ch & 0x80) { - // length of unicode byte sequence can be at most 4 in length. See RFC 3629 - int length = 0; - - // do not look back beyond 4 characters (maximum length for UTF-8 sequences) - // p will point to first byte of unicode code point upon exit from loop - char* sequenceBegin = pptr(); - for (int i = 0; i < 4; i++) { - length++; - sequenceBegin--; - // check for beginning of code point - if (*sequenceBegin & 0x40) { - break; - } - // check for invalid byte. all bytes in multi-byte sequence - // should have left most bit set - if (!(*sequenceBegin & 0x80)) { - break; - } - } + int_type overflow(int_type ch) { + if (ch == traits_type::eof()) { + return ch; + } - // get expected length of code point - // cast to unsigned type to avoid sign extension - int expectedLength = _bitsToSequenceLength[uint8_t(*sequenceBegin) >> 4]; - - // if beginning of sequence was not found, expectedLength will be zero and - // we will consider the multi-byte sequence to be garbage and flush the - // entire buffer - - // if code point is incomplete, rewind and flush buffer before - // refilling with incomplete byte sequence - if (length < expectedLength) - { - // rewind internal buffer to end before unfinished byte sequence - pbump(-length); - - // store result. should eventually return - // original overflow character on success - int_type result = flushToConsole() ? ch : traits_type::eof(); - - // after flushing pptr() will point to beginning of buffer - // copy bytes starting from p to beginning of internal buffer - for (int i = 0; i < length; i++) { - *(pptr()) = *sequenceBegin; - pbump(1); - sequenceBegin++; - } - - return result; + // push to end of buffer + *(pptr()) = ch; + pbump(1); + + // If the overflow byte is part of a UTF-8 multi-byte sequence, + // locate the beginning of the byte sequence and determine if + // the byte sequence represents a complete unicode code point. + // If the sequence is complete, proceed to flush the buffer. + // If the sequence is incomplete, flush the buffer up to but + // not including incomplete code point before re-inserting the + // bytes back into the internal buffer. + + if (ch & 0x80) { + // length of unicode byte sequence can be at most 4 in length. See RFC 3629 + int length = 0; + + // do not look back beyond 4 characters (maximum length for UTF-8 sequences) + // p will point to first byte of unicode code point upon exit from loop + char* sequenceBegin = pptr(); + for (int i = 0; i < 4; i++) { + length++; + sequenceBegin--; + // check for beginning of code point + if (*sequenceBegin & 0x40) { + break; + } + // check for invalid byte. all bytes in multi-byte sequence + // should have left most bit set + if (!(*sequenceBegin & 0x80)) { + break; } } - return flushToConsole() ? ch : traits_type::eof(); - } + // get expected length of code point + // cast to unsigned type to avoid sign extension + int expectedLength = _bitsToSequenceLength[uint8_t(*sequenceBegin) >> 4]; + + // if beginning of sequence was not found, expectedLength will be zero and + // we will consider the multi-byte sequence to be garbage and flush the + // entire buffer + + // if code point is incomplete, rewind and flush buffer before + // refilling with incomplete byte sequence + if (length < expectedLength) { + // rewind internal buffer to end before unfinished byte sequence + pbump(-length); + + // store result. should eventually return + // original overflow character on success + int_type result = flushToConsole() ? ch : traits_type::eof(); + + // after flushing pptr() will point to beginning of buffer + // copy bytes starting from p to beginning of internal buffer + for (int i = 0; i < length; i++) { + *(pptr()) = *sequenceBegin; + pbump(1); + sequenceBegin++; + } - int sync() { - return flushToConsole() ? 0 : -1; + return result; + } } - private: - - // keep this value reasonable. this class is used primarily - // to buffer log messages - static const size_t _bufferSize = 1024U; - - // mapping of leftmost 4 bits of first byte of code point - // to number of expected bytes in complete code point - // 110x -> 2 - // 1110 -> 3 - // 1111 -> 4 - static const int _bitsToSequenceLength[]; - - // In the event that WriteConsoleW fails, return false - // to allow stream to update error state flags (most likely badbit) - - bool flushToConsole() { - std::ptrdiff_t n = pptr() - pbase(); - pbump(-n); - - // convert multi-byte buffer to wide characters and output using WriteConsoleW + return flushToConsole() ? ch : traits_type::eof(); + } - wchar_t bufferWide[_bufferSize]; - int length = MultiByteToWideChar(CP_UTF8, 0, _buffer, n, bufferWide, _bufferSize); - const wchar_t* unwrittenBegin = bufferWide; - int unwrittenCount = length; // m holds number of unwritten wide characters in buffer + int sync() { + return flushToConsole() ? 0 : -1; + } - while (unwrittenCount > 0) { - DWORD written; - BOOL success = WriteConsoleW(_consoleHandle, unwrittenBegin, unwrittenCount, - &written, NULL); - if (!success) { - return false; - } - unwrittenCount -= written; - unwrittenBegin += written; +private: + // keep this value reasonable. this class is used primarily + // to buffer log messages + static const size_t _bufferSize = 1024U; + + // mapping of leftmost 4 bits of first byte of code point + // to number of expected bytes in complete code point + // 110x -> 2 + // 1110 -> 3 + // 1111 -> 4 + static const int _bitsToSequenceLength[]; + + // In the event that WriteConsoleW fails, return false + // to allow stream to update error state flags (most likely badbit) + + bool flushToConsole() { + std::ptrdiff_t n = pptr() - pbase(); + pbump(-n); + + // convert multi-byte buffer to wide characters and output using WriteConsoleW + + wchar_t bufferWide[_bufferSize]; + int length = MultiByteToWideChar(CP_UTF8, 0, _buffer, n, bufferWide, _bufferSize); + const wchar_t* unwrittenBegin = bufferWide; + int unwrittenCount = length; // m holds number of unwritten wide characters in buffer + + while (unwrittenCount > 0) { + DWORD written; + BOOL success = + WriteConsoleW(_consoleHandle, unwrittenBegin, unwrittenCount, &written, NULL); + if (!success) { + return false; } - return true; + unwrittenCount -= written; + unwrittenBegin += written; } + return true; + } - HANDLE _consoleHandle; - char _buffer[_bufferSize]; - }; + HANDLE _consoleHandle; + char _buffer[_bufferSize]; +}; // 0x0 - 0xb - invalid start of multi-byte sequence` const int ConsoleStreamBuffer::_bitsToSequenceLength[] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 2, 2, 3, 4 }; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 4}; // Create a output stream to redirect console writes // to WriteConsoleW() if there is a real console available (FILE_TYPE_CHAR) @@ -229,26 +223,26 @@ std::ostream* getWindowsOutputStream() { } std::ostream* windowsOutputStream = getWindowsOutputStream(); -#endif // defined(_WIN32) +#endif // defined(_WIN32) } // namespace - Console::Console() : _consoleLock() { - if (consoleMutex) { - stdx::unique_lock<stdx::mutex> lk(*consoleMutex); - lk.swap(_consoleLock); - } +Console::Console() : _consoleLock() { + if (consoleMutex) { + stdx::unique_lock<stdx::mutex> lk(*consoleMutex); + lk.swap(_consoleLock); } +} - std::ostream& Console::out() { +std::ostream& Console::out() { #if defined(_WIN32) - // check value of ostream in case - // static initializer has not been invoked - if (windowsOutputStream) { - return *windowsOutputStream; - } -#endif // defined(_WIN32) - return std::cout; + // check value of ostream in case + // static initializer has not been invoked + if (windowsOutputStream) { + return *windowsOutputStream; } +#endif // defined(_WIN32) + return std::cout; +} } // namespace mongo |