aboutsummaryrefslogtreecommitdiff
path: root/src/client/windows/handler/exception_handler.cc
diff options
context:
space:
mode:
authordoshimun <doshimun@4c0a9323-5329-0410-9bdc-e9ce6186880e>2009-01-14 20:51:51 +0000
committerdoshimun <doshimun@4c0a9323-5329-0410-9bdc-e9ce6186880e>2009-01-14 20:51:51 +0000
commita6f58a1ac8468bc4d1dd785475d535e08b2aa5e9 (patch)
tree33e4b82b8ee0e16c284e6fb34e8cc850f5e99f98 /src/client/windows/handler/exception_handler.cc
parentNew test data to reflect Ted's changes that add function parameters to symbol... (diff)
downloadbreakpad-a6f58a1ac8468bc4d1dd785475d535e08b2aa5e9.tar.xz
Minor fixes to windows exception handler.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@306 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/windows/handler/exception_handler.cc')
-rw-r--r--src/client/windows/handler/exception_handler.cc57
1 files changed, 45 insertions, 12 deletions
diff --git a/src/client/windows/handler/exception_handler.cc b/src/client/windows/handler/exception_handler.cc
index 7217e19d..48cb8df3 100644
--- a/src/client/windows/handler/exception_handler.cc
+++ b/src/client/windows/handler/exception_handler.cc
@@ -40,12 +40,13 @@
namespace google_breakpad {
+static const int kWaitForHandlerThreadMs = 60000;
static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
LONG ExceptionHandler::handler_stack_index_ = 0;
CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
-bool ExceptionHandler::handler_stack_critical_section_initialized_ = false;
+volatile LONG ExceptionHandler::instance_count_ = 0;
ExceptionHandler::ExceptionHandler(const wstring& dump_path,
FilterCallback filter,
@@ -88,6 +89,7 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
const CustomClientInfo* custom_info) {
+ LONG instance_count = InterlockedIncrement(&instance_count_);
filter_ = filter;
callback_ = callback;
callback_context_ = callback_context;
@@ -106,6 +108,7 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
#endif // _MSC_VER >= 1400
previous_pch_ = NULL;
handler_thread_ = NULL;
+ is_shutdown_ = false;
handler_start_semaphore_ = NULL;
handler_finish_semaphore_ = NULL;
requesting_thread_id_ = 0;
@@ -177,12 +180,22 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
set_dump_path(dump_path);
}
- if (handler_types != HANDLER_NONE) {
- if (!handler_stack_critical_section_initialized_) {
- InitializeCriticalSection(&handler_stack_critical_section_);
- handler_stack_critical_section_initialized_ = true;
- }
+ // There is a race condition here. If the first instance has not yet
+ // initialized the critical section, the second (and later) instances will
+ // try to use uninitialized critical section object. The featuer of multiple
+ // instnaces in one module is not used much, so leave it as is for now.
+ // One way to solve this in the current design (that is, keeping the static
+ // handler stack) is to use spin locks with volatile bools to synchronize
+ // the handler stack. This works only if the compiler guarntees to generate
+ // cache coherent code for volatile.
+ // TODO(munjal): Fix this in a better way by changing the design if possible.
+
+ // Lazy initialization of the handler_stack_critical_section_
+ if (instance_count == 1) {
+ InitializeCriticalSection(&handler_stack_critical_section_);
+ }
+ if (handler_types != HANDLER_NONE) {
EnterCriticalSection(&handler_stack_critical_section_);
// The first time an ExceptionHandler that installs a handler is
@@ -259,12 +272,27 @@ ExceptionHandler::~ExceptionHandler() {
// Some of the objects were only initialized if out of process
// registration was not done.
if (!IsOutOfProcess()) {
- // Clean up the handler thread and synchronization primitives.
- TerminateThread(handler_thread_, 1);
+ // Clean up the handler thread and synchronization primitives. The handler
+ // thread is either waiting on the semaphore to handle a crash or it is
+ // handling a crash. Coming out of the wait is fast but wait more in the
+ // eventuality a crash is handled.
+ is_shutdown_ = true;
+ ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
+ WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
DeleteCriticalSection(&handler_critical_section_);
CloseHandle(handler_start_semaphore_);
CloseHandle(handler_finish_semaphore_);
}
+
+ // There is a race condition in the code below: if this instance is
+ // deleting the static critical section and a new instance of the class
+ // is created, then there is a possibility that the critical section be
+ // initialized while the same critical section is being deleted. Given the
+ // usage pattern for the code, this race condition is unlikely to hit, but it
+ // is a race condition nonetheless.
+ if (InterlockedDecrement(&instance_count_) == 0) {
+ DeleteCriticalSection(&handler_stack_critical_section_);
+ }
}
// static
@@ -278,16 +306,21 @@ DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {
if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) ==
WAIT_OBJECT_0) {
// Perform the requested action.
- self->handler_return_value_ = self->WriteMinidumpWithException(
- self->requesting_thread_id_, self->exception_info_, self->assertion_);
+ if (self->is_shutdown_) {
+ // The instance of the exception handler is being destroyed.
+ break;
+ } else {
+ self->handler_return_value_ =
+ self->WriteMinidumpWithException(self->requesting_thread_id_,
+ self->exception_info_,
+ self->assertion_);
+ }
// Allow the requesting thread to proceed.
ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL);
}
}
- // Not reached. This thread will be terminated by ExceptionHandler's
- // destructor.
return 0;
}