| // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- |
| // Copyright (c) 2005, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // --- |
| // Sanjay Ghemawat <opensource@google.com> |
| |
| #include <config.h> |
| #include "internal_logging.h" |
| #include <stdarg.h> // for va_end, va_start |
| #include <stdio.h> // for vsnprintf, va_list, etc |
| #include <stdlib.h> // for abort |
| #include <string.h> // for strlen, memcpy |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> // for write() |
| #endif |
| |
| #include <gperftools/malloc_extension.h> |
| #include "base/logging.h" |
| #include "base/spinlock.h" // for SpinLockHolder, SpinLock |
| |
| namespace tcmalloc { |
| |
| static void WriteMessage(const char* msg, int length) { |
| WRITE_TO_STDERR(msg, length); |
| } |
| |
| class Logger { |
| public: |
| bool Add(const LogItem& item); |
| bool AddStr(const char* str, int n); |
| bool AddNum(uint64_t num, int base); // base must be 10 or 16. |
| |
| static const int kBufSize = 200; |
| char* p_; |
| char* end_; |
| char buf_[kBufSize]; |
| }; |
| |
| void Log(LogMode mode, const char* filename, int line, |
| LogItem a, LogItem b, LogItem c, LogItem d) { |
| Logger state; |
| state.p_ = state.buf_; |
| state.end_ = state.buf_ + sizeof(state.buf_); |
| state.AddStr(filename, strlen(filename)) |
| && state.AddStr(":", 1) |
| && state.AddNum(line, 10) |
| && state.AddStr("]", 1) |
| && state.Add(a) |
| && state.Add(b) |
| && state.Add(c) |
| && state.Add(d); |
| |
| // Teminate with newline |
| if (state.p_ >= state.end_) { |
| state.p_ = state.end_ - 1; |
| } |
| *state.p_ = '\n'; |
| state.p_++; |
| |
| int msglen = state.p_ - state.buf_; |
| if (mode == kLog) { |
| WriteMessage(state.buf_, msglen); |
| return; |
| } |
| |
| WriteMessage(state.buf_, msglen); |
| |
| #if defined(__has_builtin) |
| #if __has_builtin(__builtin_trap) |
| __builtin_trap(); |
| #endif |
| #endif // defined(__has_builtin) |
| |
| abort(); |
| } |
| |
| bool Logger::Add(const LogItem& item) { |
| // Separate items with spaces |
| if (p_ < end_) { |
| *p_ = ' '; |
| p_++; |
| } |
| |
| switch (item.tag_) { |
| case LogItem::kStr: |
| return AddStr(item.u_.str, strlen(item.u_.str)); |
| case LogItem::kUnsigned: |
| return AddNum(item.u_.unum, 10); |
| case LogItem::kSigned: |
| if (item.u_.snum < 0) { |
| // The cast to uint64_t is intentionally before the negation |
| // so that we do not attempt to negate -2^63. |
| return AddStr("-", 1) |
| && AddNum(- static_cast<uint64_t>(item.u_.snum), 10); |
| } else { |
| return AddNum(static_cast<uint64_t>(item.u_.snum), 10); |
| } |
| case LogItem::kPtr: |
| return AddStr("0x", 2) |
| && AddNum(reinterpret_cast<uintptr_t>(item.u_.ptr), 16); |
| default: |
| return false; |
| } |
| } |
| |
| bool Logger::AddStr(const char* str, int n) { |
| if (end_ - p_ < n) { |
| return false; |
| } else { |
| memcpy(p_, str, n); |
| p_ += n; |
| return true; |
| } |
| } |
| |
| bool Logger::AddNum(uint64_t num, int base) { |
| static const char kDigits[] = "0123456789abcdef"; |
| char space[22]; // more than enough for 2^64 in smallest supported base (10) |
| char* end = space + sizeof(space); |
| char* pos = end; |
| do { |
| pos--; |
| *pos = kDigits[num % base]; |
| num /= base; |
| } while (num > 0 && pos > space); |
| return AddStr(pos, end - pos); |
| } |
| |
| } // end tcmalloc namespace |
| |
| void TCMalloc_Printer::printf(const char* format, ...) { |
| if (left_ > 0) { |
| va_list ap; |
| va_start(ap, format); |
| const int r = vsnprintf(buf_, left_, format, ap); |
| va_end(ap); |
| if (r < 0) { |
| // Some kind of error |
| left_ = 0; |
| } else if (r > left_) { |
| // Truncation |
| left_ = 0; |
| } else { |
| left_ -= r; |
| buf_ += r; |
| } |
| } |
| } |