mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-29 00:30:04 +02:00
* Updated breakpad to latest version.
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#include "client/windows/common/ipc_protocol.h"
|
||||
|
||||
static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
|
||||
static const size_t kMaxCustomInfoEntries = 4096;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@@ -52,7 +53,8 @@ ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
|
||||
dump_requested_handle_(NULL),
|
||||
dump_generated_handle_(NULL),
|
||||
dump_request_wait_handle_(NULL),
|
||||
process_exit_wait_handle_(NULL) {
|
||||
process_exit_wait_handle_(NULL),
|
||||
crash_id_(NULL) {
|
||||
GetSystemTimeAsFileTime(&start_time_);
|
||||
}
|
||||
|
||||
@@ -62,6 +64,12 @@ bool ClientInfo::Initialize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The crash_id will be the low order word of the process creation time.
|
||||
FILETIME creation_time, exit_time, kernel_time, user_time;
|
||||
if (GetProcessTimes(process_handle_, &creation_time, &exit_time,
|
||||
&kernel_time, &user_time))
|
||||
crash_id_ = creation_time.dwLowDateTime;
|
||||
|
||||
dump_requested_handle_ = CreateEvent(NULL, // Security attributes.
|
||||
TRUE, // Manual reset.
|
||||
FALSE, // Initial state.
|
||||
@@ -160,6 +168,9 @@ void ClientInfo::SetProcessUptime() {
|
||||
}
|
||||
|
||||
bool ClientInfo::PopulateCustomInfo() {
|
||||
if (custom_client_info_.count > kMaxCustomInfoEntries)
|
||||
return false;
|
||||
|
||||
SIZE_T bytes_count = 0;
|
||||
SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;
|
||||
|
||||
|
@@ -65,6 +65,7 @@ class ClientInfo {
|
||||
HANDLE process_handle() const { return process_handle_; }
|
||||
HANDLE dump_requested_handle() const { return dump_requested_handle_; }
|
||||
HANDLE dump_generated_handle() const { return dump_generated_handle_; }
|
||||
DWORD crash_id() const { return crash_id_; }
|
||||
|
||||
HANDLE dump_request_wait_handle() const {
|
||||
return dump_request_wait_handle_;
|
||||
@@ -160,6 +161,11 @@ class ClientInfo {
|
||||
// for the client process when it signals a crash.
|
||||
FILETIME start_time_;
|
||||
|
||||
// The crash id which can be used to request an upload. This will be the
|
||||
// value of the low order dword of the process creation time for the process
|
||||
// being dumped.
|
||||
DWORD crash_id_;
|
||||
|
||||
// Disallow copy ctor and operator=.
|
||||
ClientInfo(const ClientInfo& client_info);
|
||||
ClientInfo& operator=(const ClientInfo& client_info);
|
||||
|
0
thirdparty/breakpad/client/windows/crash_generation/crash_generation.gyp
vendored
Executable file → Normal file
0
thirdparty/breakpad/client/windows/crash_generation/crash_generation.gyp
vendored
Executable file → Normal file
@@ -167,6 +167,23 @@ bool CrashGenerationClient::Register() {
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CrashGenerationClient::RequestUpload(DWORD crash_id) {
|
||||
HANDLE pipe = ConnectToServer();
|
||||
if (!pipe) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomClientInfo custom_info = {NULL, 0};
|
||||
ProtocolMessage msg(MESSAGE_TAG_UPLOAD_REQUEST, crash_id,
|
||||
static_cast<MINIDUMP_TYPE>(NULL), NULL, NULL, NULL,
|
||||
custom_info, NULL, NULL, NULL);
|
||||
DWORD bytes_count = 0;
|
||||
bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, NULL) != 0;
|
||||
|
||||
CloseHandle(pipe);
|
||||
return success;
|
||||
}
|
||||
|
||||
HANDLE CrashGenerationClient::ConnectToServer() {
|
||||
HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
|
||||
kPipeDesiredAccess,
|
||||
@@ -223,7 +240,7 @@ bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
|
||||
crash_event_ = reply.dump_request_handle;
|
||||
crash_generated_ = reply.dump_generated_handle;
|
||||
server_alive_ = reply.server_alive_handle;
|
||||
server_process_id_ = reply.pid;
|
||||
server_process_id_ = reply.id;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -261,7 +278,7 @@ HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
|
||||
bool CrashGenerationClient::ValidateResponse(
|
||||
const ProtocolMessage& msg) const {
|
||||
return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
|
||||
(msg.pid != 0) &&
|
||||
(msg.id != 0) &&
|
||||
(msg.dump_request_handle != NULL) &&
|
||||
(msg.dump_generated_handle != NULL) &&
|
||||
(msg.server_alive_handle != NULL);
|
||||
|
@@ -73,6 +73,10 @@ class CrashGenerationClient {
|
||||
// Returns true if the registration is successful; false otherwise.
|
||||
bool Register();
|
||||
|
||||
// Requests the crash server to upload a previous dump with the
|
||||
// given crash id.
|
||||
bool RequestUpload(DWORD crash_id);
|
||||
|
||||
bool RequestDump(EXCEPTION_POINTERS* ex_info,
|
||||
MDRawAssertionInfo* assert_info);
|
||||
|
||||
|
@@ -84,11 +84,12 @@ static const int kShutdownDelayMs = 10000;
|
||||
static const int kShutdownSleepIntervalMs = 5;
|
||||
|
||||
static bool IsClientRequestValid(const ProtocolMessage& msg) {
|
||||
return msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
|
||||
msg.pid != 0 &&
|
||||
msg.thread_id != NULL &&
|
||||
msg.exception_pointers != NULL &&
|
||||
msg.assert_info != NULL;
|
||||
return msg.tag == MESSAGE_TAG_UPLOAD_REQUEST ||
|
||||
(msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
|
||||
msg.id != 0 &&
|
||||
msg.thread_id != NULL &&
|
||||
msg.exception_pointers != NULL &&
|
||||
msg.assert_info != NULL);
|
||||
}
|
||||
|
||||
CrashGenerationServer::CrashGenerationServer(
|
||||
@@ -100,6 +101,8 @@ CrashGenerationServer::CrashGenerationServer(
|
||||
void* dump_context,
|
||||
OnClientExitedCallback exit_callback,
|
||||
void* exit_context,
|
||||
OnClientUploadRequestCallback upload_request_callback,
|
||||
void* upload_context,
|
||||
bool generate_dumps,
|
||||
const std::wstring* dump_path)
|
||||
: pipe_name_(pipe_name),
|
||||
@@ -113,6 +116,8 @@ CrashGenerationServer::CrashGenerationServer(
|
||||
dump_context_(dump_context),
|
||||
exit_callback_(exit_callback),
|
||||
exit_context_(exit_context),
|
||||
upload_request_callback_(upload_request_callback),
|
||||
upload_context_(upload_context),
|
||||
generate_dumps_(generate_dumps),
|
||||
dump_generator_(NULL),
|
||||
server_state_(IPC_SERVER_STATE_UNINITIALIZED),
|
||||
@@ -120,7 +125,7 @@ CrashGenerationServer::CrashGenerationServer(
|
||||
overlapped_(),
|
||||
client_info_(NULL),
|
||||
cleanup_item_count_(0) {
|
||||
InitializeCriticalSection(&clients_sync_);
|
||||
InitializeCriticalSection(&sync_);
|
||||
|
||||
if (dump_path) {
|
||||
dump_generator_.reset(new MinidumpGenerator(*dump_path));
|
||||
@@ -128,38 +133,41 @@ CrashGenerationServer::CrashGenerationServer(
|
||||
}
|
||||
|
||||
CrashGenerationServer::~CrashGenerationServer() {
|
||||
// Indicate to existing threads that server is shutting down.
|
||||
shutting_down_ = true;
|
||||
|
||||
// Even if there are no current worker threads running, it is possible that
|
||||
// an I/O request is pending on the pipe right now but not yet done. In fact,
|
||||
// it's very likely this is the case unless we are in an ERROR state. If we
|
||||
// don't wait for the pending I/O to be done, then when the I/O completes,
|
||||
// it may write to invalid memory. AppVerifier will flag this problem too.
|
||||
// So we disconnect from the pipe and then wait for the server to get into
|
||||
// error state so that the pending I/O will fail and get cleared.
|
||||
DisconnectNamedPipe(pipe_);
|
||||
int num_tries = 100;
|
||||
while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
// Unregister wait on the pipe.
|
||||
if (pipe_wait_handle_) {
|
||||
// Wait for already executing callbacks to finish.
|
||||
UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
// Close the pipe to avoid further client connections.
|
||||
if (pipe_) {
|
||||
CloseHandle(pipe_);
|
||||
}
|
||||
|
||||
// Request all ClientInfo objects to unregister all waits.
|
||||
// New scope to hold the lock for the shortest time.
|
||||
// New scope to release the lock automatically.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
AutoCriticalSection lock(&sync_);
|
||||
|
||||
// Indicate to existing threads that server is shutting down.
|
||||
shutting_down_ = true;
|
||||
|
||||
// Even if there are no current worker threads running, it is possible that
|
||||
// an I/O request is pending on the pipe right now but not yet done.
|
||||
// In fact, it's very likely this is the case unless we are in an ERROR
|
||||
// state. If we don't wait for the pending I/O to be done, then when the I/O
|
||||
// completes, it may write to invalid memory. AppVerifier will flag this
|
||||
// problem too. So we disconnect from the pipe and then wait for the server
|
||||
// to get into error state so that the pending I/O will fail and get
|
||||
// cleared.
|
||||
DisconnectNamedPipe(pipe_);
|
||||
int num_tries = 100;
|
||||
while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
|
||||
lock.Release();
|
||||
Sleep(10);
|
||||
lock.Acquire();
|
||||
}
|
||||
|
||||
// Unregister wait on the pipe.
|
||||
if (pipe_wait_handle_) {
|
||||
// Wait for already executing callbacks to finish.
|
||||
UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
// Close the pipe to avoid further client connections.
|
||||
if (pipe_) {
|
||||
CloseHandle(pipe_);
|
||||
}
|
||||
|
||||
// Request all ClientInfo objects to unregister all waits.
|
||||
std::list<ClientInfo*>::iterator iter;
|
||||
for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
|
||||
ClientInfo* client_info = *iter;
|
||||
@@ -180,33 +188,35 @@ CrashGenerationServer::~CrashGenerationServer() {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up all the ClientInfo objects.
|
||||
// New scope to hold the lock for the shortest time.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
AutoCriticalSection lock(&sync_);
|
||||
|
||||
// Clean up all the ClientInfo objects.
|
||||
std::list<ClientInfo*>::iterator iter;
|
||||
for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
|
||||
ClientInfo* client_info = *iter;
|
||||
delete client_info;
|
||||
}
|
||||
|
||||
if (server_alive_handle_) {
|
||||
// Release the mutex before closing the handle so that clients requesting
|
||||
// dumps wait for a long time for the server to generate a dump.
|
||||
ReleaseMutex(server_alive_handle_);
|
||||
CloseHandle(server_alive_handle_);
|
||||
}
|
||||
|
||||
if (overlapped_.hEvent) {
|
||||
CloseHandle(overlapped_.hEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (server_alive_handle_) {
|
||||
// Release the mutex before closing the handle so that clients requesting
|
||||
// dumps wait for a long time for the server to generate a dump.
|
||||
ReleaseMutex(server_alive_handle_);
|
||||
CloseHandle(server_alive_handle_);
|
||||
}
|
||||
|
||||
if (overlapped_.hEvent) {
|
||||
CloseHandle(overlapped_.hEvent);
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&clients_sync_);
|
||||
DeleteCriticalSection(&sync_);
|
||||
}
|
||||
|
||||
bool CrashGenerationServer::Start() {
|
||||
AutoCriticalSection lock(&sync_);
|
||||
|
||||
if (server_state_ != IPC_SERVER_STATE_UNINITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
@@ -416,9 +426,16 @@ void CrashGenerationServer::HandleReadDoneState() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_.tag == MESSAGE_TAG_UPLOAD_REQUEST) {
|
||||
if (upload_request_callback_)
|
||||
upload_request_callback_(upload_context_, msg_.id);
|
||||
EnterStateImmediately(IPC_SERVER_STATE_DISCONNECTING);
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<ClientInfo> client_info(
|
||||
new ClientInfo(this,
|
||||
msg_.pid,
|
||||
msg_.id,
|
||||
msg_.dump_type,
|
||||
msg_.thread_id,
|
||||
msg_.exception_pointers,
|
||||
@@ -582,7 +599,7 @@ void CrashGenerationServer::EnterStateImmediately(IPCServerState state) {
|
||||
bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
|
||||
ProtocolMessage* reply) const {
|
||||
reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
|
||||
reply->pid = GetCurrentProcessId();
|
||||
reply->id = GetCurrentProcessId();
|
||||
|
||||
if (CreateClientHandles(client_info, reply)) {
|
||||
return true;
|
||||
@@ -670,6 +687,8 @@ bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
|
||||
// implements the state machine described in ReadMe.txt along with the
|
||||
// helper methods HandleXXXState.
|
||||
void CrashGenerationServer::HandleConnectionRequest() {
|
||||
AutoCriticalSection lock(&sync_);
|
||||
|
||||
// If we are shutting doen then get into ERROR state, reset the event so more
|
||||
// workers don't run and return immediately.
|
||||
if (shutting_down_) {
|
||||
@@ -756,7 +775,7 @@ bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
|
||||
|
||||
// New scope to hold the lock for the shortest time.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
AutoCriticalSection lock(&sync_);
|
||||
clients_.push_back(client_info);
|
||||
}
|
||||
|
||||
@@ -793,6 +812,7 @@ void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
|
||||
CrashGenerationServer* crash_server = client_info->crash_server();
|
||||
assert(crash_server);
|
||||
|
||||
client_info->UnregisterWaits();
|
||||
InterlockedIncrement(&crash_server->cleanup_item_count_);
|
||||
|
||||
if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT)) {
|
||||
@@ -823,7 +843,7 @@ void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {
|
||||
|
||||
// Start a new scope to release lock automatically.
|
||||
{
|
||||
AutoCriticalSection lock(&clients_sync_);
|
||||
AutoCriticalSection lock(&sync_);
|
||||
clients_.remove(client_info);
|
||||
}
|
||||
|
||||
|
@@ -59,6 +59,9 @@ class CrashGenerationServer {
|
||||
typedef void (*OnClientExitedCallback)(void* context,
|
||||
const ClientInfo* client_info);
|
||||
|
||||
typedef void (*OnClientUploadRequestCallback)(void* context,
|
||||
const DWORD crash_id);
|
||||
|
||||
// Creates an instance with the given parameters.
|
||||
//
|
||||
// Parameter pipe_name: Name of the Windows named pipe
|
||||
@@ -86,6 +89,8 @@ class CrashGenerationServer {
|
||||
void* dump_context,
|
||||
OnClientExitedCallback exit_callback,
|
||||
void* exit_context,
|
||||
OnClientUploadRequestCallback upload_request_callback,
|
||||
void* upload_context,
|
||||
bool generate_dumps,
|
||||
const std::wstring* dump_path);
|
||||
|
||||
@@ -211,8 +216,9 @@ class CrashGenerationServer {
|
||||
// asynchronous IO operation.
|
||||
void EnterStateWhenSignaled(IPCServerState state);
|
||||
|
||||
// Sync object for thread-safe access to the shared list of clients.
|
||||
CRITICAL_SECTION clients_sync_;
|
||||
// Sync object for thread-safe access to the shared list of clients and
|
||||
// the server's state.
|
||||
CRITICAL_SECTION sync_;
|
||||
|
||||
// List of clients.
|
||||
std::list<ClientInfo*> clients_;
|
||||
@@ -250,6 +256,12 @@ class CrashGenerationServer {
|
||||
// Context for client process exit callback.
|
||||
void* exit_context_;
|
||||
|
||||
// Callback for upload request.
|
||||
OnClientUploadRequestCallback upload_request_callback_;
|
||||
|
||||
// Context for upload request callback.
|
||||
void* upload_context_;
|
||||
|
||||
// Whether to generate dumps.
|
||||
bool generate_dumps_;
|
||||
|
||||
@@ -260,10 +272,10 @@ class CrashGenerationServer {
|
||||
// Note that since we restrict the pipe to one instance, we
|
||||
// only need to keep one state of the server. Otherwise, server
|
||||
// would have one state per client it is talking to.
|
||||
volatile IPCServerState server_state_;
|
||||
IPCServerState server_state_;
|
||||
|
||||
// Whether the server is shutting down.
|
||||
volatile bool shutting_down_;
|
||||
bool shutting_down_;
|
||||
|
||||
// Overlapped instance for async I/O on the pipe.
|
||||
OVERLAPPED overlapped_;
|
||||
|
Reference in New Issue
Block a user