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:
ladderbreaker
2007-05-02 21:05:49 +00:00
parent c455a76c03
commit de2fd15db9
4 changed files with 155 additions and 77 deletions

View File

@@ -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