|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include <stdio.h> |
|
6 #include <string.h> |
|
7 #include <stdarg.h> |
|
8 |
|
9 #include "CSFLog.h" |
|
10 #include "base/basictypes.h" |
|
11 |
|
12 #include <map> |
|
13 #include "cpr_threads.h" |
|
14 #include "prrwlock.h" |
|
15 #include "prthread.h" |
|
16 #include "nsThreadUtils.h" |
|
17 #ifndef WIN32 |
|
18 #include <pthread.h> |
|
19 #endif |
|
20 #ifdef OS_MACOSX |
|
21 #include <dlfcn.h> |
|
22 #endif |
|
23 #ifdef OS_LINUX |
|
24 #include <sys/prctl.h> |
|
25 #endif |
|
26 |
|
27 static PRLogModuleInfo *gLogModuleInfo = nullptr; |
|
28 |
|
29 PRLogModuleInfo *GetSignalingLogInfo() |
|
30 { |
|
31 if (gLogModuleInfo == nullptr) |
|
32 gLogModuleInfo = PR_NewLogModule("signaling"); |
|
33 |
|
34 return gLogModuleInfo; |
|
35 } |
|
36 |
|
37 static PRLogModuleInfo *gWebRTCLogModuleInfo = nullptr; |
|
38 int gWebrtcTraceLoggingOn = 0; |
|
39 |
|
40 PRLogModuleInfo *GetWebRTCLogInfo() |
|
41 { |
|
42 if (gWebRTCLogModuleInfo == nullptr) |
|
43 gWebRTCLogModuleInfo = PR_NewLogModule("webrtc_trace"); |
|
44 |
|
45 return gWebRTCLogModuleInfo; |
|
46 } |
|
47 |
|
48 extern "C" { |
|
49 void CSFLogRegisterThread(const cprThread_t thread); |
|
50 void CSFLogUnregisterThread(const cprThread_t thread); |
|
51 #ifndef WIN32 |
|
52 pthread_t cprGetThreadId(cprThread_t thread); |
|
53 #endif |
|
54 } |
|
55 |
|
56 #ifdef WIN32 |
|
57 typedef unsigned int thread_key_t; |
|
58 #else |
|
59 typedef pthread_t thread_key_t; |
|
60 #endif |
|
61 static PRRWLock *maplock = PR_NewRWLock(0,"thread map"); |
|
62 typedef std::map<thread_key_t,const cpr_thread_t*> threadMap_t; |
|
63 static threadMap_t threadMap; |
|
64 |
|
65 void CSFLogRegisterThread(const cprThread_t thread) { |
|
66 const cpr_thread_t *t = reinterpret_cast<cpr_thread_t *>(thread); |
|
67 thread_key_t key; |
|
68 #ifdef WIN32 |
|
69 key = t->threadId; |
|
70 #else |
|
71 key = cprGetThreadId(thread); |
|
72 #endif |
|
73 |
|
74 CSFLog(CSF_LOG_DEBUG, __FILE__, __LINE__, "log", |
|
75 "Registering new thread with logging system: %s", t->name); |
|
76 PR_RWLock_Wlock(maplock); |
|
77 threadMap[key] = t; |
|
78 PR_RWLock_Unlock(maplock); |
|
79 } |
|
80 |
|
81 void CSFLogUnregisterThread(const cprThread_t thread) { |
|
82 const cpr_thread_t *t = reinterpret_cast<cpr_thread_t *>(thread); |
|
83 thread_key_t key; |
|
84 #ifdef WIN32 |
|
85 key = t->threadId; |
|
86 #else |
|
87 key = cprGetThreadId(thread); |
|
88 #endif |
|
89 CSFLog(CSF_LOG_DEBUG, __FILE__, __LINE__, "log", |
|
90 "Unregistering thread from logging system: %s", t->name); |
|
91 PR_RWLock_Wlock(maplock); |
|
92 threadMap.erase(key); |
|
93 PR_RWLock_Unlock(maplock); |
|
94 } |
|
95 |
|
96 const char *CSFCurrentThreadName() { |
|
97 const char *name = nullptr; |
|
98 #ifdef WIN32 |
|
99 thread_key_t key = GetCurrentThreadId(); |
|
100 #else |
|
101 thread_key_t key = pthread_self(); |
|
102 #endif |
|
103 PR_RWLock_Rlock(maplock); |
|
104 threadMap_t::iterator i = threadMap.find(key); |
|
105 if (i != threadMap.end()) { |
|
106 name = i->second->name; |
|
107 } |
|
108 PR_RWLock_Unlock(maplock); |
|
109 return name; |
|
110 } |
|
111 |
|
112 #ifdef OS_MACOSX |
|
113 // pthread_getname_np isn't available on all versions of OS X, so |
|
114 // we need to load it in dynamically and check for its presence |
|
115 static int (*dynamic_pthread_getname_np)(pthread_t,char*,size_t); |
|
116 bool init_pthread_getname() { |
|
117 *reinterpret_cast<void**>(&dynamic_pthread_getname_np) = |
|
118 dlsym(RTLD_DEFAULT, "pthread_getname_np"); |
|
119 return dynamic_pthread_getname_np; |
|
120 } |
|
121 static bool have_pthread_getname_np = init_pthread_getname(); |
|
122 #endif |
|
123 |
|
124 void CSFLogV(CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, va_list args) |
|
125 { |
|
126 #ifdef STDOUT_LOGGING |
|
127 printf("%s\n:",tag); |
|
128 vprintf(format, args); |
|
129 #else |
|
130 |
|
131 PRLogModuleLevel level = static_cast<PRLogModuleLevel>(priority); |
|
132 |
|
133 GetSignalingLogInfo(); |
|
134 |
|
135 // Skip doing any of this work if we're not logging the indicated level... |
|
136 if (!PR_LOG_TEST(gLogModuleInfo,level)) { |
|
137 return; |
|
138 } |
|
139 |
|
140 // Trim the path component from the filename |
|
141 const char *lastSlash = sourceFile; |
|
142 while (*sourceFile) { |
|
143 if (*sourceFile == '/' || *sourceFile == '\\') { |
|
144 lastSlash = sourceFile; |
|
145 } |
|
146 sourceFile++; |
|
147 } |
|
148 sourceFile = lastSlash; |
|
149 if (*sourceFile == '/' || *sourceFile == '\\') { |
|
150 sourceFile++; |
|
151 } |
|
152 |
|
153 #define MAX_MESSAGE_LENGTH 1024 |
|
154 char message[MAX_MESSAGE_LENGTH]; |
|
155 char buffer[64] = ""; |
|
156 |
|
157 const char *threadName = CSFCurrentThreadName(); |
|
158 |
|
159 // Check if we're the main thread... |
|
160 if (!threadName && NS_IsMainThread()) { |
|
161 threadName = "main"; |
|
162 } |
|
163 |
|
164 // If null, the name wasn't set up by CPR -- try NSPR |
|
165 if (!threadName) { |
|
166 threadName = PR_GetThreadName(PR_GetCurrentThread()); |
|
167 } |
|
168 |
|
169 // If not NSPR, it might be from some other imported library that uses |
|
170 // one of the variety of non-portable means of naming threads. |
|
171 #ifdef OS_LINUX |
|
172 if (!threadName && |
|
173 !prctl(PR_GET_NAME,reinterpret_cast<uintptr_t>(buffer),0,0,0)) { |
|
174 buffer[16]='\0'; |
|
175 if (buffer[0] != '\0') { |
|
176 threadName = buffer; |
|
177 } |
|
178 } |
|
179 #endif |
|
180 #ifdef OS_MACOSX |
|
181 if (!threadName && have_pthread_getname_np) { |
|
182 dynamic_pthread_getname_np(pthread_self(), buffer, sizeof(buffer)); |
|
183 if (buffer[0] != '\0') { |
|
184 threadName = buffer; |
|
185 } |
|
186 } |
|
187 #endif |
|
188 |
|
189 // If we can't find it anywhere, use a blank string |
|
190 if (!threadName) { |
|
191 threadName = ""; |
|
192 } |
|
193 |
|
194 vsnprintf(message, MAX_MESSAGE_LENGTH, format, args); |
|
195 PR_LOG(gLogModuleInfo, level, ("[%s|%s] %s:%d: %s", |
|
196 threadName, tag, sourceFile, sourceLine, |
|
197 message)); |
|
198 #endif |
|
199 |
|
200 } |
|
201 |
|
202 void CSFLog( CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, ...) |
|
203 { |
|
204 va_list ap; |
|
205 va_start(ap, format); |
|
206 |
|
207 CSFLogV(priority, sourceFile, sourceLine, tag, format, ap); |
|
208 va_end(ap); |
|
209 } |
|
210 |