Index: gpu/ipc/service/gpu_channel.cc |
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc |
index 08213b66d18ef02b6e3cb504b3d9d3a2c84876d5..bb25f639da97b14d7ebe646ad581cbd2393a3329 100644 |
--- a/gpu/ipc/service/gpu_channel.cc |
+++ b/gpu/ipc/service/gpu_channel.cc |
@@ -71,31 +71,19 @@ CommandBufferId GenerateCommandBufferId(int channel_id, int32_t route_id) { |
} // anonymous namespace |
-scoped_refptr<GpuChannelMessageQueue> GpuChannelMessageQueue::Create( |
- GpuChannel* channel, |
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
- scoped_refptr<PreemptionFlag> preempting_flag, |
- scoped_refptr<PreemptionFlag> preempted_flag, |
- SyncPointManager* sync_point_manager) { |
- return new GpuChannelMessageQueue( |
- channel, std::move(io_task_runner), std::move(preempting_flag), |
- std::move(preempted_flag), sync_point_manager); |
-} |
- |
GpuChannelMessageQueue::GpuChannelMessageQueue( |
GpuChannel* channel, |
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
scoped_refptr<PreemptionFlag> preempting_flag, |
scoped_refptr<PreemptionFlag> preempted_flag, |
SyncPointManager* sync_point_manager) |
- : enabled_(true), |
- scheduled_(true), |
- channel_(channel), |
- preemption_state_(IDLE), |
+ : channel_(channel), |
max_preemption_time_( |
base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs)), |
timer_(new base::OneShotTimer), |
sync_point_order_data_(sync_point_manager->CreateSyncPointOrderData()), |
+ main_task_runner_(std::move(main_task_runner)), |
io_task_runner_(std::move(io_task_runner)), |
preempting_flag_(std::move(preempting_flag)), |
preempted_flag_(std::move(preempted_flag)), |
@@ -105,21 +93,14 @@ GpuChannelMessageQueue::GpuChannelMessageQueue( |
} |
GpuChannelMessageQueue::~GpuChannelMessageQueue() { |
- DCHECK(!enabled_); |
DCHECK(channel_messages_.empty()); |
} |
-void GpuChannelMessageQueue::Disable() { |
- { |
- base::AutoLock auto_lock(channel_lock_); |
- DCHECK(enabled_); |
- enabled_ = false; |
- } |
- |
- // We guarantee that the queues will no longer be modified after enabled_ |
- // is set to false, it is now safe to modify the queue without the lock. |
- // All public facing modifying functions check enabled_ while all |
- // private modifying functions DCHECK(enabled_) to enforce this. |
+void GpuChannelMessageQueue::Destroy() { |
+ // We guarantee that the queue will no longer be modified after Destroy is |
+ // called, it is now safe to modify the queue without the lock. All public |
+ // facing modifying functions check enabled_ while all private modifying |
+ // functions DCHECK(enabled_) to enforce this. |
while (!channel_messages_.empty()) { |
const IPC::Message& msg = channel_messages_.front()->message; |
if (msg.is_sync()) { |
@@ -130,18 +111,14 @@ void GpuChannelMessageQueue::Disable() { |
channel_messages_.pop_front(); |
} |
- if (sync_point_order_data_) { |
- sync_point_order_data_->Destroy(); |
- sync_point_order_data_ = nullptr; |
- } |
+ sync_point_order_data_->Destroy(); |
+ // Destroy timer on io thread. |
io_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&GpuChannelMessageQueue::DisableIO, this)); |
-} |
+ FROM_HERE, base::Bind([](std::unique_ptr<base::OneShotTimer>) {}, |
+ base::Passed(&timer_))); |
-void GpuChannelMessageQueue::DisableIO() { |
- DCHECK(io_thread_checker_.CalledOnValidThread()); |
- timer_ = nullptr; |
+ channel_ = nullptr; |
} |
bool GpuChannelMessageQueue::IsScheduled() const { |
@@ -151,12 +128,11 @@ bool GpuChannelMessageQueue::IsScheduled() const { |
void GpuChannelMessageQueue::SetScheduled(bool scheduled) { |
base::AutoLock lock(channel_lock_); |
- DCHECK(enabled_); |
if (scheduled_ == scheduled) |
return; |
scheduled_ = scheduled; |
if (scheduled) |
- channel_->PostHandleMessage(); |
+ PostHandleMessageOnQueue(); |
if (preempting_flag_) { |
io_task_runner_->PostTask( |
FROM_HERE, |
@@ -164,45 +140,46 @@ void GpuChannelMessageQueue::SetScheduled(bool scheduled) { |
} |
} |
-bool GpuChannelMessageQueue::PushBackMessage(const IPC::Message& message) { |
+void GpuChannelMessageQueue::PushBackMessage(const IPC::Message& message) { |
base::AutoLock auto_lock(channel_lock_); |
- if (enabled_) { |
- if (message.type() == GpuCommandBufferMsg_WaitForTokenInRange::ID || |
- message.type() == GpuCommandBufferMsg_WaitForGetOffsetInRange::ID) { |
- channel_->PostHandleOutOfOrderMessage(message); |
- return true; |
- } |
- |
- uint32_t order_num = |
- sync_point_order_data_->GenerateUnprocessedOrderNumber(); |
- std::unique_ptr<GpuChannelMessage> msg( |
- new GpuChannelMessage(message, order_num, base::TimeTicks::Now())); |
+ DCHECK(channel_); |
+ uint32_t order_num = sync_point_order_data_->GenerateUnprocessedOrderNumber(); |
+ std::unique_ptr<GpuChannelMessage> msg( |
+ new GpuChannelMessage(message, order_num, base::TimeTicks::Now())); |
- if (channel_messages_.empty()) { |
- DCHECK(scheduled_); |
- channel_->PostHandleMessage(); |
- } |
+ channel_messages_.push_back(std::move(msg)); |
- channel_messages_.push_back(std::move(msg)); |
+ bool first_message = channel_messages_.size() == 1; |
+ if (first_message) |
+ PostHandleMessageOnQueue(); |
- if (preempting_flag_) |
- UpdatePreemptionStateHelper(); |
+ if (preempting_flag_) |
+ UpdatePreemptionStateHelper(); |
+} |
- return true; |
- } |
- return false; |
+void GpuChannelMessageQueue::PostHandleMessageOnQueue() { |
+ channel_lock_.AssertAcquired(); |
+ DCHECK(channel_); |
+ DCHECK(scheduled_); |
+ DCHECK(!channel_messages_.empty()); |
+ DCHECK(!handle_message_post_task_pending_); |
+ handle_message_post_task_pending_ = true; |
+ main_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&GpuChannel::HandleMessageOnQueue, channel_->AsWeakPtr())); |
} |
const GpuChannelMessage* GpuChannelMessageQueue::BeginMessageProcessing() { |
base::AutoLock auto_lock(channel_lock_); |
- DCHECK(enabled_); |
+ DCHECK(channel_); |
+ DCHECK(scheduled_); |
+ DCHECK(!channel_messages_.empty()); |
+ handle_message_post_task_pending_ = false; |
// If we have been preempted by another channel, just post a task to wake up. |
if (preempted_flag_ && preempted_flag_->IsSet()) { |
- channel_->PostHandleMessage(); |
+ PostHandleMessageOnQueue(); |
return nullptr; |
} |
- if (channel_messages_.empty()) |
- return nullptr; |
sync_point_order_data_->BeginProcessingOrderNumber( |
channel_messages_.front()->order_number); |
return channel_messages_.front().get(); |
@@ -214,7 +191,7 @@ void GpuChannelMessageQueue::PauseMessageProcessing() { |
// If we have been preempted by another channel, just post a task to wake up. |
if (scheduled_) |
- channel_->PostHandleMessage(); |
+ PostHandleMessageOnQueue(); |
sync_point_order_data_->PauseProcessingOrderNumber( |
channel_messages_.front()->order_number); |
@@ -230,7 +207,7 @@ void GpuChannelMessageQueue::FinishMessageProcessing() { |
channel_messages_.pop_front(); |
if (!channel_messages_.empty()) |
- channel_->PostHandleMessage(); |
+ PostHandleMessageOnQueue(); |
if (preempting_flag_) { |
io_task_runner_->PostTask( |
@@ -431,68 +408,71 @@ void GpuChannelMessageQueue::TransitionToWouldPreemptDescheduled() { |
} |
GpuChannelMessageFilter::GpuChannelMessageFilter( |
- scoped_refptr<GpuChannelMessageQueue> message_queue) |
- : message_queue_(std::move(message_queue)), |
- channel_(nullptr), |
- peer_pid_(base::kNullProcessId) {} |
+ GpuChannel* gpu_channel, |
+ scoped_refptr<GpuChannelMessageQueue> message_queue, |
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) |
+ : gpu_channel_(gpu_channel), |
+ message_queue_(std::move(message_queue)), |
+ main_task_runner_(std::move(main_task_runner)) {} |
-GpuChannelMessageFilter::~GpuChannelMessageFilter() {} |
+GpuChannelMessageFilter::~GpuChannelMessageFilter() { |
+ DCHECK(!gpu_channel_); |
+} |
+ |
+void GpuChannelMessageFilter::Destroy() { |
+ base::AutoLock auto_lock(gpu_channel_lock_); |
+ gpu_channel_ = nullptr; |
+} |
void GpuChannelMessageFilter::OnFilterAdded(IPC::Channel* channel) { |
- DCHECK(!channel_); |
- channel_ = channel; |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
- filter->OnFilterAdded(channel_); |
- } |
+ DCHECK(!ipc_channel_); |
+ ipc_channel_ = channel; |
+ for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) |
+ filter->OnFilterAdded(ipc_channel_); |
} |
void GpuChannelMessageFilter::OnFilterRemoved() { |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
+ for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) |
filter->OnFilterRemoved(); |
- } |
- channel_ = nullptr; |
+ ipc_channel_ = nullptr; |
peer_pid_ = base::kNullProcessId; |
} |
void GpuChannelMessageFilter::OnChannelConnected(int32_t peer_pid) { |
DCHECK(peer_pid_ == base::kNullProcessId); |
peer_pid_ = peer_pid; |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
+ for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) |
filter->OnChannelConnected(peer_pid); |
- } |
} |
void GpuChannelMessageFilter::OnChannelError() { |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
+ for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) |
filter->OnChannelError(); |
- } |
} |
void GpuChannelMessageFilter::OnChannelClosing() { |
- for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) { |
+ for (scoped_refptr<IPC::MessageFilter>& filter : channel_filters_) |
filter->OnChannelClosing(); |
- } |
} |
void GpuChannelMessageFilter::AddChannelFilter( |
scoped_refptr<IPC::MessageFilter> filter) { |
channel_filters_.push_back(filter); |
- if (channel_) |
- filter->OnFilterAdded(channel_); |
+ if (ipc_channel_) |
+ filter->OnFilterAdded(ipc_channel_); |
if (peer_pid_ != base::kNullProcessId) |
filter->OnChannelConnected(peer_pid_); |
} |
void GpuChannelMessageFilter::RemoveChannelFilter( |
scoped_refptr<IPC::MessageFilter> filter) { |
- if (channel_) |
+ if (ipc_channel_) |
filter->OnFilterRemoved(); |
- channel_filters_.erase( |
- std::find(channel_filters_.begin(), channel_filters_.end(), filter)); |
+ base::Erase(channel_filters_, filter); |
} |
bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) { |
- DCHECK(channel_); |
+ DCHECK(ipc_channel_); |
if (message.should_unblock() || message.is_reply()) |
return MessageErrorHandler(message, "Unexpected message type"); |
@@ -508,14 +488,28 @@ bool GpuChannelMessageFilter::OnMessageReceived(const IPC::Message& message) { |
return true; |
} |
- if (!message_queue_->PushBackMessage(message)) |
+ base::AutoLock auto_lock(gpu_channel_lock_); |
+ if (!gpu_channel_) |
return MessageErrorHandler(message, "Channel destroyed"); |
+ if (message.routing_id() == MSG_ROUTING_CONTROL || |
+ message.type() == GpuCommandBufferMsg_WaitForTokenInRange::ID || |
+ message.type() == GpuCommandBufferMsg_WaitForGetOffsetInRange::ID) { |
+ // It's OK to post task that may never run even for sync messages, because |
+ // if the channel is destroyed, the client Send will fail. |
+ main_task_runner_->PostTask(FROM_HERE, |
+ base::Bind(&GpuChannel::HandleOutOfOrderMessage, |
+ gpu_channel_->AsWeakPtr(), message)); |
+ } else { |
+ // Message queue takes care of PostTask. |
+ message_queue_->PushBackMessage(message); |
+ } |
+ |
return true; |
} |
bool GpuChannelMessageFilter::Send(IPC::Message* message) { |
- return channel_->Send(message); |
+ return ipc_channel_->Send(message); |
} |
bool GpuChannelMessageFilter::MessageErrorHandler(const IPC::Message& message, |
@@ -550,7 +544,6 @@ GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, |
bool allow_real_time_streams) |
: gpu_channel_manager_(gpu_channel_manager), |
sync_point_manager_(sync_point_manager), |
- unhandled_message_listener_(nullptr), |
preempting_flag_(preempting_flag), |
preempted_flag_(preempted_flag), |
client_id_(client_id), |
@@ -566,18 +559,21 @@ GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager, |
DCHECK(gpu_channel_manager); |
DCHECK(client_id); |
- message_queue_ = |
- GpuChannelMessageQueue::Create(this, io_task_runner, preempting_flag, |
- preempted_flag, sync_point_manager); |
+ message_queue_ = new GpuChannelMessageQueue(this, task_runner, io_task_runner, |
+ preempting_flag, preempted_flag, |
+ sync_point_manager); |
- filter_ = new GpuChannelMessageFilter(message_queue_); |
+ filter_ = new GpuChannelMessageFilter(this, message_queue_, task_runner); |
} |
GpuChannel::~GpuChannel() { |
// Clear stubs first because of dependencies. |
stubs_.clear(); |
- message_queue_->Disable(); |
+ // Destroy filter first so that no message queue gets no more messages. |
+ filter_->Destroy(); |
+ |
+ message_queue_->Destroy(); |
if (preempting_flag_.get()) |
preempting_flag_->Reset(); |
@@ -692,18 +688,7 @@ bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { |
return handled; |
} |
-void GpuChannel::PostHandleMessage() { |
- task_runner_->PostTask(FROM_HERE, base::Bind(&GpuChannel::HandleMessage, |
- weak_factory_.GetWeakPtr())); |
-} |
- |
-void GpuChannel::PostHandleOutOfOrderMessage(const IPC::Message& msg) { |
- task_runner_->PostTask(FROM_HERE, |
- base::Bind(&GpuChannel::HandleOutOfOrderMessage, |
- weak_factory_.GetWeakPtr(), msg)); |
-} |
- |
-void GpuChannel::HandleMessage() { |
+void GpuChannel::HandleMessageOnQueue() { |
const GpuChannelMessage* channel_msg = |
message_queue_->BeginMessageProcessing(); |
if (!channel_msg) |
@@ -896,14 +881,14 @@ void GpuChannel::CacheShader(const std::string& key, |
void GpuChannel::AddFilter(IPC::MessageFilter* filter) { |
io_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&GpuChannelMessageFilter::AddChannelFilter, filter_, |
- make_scoped_refptr(filter))); |
+ FROM_HERE, |
+ base::Bind(&GpuChannelMessageFilter::AddChannelFilter, filter_, filter)); |
} |
void GpuChannel::RemoveFilter(IPC::MessageFilter* filter) { |
io_task_runner_->PostTask( |
FROM_HERE, base::Bind(&GpuChannelMessageFilter::RemoveChannelFilter, |
- filter_, make_scoped_refptr(filter))); |
+ filter_, filter)); |
} |
uint64_t GpuChannel::GetMemoryUsage() { |