OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/cygprofile/cygprofile.h" | 5 #include "tools/cygprofile/cygprofile.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <pthread.h> | 8 #include <pthread.h> |
9 #include <stddef.h> | 9 #include <stddef.h> |
10 #include <stdint.h> | 10 #include <stdint.h> |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
44 | 44 |
45 // "cyglog.PID.LWP.PPID" | 45 // "cyglog.PID.LWP.PPID" |
46 const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d"; | 46 const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d"; |
47 | 47 |
48 // Magic value of above to prevent instrumentation. Used when ThreadLog is being | 48 // Magic value of above to prevent instrumentation. Used when ThreadLog is being |
49 // constructed (to prevent reentering by malloc, for example) and by the flush | 49 // constructed (to prevent reentering by malloc, for example) and by the flush |
50 // log thread (to prevent it from being logged0. | 50 // log thread (to prevent it from being logged0. |
51 ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1); | 51 ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1); |
52 | 52 |
53 // Per-thread pointer to the current log object. | 53 // Per-thread pointer to the current log object. |
54 static __thread ThreadLog* g_tls_log = NULL; | 54 pthread_key_t g_tls_slot; |
55 | |
56 // Used to initialize the tls slot, once per the entire process. | |
57 pthread_once_t g_tls_slot_initializer_once = PTHREAD_ONCE_INIT; | |
58 | |
59 // This variable is to prevent re-entrancy in the __cyg_profile_func_enter() | |
60 // while the TLS slot itself is being initialized. Volatile here is required | |
61 // to avoid compiler otpimizations, as this need to be read in re-entrant code. | |
62 // This variable is NOT accessed from multiple threads (pthread_once guarantees | |
pasko
2016/04/15 11:42:14
as per offline discussion, this comment needs to b
Primiano Tucci (use gerrit)
2016/04/15 12:51:07
Done.
| |
63 // that). | |
64 volatile bool g_tls_slot_being_initialized = false; | |
65 | |
66 // Initializes the global TLS slot. This is invoked only once per process. | |
67 static void TLSSlotInitializer() | |
68 { | |
69 g_tls_slot_being_initialized = true; | |
70 (void) pthread_key_create(&g_tls_slot, NULL); | |
pasko
2016/04/15 11:42:14
Everywhere in this file please check return value
Primiano Tucci (use gerrit)
2016/04/15 12:51:07
Went for CHECK. perror doesn't really help on andr
| |
71 g_tls_slot_being_initialized = false; | |
72 } | |
55 | 73 |
56 // Returns light-weight process ID. On Linux, this is a system-wide unique | 74 // Returns light-weight process ID. On Linux, this is a system-wide unique |
57 // thread id. | 75 // thread id. |
58 pid_t GetTID() { | 76 pid_t GetTID() { |
59 return syscall(__NR_gettid); | 77 return syscall(__NR_gettid); |
60 } | 78 } |
61 | 79 |
62 timespec GetCurrentTime() { | 80 timespec GetCurrentTime() { |
63 timespec timestamp; | 81 timespec timestamp; |
64 clock_gettime(CLOCK_MONOTONIC, ×tamp); | 82 clock_gettime(CLOCK_MONOTONIC, ×tamp); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 | 174 |
157 ~Thread() { | 175 ~Thread() { |
158 CHECK_EQ(0, pthread_join(handle_, NULL)); | 176 CHECK_EQ(0, pthread_join(handle_, NULL)); |
159 } | 177 } |
160 | 178 |
161 private: | 179 private: |
162 static void* EntryPoint(void* data) { | 180 static void* EntryPoint(void* data) { |
163 // Disable logging on this thread. Although this routine is not instrumented | 181 // Disable logging on this thread. Although this routine is not instrumented |
164 // (cygprofile.gyp provides that), the called routines are and thus will | 182 // (cygprofile.gyp provides that), the called routines are and thus will |
165 // call instrumentation. | 183 // call instrumentation. |
166 CHECK(g_tls_log == NULL); // Must be 0 as this is a new thread. | 184 pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer); |
167 g_tls_log = kMagicBeingConstructed; | 185 ThreadLog* thread_log = reinterpret_cast<ThreadLog*>( |
186 pthread_getspecific(g_tls_slot)); | |
187 CHECK(thread_log == NULL); // Must be 0 as this is a new thread. | |
188 pthread_setspecific(g_tls_slot, kMagicBeingConstructed); | |
168 | 189 |
169 Thread* const instance = reinterpret_cast<Thread*>(data); | 190 Thread* const instance = reinterpret_cast<Thread*>(data); |
170 instance->thread_callback_.Run(); | 191 instance->thread_callback_.Run(); |
171 return NULL; | 192 return NULL; |
172 } | 193 } |
173 | 194 |
174 const base::Closure thread_callback_; | 195 const base::Closure thread_callback_; |
175 pthread_t handle_; | 196 pthread_t handle_; |
176 | 197 |
177 DISALLOW_COPY_AND_ASSIGN(Thread); | 198 DISALLOW_COPY_AND_ASSIGN(Thread); |
(...skipping 14 matching lines...) Expand all Loading... | |
192 base::Bind(&ThreadLog::FlushInternal, base::Unretained(this))) { | 213 base::Bind(&ThreadLog::FlushInternal, base::Unretained(this))) { |
193 } | 214 } |
194 | 215 |
195 ThreadLog::ThreadLog(const FlushCallback& flush_callback) | 216 ThreadLog::ThreadLog(const FlushCallback& flush_callback) |
196 : tid_(GetTID()), | 217 : tid_(GetTID()), |
197 in_use_(false), | 218 in_use_(false), |
198 flush_callback_(flush_callback) { | 219 flush_callback_(flush_callback) { |
199 } | 220 } |
200 | 221 |
201 ThreadLog::~ThreadLog() { | 222 ThreadLog::~ThreadLog() { |
202 g_tls_log = NULL; | 223 pthread_setspecific(g_tls_slot, NULL); |
203 } | 224 } |
204 | 225 |
205 void ThreadLog::AddEntry(void* address) { | 226 void ThreadLog::AddEntry(void* address) { |
206 if (in_use_) | 227 if (in_use_) |
207 return; | 228 return; |
208 in_use_ = true; | 229 in_use_ = true; |
209 | 230 |
210 CHECK_EQ(tid_, GetTID()); | 231 CHECK_EQ(tid_, GetTID()); |
211 const std::pair<base::hash_set<void*>::iterator, bool> pair = | 232 const std::pair<base::hash_set<void*>::iterator, bool> pair = |
212 called_functions_.insert(address); | 233 called_functions_.insert(address); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
351 extern "C" { | 372 extern "C" { |
352 | 373 |
353 // The GCC compiler callbacks, called on every function invocation providing | 374 // The GCC compiler callbacks, called on every function invocation providing |
354 // addresses of caller and callee codes. | 375 // addresses of caller and callee codes. |
355 void __cyg_profile_func_enter(void* this_fn, void* call_site) | 376 void __cyg_profile_func_enter(void* this_fn, void* call_site) |
356 __attribute__((no_instrument_function)); | 377 __attribute__((no_instrument_function)); |
357 void __cyg_profile_func_exit(void* this_fn, void* call_site) | 378 void __cyg_profile_func_exit(void* this_fn, void* call_site) |
358 __attribute__((no_instrument_function)); | 379 __attribute__((no_instrument_function)); |
359 | 380 |
360 void __cyg_profile_func_enter(void* this_fn, void* callee_unused) { | 381 void __cyg_profile_func_enter(void* this_fn, void* callee_unused) { |
361 if (g_tls_log == NULL) { | 382 // Avoid re-entrancy while initializing the TLS slot (once per process). |
362 g_tls_log = kMagicBeingConstructed; | 383 if (g_tls_slot_being_initialized) |
363 ThreadLog* new_log = new ThreadLog(); | 384 return; |
364 CHECK(new_log); | 385 |
365 g_logs_manager.Pointer()->AddLog(base::WrapUnique(new_log)); | 386 pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer); |
366 g_tls_log = new_log; | 387 ThreadLog* thread_log = reinterpret_cast<ThreadLog*>( |
388 pthread_getspecific(g_tls_slot)); | |
389 | |
390 if (thread_log == NULL) { | |
391 pthread_setspecific(g_tls_slot, kMagicBeingConstructed); | |
392 thread_log = new ThreadLog(); | |
393 CHECK(thread_log); | |
394 g_logs_manager.Pointer()->AddLog(base::WrapUnique(thread_log)); | |
395 pthread_setspecific(g_tls_slot, thread_log); | |
367 } | 396 } |
368 | 397 |
369 if (g_tls_log != kMagicBeingConstructed) | 398 if (thread_log != kMagicBeingConstructed) |
370 g_tls_log->AddEntry(this_fn); | 399 thread_log->AddEntry(this_fn); |
371 } | 400 } |
372 | 401 |
373 void __cyg_profile_func_exit(void* this_fn, void* call_site) {} | 402 void __cyg_profile_func_exit(void* this_fn, void* call_site) {} |
374 | 403 |
375 } // extern "C" | 404 } // extern "C" |
376 } // namespace cygprofile | 405 } // namespace cygprofile |
OLD | NEW |