OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/metrics/thread_watcher.h" | 5 #include "chrome/browser/metrics/thread_watcher.h" |
6 | 6 |
7 #include <math.h> // ceil | 7 #include <math.h> // ceil |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/debug/alias.h" | 11 #include "base/debug/alias.h" |
| 12 #include "base/debug/debugger.h" |
12 #include "base/debug/dump_without_crashing.h" | 13 #include "base/debug/dump_without_crashing.h" |
13 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
14 #include "base/metrics/field_trial.h" | 15 #include "base/metrics/field_trial.h" |
15 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
16 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
17 #include "base/strings/string_tokenizer.h" | 18 #include "base/strings/string_tokenizer.h" |
18 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
19 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
20 #include "build/build_config.h" | 21 #include "build/build_config.h" |
21 #include "chrome/browser/chrome_notification_types.h" | 22 #include "chrome/browser/chrome_notification_types.h" |
(...skipping 12 matching lines...) Expand all Loading... |
34 | 35 |
35 // The following are unique function names for forcing the crash when a thread | 36 // The following are unique function names for forcing the crash when a thread |
36 // is unresponsive. This makes it possible to tell from the callstack alone what | 37 // is unresponsive. This makes it possible to tell from the callstack alone what |
37 // thread was unresponsive. | 38 // thread was unresponsive. |
38 // | 39 // |
39 // We disable optimizations for this block of functions so the compiler doesn't | 40 // We disable optimizations for this block of functions so the compiler doesn't |
40 // merge them all together. | 41 // merge them all together. |
41 MSVC_DISABLE_OPTIMIZE() | 42 MSVC_DISABLE_OPTIMIZE() |
42 MSVC_PUSH_DISABLE_WARNING(4748) | 43 MSVC_PUSH_DISABLE_WARNING(4748) |
43 | 44 |
44 #ifndef NDEBUG | 45 void ReportThreadHang() { |
45 int* NullPointer() { | 46 #if defined(NDEBUG) |
46 return reinterpret_cast<int*>(NULL); | 47 base::debug::DumpWithoutCrashing(); |
47 } | |
48 #endif | |
49 | |
50 void NullPointerCrash(int line_number) { | |
51 #ifndef NDEBUG | |
52 *NullPointer() = line_number; // Crash. | |
53 #else | 48 #else |
54 base::debug::DumpWithoutCrashing(); | 49 base::debug::BreakDebugger(); |
55 #endif | 50 #endif |
56 } | 51 } |
57 | 52 |
58 #if !defined(OS_ANDROID) || !defined(NDEBUG) | 53 #if !defined(OS_ANDROID) || !defined(NDEBUG) |
59 // TODO(rtenneti): Enabled crashing, after getting data. | 54 // TODO(rtenneti): Enabled crashing, after getting data. |
60 NOINLINE void StartupCrash() { | 55 NOINLINE void StartupHang() { |
61 NullPointerCrash(__LINE__); | 56 ReportThreadHang(); |
62 } | 57 } |
63 #endif // OS_ANDROID | 58 #endif // OS_ANDROID |
64 | 59 |
65 NOINLINE void ShutdownCrash() { | 60 NOINLINE void ShutdownHang() { |
66 NullPointerCrash(__LINE__); | 61 ReportThreadHang(); |
67 } | 62 } |
68 | 63 |
69 NOINLINE void ThreadUnresponsive_UI() { | 64 NOINLINE void ThreadUnresponsive_UI() { |
70 NullPointerCrash(__LINE__); | 65 ReportThreadHang(); |
71 } | 66 } |
72 | 67 |
73 NOINLINE void ThreadUnresponsive_DB() { | 68 NOINLINE void ThreadUnresponsive_DB() { |
74 NullPointerCrash(__LINE__); | 69 ReportThreadHang(); |
75 } | 70 } |
76 | 71 |
77 NOINLINE void ThreadUnresponsive_FILE() { | 72 NOINLINE void ThreadUnresponsive_FILE() { |
78 NullPointerCrash(__LINE__); | 73 ReportThreadHang(); |
79 } | 74 } |
80 | 75 |
81 NOINLINE void ThreadUnresponsive_FILE_USER_BLOCKING() { | 76 NOINLINE void ThreadUnresponsive_FILE_USER_BLOCKING() { |
82 NullPointerCrash(__LINE__); | 77 ReportThreadHang(); |
83 } | 78 } |
84 | 79 |
85 NOINLINE void ThreadUnresponsive_PROCESS_LAUNCHER() { | 80 NOINLINE void ThreadUnresponsive_PROCESS_LAUNCHER() { |
86 NullPointerCrash(__LINE__); | 81 ReportThreadHang(); |
87 } | 82 } |
88 | 83 |
89 NOINLINE void ThreadUnresponsive_CACHE() { | 84 NOINLINE void ThreadUnresponsive_CACHE() { |
90 NullPointerCrash(__LINE__); | 85 ReportThreadHang(); |
91 } | 86 } |
92 | 87 |
93 NOINLINE void ThreadUnresponsive_IO() { | 88 NOINLINE void ThreadUnresponsive_IO() { |
94 NullPointerCrash(__LINE__); | 89 ReportThreadHang(); |
95 } | 90 } |
96 | 91 |
97 MSVC_POP_WARNING() | 92 MSVC_POP_WARNING() |
98 MSVC_ENABLE_OPTIMIZE(); | 93 MSVC_ENABLE_OPTIMIZE(); |
99 | 94 |
100 void CrashBecauseThreadWasUnresponsive(BrowserThread::ID thread_id) { | 95 void CrashBecauseThreadWasUnresponsive(BrowserThread::ID thread_id) { |
101 base::debug::Alias(&thread_id); | 96 base::debug::Alias(&thread_id); |
102 | 97 |
103 switch (thread_id) { | 98 switch (thread_id) { |
104 case BrowserThread::UI: | 99 case BrowserThread::UI: |
(...skipping 821 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
926 start_time_thread_now_ = base::TimeTicks::IsThreadNowSupported() | 921 start_time_thread_now_ = base::TimeTicks::IsThreadNowSupported() |
927 ? base::TimeTicks::ThreadNow() : base::TimeTicks::Now(); | 922 ? base::TimeTicks::ThreadNow() : base::TimeTicks::Now(); |
928 #endif // OS_ANDROID | 923 #endif // OS_ANDROID |
929 } | 924 } |
930 | 925 |
931 // Alarm is called if the time expires after an Arm() without someone calling | 926 // Alarm is called if the time expires after an Arm() without someone calling |
932 // Disarm(). When Alarm goes off, in release mode we get the crash dump | 927 // Disarm(). When Alarm goes off, in release mode we get the crash dump |
933 // without crashing and in debug mode we break into the debugger. | 928 // without crashing and in debug mode we break into the debugger. |
934 virtual void Alarm() OVERRIDE { | 929 virtual void Alarm() OVERRIDE { |
935 #if !defined(NDEBUG) | 930 #if !defined(NDEBUG) |
936 StartupCrash(); | 931 StartupHang(); |
937 return; | 932 return; |
938 #elif !defined(OS_ANDROID) | 933 #elif !defined(OS_ANDROID) |
939 WatchDogThread::PostTask(FROM_HERE, base::Bind(&StartupCrash)); | 934 WatchDogThread::PostTask(FROM_HERE, base::Bind(&StartupHang)); |
940 return; | 935 return; |
941 #else // Android release: gather stats to figure out when to crash. | 936 #else // Android release: gather stats to figure out when to crash. |
942 // TODO(rtenneti): Delete this code, after getting data. | 937 // TODO(rtenneti): Delete this code, after getting data. |
943 UMA_HISTOGRAM_TIMES("StartupTimeBomb.Alarm.TimeDuration", | 938 UMA_HISTOGRAM_TIMES("StartupTimeBomb.Alarm.TimeDuration", |
944 base::Time::Now() - start_time_clock_); | 939 base::Time::Now() - start_time_clock_); |
945 UMA_HISTOGRAM_TIMES("StartupTimeBomb.Alarm.TimeTicksDuration", | 940 UMA_HISTOGRAM_TIMES("StartupTimeBomb.Alarm.TimeTicksDuration", |
946 base::TimeTicks::Now() - start_time_monotonic_); | 941 base::TimeTicks::Now() - start_time_monotonic_); |
947 if (base::TimeTicks::IsThreadNowSupported()) { | 942 if (base::TimeTicks::IsThreadNowSupported()) { |
948 UMA_HISTOGRAM_TIMES( | 943 UMA_HISTOGRAM_TIMES( |
949 "StartupTimeBomb.Alarm.ThreadNowDuration", | 944 "StartupTimeBomb.Alarm.ThreadNowDuration", |
(...skipping 21 matching lines...) Expand all Loading... |
971 public: | 966 public: |
972 // Constructor specifies how long the ShutdownWatchDogThread will wait before | 967 // Constructor specifies how long the ShutdownWatchDogThread will wait before |
973 // alarming. | 968 // alarming. |
974 explicit ShutdownWatchDogThread(const base::TimeDelta& duration) | 969 explicit ShutdownWatchDogThread(const base::TimeDelta& duration) |
975 : base::Watchdog(duration, "Shutdown watchdog thread", true) { | 970 : base::Watchdog(duration, "Shutdown watchdog thread", true) { |
976 } | 971 } |
977 | 972 |
978 // Alarm is called if the time expires after an Arm() without someone calling | 973 // Alarm is called if the time expires after an Arm() without someone calling |
979 // Disarm(). We crash the browser if this method is called. | 974 // Disarm(). We crash the browser if this method is called. |
980 virtual void Alarm() OVERRIDE { | 975 virtual void Alarm() OVERRIDE { |
981 ShutdownCrash(); | 976 ShutdownHang(); |
982 } | 977 } |
983 | 978 |
984 private: | 979 private: |
985 DISALLOW_COPY_AND_ASSIGN(ShutdownWatchDogThread); | 980 DISALLOW_COPY_AND_ASSIGN(ShutdownWatchDogThread); |
986 }; | 981 }; |
987 } // namespace | 982 } // namespace |
988 | 983 |
989 // StartupTimeBomb methods and members. | 984 // StartupTimeBomb methods and members. |
990 // | 985 // |
991 // static | 986 // static |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 | 1075 |
1081 #if defined(OS_WIN) | 1076 #if defined(OS_WIN) |
1082 // On Windows XP, give twice the time for shutdown. | 1077 // On Windows XP, give twice the time for shutdown. |
1083 if (base::win::GetVersion() <= base::win::VERSION_XP) | 1078 if (base::win::GetVersion() <= base::win::VERSION_XP) |
1084 actual_duration *= 2; | 1079 actual_duration *= 2; |
1085 #endif | 1080 #endif |
1086 | 1081 |
1087 shutdown_watchdog_ = new ShutdownWatchDogThread(actual_duration); | 1082 shutdown_watchdog_ = new ShutdownWatchDogThread(actual_duration); |
1088 shutdown_watchdog_->Arm(); | 1083 shutdown_watchdog_->Arm(); |
1089 } | 1084 } |
OLD | NEW |