michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "CSFLog.h" michael@0: #include "base/basictypes.h" michael@0: michael@0: #include michael@0: #include "cpr_threads.h" michael@0: #include "prrwlock.h" michael@0: #include "prthread.h" michael@0: #include "nsThreadUtils.h" michael@0: #ifndef WIN32 michael@0: #include michael@0: #endif michael@0: #ifdef OS_MACOSX michael@0: #include michael@0: #endif michael@0: #ifdef OS_LINUX michael@0: #include michael@0: #endif michael@0: michael@0: static PRLogModuleInfo *gLogModuleInfo = nullptr; michael@0: michael@0: PRLogModuleInfo *GetSignalingLogInfo() michael@0: { michael@0: if (gLogModuleInfo == nullptr) michael@0: gLogModuleInfo = PR_NewLogModule("signaling"); michael@0: michael@0: return gLogModuleInfo; michael@0: } michael@0: michael@0: static PRLogModuleInfo *gWebRTCLogModuleInfo = nullptr; michael@0: int gWebrtcTraceLoggingOn = 0; michael@0: michael@0: PRLogModuleInfo *GetWebRTCLogInfo() michael@0: { michael@0: if (gWebRTCLogModuleInfo == nullptr) michael@0: gWebRTCLogModuleInfo = PR_NewLogModule("webrtc_trace"); michael@0: michael@0: return gWebRTCLogModuleInfo; michael@0: } michael@0: michael@0: extern "C" { michael@0: void CSFLogRegisterThread(const cprThread_t thread); michael@0: void CSFLogUnregisterThread(const cprThread_t thread); michael@0: #ifndef WIN32 michael@0: pthread_t cprGetThreadId(cprThread_t thread); michael@0: #endif michael@0: } michael@0: michael@0: #ifdef WIN32 michael@0: typedef unsigned int thread_key_t; michael@0: #else michael@0: typedef pthread_t thread_key_t; michael@0: #endif michael@0: static PRRWLock *maplock = PR_NewRWLock(0,"thread map"); michael@0: typedef std::map threadMap_t; michael@0: static threadMap_t threadMap; michael@0: michael@0: void CSFLogRegisterThread(const cprThread_t thread) { michael@0: const cpr_thread_t *t = reinterpret_cast(thread); michael@0: thread_key_t key; michael@0: #ifdef WIN32 michael@0: key = t->threadId; michael@0: #else michael@0: key = cprGetThreadId(thread); michael@0: #endif michael@0: michael@0: CSFLog(CSF_LOG_DEBUG, __FILE__, __LINE__, "log", michael@0: "Registering new thread with logging system: %s", t->name); michael@0: PR_RWLock_Wlock(maplock); michael@0: threadMap[key] = t; michael@0: PR_RWLock_Unlock(maplock); michael@0: } michael@0: michael@0: void CSFLogUnregisterThread(const cprThread_t thread) { michael@0: const cpr_thread_t *t = reinterpret_cast(thread); michael@0: thread_key_t key; michael@0: #ifdef WIN32 michael@0: key = t->threadId; michael@0: #else michael@0: key = cprGetThreadId(thread); michael@0: #endif michael@0: CSFLog(CSF_LOG_DEBUG, __FILE__, __LINE__, "log", michael@0: "Unregistering thread from logging system: %s", t->name); michael@0: PR_RWLock_Wlock(maplock); michael@0: threadMap.erase(key); michael@0: PR_RWLock_Unlock(maplock); michael@0: } michael@0: michael@0: const char *CSFCurrentThreadName() { michael@0: const char *name = nullptr; michael@0: #ifdef WIN32 michael@0: thread_key_t key = GetCurrentThreadId(); michael@0: #else michael@0: thread_key_t key = pthread_self(); michael@0: #endif michael@0: PR_RWLock_Rlock(maplock); michael@0: threadMap_t::iterator i = threadMap.find(key); michael@0: if (i != threadMap.end()) { michael@0: name = i->second->name; michael@0: } michael@0: PR_RWLock_Unlock(maplock); michael@0: return name; michael@0: } michael@0: michael@0: #ifdef OS_MACOSX michael@0: // pthread_getname_np isn't available on all versions of OS X, so michael@0: // we need to load it in dynamically and check for its presence michael@0: static int (*dynamic_pthread_getname_np)(pthread_t,char*,size_t); michael@0: bool init_pthread_getname() { michael@0: *reinterpret_cast(&dynamic_pthread_getname_np) = michael@0: dlsym(RTLD_DEFAULT, "pthread_getname_np"); michael@0: return dynamic_pthread_getname_np; michael@0: } michael@0: static bool have_pthread_getname_np = init_pthread_getname(); michael@0: #endif michael@0: michael@0: void CSFLogV(CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, va_list args) michael@0: { michael@0: #ifdef STDOUT_LOGGING michael@0: printf("%s\n:",tag); michael@0: vprintf(format, args); michael@0: #else michael@0: michael@0: PRLogModuleLevel level = static_cast(priority); michael@0: michael@0: GetSignalingLogInfo(); michael@0: michael@0: // Skip doing any of this work if we're not logging the indicated level... michael@0: if (!PR_LOG_TEST(gLogModuleInfo,level)) { michael@0: return; michael@0: } michael@0: michael@0: // Trim the path component from the filename michael@0: const char *lastSlash = sourceFile; michael@0: while (*sourceFile) { michael@0: if (*sourceFile == '/' || *sourceFile == '\\') { michael@0: lastSlash = sourceFile; michael@0: } michael@0: sourceFile++; michael@0: } michael@0: sourceFile = lastSlash; michael@0: if (*sourceFile == '/' || *sourceFile == '\\') { michael@0: sourceFile++; michael@0: } michael@0: michael@0: #define MAX_MESSAGE_LENGTH 1024 michael@0: char message[MAX_MESSAGE_LENGTH]; michael@0: char buffer[64] = ""; michael@0: michael@0: const char *threadName = CSFCurrentThreadName(); michael@0: michael@0: // Check if we're the main thread... michael@0: if (!threadName && NS_IsMainThread()) { michael@0: threadName = "main"; michael@0: } michael@0: michael@0: // If null, the name wasn't set up by CPR -- try NSPR michael@0: if (!threadName) { michael@0: threadName = PR_GetThreadName(PR_GetCurrentThread()); michael@0: } michael@0: michael@0: // If not NSPR, it might be from some other imported library that uses michael@0: // one of the variety of non-portable means of naming threads. michael@0: #ifdef OS_LINUX michael@0: if (!threadName && michael@0: !prctl(PR_GET_NAME,reinterpret_cast(buffer),0,0,0)) { michael@0: buffer[16]='\0'; michael@0: if (buffer[0] != '\0') { michael@0: threadName = buffer; michael@0: } michael@0: } michael@0: #endif michael@0: #ifdef OS_MACOSX michael@0: if (!threadName && have_pthread_getname_np) { michael@0: dynamic_pthread_getname_np(pthread_self(), buffer, sizeof(buffer)); michael@0: if (buffer[0] != '\0') { michael@0: threadName = buffer; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: // If we can't find it anywhere, use a blank string michael@0: if (!threadName) { michael@0: threadName = ""; michael@0: } michael@0: michael@0: vsnprintf(message, MAX_MESSAGE_LENGTH, format, args); michael@0: PR_LOG(gLogModuleInfo, level, ("[%s|%s] %s:%d: %s", michael@0: threadName, tag, sourceFile, sourceLine, michael@0: message)); michael@0: #endif michael@0: michael@0: } michael@0: michael@0: void CSFLog( CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, ...) michael@0: { michael@0: va_list ap; michael@0: va_start(ap, format); michael@0: michael@0: CSFLogV(priority, sourceFile, sourceLine, tag, format, ap); michael@0: va_end(ap); michael@0: } michael@0: