| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/threading/thread.h" | 5 #include "base/threading/thread.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 // another sequence as long as every other operation is then performed on that | 53 // another sequence as long as every other operation is then performed on that |
| 54 // sequence. | 54 // sequence. |
| 55 owning_sequence_checker_.DetachFromSequence(); | 55 owning_sequence_checker_.DetachFromSequence(); |
| 56 } | 56 } |
| 57 | 57 |
| 58 Thread::~Thread() { | 58 Thread::~Thread() { |
| 59 Stop(); | 59 Stop(); |
| 60 } | 60 } |
| 61 | 61 |
| 62 bool Thread::Start() { | 62 bool Thread::Start() { |
| 63 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 63 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 64 | 64 |
| 65 Options options; | 65 Options options; |
| 66 #if defined(OS_WIN) | 66 #if defined(OS_WIN) |
| 67 if (com_status_ == STA) | 67 if (com_status_ == STA) |
| 68 options.message_loop_type = MessageLoop::TYPE_UI; | 68 options.message_loop_type = MessageLoop::TYPE_UI; |
| 69 #endif | 69 #endif |
| 70 return StartWithOptions(options); | 70 return StartWithOptions(options); |
| 71 } | 71 } |
| 72 | 72 |
| 73 bool Thread::StartWithOptions(const Options& options) { | 73 bool Thread::StartWithOptions(const Options& options) { |
| 74 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 74 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 75 DCHECK(!message_loop_); | 75 DCHECK(!message_loop_); |
| 76 DCHECK(!IsRunning()); | 76 DCHECK(!IsRunning()); |
| 77 #if defined(OS_WIN) | 77 #if defined(OS_WIN) |
| 78 DCHECK((com_status_ != STA) || | 78 DCHECK((com_status_ != STA) || |
| 79 (options.message_loop_type == MessageLoop::TYPE_UI)); | 79 (options.message_loop_type == MessageLoop::TYPE_UI)); |
| 80 #endif | 80 #endif |
| 81 | 81 |
| 82 // Reset |id_| here to support restarting the thread. | 82 // Reset |id_| here to support restarting the thread. |
| 83 id_event_.Reset(); | 83 id_event_.Reset(); |
| 84 id_ = kInvalidThreadId; | 84 id_ = kInvalidThreadId; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 110 | 110 |
| 111 // The ownership of |message_loop_| is managed by the newly created thread | 111 // The ownership of |message_loop_| is managed by the newly created thread |
| 112 // within the ThreadMain. | 112 // within the ThreadMain. |
| 113 ignore_result(message_loop_owned.release()); | 113 ignore_result(message_loop_owned.release()); |
| 114 | 114 |
| 115 DCHECK(message_loop_); | 115 DCHECK(message_loop_); |
| 116 return true; | 116 return true; |
| 117 } | 117 } |
| 118 | 118 |
| 119 bool Thread::StartAndWaitForTesting() { | 119 bool Thread::StartAndWaitForTesting() { |
| 120 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 120 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 121 bool result = Start(); | 121 bool result = Start(); |
| 122 if (!result) | 122 if (!result) |
| 123 return false; | 123 return false; |
| 124 WaitUntilThreadStarted(); | 124 WaitUntilThreadStarted(); |
| 125 return true; | 125 return true; |
| 126 } | 126 } |
| 127 | 127 |
| 128 bool Thread::WaitUntilThreadStarted() const { | 128 bool Thread::WaitUntilThreadStarted() const { |
| 129 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 129 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 130 if (!message_loop_) | 130 if (!message_loop_) |
| 131 return false; | 131 return false; |
| 132 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 132 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 133 start_event_.Wait(); | 133 start_event_.Wait(); |
| 134 return true; | 134 return true; |
| 135 } | 135 } |
| 136 | 136 |
| 137 void Thread::Stop() { | 137 void Thread::Stop() { |
| 138 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and | 138 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and |
| 139 // enable this check, until then synchronization with Start() via | 139 // enable this check, until then synchronization with Start() via |
| 140 // |thread_lock_| is required... | 140 // |thread_lock_| is required... |
| 141 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 141 // DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 142 AutoLock lock(thread_lock_); | 142 AutoLock lock(thread_lock_); |
| 143 | 143 |
| 144 if (thread_.is_null()) | 144 if (thread_.is_null()) |
| 145 return; | 145 return; |
| 146 | 146 |
| 147 StopSoon(); | 147 StopSoon(); |
| 148 | 148 |
| 149 // Wait for the thread to exit. | 149 // Wait for the thread to exit. |
| 150 // | 150 // |
| 151 // TODO(darin): Unfortunately, we need to keep |message_loop_| around until | 151 // TODO(darin): Unfortunately, we need to keep |message_loop_| around until |
| 152 // the thread exits. Some consumers are abusing the API. Make them stop. | 152 // the thread exits. Some consumers are abusing the API. Make them stop. |
| 153 // | 153 // |
| 154 PlatformThread::Join(thread_); | 154 PlatformThread::Join(thread_); |
| 155 thread_ = base::PlatformThreadHandle(); | 155 thread_ = base::PlatformThreadHandle(); |
| 156 | 156 |
| 157 // The thread should nullify |message_loop_| on exit (note: Join() adds an | 157 // The thread should nullify |message_loop_| on exit (note: Join() adds an |
| 158 // implicit memory barrier and no lock is thus required for this check). | 158 // implicit memory barrier and no lock is thus required for this check). |
| 159 DCHECK(!message_loop_); | 159 DCHECK(!message_loop_); |
| 160 | 160 |
| 161 stopping_ = false; | 161 stopping_ = false; |
| 162 } | 162 } |
| 163 | 163 |
| 164 void Thread::StopSoon() { | 164 void Thread::StopSoon() { |
| 165 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and | 165 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and |
| 166 // enable this check. | 166 // enable this check. |
| 167 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 167 // DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 168 | 168 |
| 169 if (stopping_ || !message_loop_) | 169 if (stopping_ || !message_loop_) |
| 170 return; | 170 return; |
| 171 | 171 |
| 172 stopping_ = true; | 172 stopping_ = true; |
| 173 task_runner()->PostTask( | 173 task_runner()->PostTask( |
| 174 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this))); | 174 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this))); |
| 175 } | 175 } |
| 176 | 176 |
| 177 PlatformThreadId Thread::GetThreadId() const { | 177 PlatformThreadId Thread::GetThreadId() const { |
| 178 // If the thread is created but not started yet, wait for |id_| being ready. | 178 // If the thread is created but not started yet, wait for |id_| being ready. |
| 179 base::ThreadRestrictions::ScopedAllowWait allow_wait; | 179 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 180 id_event_.Wait(); | 180 id_event_.Wait(); |
| 181 return id_; | 181 return id_; |
| 182 } | 182 } |
| 183 | 183 |
| 184 bool Thread::IsRunning() const { | 184 bool Thread::IsRunning() const { |
| 185 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and | 185 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and |
| 186 // enable this check. | 186 // enable this check. |
| 187 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); | 187 // DCHECK(owning_sequence_checker_.CalledOnValidSequence()); |
| 188 | 188 |
| 189 // If the thread's already started (i.e. |message_loop_| is non-null) and not | 189 // If the thread's already started (i.e. |message_loop_| is non-null) and not |
| 190 // yet requested to stop (i.e. |stopping_| is false) we can just return true. | 190 // yet requested to stop (i.e. |stopping_| is false) we can just return true. |
| 191 // (Note that |stopping_| is touched only on the same sequence that starts / | 191 // (Note that |stopping_| is touched only on the same sequence that starts / |
| 192 // started the new thread so we need no locking here.) | 192 // started the new thread so we need no locking here.) |
| 193 if (message_loop_ && !stopping_) | 193 if (message_loop_ && !stopping_) |
| 194 return true; | 194 return true; |
| 195 // Otherwise check the |running_| flag, which is set to true by the new thread | 195 // Otherwise check the |running_| flag, which is set to true by the new thread |
| 196 // only while it is inside Run(). | 196 // only while it is inside Run(). |
| 197 AutoLock lock(running_lock_); | 197 AutoLock lock(running_lock_); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 run_loop_ = nullptr; | 284 run_loop_ = nullptr; |
| 285 } | 285 } |
| 286 | 286 |
| 287 void Thread::ThreadQuitHelper() { | 287 void Thread::ThreadQuitHelper() { |
| 288 DCHECK(run_loop_); | 288 DCHECK(run_loop_); |
| 289 run_loop_->QuitWhenIdle(); | 289 run_loop_->QuitWhenIdle(); |
| 290 SetThreadWasQuitProperly(true); | 290 SetThreadWasQuitProperly(true); |
| 291 } | 291 } |
| 292 | 292 |
| 293 } // namespace base | 293 } // namespace base |
| OLD | NEW |