Issue 159: reviewer Waylonis
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@151 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
@@ -133,6 +133,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
|
||||
filter_(filter),
|
||||
callback_(callback),
|
||||
callback_context_(callback_context),
|
||||
directCallback_(NULL),
|
||||
handler_thread_(NULL),
|
||||
handler_port_(0),
|
||||
previous_(NULL),
|
||||
@@ -146,6 +147,27 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
|
||||
Setup(install_handler);
|
||||
}
|
||||
|
||||
// special constructor if we want to bypass minidump writing and
|
||||
// simply get a callback with the exception information
|
||||
ExceptionHandler::ExceptionHandler(DirectCallback callback,
|
||||
void *callback_context,
|
||||
bool install_handler)
|
||||
: dump_path_(),
|
||||
filter_(NULL),
|
||||
callback_(NULL),
|
||||
callback_context_(callback_context),
|
||||
directCallback_(callback),
|
||||
handler_thread_(NULL),
|
||||
handler_port_(0),
|
||||
previous_(NULL),
|
||||
installed_exception_handler_(false),
|
||||
is_in_teardown_(false),
|
||||
last_minidump_write_result_(false),
|
||||
use_minidump_write_mutex_(false) {
|
||||
MinidumpGenerator::GatherSystemInformation();
|
||||
Setup(install_handler);
|
||||
}
|
||||
|
||||
ExceptionHandler::~ExceptionHandler() {
|
||||
Teardown();
|
||||
}
|
||||
@@ -186,36 +208,47 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
|
||||
int exception_code,
|
||||
mach_port_t thread_name) {
|
||||
bool result = false;
|
||||
string minidump_id;
|
||||
|
||||
// Putting the MinidumpGenerator in its own context will ensure that the
|
||||
// destructor is executed, closing the newly created minidump file.
|
||||
if (!dump_path_.empty()) {
|
||||
MinidumpGenerator md;
|
||||
if (exception_type && exception_code) {
|
||||
// If this is a real exception, give the filter (if any) a chance to
|
||||
// decided if this should be sent
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
|
||||
md.SetExceptionInformation(exception_type, exception_code, thread_name);
|
||||
}
|
||||
|
||||
result = md.Write(next_minidump_path_c_);
|
||||
}
|
||||
|
||||
// Call user specified callback (if any)
|
||||
if (callback_) {
|
||||
// If the user callback returned true and we're handling an exception
|
||||
// (rather than just writing out the file), then we should exit without
|
||||
// forwarding the exception to the next handler.
|
||||
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
|
||||
result)) {
|
||||
if (directCallback_) {
|
||||
if (directCallback_(callback_context_,
|
||||
exception_type,
|
||||
exception_code,
|
||||
thread_name) ) {
|
||||
if (exception_type && exception_code)
|
||||
exit(exception_type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
string minidump_id;
|
||||
|
||||
// Putting the MinidumpGenerator in its own context will ensure that the
|
||||
// destructor is executed, closing the newly created minidump file.
|
||||
if (!dump_path_.empty()) {
|
||||
MinidumpGenerator md;
|
||||
if (exception_type && exception_code) {
|
||||
// If this is a real exception, give the filter (if any) a chance to
|
||||
// decided if this should be sent
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
|
||||
md.SetExceptionInformation(exception_type, exception_code, thread_name);
|
||||
}
|
||||
|
||||
result = md.Write(next_minidump_path_c_);
|
||||
}
|
||||
|
||||
// Call user specified callback (if any)
|
||||
if (callback_) {
|
||||
// If the user callback returned true and we're handling an exception
|
||||
// (rather than just writing out the file), then we should exit without
|
||||
// forwarding the exception to the next handler.
|
||||
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
|
||||
result)) {
|
||||
if (exception_type && exception_code)
|
||||
exit(exception_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -326,14 +359,11 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
|
||||
MACH_RCV_MSG | MACH_RCV_LARGE, 0,
|
||||
sizeof(receive), self->handler_port_,
|
||||
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
|
||||
|
||||
if (result == KERN_SUCCESS) {
|
||||
// Uninstall our handler so that we don't get in a loop if the process of
|
||||
// writing out a minidump causes an exception. However, if the exception
|
||||
// was caused by a fork'd process, don't uninstall things
|
||||
if (receive.task.name == mach_task_self())
|
||||
self->UninstallHandler();
|
||||
|
||||
// If the actual exception code is zero, then we're calling this handler
|
||||
// in a way that indicates that we want to either exit this thread or
|
||||
// generate a minidump
|
||||
@@ -342,6 +372,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
|
||||
// to avoid misleading stacks. If appropriate they will be resumed
|
||||
// afterwards.
|
||||
if (!receive.exception) {
|
||||
self->UninstallHandler(false);
|
||||
|
||||
if (self->is_in_teardown_)
|
||||
return NULL;
|
||||
|
||||
@@ -356,6 +388,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
|
||||
if (self->use_minidump_write_mutex_)
|
||||
pthread_mutex_unlock(&self->minidump_write_mutex_);
|
||||
} else {
|
||||
self->UninstallHandler(true);
|
||||
|
||||
// When forking a child process with the exception handler installed,
|
||||
// if the child crashes, it will send the exception back to the parent
|
||||
// process. The check for task == self_task() ensures that only
|
||||
@@ -419,7 +453,7 @@ bool ExceptionHandler::InstallHandler() {
|
||||
return installed_exception_handler_;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::UninstallHandler() {
|
||||
bool ExceptionHandler::UninstallHandler(bool in_exception) {
|
||||
kern_return_t result = KERN_SUCCESS;
|
||||
|
||||
if (installed_exception_handler_) {
|
||||
@@ -435,7 +469,11 @@ bool ExceptionHandler::UninstallHandler() {
|
||||
return false;
|
||||
}
|
||||
|
||||
delete previous_;
|
||||
// this delete should NOT happen if an exception just occurred!
|
||||
if (!in_exception) {
|
||||
delete previous_;
|
||||
}
|
||||
|
||||
previous_ = NULL;
|
||||
installed_exception_handler_ = false;
|
||||
}
|
||||
@@ -479,7 +517,7 @@ bool ExceptionHandler::Teardown() {
|
||||
kern_return_t result = KERN_SUCCESS;
|
||||
is_in_teardown_ = true;
|
||||
|
||||
if (!UninstallHandler())
|
||||
if (!UninstallHandler(false))
|
||||
return false;
|
||||
|
||||
// Send an empty message so that the handler_thread exits
|
||||
|
||||
Reference in New Issue
Block a user