blob: 4197d28175a05037f5ad953aba64d6b72ae62bef [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/thread.h"
12
13#ifndef __has_feature
14#define __has_feature(x) 0 // Compatibility with non-clang or LLVM compilers.
15#endif // __has_feature
16
17#if defined(WEBRTC_WIN)
18#include <comdef.h>
19#elif defined(WEBRTC_POSIX)
20#include <time.h>
21#endif
22
23#include "webrtc/base/common.h"
24#include "webrtc/base/logging.h"
Tommiea14f0a2015-05-18 13:51:06 +020025#include "webrtc/base/platform_thread.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026#include "webrtc/base/stringutils.h"
27#include "webrtc/base/timeutils.h"
28
29#if !__has_feature(objc_arc) && (defined(WEBRTC_MAC))
30#include "webrtc/base/maccocoathreadhelper.h"
31#include "webrtc/base/scoped_autorelease_pool.h"
32#endif
33
tommi@webrtc.org7c64ed22015-03-17 14:25:37 +000034#include "webrtc/base/trace_event.h"
35
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036namespace rtc {
37
38ThreadManager* ThreadManager::Instance() {
Andrew MacDonald469c2c02015-05-22 17:50:26 -070039 RTC_DEFINE_STATIC_LOCAL(ThreadManager, thread_manager, ());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040 return &thread_manager;
41}
42
43// static
44Thread* Thread::Current() {
45 return ThreadManager::Instance()->CurrentThread();
46}
47
48#if defined(WEBRTC_POSIX)
49ThreadManager::ThreadManager() {
50 pthread_key_create(&key_, NULL);
51#ifndef NO_MAIN_THREAD_WRAPPING
52 WrapCurrentThread();
53#endif
54#if !__has_feature(objc_arc) && (defined(WEBRTC_MAC))
55 // Under Automatic Reference Counting (ARC), you cannot use autorelease pools
56 // directly. Instead, you use @autoreleasepool blocks instead. Also, we are
57 // maintaining thread safety using immutability within context of GCD dispatch
58 // queues in this case.
59 InitCocoaMultiThreading();
60#endif
61}
62
63ThreadManager::~ThreadManager() {
64#if __has_feature(objc_arc)
65 @autoreleasepool
66#elif defined(WEBRTC_MAC)
67 // This is called during exit, at which point apparently no NSAutoreleasePools
68 // are available; but we might still need them to do cleanup (or we get the
69 // "no autoreleasepool in place, just leaking" warning when exiting).
70 ScopedAutoreleasePool pool;
71#endif
72 {
73 UnwrapCurrentThread();
74 pthread_key_delete(key_);
75 }
76}
77
78Thread *ThreadManager::CurrentThread() {
79 return static_cast<Thread *>(pthread_getspecific(key_));
80}
81
82void ThreadManager::SetCurrentThread(Thread *thread) {
83 pthread_setspecific(key_, thread);
84}
85#endif
86
87#if defined(WEBRTC_WIN)
88ThreadManager::ThreadManager() {
89 key_ = TlsAlloc();
90#ifndef NO_MAIN_THREAD_WRAPPING
91 WrapCurrentThread();
92#endif
93}
94
95ThreadManager::~ThreadManager() {
96 UnwrapCurrentThread();
97 TlsFree(key_);
98}
99
100Thread *ThreadManager::CurrentThread() {
101 return static_cast<Thread *>(TlsGetValue(key_));
102}
103
104void ThreadManager::SetCurrentThread(Thread *thread) {
105 TlsSetValue(key_, thread);
106}
107#endif
108
109Thread *ThreadManager::WrapCurrentThread() {
110 Thread* result = CurrentThread();
111 if (NULL == result) {
112 result = new Thread();
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000113 result->WrapCurrentWithThreadManager(this, true);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000114 }
115 return result;
116}
117
118void ThreadManager::UnwrapCurrentThread() {
119 Thread* t = CurrentThread();
120 if (t && !(t->IsOwned())) {
121 t->UnwrapCurrent();
122 delete t;
123 }
124}
125
126struct ThreadInit {
127 Thread* thread;
128 Runnable* runnable;
129};
130
henrike@webrtc.org92a9bac2014-07-14 22:03:57 +0000131Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
132 : thread_(Thread::Current()),
133 previous_state_(thread_->SetAllowBlockingCalls(false)) {
134}
135
136Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() {
137 ASSERT(thread_->IsCurrent());
138 thread_->SetAllowBlockingCalls(previous_state_);
139}
140
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141Thread::Thread(SocketServer* ss)
142 : MessageQueue(ss),
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000143 running_(true, false),
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144#if defined(WEBRTC_WIN)
145 thread_(NULL),
146 thread_id_(0),
147#endif
henrike@webrtc.org92a9bac2014-07-14 22:03:57 +0000148 owned_(true),
149 blocking_calls_allowed_(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150 SetName("Thread", this); // default name
151}
152
153Thread::~Thread() {
154 Stop();
henrike@webrtc.org99b41622014-05-21 20:42:17 +0000155 Clear(NULL);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156}
157
158bool Thread::SleepMs(int milliseconds) {
henrike@webrtc.org92a9bac2014-07-14 22:03:57 +0000159 AssertBlockingIsAllowedOnCurrentThread();
160
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161#if defined(WEBRTC_WIN)
162 ::Sleep(milliseconds);
163 return true;
164#else
165 // POSIX has both a usleep() and a nanosleep(), but the former is deprecated,
166 // so we use nanosleep() even though it has greater precision than necessary.
167 struct timespec ts;
168 ts.tv_sec = milliseconds / 1000;
169 ts.tv_nsec = (milliseconds % 1000) * 1000000;
170 int ret = nanosleep(&ts, NULL);
171 if (ret != 0) {
172 LOG_ERR(LS_WARNING) << "nanosleep() returning early";
173 return false;
174 }
175 return true;
176#endif
177}
178
179bool Thread::SetName(const std::string& name, const void* obj) {
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000180 if (running()) return false;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000181 name_ = name;
182 if (obj) {
183 char buf[16];
184 sprintfn(buf, sizeof(buf), " 0x%p", obj);
185 name_ += buf;
186 }
187 return true;
188}
189
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000190bool Thread::Start(Runnable* runnable) {
191 ASSERT(owned_);
192 if (!owned_) return false;
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000193 ASSERT(!running());
194 if (running()) return false;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000195
196 Restart(); // reset fStop_ if the thread is being restarted
197
198 // Make sure that ThreadManager is created on the main thread before
199 // we start a new thread.
200 ThreadManager::Instance();
201
202 ThreadInit* init = new ThreadInit;
203 init->thread = this;
204 init->runnable = runnable;
205#if defined(WEBRTC_WIN)
Peter Boström8c38e8b2015-11-26 17:45:47 +0100206 thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreRun, init, 0,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207 &thread_id_);
208 if (thread_) {
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000209 running_.Set();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210 } else {
211 return false;
212 }
213#elif defined(WEBRTC_POSIX)
214 pthread_attr_t attr;
215 pthread_attr_init(&attr);
216
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217 int error_code = pthread_create(&thread_, &attr, PreRun, init);
218 if (0 != error_code) {
219 LOG(LS_ERROR) << "Unable to create pthread, error " << error_code;
220 return false;
221 }
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000222 running_.Set();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223#endif
224 return true;
225}
226
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000227bool Thread::WrapCurrent() {
228 return WrapCurrentWithThreadManager(ThreadManager::Instance(), true);
229}
230
231void Thread::UnwrapCurrent() {
232 // Clears the platform-specific thread-specific storage.
233 ThreadManager::Instance()->SetCurrentThread(NULL);
234#if defined(WEBRTC_WIN)
235 if (thread_ != NULL) {
236 if (!CloseHandle(thread_)) {
237 LOG_GLE(LS_ERROR) << "When unwrapping thread, failed to close handle.";
238 }
239 thread_ = NULL;
240 }
241#endif
242 running_.Reset();
243}
244
245void Thread::SafeWrapCurrent() {
246 WrapCurrentWithThreadManager(ThreadManager::Instance(), false);
247}
248
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000249void Thread::Join() {
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000250 if (running()) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000251 ASSERT(!IsCurrent());
jiayl@webrtc.org1fd362c2014-09-26 16:57:07 +0000252 if (Current() && !Current()->blocking_calls_allowed_) {
253 LOG(LS_WARNING) << "Waiting for the thread to join, "
254 << "but blocking calls have been disallowed";
255 }
256
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000257#if defined(WEBRTC_WIN)
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000258 ASSERT(thread_ != NULL);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000259 WaitForSingleObject(thread_, INFINITE);
260 CloseHandle(thread_);
261 thread_ = NULL;
262 thread_id_ = 0;
263#elif defined(WEBRTC_POSIX)
264 void *pv;
265 pthread_join(thread_, &pv);
266#endif
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000267 running_.Reset();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000268 }
269}
270
henrike@webrtc.org92a9bac2014-07-14 22:03:57 +0000271bool Thread::SetAllowBlockingCalls(bool allow) {
272 ASSERT(IsCurrent());
273 bool previous = blocking_calls_allowed_;
274 blocking_calls_allowed_ = allow;
275 return previous;
276}
277
278// static
279void Thread::AssertBlockingIsAllowedOnCurrentThread() {
tfarinaa41ab932015-10-30 16:08:48 -0700280#if !defined(NDEBUG)
henrike@webrtc.org92a9bac2014-07-14 22:03:57 +0000281 Thread* current = Thread::Current();
282 ASSERT(!current || current->blocking_calls_allowed_);
283#endif
284}
285
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000286void* Thread::PreRun(void* pv) {
287 ThreadInit* init = static_cast<ThreadInit*>(pv);
288 ThreadManager::Instance()->SetCurrentThread(init->thread);
Tommiea14f0a2015-05-18 13:51:06 +0200289 rtc::SetCurrentThreadName(init->thread->name_.c_str());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000290#if __has_feature(objc_arc)
291 @autoreleasepool
292#elif defined(WEBRTC_MAC)
293 // Make sure the new thread has an autoreleasepool
294 ScopedAutoreleasePool pool;
295#endif
296 {
297 if (init->runnable) {
298 init->runnable->Run(init->thread);
299 } else {
300 init->thread->Run();
301 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000302 delete init;
303 return NULL;
304 }
305}
306
307void Thread::Run() {
308 ProcessMessages(kForever);
309}
310
311bool Thread::IsOwned() {
312 return owned_;
313}
314
315void Thread::Stop() {
316 MessageQueue::Quit();
317 Join();
318}
319
Peter Boström0c4e06b2015-10-07 12:23:21 +0200320void Thread::Send(MessageHandler* phandler, uint32_t id, MessageData* pdata) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000321 if (fStop_)
322 return;
323
324 // Sent messages are sent to the MessageHandler directly, in the context
325 // of "thread", like Win32 SendMessage. If in the right context,
326 // call the handler directly.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000327 Message msg;
328 msg.phandler = phandler;
329 msg.message_id = id;
330 msg.pdata = pdata;
331 if (IsCurrent()) {
332 phandler->OnMessage(&msg);
333 return;
334 }
335
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000336 AssertBlockingIsAllowedOnCurrentThread();
337
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000338 AutoThread thread;
339 Thread *current_thread = Thread::Current();
340 ASSERT(current_thread != NULL); // AutoThread ensures this
341
342 bool ready = false;
343 {
344 CritScope cs(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000345 _SendMessage smsg;
346 smsg.thread = current_thread;
347 smsg.msg = msg;
348 smsg.ready = &ready;
349 sendlist_.push_back(smsg);
350 }
351
352 // Wait for a reply
353
354 ss_->WakeUp();
355
356 bool waited = false;
357 crit_.Enter();
358 while (!ready) {
359 crit_.Leave();
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000360 // We need to limit "ReceiveSends" to |this| thread to avoid an arbitrary
361 // thread invoking calls on the current thread.
362 current_thread->ReceiveSendsFromThread(this);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000363 current_thread->socketserver()->Wait(kForever, false);
364 waited = true;
365 crit_.Enter();
366 }
367 crit_.Leave();
368
369 // Our Wait loop above may have consumed some WakeUp events for this
370 // MessageQueue, that weren't relevant to this Send. Losing these WakeUps can
371 // cause problems for some SocketServers.
372 //
373 // Concrete example:
374 // Win32SocketServer on thread A calls Send on thread B. While processing the
375 // message, thread B Posts a message to A. We consume the wakeup for that
376 // Post while waiting for the Send to complete, which means that when we exit
377 // this loop, we need to issue another WakeUp, or else the Posted message
378 // won't be processed in a timely manner.
379
380 if (waited) {
381 current_thread->socketserver()->WakeUp();
382 }
383}
384
385void Thread::ReceiveSends() {
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000386 ReceiveSendsFromThread(NULL);
387}
388
389void Thread::ReceiveSendsFromThread(const Thread* source) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000390 // Receive a sent message. Cleanup scenarios:
391 // - thread sending exits: We don't allow this, since thread can exit
392 // only via Join, so Send must complete.
393 // - thread receiving exits: Wakeup/set ready in Thread::Clear()
394 // - object target cleared: Wakeup/set ready in Thread::Clear()
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000395 _SendMessage smsg;
396
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000397 crit_.Enter();
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000398 while (PopSendMessageFromThread(source, &smsg)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000399 crit_.Leave();
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000400
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000401 smsg.msg.phandler->OnMessage(&smsg.msg);
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000402
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000403 crit_.Enter();
404 *smsg.ready = true;
405 smsg.thread->socketserver()->WakeUp();
406 }
407 crit_.Leave();
408}
409
jiayl@webrtc.org3987b6d2014-09-24 17:14:05 +0000410bool Thread::PopSendMessageFromThread(const Thread* source, _SendMessage* msg) {
411 for (std::list<_SendMessage>::iterator it = sendlist_.begin();
412 it != sendlist_.end(); ++it) {
413 if (it->thread == source || source == NULL) {
414 *msg = *it;
415 sendlist_.erase(it);
416 return true;
417 }
418 }
419 return false;
420}
421
tommi@webrtc.org7c64ed22015-03-17 14:25:37 +0000422void Thread::InvokeBegin() {
423 TRACE_EVENT_BEGIN0("webrtc", "Thread::Invoke");
424}
425
426void Thread::InvokeEnd() {
427 TRACE_EVENT_END0("webrtc", "Thread::Invoke");
428}
429
Peter Boström0c4e06b2015-10-07 12:23:21 +0200430void Thread::Clear(MessageHandler* phandler,
431 uint32_t id,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000432 MessageList* removed) {
433 CritScope cs(&crit_);
434
435 // Remove messages on sendlist_ with phandler
436 // Object target cleared: remove from send list, wakeup/set ready
437 // if sender not NULL.
438
439 std::list<_SendMessage>::iterator iter = sendlist_.begin();
440 while (iter != sendlist_.end()) {
441 _SendMessage smsg = *iter;
442 if (smsg.msg.Match(phandler, id)) {
443 if (removed) {
444 removed->push_back(smsg.msg);
445 } else {
446 delete smsg.msg.pdata;
447 }
448 iter = sendlist_.erase(iter);
449 *smsg.ready = true;
450 smsg.thread->socketserver()->WakeUp();
451 continue;
452 }
453 ++iter;
454 }
455
456 MessageQueue::Clear(phandler, id, removed);
457}
458
459bool Thread::ProcessMessages(int cmsLoop) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200460 uint32_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000461 int cmsNext = cmsLoop;
462
463 while (true) {
464#if __has_feature(objc_arc)
465 @autoreleasepool
466#elif defined(WEBRTC_MAC)
467 // see: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html
468 // Each thread is supposed to have an autorelease pool. Also for event loops
469 // like this, autorelease pool needs to be created and drained/released
470 // for each cycle.
471 ScopedAutoreleasePool pool;
472#endif
473 {
474 Message msg;
475 if (!Get(&msg, cmsNext))
476 return !IsQuitting();
477 Dispatch(&msg);
478
479 if (cmsLoop != kForever) {
480 cmsNext = TimeUntil(msEnd);
481 if (cmsNext < 0)
482 return true;
483 }
484 }
485 }
486}
487
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000488bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager,
489 bool need_synchronize_access) {
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000490 if (running())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000491 return false;
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000492
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000493#if defined(WEBRTC_WIN)
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000494 if (need_synchronize_access) {
495 // We explicitly ask for no rights other than synchronization.
496 // This gives us the best chance of succeeding.
497 thread_ = OpenThread(SYNCHRONIZE, FALSE, GetCurrentThreadId());
498 if (!thread_) {
499 LOG_GLE(LS_ERROR) << "Unable to get handle to thread.";
500 return false;
501 }
502 thread_id_ = GetCurrentThreadId();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000503 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000504#elif defined(WEBRTC_POSIX)
505 thread_ = pthread_self();
506#endif
jiayl@webrtc.orgba737cb2014-09-18 16:45:21 +0000507
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000508 owned_ = false;
fischman@webrtc.orge5063b12014-05-23 17:28:50 +0000509 running_.Set();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000510 thread_manager->SetCurrentThread(this);
511 return true;
512}
513
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000514AutoThread::AutoThread(SocketServer* ss) : Thread(ss) {
515 if (!ThreadManager::Instance()->CurrentThread()) {
516 ThreadManager::Instance()->SetCurrentThread(this);
517 }
518}
519
520AutoThread::~AutoThread() {
521 Stop();
522 if (ThreadManager::Instance()->CurrentThread() == this) {
523 ThreadManager::Instance()->SetCurrentThread(NULL);
524 }
525}
526
527#if defined(WEBRTC_WIN)
528void ComThread::Run() {
529 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
530 ASSERT(SUCCEEDED(hr));
531 if (SUCCEEDED(hr)) {
532 Thread::Run();
533 CoUninitialize();
534 } else {
535 LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr;
536 }
537}
538#endif
539
540} // namespace rtc