Logging cleanup for mac and linux


git-svn-id: svn://svn.chromium.org/chrome/trunk/src@561 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/logging.cc b/base/logging.cc
index ca9905d..559934b 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -27,17 +27,39 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include "build/build_config.h"
+
+#if defined(WIN32)
+#include <windows.h>
+typedef HANDLE FileHandle;
+typedef HANDLE MutexHandle;
+#endif
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#define MAX_PATH PATH_MAX
+typedef FILE* FileHandle;
+typedef pthread_mutex_t* MutexHandle;
+#endif
+
 #include <ctime>
 #include <iomanip>
 #include <cstring>
-#include <windows.h>
 #include <algorithm>
 #include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/lock_impl.h"
 #include "base/logging.h"
+#include "base/string_util.h"
 #include "base/sys_string_conversions.h"
-
+  
 namespace logging {
 
 bool g_enable_dcheck = false;
@@ -55,10 +77,15 @@
 // which log file to use? This is initialized by InitLogging or
 // will be lazily initialized to the default value when it is
 // first needed.
-wchar_t log_file_name[MAX_PATH] = { 0 };
+#if defined(OS_WIN)
+typedef wchar_t PathChar;
+#else
+typedef char PathChar;
+#endif
+PathChar log_file_name[MAX_PATH] = { 0 };
 
 // this file is lazily opened and the handle may be NULL
-HANDLE log_file = NULL;
+FileHandle log_file = NULL;
 
 // what should be prepended to each message?
 bool log_process_id = false;
@@ -77,7 +104,59 @@
 
 // When we don't use a lock, we are using a global mutex. We need to do this
 // because LockFileEx is not thread safe.
-HANDLE log_mutex = NULL;
+#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() {
+#if defined(OS_WIN)
+  return GetCurrentProcessId();
+#elif defined(OS_POSIX)
+  return getpid();
+#endif
+}
+
+int32 CurrentThreadId() {
+#if defined(OS_WIN)
+  return GetCurrentThreadId();
+#elif defined(OS_MACOSX)
+  return mach_thread_self();
+#else
+  // TODO(pinkerton): need linux-fu to fill in thread id here
+  return 0;
+#endif
+}
+
+uint64 TickCount() {
+#if defined(OS_WIN)
+  return GetTickCount();
+#elif defined(OS_MACOSX)
+  return mach_absolute_time();
+#else
+  // TODO(pinkerton): need linux-fu to fill in time here
+  return 0;
+#endif
+}
+
+void CloseFile(FileHandle log) {
+#if defined(OS_WIN)
+  CloseHandle(log);
+#else
+  fclose(log);
+#endif
+}
+
+void DeleteFile(PathChar* log_name) {
+#if defined(OS_WIN)
+  DeleteFile(log_name);
+#else
+  unlink(log_name);
+#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
@@ -86,13 +165,14 @@
   if (log_file)
     return true;
 
+#if defined(OS_WIN)
   if (!log_file_name[0]) {
     // nobody has called InitLogging to specify a debug log file, so here we
     // initialize the log file name to the default
     GetModuleFileName(NULL, log_file_name, MAX_PATH);
     wchar_t* last_backslash = wcsrchr(log_file_name, '\\');
     if (last_backslash)
-      last_backslash[1] = 0; // name now ends with the backslash
+      last_backslash[1] = 0;      // name now ends with the backslash
     wcscat_s(log_file_name, L"debug.log");
   }
 
@@ -110,10 +190,34 @@
     }
   }
   SetFilePointer(log_file, 0, 0, FILE_END);
+#elif defined(OS_POSIX)
+  if (!log_file_name[0]) {
+#if defined(OS_MACOSX)
+    // nobody has called InitLogging to specify a debug log file, so here we
+    // initialize the log file name to the default
+    uint32_t log_file_name_size = arraysize(log_file_name);
+    _NSGetExecutablePath(log_file_name, &log_file_name_size);
+    char* last_slash = strrchr(log_file_name, '/');
+    if (last_slash)
+      last_slash[1] = 0; // name now ends with the slash
+    strlcat(log_file_name, "debug.log", arraysize(log_file_name));    
+#endif
+  }
+  
+  log_file = fopen(log_file_name, "a");
+  if (log_file == NULL) {
+    // try the current directory 
+    log_file = fopen("debug.log", "a");
+    if (log_file == NULL) {
+      return false;
+    }
+  }
+#endif
   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);
@@ -122,16 +226,19 @@
     t.append(safe_name);
     log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
   }
+#elif defined(OS_POSIX)
+  // statically initialized
+#endif
 }
 
-void InitLogging(const wchar_t* new_log_file, LoggingDestination logging_dest,
+void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
                  LogLockingState lock_log, OldFileDeletionState delete_old) {
   g_enable_dcheck = CommandLine().HasSwitch(switches::kEnableDCHECK);
 
   if (log_file) {
     // calling InitLogging twice or after some log call has already opened the
     // default log file will re-initialize to the new options
-    CloseHandle(log_file);
+    CloseFile(log_file);
     log_file = NULL;
   }
 
@@ -143,7 +250,11 @@
       logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
     return;
 
+#if defined(OS_WIN)
   wcscpy_s(log_file_name, MAX_PATH, new_log_file);
+#elif defined(OS_POSIX)
+  strlcpy(log_file_name, new_log_file, arraysize(log_file_name));
+#endif
   if (delete_old == DELETE_OLD_LOG_FILE)
     DeleteFile(log_file_name);
 
@@ -173,7 +284,11 @@
   if (filter) {
     size_t size = strlen(filter)+1;
     log_filter_prefix = new char[size];
+#if defined(OS_WIN)
     strcpy_s(log_filter_prefix, size, filter);
+#elif defined(OS_POSIX)
+    strlcpy(log_filter_prefix, filter, size);
+#endif
   }
 }
 
@@ -200,6 +315,7 @@
   if (str.empty())
     return;
 
+#if defined(OS_WIN)
   // look for the debug dialog program next to our application
   wchar_t prog_name[MAX_PATH];
   GetModuleFileNameW(NULL, prog_name, MAX_PATH);
@@ -228,6 +344,9 @@
     MessageBoxW(NULL, cmdline, L"Fatal error",
                 MB_OK | MB_ICONHAND | MB_TOPMOST);
   }
+#else
+  fprintf(stderr, "%s\n", str.c_str());
+#endif
 }
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
@@ -263,9 +382,9 @@
 
   stream_ <<  '[';
   if (log_process_id)
-    stream_ << GetCurrentProcessId() << ':';
+    stream_ << CurrentProcessId() << ':';
   if (log_thread_id)
-    stream_ << GetCurrentThreadId() << ':';
+    stream_ << CurrentThreadId() << ':';
   if (log_timestamp) {
      time_t t = time(NULL);
 #if _MSC_VER >= 1400
@@ -285,7 +404,7 @@
             << ':';
   }
   if (log_tickcount)
-    stream_ << GetTickCount() << ':';
+    stream_ << TickCount() << ':';
   stream_ << log_severity_names[severity_] << ":" << file << "(" << line << ")] ";
 
   message_start_ = stream_.tellp();
@@ -307,9 +426,14 @@
   }
 
   if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
-      logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG)
+      logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
+#if defined(OS_WIN)
     OutputDebugStringA(str_newline.c_str());
-
+#else
+    fprintf(stderr, str_newline.c_str());
+#endif
+  }
+  
   // write to log file
   if (logging_destination != LOG_NONE &&
       logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
@@ -321,8 +445,12 @@
       // call InitLogging. This is not thread safe. See below
       InitLogMutex();
 
+#if defined(OS_WIN)
       DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
       DCHECK(r != WAIT_ABANDONED);
+#elif defined(OS_POSIX)
+      pthread_mutex_lock(&log_mutex);
+#endif
     } else {
       // use the lock
       if (!log_lock) {
@@ -336,12 +464,20 @@
       log_lock->Lock();
     }
 
+#if defined(OS_WIN)
     SetFilePointer(log_file, 0, 0, SEEK_END);
     DWORD num_written;
     WriteFile(log_file, (void*)str_newline.c_str(), (DWORD)str_newline.length(), &num_written, NULL);
+#else
+    fprintf(log_file, "%s", str_newline.c_str());
+#endif
 
     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();
     }
@@ -349,9 +485,13 @@
 
   if (severity_ == LOG_FATAL) {
     // display a message or break into the debugger on a fatal error
+#if defined(OS_WIN)
     if (::IsDebuggerPresent()) {
       __debugbreak();
-    } else {
+    } 
+    else
+#endif
+    {
       if (log_assert_handler) {
         // make a copy of the string for the handler out of paranoia
         log_assert_handler(std::string(stream_.str()));
@@ -360,7 +500,16 @@
         // the debug message process
         DisplayDebugMessage(stream_.str());
         // Crash the process to generate a dump.
+#if defined(OS_WIN)
         __debugbreak();
+#elif defined(OS_POSIX)
+#if defined(OS_MACOSX)
+        // TODO: when we have breakpad support, generate a breakpad dump, but
+        // until then, do not invoke the Apple crash reporter.
+        Debugger();
+#endif
+        exit(-1);
+#endif
       }
     }
   }
@@ -370,7 +519,7 @@
   if (!log_file)
     return;
 
-  CloseHandle(log_file);
+  CloseFile(log_file);
   log_file = NULL;
 }