Chromium Code Reviews| 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 |