Commit b87935ec authored by piman@chromium.org's avatar piman@chromium.org

Fix lost context recreation race in BrowserGpuChannelHostFactory

An existing GPU process may have died between the last message we sent on its
channel and the next time we try to establish a new GPU channel. In that case,
we would re-use the GpuProcessHost but fail on the Send.

When that happens, we want to retry with a fresh GPU process.

BUG=129067


Review URL: https://chromiumcodereview.appspot.com/10852012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149993 0039d316-1c4b-4281-b951-d872f2087c98
parent 826df827
...@@ -20,14 +20,19 @@ BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL; ...@@ -20,14 +20,19 @@ BrowserGpuChannelHostFactory* BrowserGpuChannelHostFactory::instance_ = NULL;
BrowserGpuChannelHostFactory::CreateRequest::CreateRequest() BrowserGpuChannelHostFactory::CreateRequest::CreateRequest()
: event(false, false), : event(false, false),
gpu_host_id(0),
route_id(MSG_ROUTING_NONE) { route_id(MSG_ROUTING_NONE) {
} }
BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() { BrowserGpuChannelHostFactory::CreateRequest::~CreateRequest() {
} }
BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest() BrowserGpuChannelHostFactory::EstablishRequest::EstablishRequest(
: event(false, false) { CauseForGpuLaunch cause)
: event(false, false),
cause_for_gpu_launch(cause),
gpu_host_id(0),
reused_gpu_process(true) {
} }
BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() { BrowserGpuChannelHostFactory::EstablishRequest::~EstablishRequest() {
...@@ -130,34 +135,51 @@ int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer( ...@@ -130,34 +135,51 @@ int32 BrowserGpuChannelHostFactory::CreateViewCommandBuffer(
} }
void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO( void BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO(
EstablishRequest* request, EstablishRequest* request) {
CauseForGpuLaunch cause_for_gpu_launch) {
GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_);
if (!host) { if (!host) {
host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
cause_for_gpu_launch); request->cause_for_gpu_launch);
if (!host) { if (!host) {
request->event.Signal(); request->event.Signal();
return; return;
} }
gpu_host_id_ = host->host_id(); gpu_host_id_ = host->host_id();
request->reused_gpu_process = false;
} else {
if (host->host_id() == request->gpu_host_id) {
// We come here if we retried to establish the channel because of a
// failure in GpuChannelEstablishedOnIO, but we ended up with the same
// process ID, meaning the failure was not because of a channel error, but
// another reason. So fail now.
request->event.Signal();
return;
} }
request->reused_gpu_process = true;
}
request->gpu_host_id = gpu_host_id_;
host->EstablishGpuChannel( host->EstablishGpuChannel(
gpu_client_id_, gpu_client_id_,
true, true,
base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO, base::Bind(&BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO,
base::Unretained(this),
request)); request));
} }
// static
void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO( void BrowserGpuChannelHostFactory::GpuChannelEstablishedOnIO(
EstablishRequest* request, EstablishRequest* request,
const IPC::ChannelHandle& channel_handle, const IPC::ChannelHandle& channel_handle,
const GPUInfo& gpu_info) { const GPUInfo& gpu_info) {
if (channel_handle.name.empty() && request->reused_gpu_process) {
// We failed after re-using the GPU process, but it may have died in the
// mean time. Retry to have a chance to create a fresh GPU process.
EstablishGpuChannelOnIO(request);
} else {
request->channel_handle = channel_handle; request->channel_handle = channel_handle;
request->gpu_info = gpu_info; request->gpu_info = gpu_info;
request->event.Signal(); request->event.Signal();
}
} }
GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync( GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
...@@ -172,14 +194,13 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync( ...@@ -172,14 +194,13 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
// Ensure initialization on the main thread. // Ensure initialization on the main thread.
GpuDataManagerImpl::GetInstance(); GpuDataManagerImpl::GetInstance();
EstablishRequest request; EstablishRequest request(cause_for_gpu_launch);
GetIOLoopProxy()->PostTask( GetIOLoopProxy()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind( base::Bind(
&BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO, &BrowserGpuChannelHostFactory::EstablishGpuChannelOnIO,
base::Unretained(this), base::Unretained(this),
&request, &request));
cause_for_gpu_launch));
{ {
// We're blocking the UI thread, which is generally undesirable. // We're blocking the UI thread, which is generally undesirable.
...@@ -193,7 +214,7 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync( ...@@ -193,7 +214,7 @@ GpuChannelHost* BrowserGpuChannelHostFactory::EstablishGpuChannelSync(
if (request.channel_handle.name.empty()) if (request.channel_handle.name.empty())
return NULL; return NULL;
gpu_channel_ = new GpuChannelHost(this, gpu_host_id_, gpu_client_id_); gpu_channel_ = new GpuChannelHost(this, request.gpu_host_id, gpu_client_id_);
gpu_channel_->set_gpu_info(request.gpu_info); gpu_channel_->set_gpu_info(request.gpu_info);
content::GetContentClient()->SetGpuInfo(request.gpu_info); content::GetContentClient()->SetGpuInfo(request.gpu_info);
......
...@@ -39,13 +39,17 @@ class BrowserGpuChannelHostFactory : public GpuChannelHostFactory { ...@@ -39,13 +39,17 @@ class BrowserGpuChannelHostFactory : public GpuChannelHostFactory {
CreateRequest(); CreateRequest();
~CreateRequest(); ~CreateRequest();
base::WaitableEvent event; base::WaitableEvent event;
int gpu_host_id;
int32 route_id; int32 route_id;
}; };
struct EstablishRequest { struct EstablishRequest {
EstablishRequest(); explicit EstablishRequest(CauseForGpuLaunch);
~EstablishRequest(); ~EstablishRequest();
base::WaitableEvent event; base::WaitableEvent event;
CauseForGpuLaunch cause_for_gpu_launch;
int gpu_host_id;
bool reused_gpu_process;
IPC::ChannelHandle channel_handle; IPC::ChannelHandle channel_handle;
GPUInfo gpu_info; GPUInfo gpu_info;
}; };
...@@ -58,9 +62,8 @@ class BrowserGpuChannelHostFactory : public GpuChannelHostFactory { ...@@ -58,9 +62,8 @@ class BrowserGpuChannelHostFactory : public GpuChannelHostFactory {
int32 surface_id, int32 surface_id,
const GPUCreateCommandBufferConfig& init_params); const GPUCreateCommandBufferConfig& init_params);
static void CommandBufferCreatedOnIO(CreateRequest* request, int32 route_id); static void CommandBufferCreatedOnIO(CreateRequest* request, int32 route_id);
void EstablishGpuChannelOnIO(EstablishRequest* request, void EstablishGpuChannelOnIO(EstablishRequest* request);
CauseForGpuLaunch cause_for_gpu_launch); void GpuChannelEstablishedOnIO(
static void GpuChannelEstablishedOnIO(
EstablishRequest* request, EstablishRequest* request,
const IPC::ChannelHandle& channel_handle, const IPC::ChannelHandle& channel_handle,
const GPUInfo& gpu_info); const GPUInfo& gpu_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment