 Chromium Code Reviews
 Chromium Code Reviews Issue 1139613003:
  cc: Avoid deadlock with the UI thread and NPAPI in more cases  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 1139613003:
  cc: Avoid deadlock with the UI thread and NPAPI in more cases  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| OLD | NEW | 
|---|---|
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "cc/scheduler/scheduler_state_machine.h" | 5 #include "cc/scheduler/scheduler_state_machine.h" | 
| 6 | 6 | 
| 7 #include "base/format_macros.h" | 7 #include "base/format_macros.h" | 
| 8 #include "base/logging.h" | 8 #include "base/logging.h" | 
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" | 
| 10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" | 
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 | 404 | 
| 405 bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { | 405 bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { | 
| 406 if (!CouldSendBeginMainFrame()) | 406 if (!CouldSendBeginMainFrame()) | 
| 407 return false; | 407 return false; | 
| 408 | 408 | 
| 409 // Do not send begin main frame too many times in a single frame. | 409 // Do not send begin main frame too many times in a single frame. | 
| 410 if (send_begin_main_frame_funnel_) | 410 if (send_begin_main_frame_funnel_) | 
| 411 return false; | 411 return false; | 
| 412 | 412 | 
| 413 // Only send BeginMainFrame when there isn't another commit pending already. | 413 // Only send BeginMainFrame when there isn't another commit pending already. | 
| 414 // Other parts of the state machine indirectly defer the BeginMainFrame | |
| 415 // by transitioning to WAITING commit states rather than going | |
| 416 // immediately to IDLE. | |
| 414 if (commit_state_ != COMMIT_STATE_IDLE) | 417 if (commit_state_ != COMMIT_STATE_IDLE) | 
| 415 return false; | 418 return false; | 
| 416 | 419 | 
| 417 // Don't send BeginMainFrame early if we are prioritizing the active tree | 420 // Don't send BeginMainFrame early if we are prioritizing the active tree | 
| 418 // because of impl_latency_takes_priority_. | 421 // because of impl_latency_takes_priority_. | 
| 419 if (impl_latency_takes_priority_ && | 422 if (impl_latency_takes_priority_ && | 
| 420 (has_pending_tree_ || active_tree_needs_first_draw_)) { | 423 (has_pending_tree_ || active_tree_needs_first_draw_)) { | 
| 421 return false; | 424 return false; | 
| 422 } | 425 } | 
| 423 | 426 | 
| 424 // We should not send BeginMainFrame while we are in | 427 // We should not send BeginMainFrame while we are in | 
| 425 // BEGIN_IMPL_FRAME_STATE_IDLE since we might have new | 428 // BEGIN_IMPL_FRAME_STATE_IDLE since we might have new | 
| 426 // user input arriving soon. | 429 // user input arriving soon. | 
| 427 // TODO(brianderson): Allow sending BeginMainFrame while idle when the main | 430 // TODO(brianderson): Allow sending BeginMainFrame while idle when the main | 
| 428 // thread isn't consuming user input. | 431 // thread isn't consuming user input. | 
| 429 if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE && | 432 if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE && | 
| 430 BeginFrameNeeded()) | 433 BeginFrameNeeded()) | 
| 431 return false; | 434 return false; | 
| 432 | 435 | 
| 433 // We need a new commit for the forced redraw. This honors the | 436 // We need a new commit for the forced redraw. This honors the | 
| 434 // single commit per interval because the result will be swapped to screen. | 437 // single commit per interval because the result will be swapped to screen. | 
| 435 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) | 438 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) | 
| 436 return true; | 439 return true; | 
| 437 | 440 | 
| 438 // We shouldn't normally accept commits if there isn't an OutputSurface. | 441 // We shouldn't normally accept commits if there isn't an OutputSurface. | 
| 439 if (!HasInitializedOutputSurface()) | 442 if (!HasInitializedOutputSurface()) | 
| 440 return false; | 443 return false; | 
| 441 | 444 | 
| 442 // SwapAck throttle the BeginMainFrames unless we just swapped. | 445 // We risk deadlock with NPAPI on Windows if we get *this* far ahead of | 
| 443 // TODO(brianderson): Remove this restriction to improve throughput. | 446 // ourselves. Don't do it. | 
| 444 bool just_swapped_in_deadline = | 447 if (pending_swaps_ >= max_pending_swaps_ && has_pending_tree_ && | 
| 445 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && | 448 active_tree_needs_first_draw_) | 
| 446 did_perform_swap_in_last_draw_; | |
| 447 if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline) | |
| 448 return false; | 449 return false; | 
| 449 | 450 | 
| 451 if (!settings_.main_frame_while_swap_throttled_enabled) { | |
| 452 // SwapAck throttle the BeginMainFrames unless we just swapped to | |
| 453 // potentially improve impl-thread latency over main-thread throughput. | |
| 454 // TODO(brianderson): Remove this restriction to improve throughput or | |
| 455 // make it conditional on impl_latency_takes_priority_. | |
| 456 bool just_swapped_in_deadline = | |
| 
sunnyps
2015/05/19 02:36:12
Isn't this just a different way of saying that the
 
brianderson
2015/05/19 20:06:24
I looked into it and it's not quite the same since
 | |
| 457 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && | |
| 458 did_perform_swap_in_last_draw_; | |
| 459 if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline) | |
| 460 return false; | |
| 461 } | |
| 462 | |
| 450 if (skip_begin_main_frame_to_reduce_latency_) | 463 if (skip_begin_main_frame_to_reduce_latency_) | 
| 451 return false; | 464 return false; | 
| 452 | 465 | 
| 453 return true; | 466 return true; | 
| 454 } | 467 } | 
| 455 | 468 | 
| 456 bool SchedulerStateMachine::ShouldCommit() const { | 469 bool SchedulerStateMachine::ShouldCommit() const { | 
| 457 if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT) | 470 if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT) | 
| 458 return false; | 471 return false; | 
| 459 | 472 | 
| 460 // We must not finish the commit until the pending tree is free. | 473 // We must not finish the commit until the pending tree is free. | 
| 461 if (has_pending_tree_) { | 474 if (has_pending_tree_) { | 
| 462 DCHECK(settings_.main_frame_before_activation_enabled); | 475 DCHECK(settings_.main_frame_before_activation_enabled); | 
| 463 return false; | 476 return false; | 
| 464 } | 477 } | 
| 465 | 478 | 
| 466 // Prioritize drawing the previous commit before finishing the next commit. | 479 if (settings_.impl_side_painting) { | 
| 
sunnyps
2015/05/19 02:36:12
Discussed this offline with brianderson:
It seems
 
brianderson
2015/05/19 20:06:24
I tried reordering draw and commit in NextAction.
 | |
| 467 if (active_tree_needs_first_draw_) | 480 // Prioritize drawing the previous commit before finishing the next commit, | 
| 481 // but only if the draw is imminent. | |
| 482 // Note: We must not block the commit indefinitely when swap throttled and | |
| 483 // active_tree_needs_first_draw_ is true, otherwise we could deadlock with | |
| 484 // NPAPI plugins on Windows. The commit could be blocking the Browser | |
| 485 // UI thread, which prevents it from sending us a swap ack. | |
| 
mithro-old
2015/05/19 01:45:32
Is what happening here is that;
  * The browser U
 | |
| 486 bool active_tree_first_draw_is_imminent = | |
| 487 active_tree_needs_first_draw_ && | |
| 488 begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE && | |
| 489 pending_swaps_ < max_pending_swaps_; | |
| 490 if (active_tree_first_draw_is_imminent) | |
| 491 return false; | |
| 492 } else if (active_tree_needs_first_draw_) { | |
| 493 // If we only have an active tree, it is incorrect to replace it | |
| 494 // before we've drawn it. | |
| 468 return false; | 495 return false; | 
| 496 } | |
| 469 | 497 | 
| 470 return true; | 498 return true; | 
| 471 } | 499 } | 
| 472 | 500 | 
| 473 bool SchedulerStateMachine::ShouldPrepareTiles() const { | 501 bool SchedulerStateMachine::ShouldPrepareTiles() const { | 
| 474 // PrepareTiles only really needs to be called immediately after commit | 502 // PrepareTiles only really needs to be called immediately after commit | 
| 475 // and then periodically after that. Use a funnel to make sure we average | 503 // and then periodically after that. Use a funnel to make sure we average | 
| 476 // one PrepareTiles per BeginImplFrame in the long run. | 504 // one PrepareTiles per BeginImplFrame in the long run. | 
| 477 if (prepare_tiles_funnel_ > 0) | 505 if (prepare_tiles_funnel_ > 0) | 
| 478 return false; | 506 return false; | 
| (...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1138 static_cast<int>(begin_impl_frame_state_), | 1166 static_cast<int>(begin_impl_frame_state_), | 
| 1139 static_cast<int>(commit_state_), | 1167 static_cast<int>(commit_state_), | 
| 1140 has_pending_tree_ ? 'T' : 'F', | 1168 has_pending_tree_ ? 'T' : 'F', | 
| 1141 pending_tree_is_ready_for_activation_ ? 'T' : 'F', | 1169 pending_tree_is_ready_for_activation_ ? 'T' : 'F', | 
| 1142 active_tree_needs_first_draw_ ? 'T' : 'F', | 1170 active_tree_needs_first_draw_ ? 'T' : 'F', | 
| 1143 max_pending_swaps_, | 1171 max_pending_swaps_, | 
| 1144 pending_swaps_); | 1172 pending_swaps_); | 
| 1145 } | 1173 } | 
| 1146 | 1174 | 
| 1147 } // namespace cc | 1175 } // namespace cc | 
| OLD | NEW |