summaryrefslogtreecommitdiffstats
path: root/base/logging.cc
diff options
context:
space:
mode:
authordavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-14 22:24:55 +0000
committerdavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-14 22:24:55 +0000
commit5b84fe3a0f6b9319e18f31db4d3c943616a91090 (patch)
treee6c4afcd14264fdfb4503514a1572a20684389be /base/logging.cc
parenta5e84bda360798580ed0eb6f27dc0342999c9675 (diff)
downloadchromium_src-5b84fe3a0f6b9319e18f31db4d3c943616a91090.zip
chromium_src-5b84fe3a0f6b9319e18f31db4d3c943616a91090.tar.gz
chromium_src-5b84fe3a0f6b9319e18f31db4d3c943616a91090.tar.bz2
Lock log files when reiniting them.
This is a second attempt of this cl: http://codereview.chromium.org/3195014/show BUG=NONE TEST=NONE Review URL: http://codereview.chromium.org/3347016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59439 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/logging.cc')
-rw-r--r--base/logging.cc248
1 files changed, 148 insertions, 100 deletions
diff --git a/base/logging.cc b/base/logging.cc
index f90a369..9808860 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -60,7 +60,6 @@ const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
"INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
int min_log_level = 0;
-LogLockingState lock_log_file = LOCK_LOG_FILE;
// The default set here for logging_destination will only be used if
// InitLogging is not called. On Windows, use a file next to the exe;
@@ -109,19 +108,6 @@ LogReportHandlerFunction log_report_handler = NULL;
// A log message handler that gets notified of every log message we process.
LogMessageHandlerFunction log_message_handler = NULL;
-// The lock is used if log file locking is false. It helps us avoid problems
-// with multiple threads writing to the log file at the same time. Use
-// LockImpl directly instead of using Lock, because Lock makes logging calls.
-static LockImpl* log_lock = NULL;
-
-// When we don't use a lock, we are using a global mutex. We need to do this
-// because LockFileEx is not thread safe.
-#if defined(OS_WIN)
-MutexHandle log_mutex = NULL;
-#elif defined(OS_POSIX)
-pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
// Helper functions to wrap platform differences.
int32 CurrentProcessId() {
@@ -178,6 +164,126 @@ void DeleteFilePath(const PathString& log_name) {
#endif
}
+void GetDefaultLogFile(PathString default_log_file) {
+#if defined(OS_WIN)
+ // On Windows we use the same path as the exe.
+ wchar_t module_name[MAX_PATH];
+ GetModuleFileName(NULL, module_name, MAX_PATH);
+ default_log_file = module_name;
+ std::wstring::size_type last_backslash =
+ default_log_file.rfind('\\', default_log_file.size());
+ if (last_backslash != std::wstring::npos)
+ default_log_file.erase(last_backslash + 1);
+ default_log_file += L"debug.log";
+#elif defined(OS_POSIX)
+ // On other platforms we just use the current directory.
+ default_log_file = "debug.log";
+#endif
+}
+
+// This class acts as a wrapper for locking the logging files.
+// LoggingLock::Init() should be called from the main thread before any logging
+// is done. Then whenever logging, be sure to have a local LoggingLock
+// instance on the stack. This will ensure that the lock is unlocked upon
+// exiting the frame.
+// LoggingLocks can not be nested.
+class LoggingLock {
+ public:
+ LoggingLock() {
+ LockLogging();
+ }
+
+ ~LoggingLock() {
+ UnlockLogging();
+ }
+
+ static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
+ if (initialized)
+ return;
+ lock_log_file = lock_log;
+ if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+ if (!log_mutex) {
+ std::wstring safe_name;
+ if (new_log_file)
+ safe_name = new_log_file;
+ else
+ GetDefaultLogFile(safe_name);
+ // \ is not a legal character in mutex names so we replace \ with /
+ std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
+ std::wstring t(L"Global\\");
+ t.append(safe_name);
+ log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
+ }
+#endif
+ } else {
+ log_lock = new LockImpl();
+ }
+ initialized = true;
+ }
+
+ private:
+ static void LockLogging() {
+ if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+ ::WaitForSingleObject(log_mutex, INFINITE);
+ // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
+ // abort the process here. UI tests might be crashy sometimes,
+ // and aborting the test binary only makes the problem worse.
+ // We also don't use LOG macros because that might lead to an infinite
+ // loop. For more info see http://crbug.com/18028.
+#elif defined(OS_POSIX)
+ pthread_mutex_lock(&log_mutex);
+#endif
+ } else {
+ // use the lock
+ log_lock->Lock();
+ }
+ }
+
+ static void UnlockLogging() {
+ if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+ ReleaseMutex(log_mutex);
+#elif defined(OS_POSIX)
+ pthread_mutex_unlock(&log_mutex);
+#endif
+ } else {
+ log_lock->Unlock();
+ }
+ }
+
+ // The lock is used if log file locking is false. It helps us avoid problems
+ // with multiple threads writing to the log file at the same time. Use
+ // LockImpl directly instead of using Lock, because Lock makes logging calls.
+ static LockImpl* log_lock;
+
+ // When we don't use a lock, we are using a global mutex. We need to do this
+ // because LockFileEx is not thread safe.
+#if defined(OS_WIN)
+ static MutexHandle log_mutex;
+#elif defined(OS_POSIX)
+ static pthread_mutex_t log_mutex;
+#endif
+
+ static bool initialized;
+ static LogLockingState lock_log_file;
+};
+
+// static
+bool LoggingLock::initialized = false;
+// static
+LockImpl* LoggingLock::log_lock = NULL;
+// static
+LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
+
+#if defined(OS_WIN)
+// static
+MutexHandle LoggingLock::log_mutex = NULL;
+#elif defined(OS_POSIX)
+pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
// Called by logging functions to ensure that debug_file is initialized
// and can be used for writing. Returns false if the file could not be
// initialized. debug_file will be NULL in this case.
@@ -188,20 +294,8 @@ bool InitializeLogFileHandle() {
if (!log_file_name) {
// Nobody has called InitLogging to specify a debug log file, so here we
// initialize the log file name to a default.
-#if defined(OS_WIN)
- // On Windows we use the same path as the exe.
- wchar_t module_name[MAX_PATH];
- GetModuleFileName(NULL, module_name, MAX_PATH);
- log_file_name = new std::wstring(module_name);
- std::wstring::size_type last_backslash =
- log_file_name->rfind('\\', log_file_name->size());
- if (last_backslash != std::wstring::npos)
- log_file_name->erase(last_backslash + 1);
- *log_file_name += L"debug.log";
-#elif defined(OS_POSIX)
- // On other platforms we just use the current directory.
- log_file_name = new std::string("debug.log");
-#endif
+ log_file_name = new PathString();
+ GetDefaultLogFile(*log_file_name);
}
if (logging_destination == LOG_ONLY_TO_FILE ||
@@ -231,27 +325,15 @@ bool InitializeLogFileHandle() {
return true;
}
-void InitLogMutex() {
-#if defined(OS_WIN)
- if (!log_mutex) {
- // \ is not a legal character in mutex names so we replace \ with /
- std::wstring safe_name(*log_file_name);
- std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
- std::wstring t(L"Global\\");
- t.append(safe_name);
- log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
- }
-#elif defined(OS_POSIX)
- // statically initialized
-#endif
-}
-
void BaseInitLoggingImpl(const PathChar* new_log_file,
LoggingDestination logging_dest,
LogLockingState lock_log,
OldFileDeletionState delete_old) {
g_enable_dcheck =
CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
+ LoggingLock::Init(lock_log, new_log_file);
+
+ LoggingLock logging_lock;
if (log_file) {
// calling InitLogging twice or after some log call has already opened the
@@ -260,7 +342,6 @@ void BaseInitLoggingImpl(const PathChar* new_log_file,
log_file = NULL;
}
- lock_log_file = lock_log;
logging_destination = logging_dest;
// ignore file options if logging is disabled or only to system
@@ -274,13 +355,8 @@ void BaseInitLoggingImpl(const PathChar* new_log_file,
if (delete_old == DELETE_OLD_LOG_FILE)
DeleteFilePath(*log_file_name);
- if (lock_log_file == LOCK_LOG_FILE) {
- InitLogMutex();
- } else if (!log_lock) {
- log_lock = new LockImpl();
- }
-
InitializeLogFileHandle();
+
}
void SetMinLogLevel(int level) {
@@ -517,61 +593,31 @@ LogMessage::~LogMessage() {
fflush(stderr);
}
+ // We can have multiple threads and/or processes, so try to prevent them
+ // from clobbering each other's writes.
+ // If the client app did not call InitLogging, and the lock has not
+ // been created do it now. We do this on demand, but if two threads try
+ // to do this at the same time, there will be a race condition to create
+ // the lock. This is why InitLogging should be called from the main
+ // thread at the beginning of execution.
+ LoggingLock::Init(LOCK_LOG_FILE, NULL);
// write to log file
if (logging_destination != LOG_NONE &&
- logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
- InitializeLogFileHandle()) {
- // We can have multiple threads and/or processes, so try to prevent them
- // from clobbering each other's writes.
- if (lock_log_file == LOCK_LOG_FILE) {
- // Ensure that the mutex is initialized in case the client app did not
- // call InitLogging. This is not thread safe. See below.
- InitLogMutex();
-
+ logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG) {
+ LoggingLock logging_lock;
+ if (InitializeLogFileHandle()) {
#if defined(OS_WIN)
- ::WaitForSingleObject(log_mutex, INFINITE);
- // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
- // abort the process here. UI tests might be crashy sometimes,
- // and aborting the test binary only makes the problem worse.
- // We also don't use LOG macros because that might lead to an infinite
- // loop. For more info see http://crbug.com/18028.
-#elif defined(OS_POSIX)
- pthread_mutex_lock(&log_mutex);
-#endif
- } else {
- // use the lock
- if (!log_lock) {
- // The client app did not call InitLogging, and so the lock has not
- // been created. We do this on demand, but if two threads try to do
- // this at the same time, there will be a race condition to create
- // the lock. This is why InitLogging should be called from the main
- // thread at the beginning of execution.
- log_lock = new LockImpl();
- }
- log_lock->Lock();
- }
-
-#if defined(OS_WIN)
- SetFilePointer(log_file, 0, 0, SEEK_END);
- DWORD num_written;
- WriteFile(log_file,
- static_cast<const void*>(str_newline.c_str()),
- static_cast<DWORD>(str_newline.length()),
- &num_written,
- NULL);
+ SetFilePointer(log_file, 0, 0, SEEK_END);
+ DWORD num_written;
+ WriteFile(log_file,
+ static_cast<const void*>(str_newline.c_str()),
+ static_cast<DWORD>(str_newline.length()),
+ &num_written,
+ NULL);
#else
- fprintf(log_file, "%s", str_newline.c_str());
- fflush(log_file);
-#endif
-
- if (lock_log_file == LOCK_LOG_FILE) {
-#if defined(OS_WIN)
- ReleaseMutex(log_mutex);
-#elif defined(OS_POSIX)
- pthread_mutex_unlock(&log_mutex);
+ fprintf(log_file, "%s", str_newline.c_str());
+ fflush(log_file);
#endif
- } else {
- log_lock->Unlock();
}
}
@@ -695,6 +741,8 @@ ErrnoLogMessage::~ErrnoLogMessage() {
#endif // OS_WIN
void CloseLogFile() {
+ LoggingLock logging_lock;
+
if (!log_file)
return;