| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "CrashHandler.h" | 8 #include "CrashHandler.h" |
| 9 #include "DMJsonWriter.h" | 9 #include "DMJsonWriter.h" |
| 10 #include "DMSrcSink.h" | 10 #include "DMSrcSink.h" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 | 109 |
| 110 SK_DECLARE_STATIC_MUTEX(gFailuresMutex); | 110 SK_DECLARE_STATIC_MUTEX(gFailuresMutex); |
| 111 static SkTArray<SkString> gFailures; | 111 static SkTArray<SkString> gFailures; |
| 112 | 112 |
| 113 static void fail(const SkString& err) { | 113 static void fail(const SkString& err) { |
| 114 SkAutoMutexAcquire lock(gFailuresMutex); | 114 SkAutoMutexAcquire lock(gFailuresMutex); |
| 115 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); | 115 SkDebugf("\n\nFAILURE: %s\n\n", err.c_str()); |
| 116 gFailures.push_back(err); | 116 gFailures.push_back(err); |
| 117 } | 117 } |
| 118 | 118 |
| 119 struct Running { |
| 120 SkString id; |
| 121 SkThreadID thread; |
| 122 |
| 123 void dump() const { |
| 124 info("\t%s\n", id.c_str()); |
| 125 } |
| 126 }; |
| 119 | 127 |
| 120 // We use a spinlock to make locking this in a signal handler _somewhat_ safe. | 128 // We use a spinlock to make locking this in a signal handler _somewhat_ safe. |
| 121 static SkSpinlock gMutex; | 129 static SkSpinlock gMutex; |
| 122 static int32_t gPending; | 130 static int32_t gPending; |
| 123 static SkTArray<SkString> gRunning; | 131 static SkTArray<Running> gRunning; |
| 124 | 132 |
| 125 static void done(const char* config, const char* src, const char* srcOptions, co
nst char* name) { | 133 static void done(const char* config, const char* src, const char* srcOptions, co
nst char* name) { |
| 126 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name); | 134 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name); |
| 127 vlog("done %s\n", id.c_str()); | 135 vlog("done %s\n", id.c_str()); |
| 128 int pending; | 136 int pending; |
| 129 { | 137 { |
| 130 SkAutoMutexAcquire lock(gMutex); | 138 SkAutoMutexAcquire lock(gMutex); |
| 131 for (int i = 0; i < gRunning.count(); i++) { | 139 for (int i = 0; i < gRunning.count(); i++) { |
| 132 if (gRunning[i] == id) { | 140 if (gRunning[i].id == id) { |
| 133 gRunning.removeShuffle(i); | 141 gRunning.removeShuffle(i); |
| 134 break; | 142 break; |
| 135 } | 143 } |
| 136 } | 144 } |
| 137 pending = --gPending; | 145 pending = --gPending; |
| 138 } | 146 } |
| 139 // We write our dm.json file every once in a while in case we crash. | 147 // We write our dm.json file every once in a while in case we crash. |
| 140 // Notice this also handles the final dm.json when pending == 0. | 148 // Notice this also handles the final dm.json when pending == 0. |
| 141 if (pending % 500 == 0) { | 149 if (pending % 500 == 0) { |
| 142 JsonWriter::DumpJson(); | 150 JsonWriter::DumpJson(); |
| 143 } | 151 } |
| 144 } | 152 } |
| 145 | 153 |
| 146 static void start(const char* config, const char* src, const char* srcOptions, c
onst char* name) { | 154 static void start(const char* config, const char* src, const char* srcOptions, c
onst char* name) { |
| 147 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name); | 155 SkString id = SkStringPrintf("%s %s %s %s", config, src, srcOptions, name); |
| 148 vlog("start %s\n", id.c_str()); | 156 vlog("start %s\n", id.c_str()); |
| 149 SkAutoMutexAcquire lock(gMutex); | 157 SkAutoMutexAcquire lock(gMutex); |
| 150 gRunning.push_back(id); | 158 gRunning.push_back({id,SkGetThreadID()}); |
| 151 } | 159 } |
| 152 | 160 |
| 153 static void print_status() { | 161 static void print_status() { |
| 154 int curr = sk_tools::getCurrResidentSetSizeMB(), | 162 int curr = sk_tools::getCurrResidentSetSizeMB(), |
| 155 peak = sk_tools::getMaxResidentSetSizeMB(); | 163 peak = sk_tools::getMaxResidentSetSizeMB(); |
| 156 SkString elapsed = HumanizeMs(SkTime::GetMSecs() - kStartMs); | 164 SkString elapsed = HumanizeMs(SkTime::GetMSecs() - kStartMs); |
| 157 | 165 |
| 158 SkAutoMutexAcquire lock(gMutex); | 166 SkAutoMutexAcquire lock(gMutex); |
| 159 info("\n%s elapsed, %d active, %d queued, %dMB RAM, %dMB peak\n", | 167 info("\n%s elapsed, %d active, %d queued, %dMB RAM, %dMB peak\n", |
| 160 elapsed.c_str(), gRunning.count(), gPending - gRunning.count(), curr, p
eak); | 168 elapsed.c_str(), gRunning.count(), gPending - gRunning.count(), curr, p
eak); |
| 161 for (auto& task : gRunning) { | 169 for (auto& task : gRunning) { |
| 162 info("\t%s\n", task.c_str()); | 170 task.dump(); |
| 163 } | 171 } |
| 164 } | 172 } |
| 165 | 173 |
| 174 #if !defined(SK_BUILD_FOR_ANDROID) |
| 175 static void find_culprit() { |
| 176 // Assumes gMutex is locked. |
| 177 SkThreadID thisThread = SkGetThreadID(); |
| 178 for (auto& task : gRunning) { |
| 179 if (task.thread == thisThread) { |
| 180 info("Likely culprit:\n"); |
| 181 task.dump(); |
| 182 } |
| 183 } |
| 184 } |
| 185 #endif |
| 186 |
| 166 #if defined(SK_BUILD_FOR_WIN32) | 187 #if defined(SK_BUILD_FOR_WIN32) |
| 167 static LONG WINAPI crash_handler(EXCEPTION_POINTERS* e) { | 188 static LONG WINAPI crash_handler(EXCEPTION_POINTERS* e) { |
| 168 static const struct { | 189 static const struct { |
| 169 const char* name; | 190 const char* name; |
| 170 DWORD code; | 191 DWORD code; |
| 171 } kExceptions[] = { | 192 } kExceptions[] = { |
| 172 #define _(E) {#E, E} | 193 #define _(E) {#E, E} |
| 173 _(EXCEPTION_ACCESS_VIOLATION), | 194 _(EXCEPTION_ACCESS_VIOLATION), |
| 174 _(EXCEPTION_BREAKPOINT), | 195 _(EXCEPTION_BREAKPOINT), |
| 175 _(EXCEPTION_INT_DIVIDE_BY_ZERO), | 196 _(EXCEPTION_INT_DIVIDE_BY_ZERO), |
| 176 _(EXCEPTION_STACK_OVERFLOW), | 197 _(EXCEPTION_STACK_OVERFLOW), |
| 177 // TODO: more? | 198 // TODO: more? |
| 178 #undef _ | 199 #undef _ |
| 179 }; | 200 }; |
| 180 | 201 |
| 181 SkAutoMutexAcquire lock(gMutex); | 202 SkAutoMutexAcquire lock(gMutex); |
| 182 | 203 |
| 183 const DWORD code = e->ExceptionRecord->ExceptionCode; | 204 const DWORD code = e->ExceptionRecord->ExceptionCode; |
| 184 info("\nCaught exception %u", code); | 205 info("\nCaught exception %u", code); |
| 185 for (const auto& exception : kExceptions) { | 206 for (const auto& exception : kExceptions) { |
| 186 if (exception.code == code) { | 207 if (exception.code == code) { |
| 187 info(" %s", exception.name); | 208 info(" %s", exception.name); |
| 188 } | 209 } |
| 189 } | 210 } |
| 190 info(", was running:\n"); | 211 info(", was running:\n"); |
| 191 for (auto& task : gRunning) { | 212 for (auto& task : gRunning) { |
| 192 info("\t%s\n", task.c_str()); | 213 task.dump(); |
| 193 } | 214 } |
| 215 find_culprit(); |
| 194 fflush(stdout); | 216 fflush(stdout); |
| 195 | 217 |
| 196 // Execute default exception handler... hopefully, exit. | 218 // Execute default exception handler... hopefully, exit. |
| 197 return EXCEPTION_EXECUTE_HANDLER; | 219 return EXCEPTION_EXECUTE_HANDLER; |
| 198 } | 220 } |
| 199 static void setup_crash_handler() { SetUnhandledExceptionFilter(crash_handle
r); } | 221 static void setup_crash_handler() { SetUnhandledExceptionFilter(crash_handle
r); } |
| 200 | 222 |
| 201 #elif !defined(SK_BUILD_FOR_ANDROID) | 223 #elif !defined(SK_BUILD_FOR_ANDROID) |
| 202 #include <execinfo.h> | 224 #include <execinfo.h> |
| 203 #include <signal.h> | 225 #include <signal.h> |
| 204 #include <stdlib.h> | 226 #include <stdlib.h> |
| 205 | 227 |
| 206 static void crash_handler(int sig) { | 228 static void crash_handler(int sig) { |
| 207 SkAutoMutexAcquire lock(gMutex); | 229 SkAutoMutexAcquire lock(gMutex); |
| 208 | 230 |
| 209 info("\nCaught signal %d [%s], was running:\n", sig, strsignal(sig)); | 231 info("\nCaught signal %d [%s], was running:\n", sig, strsignal(sig)); |
| 210 for (auto& task : gRunning) { | 232 for (auto& task : gRunning) { |
| 211 info("\t%s\n", task.c_str()); | 233 task.dump(); |
| 212 } | 234 } |
| 235 find_culprit(); |
| 213 | 236 |
| 214 void* stack[64]; | 237 void* stack[64]; |
| 215 int count = backtrace(stack, SK_ARRAY_COUNT(stack)); | 238 int count = backtrace(stack, SK_ARRAY_COUNT(stack)); |
| 216 char** symbols = backtrace_symbols(stack, count); | 239 char** symbols = backtrace_symbols(stack, count); |
| 217 info("\nStack trace:\n"); | 240 info("\nStack trace:\n"); |
| 218 for (int i = 0; i < count; i++) { | 241 for (int i = 0; i < count; i++) { |
| 219 info(" %s\n", symbols[i]); | 242 info(" %s\n", symbols[i]); |
| 220 } | 243 } |
| 221 fflush(stdout); | 244 fflush(stdout); |
| 222 | 245 |
| (...skipping 1185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 #endif | 1431 #endif |
| 1409 } | 1432 } |
| 1410 } // namespace skiatest | 1433 } // namespace skiatest |
| 1411 | 1434 |
| 1412 #if !defined(SK_BUILD_FOR_IOS) | 1435 #if !defined(SK_BUILD_FOR_IOS) |
| 1413 int main(int argc, char** argv) { | 1436 int main(int argc, char** argv) { |
| 1414 SkCommandLineFlags::Parse(argc, argv); | 1437 SkCommandLineFlags::Parse(argc, argv); |
| 1415 return dm_main(); | 1438 return dm_main(); |
| 1416 } | 1439 } |
| 1417 #endif | 1440 #endif |
| OLD | NEW |