diff options
25 files changed, 199 insertions, 37 deletions
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc index fc68b64..25edf16 100644 --- a/base/synchronization/condition_variable_posix.cc +++ b/base/synchronization/condition_variable_posix.cc @@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/synchronization/lock.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" namespace base { @@ -29,6 +30,7 @@ ConditionVariable::~ConditionVariable() { } void ConditionVariable::Wait() { + base::ThreadRestrictions::AssertWaitAllowed(); #if !defined(NDEBUG) user_lock_->CheckHeldAndUnmark(); #endif @@ -40,6 +42,7 @@ void ConditionVariable::Wait() { } void ConditionVariable::TimedWait(const TimeDelta& max_time) { + base::ThreadRestrictions::AssertWaitAllowed(); int64 usecs = max_time.InMicroseconds(); // The timeout argument to pthread_cond_timedwait is in absolute time. diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc index 4f6827f..f32778f 100644 --- a/base/synchronization/condition_variable_win.cc +++ b/base/synchronization/condition_variable_win.cc @@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/synchronization/lock.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" namespace { @@ -94,6 +95,7 @@ void WinVistaCondVar::Wait() { } void WinVistaCondVar::TimedWait(const TimeDelta& max_time) { + base::ThreadRestrictions::AssertWaitAllowed(); DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds()); CRITICAL_SECTION* cs = user_lock_.lock_.os_lock(); @@ -240,6 +242,7 @@ void WinXPCondVar::Wait() { } void WinXPCondVar::TimedWait(const TimeDelta& max_time) { + base::ThreadRestrictions::AssertWaitAllowed(); Event* waiting_event; HANDLE handle; { diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc index fbf8d10..714c111 100644 --- a/base/synchronization/waitable_event_posix.cc +++ b/base/synchronization/waitable_event_posix.cc @@ -5,11 +5,11 @@ #include <algorithm> #include <vector> +#include "base/logging.h" #include "base/synchronization/waitable_event.h" - #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" -#include "base/logging.h" +#include "base/threading/thread_restrictions.h" // ----------------------------------------------------------------------------- // A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't @@ -158,6 +158,7 @@ void WaitableEvent::Wait() { } bool WaitableEvent::TimedWait(const TimeDelta& max_time) { + base::ThreadRestrictions::AssertWaitAllowed(); const Time end_time(Time::Now() + max_time); const bool finite_time = max_time.ToInternalValue() >= 0; @@ -224,6 +225,7 @@ cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a, // static size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables, size_t count) { + base::ThreadRestrictions::AssertWaitAllowed(); DCHECK(count) << "Cannot wait on no events"; // We need to acquire the locks in a globally consistent order. Thus we sort diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc index 31932bd..28f8fc3 100644 --- a/base/synchronization/waitable_event_win.cc +++ b/base/synchronization/waitable_event_win.cc @@ -8,6 +8,7 @@ #include <windows.h> #include "base/logging.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" namespace base { @@ -47,6 +48,7 @@ bool WaitableEvent::IsSignaled() { } void WaitableEvent::Wait() { + base::ThreadRestrictions::AssertWaitAllowed(); DWORD result = WaitForSingleObject(handle_, INFINITE); // It is most unexpected that this should ever fail. Help consumers learn // about it if it should ever fail. @@ -54,6 +56,7 @@ void WaitableEvent::Wait() { } bool WaitableEvent::TimedWait(const TimeDelta& max_time) { + base::ThreadRestrictions::AssertWaitAllowed(); DCHECK(max_time >= TimeDelta::FromMicroseconds(0)); // Be careful here. TimeDelta has a precision of microseconds, but this API // is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6? @@ -74,6 +77,7 @@ bool WaitableEvent::TimedWait(const TimeDelta& max_time) { // static size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { + base::ThreadRestrictions::AssertWaitAllowed(); HANDLE handles[MAXIMUM_WAIT_OBJECTS]; CHECK_LE(count, MAXIMUM_WAIT_OBJECTS) << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc index ad240b3..a91517d 100644 --- a/base/test/thread_test_helper.cc +++ b/base/test/thread_test_helper.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/location.h" +#include "base/threading/thread_restrictions.h" namespace base { @@ -20,6 +21,7 @@ bool ThreadTestHelper::Run() { FROM_HERE, base::Bind(&ThreadTestHelper::RunInThread, this))) { return false; } + base::ThreadRestrictions::ScopedAllowWait allow_wait; done_event_.Wait(); return test_result_; } diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc index 22f9152..59c4187 100644 --- a/base/threading/sequenced_worker_pool.cc +++ b/base/threading/sequenced_worker_pool.cc @@ -23,6 +23,7 @@ #include "base/synchronization/lock.h" #include "base/threading/platform_thread.h" #include "base/threading/simple_thread.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" #include "base/tracked_objects.h" @@ -625,6 +626,7 @@ void SequencedWorkerPool::Inner::Shutdown() { TimeTicks shutdown_wait_begin = TimeTicks::Now(); { + base::ThreadRestrictions::ScopedAllowWait allow_wait; AutoLock lock(lock_); while (!CanShutdown()) can_shutdown_cv_.Wait(); diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc index a5dd763..5419c95 100644 --- a/base/threading/simple_thread.cc +++ b/base/threading/simple_thread.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/threading/platform_thread.h" +#include "base/threading/thread_restrictions.h" #include "base/string_number_conversions.h" namespace base { @@ -30,6 +31,7 @@ void SimpleThread::Start() { DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times."; bool success = PlatformThread::Create(options_.stack_size(), this, &thread_); DCHECK(success); + base::ThreadRestrictions::ScopedAllowWait allow_wait; event_.Wait(); // Wait for the thread to complete initialization. } @@ -40,6 +42,11 @@ void SimpleThread::Join() { joined_ = true; } +bool SimpleThread::HasBeenStarted() { + base::ThreadRestrictions::ScopedAllowWait allow_wait; + return event_.IsSignaled(); +} + void SimpleThread::ThreadMain() { tid_ = PlatformThread::CurrentId(); // Construct our full name of the form "name_prefix_/TID". diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h index c864d46..47d063a 100644 --- a/base/threading/simple_thread.h +++ b/base/threading/simple_thread.h @@ -97,7 +97,7 @@ class BASE_EXPORT SimpleThread : public PlatformThread::Delegate { PlatformThreadId tid() { return tid_; } // Return True if Start() has ever been called. - bool HasBeenStarted() { return event_.IsSignaled(); } + bool HasBeenStarted(); // Return True if Join() has evern been called. bool HasBeenJoined() { return joined_; } diff --git a/base/threading/thread.cc b/base/threading/thread.cc index 7188e9f..d6913a7 100644 --- a/base/threading/thread.cc +++ b/base/threading/thread.cc @@ -8,6 +8,7 @@ #include "base/lazy_instance.h" #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/threading/thread_local.h" +#include "base/threading/thread_restrictions.h" #include "base/synchronization/waitable_event.h" namespace base { @@ -76,6 +77,7 @@ bool Thread::StartWithOptions(const Options& options) { } // Wait for the thread to start and initialize message_loop_ + base::ThreadRestrictions::ScopedAllowWait allow_wait; startup_data.event.Wait(); // set it to NULL so we don't keep a pointer to some object on the stack. diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc index b093fb4..2300a78 100644 --- a/base/threading/thread_restrictions.cc +++ b/base/threading/thread_restrictions.cc @@ -21,6 +21,9 @@ LazyInstance<ThreadLocalBoolean>::Leaky LazyInstance<ThreadLocalBoolean>::Leaky g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER; +LazyInstance<ThreadLocalBoolean>::Leaky + g_wait_disallowed = LAZY_INSTANCE_INITIALIZER; + } // anonymous namespace // static @@ -42,6 +45,7 @@ void ThreadRestrictions::AssertIOAllowed() { } } +// static bool ThreadRestrictions::SetSingletonAllowed(bool allowed) { bool previous_disallowed = g_singleton_disallowed.Get().Get(); g_singleton_disallowed.Get().Set(!allowed); @@ -58,6 +62,25 @@ void ThreadRestrictions::AssertSingletonAllowed() { } } +// static +void ThreadRestrictions::DisallowWaiting() { + g_wait_disallowed.Get().Set(true); +} + +// static +void ThreadRestrictions::AssertWaitAllowed() { + if (g_wait_disallowed.Get().Get()) { + LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent" + << "jank and deadlock."; + } +} + +bool ThreadRestrictions::SetWaitAllowed(bool allowed) { + bool previous_disallowed = g_wait_disallowed.Get().Get(); + g_wait_disallowed.Get().Set(!allowed); + return !previous_disallowed; +} + } // namespace base #endif // NDEBUG diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index fc8ab4b..f638cb3 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h @@ -8,8 +8,33 @@ #include "base/base_export.h" #include "base/basictypes.h" +class MetricsService; +class RenderWidgetHelper; +class TestingAutomationProvider; +class TextInputClientMac; +namespace chrome_browser_net { +class Predictor; +} +namespace disk_cache { +class BackendImpl; +class InFlightIO; +} +namespace media { +class AudioOutputController; +} +namespace net { +class FileStreamPosix; +class FileStreamWin; +class NetworkManagerApi; +} + namespace base { +class SequencedWorkerPool; +class SimpleThread; +class Thread; +class ThreadTestHelper; + // Certain behavior is disallowed on certain threads. ThreadRestrictions helps // enforce these rules. Examples of such rules: // @@ -83,6 +108,13 @@ class BASE_EXPORT ThreadRestrictions { // Check whether the current thread is allowed to use singletons (Singleton / // LazyInstance). DCHECKs if not. static void AssertSingletonAllowed(); + + // Disable waiting on the current thread. Threads start out in the *allowed* + // state. Returns the previous value. + static void DisallowWaiting(); + + // Check whether the current thread is allowed to wait, and DCHECK if not. + static void AssertWaitAllowed(); #else // In Release builds, inline the empty definitions of these functions so // that they can be compiled out. @@ -90,9 +122,54 @@ class BASE_EXPORT ThreadRestrictions { static void AssertIOAllowed() {} static bool SetSingletonAllowed(bool allowed) { return true; } static void AssertSingletonAllowed() {} + static void DisallowWaiting() {} + static void AssertWaitAllowed() {} #endif private: + // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first. + // BEGIN ALLOWED USAGE. + friend class ::RenderWidgetHelper; + friend class ::TestingAutomationProvider; + friend class SequencedWorkerPool; + friend class SimpleThread; + friend class Thread; + friend class ThreadTestHelper; + // END ALLOWED USAGE. + // BEGIN USAGE THAT NEEDS TO BE FIXED. + friend class chrome_browser_net::Predictor; // http://crbug.com/78451 + friend class disk_cache::BackendImpl; // http://crbug.com/74623 + friend class disk_cache::InFlightIO; // http://crbug.com/74623 + friend class media::AudioOutputController; // http://crbug.com/120973 + friend class net::FileStreamPosix; // http://crbug.com/74623 + friend class net::FileStreamWin; // http://crbug.com/74623 + friend class net::NetworkManagerApi; // http://crbug.com/125097 + friend class ::TextInputClientMac; // http://crbug.com/121917 + friend class ::MetricsService; // http://crbug.com/124954 + // END USAGE THAT NEEDS TO BE FIXED. + +#ifndef NDEBUG + static bool SetWaitAllowed(bool allowed); +#else + static bool SetWaitAllowed(bool allowed) { return true; } +#endif + + // Constructing a ScopedAllowWait temporarily allows waiting on the current + // thread. Doing this is almost always incorrect, which is why we limit who + // can use this through friend. If you find yourself needing to use this, find + // another way. Talk to jam or brettw. + class BASE_EXPORT ScopedAllowWait { + public: + ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); } + ~ScopedAllowWait() { SetWaitAllowed(previous_value_); } + private: + // Whether singleton use is allowed when the ScopedAllowWait was + // constructed. + bool previous_value_; + + DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait); + }; + DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions); }; diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc index a7ecae8..87e1564 100644 --- a/chrome/browser/automation/testing_automation_provider.cc +++ b/chrome/browser/automation/testing_automation_provider.cc @@ -325,6 +325,7 @@ void TestingAutomationProvider::Observe( bool TestingAutomationProvider::OnMessageReceived( const IPC::Message& message) { + base::ThreadRestrictions::ScopedAllowWait allow_wait; bool handled = true; bool deserialize_success = true; IPC_BEGIN_MESSAGE_MAP_EX(TestingAutomationProvider, diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 941df16..73fbaa0 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -17,7 +17,6 @@ #include "base/string_split.h" #include "base/string_util.h" #include "base/threading/thread.h" -#include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_event_router_forwarder.h" @@ -374,10 +373,6 @@ net::URLRequestContextGetter* IOThread::system_url_request_context_getter() { } void IOThread::Init() { - // Though this thread is called the "IO" thread, it actually just routes - // messages around; it shouldn't be allowed to perform any blocking disk I/O. - base::ThreadRestrictions::SetIOAllowed(false); - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); #if defined(USE_NSS) diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc index 89eb0c2..0b692aa 100644 --- a/chrome/browser/metrics/metrics_service.cc +++ b/chrome/browser/metrics/metrics_service.cc @@ -152,6 +152,7 @@ #include "base/string_number_conversions.h" #include "base/threading/platform_thread.h" #include "base/threading/thread.h" +#include "base/threading/thread_restrictions.h" #include "base/tracked_objects.h" #include "base/utf_string_conversions.h" #include "base/values.h" @@ -810,7 +811,7 @@ void MetricsService::ReceivedProfilerData( void MetricsService::FinishedReceivingProfilerData() { DCHECK_EQ(INIT_TASK_SCHEDULED, state_); - state_ = INIT_TASK_DONE; + state_ = INIT_TASK_DONE; } std::string MetricsService::GenerateClientID() { @@ -1461,6 +1462,8 @@ void MetricsService::LogCleanShutdown() { base::WaitableEvent done_writing(false, false); BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(Signal, &done_writing)); + // http://crbug.com/124954 + base::ThreadRestrictions::ScopedAllowWait allow_wait; done_writing.TimedWait(base::TimeDelta::FromHours(1)); // Redundant setting to assure that we always reset this value at shutdown diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc index f91e51e..5df69b86 100644 --- a/chrome/browser/net/predictor.cc +++ b/chrome/browser/net/predictor.cc @@ -18,6 +18,7 @@ #include "base/string_util.h" #include "base/stringprintf.h" #include "base/synchronization/waitable_event.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" #include "base/values.h" #include "chrome/browser/io_thread.h" @@ -768,8 +769,11 @@ void Predictor::SaveStateForNextStartupAndTrim(PrefService* prefs) { // TODO(jar): Synchronous waiting for the IO thread is a potential source // to deadlocks and should be investigated. See http://crbug.com/78451. DCHECK(posted); - if (posted) + if (posted) { + // http://crbug.com/124954 + base::ThreadRestrictions::ScopedAllowWait allow_wait; completion.Wait(); + } } } diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 1aed2d2..a2405fa 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -427,6 +427,7 @@ void BrowserMainLoop::CreateThreads() { // If the UI thread blocks, the whole UI is unresponsive. // Do not allow disk IO from the UI thread. base::ThreadRestrictions::SetIOAllowed(false); + base::ThreadRestrictions::DisallowWaiting(); // When running the GPU thread in-process, avoid optimistically starting it // since creating the GPU thread races against creation of the one-and-only diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc index fb80cae..c521af2 100644 --- a/content/browser/browser_process_sub_thread.cc +++ b/content/browser/browser_process_sub_thread.cc @@ -9,6 +9,7 @@ #endif #include "base/debug/leak_tracker.h" +#include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "content/browser/browser_child_process_host_impl.h" #include "content/browser/in_process_webkit/indexed_db_key_utility_client.h" @@ -36,6 +37,14 @@ void BrowserProcessSubThread::Init() { notification_service_ = new NotificationServiceImpl; BrowserThreadImpl::Init(); + + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { + // Though this thread is called the "IO" thread, it actually just routes + // messages around; it shouldn't be allowed to perform any blocking disk + // I/O. + base::ThreadRestrictions::SetIOAllowed(false); + base::ThreadRestrictions::DisallowWaiting(); + } } void BrowserProcessSubThread::CleanUp() { diff --git a/content/browser/renderer_host/render_widget_helper.cc b/content/browser/renderer_host/render_widget_helper.cc index 2290b4e..e516e6c 100644 --- a/content/browser/renderer_host/render_widget_helper.cc +++ b/content/browser/renderer_host/render_widget_helper.cc @@ -9,6 +9,7 @@ #include "base/eintr_wrapper.h" #include "base/lazy_instance.h" #include "base/threading/thread.h" +#include "base/threading/thread_restrictions.h" #include "content/browser/gpu/gpu_surface_tracker.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -145,8 +146,8 @@ void RenderWidgetHelper::SimulateSwapOutACK( bool RenderWidgetHelper::WaitForBackingStoreMsg( int render_widget_id, - const base::TimeDelta& max_delay, - IPC::Message* msg) { + const base::TimeDelta& max_delay, + IPC::Message* msg) { base::TimeTicks time_start = base::TimeTicks::Now(); for (;;) { @@ -183,6 +184,7 @@ bool RenderWidgetHelper::WaitForBackingStoreMsg( if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0)) break; + base::ThreadRestrictions::ScopedAllowWait allow_wait; event_.TimedWait(max_sleep_time); } diff --git a/content/browser/renderer_host/text_input_client_mac.mm b/content/browser/renderer_host/text_input_client_mac.mm index 933511e..b026920e 100644 --- a/content/browser/renderer_host/text_input_client_mac.mm +++ b/content/browser/renderer_host/text_input_client_mac.mm @@ -6,6 +6,7 @@ #include "base/memory/singleton.h" #include "base/metrics/histogram.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/common/text_input_client_messages.h" @@ -41,6 +42,8 @@ NSUInteger TextInputClientMac::GetCharacterIndexAtPoint(RenderWidgetHost* rwh, RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh); rwhi->Send(new TextInputClientMsg_CharacterIndexForPoint(rwhi->GetRoutingID(), point)); + // http://crbug.com/121917 + base::ThreadRestrictions::ScopedAllowWait allow_wait; condition_.TimedWait(base::TimeDelta::FromMilliseconds(kWaitTimeout)); AfterRequest(); @@ -60,6 +63,8 @@ NSRect TextInputClientMac::GetFirstRectForRange(RenderWidgetHost* rwh, rwhi->Send( new TextInputClientMsg_FirstRectForCharacterRange(rwhi->GetRoutingID(), ui::Range(range))); + // http://crbug.com/121917 + base::ThreadRestrictions::ScopedAllowWait allow_wait; condition_.TimedWait(base::TimeDelta::FromMilliseconds(kWaitTimeout)); AfterRequest(); @@ -79,6 +84,8 @@ NSAttributedString* TextInputClientMac::GetAttributedSubstringFromRange( RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh); rwhi->Send(new TextInputClientMsg_StringForRange(rwhi->GetRoutingID(), ui::Range(range))); + // http://crbug.com/121917 + base::ThreadRestrictions::ScopedAllowWait allow_wait; condition_.TimedWait(base::TimeDelta::FromMilliseconds(kWaitTimeout)); AfterRequest(); diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index c136432..1f8d78f 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -9,6 +9,7 @@ #include "base/message_loop.h" #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" +#include "base/threading/thread_restrictions.h" #include "base/time.h" using base::Time; @@ -42,6 +43,8 @@ AudioOutputController::~AudioOutputController() { if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) { DoStopCloseAndClearStream(NULL); } else { + // http://crbug.com/120973 + base::ThreadRestrictions::ScopedAllowWait allow_wait; WaitableEvent completion(true /* manual reset */, false /* initial state */); message_loop_->PostTask(FROM_HERE, diff --git a/net/base/file_stream_posix.cc b/net/base/file_stream_posix.cc index 0fe801d..e76bf83 100644 --- a/net/base/file_stream_posix.cc +++ b/net/base/file_stream_posix.cc @@ -644,6 +644,7 @@ void FileStreamPosix::OnClosed(const CompletionCallback& callback) { } void FileStreamPosix::WaitForIOCompletion() { + base::ThreadRestrictions::ScopedAllowWait allow_wait; if (on_io_complete_.get()) { on_io_complete_->Wait(); on_io_complete_.reset(); diff --git a/net/base/file_stream_win.cc b/net/base/file_stream_win.cc index 97b1975..9dad2c6 100644 --- a/net/base/file_stream_win.cc +++ b/net/base/file_stream_win.cc @@ -727,6 +727,7 @@ void FileStreamWin::ResetOnIOComplete() { } void FileStreamWin::WaitForIOCompletion() { + base::ThreadRestrictions::ScopedAllowWait allow_wait; if (on_io_complete_.get()) { on_io_complete_->Wait(); on_io_complete_.reset(); diff --git a/net/base/network_change_notifier_linux.cc b/net/base/network_change_notifier_linux.cc index 4f75542..a4bc595 100644 --- a/net/base/network_change_notifier_linux.cc +++ b/net/base/network_change_notifier_linux.cc @@ -24,6 +24,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" #include "base/threading/thread.h" +#include "base/threading/thread_restrictions.h" #include "dbus/bus.h" #include "dbus/message.h" #include "dbus/object_proxy.h" @@ -63,6 +64,30 @@ enum { NM_STATE_CONNECTED_GLOBAL = 70 }; +class DNSWatchDelegate : public FilePathWatcher::Delegate { + public: + explicit DNSWatchDelegate(const base::Closure& callback) + : callback_(callback) {} + virtual ~DNSWatchDelegate() {} + // FilePathWatcher::Delegate interface + virtual void OnFilePathChanged(const FilePath& path) OVERRIDE; + virtual void OnFilePathError(const FilePath& path) OVERRIDE; + private: + base::Closure callback_; + DISALLOW_COPY_AND_ASSIGN(DNSWatchDelegate); +}; + +void DNSWatchDelegate::OnFilePathChanged(const FilePath& path) { + // Calls NetworkChangeNotifier::NotifyObserversOfDNSChange(). + callback_.Run(); +} + +void DNSWatchDelegate::OnFilePathError(const FilePath& path) { + LOG(ERROR) << "DNSWatchDelegate::OnFilePathError for " << path.value(); +} + +} // namespace + // A wrapper around NetworkManager's D-Bus API. class NetworkManagerApi { public: @@ -232,35 +257,13 @@ bool NetworkManagerApi::StateIsOffline(uint32 state) { } bool NetworkManagerApi::IsCurrentlyOffline() { + // http://crbug.com/125097 + base::ThreadRestrictions::ScopedAllowWait allow_wait; offline_state_initialized_.Wait(); base::AutoLock lock(is_offline_lock_); return is_offline_; } -class DNSWatchDelegate : public FilePathWatcher::Delegate { - public: - explicit DNSWatchDelegate(const base::Closure& callback) - : callback_(callback) {} - virtual ~DNSWatchDelegate() {} - // FilePathWatcher::Delegate interface - virtual void OnFilePathChanged(const FilePath& path) OVERRIDE; - virtual void OnFilePathError(const FilePath& path) OVERRIDE; - private: - base::Closure callback_; - DISALLOW_COPY_AND_ASSIGN(DNSWatchDelegate); -}; - -void DNSWatchDelegate::OnFilePathChanged(const FilePath& path) { - // Calls NetworkChangeNotifier::NotifyObserversOfDNSChange(). - callback_.Run(); -} - -void DNSWatchDelegate::OnFilePathError(const FilePath& path) { - LOG(ERROR) << "DNSWatchDelegate::OnFilePathError for " << path.value(); -} - -} // namespace - class NetworkChangeNotifierLinux::Thread : public base::Thread, public MessageLoopForIO::Watcher { public: diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index eb26567..20fd40f 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -369,6 +369,8 @@ BackendImpl::~BackendImpl() { } else { background_queue_.background_thread()->PostTask( FROM_HERE, base::Bind(&FinalCleanupCallback, base::Unretained(this))); + // http://crbug.com/74623 + base::ThreadRestrictions::ScopedAllowWait allow_wait; done_.Wait(); } } diff --git a/net/disk_cache/in_flight_io.cc b/net/disk_cache/in_flight_io.cc index 86c2dcc..51ad986 100644 --- a/net/disk_cache/in_flight_io.cc +++ b/net/disk_cache/in_flight_io.cc @@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/location.h" #include "base/logging.h" +#include "base/threading/thread_restrictions.h" namespace disk_cache { @@ -82,7 +83,11 @@ void InFlightIO::OnIOComplete(BackgroundIO* operation) { // Runs on the primary thread. void InFlightIO::InvokeCallback(BackgroundIO* operation, bool cancel_task) { - operation->io_completed()->Wait(); + { + // http://crbug.com/74623 + base::ThreadRestrictions::ScopedAllowWait allow_wait; + operation->io_completed()->Wait(); + } running_ = true; if (cancel_task) |