OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/base/thread.h" | 11 #include "webrtc/base/thread.h" |
12 | 12 |
13 #if defined(WEBRTC_WIN) | 13 #if defined(WEBRTC_WIN) |
14 #include <comdef.h> | 14 #include <comdef.h> |
15 #elif defined(WEBRTC_POSIX) | 15 #elif defined(WEBRTC_POSIX) |
16 #include <time.h> | 16 #include <time.h> |
17 #endif | 17 #endif |
18 | 18 |
19 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
20 #include "webrtc/base/logging.h" | 20 #include "webrtc/base/logging.h" |
21 #include "webrtc/base/nullsocketserver.h" | 21 #include "webrtc/base/nullsocketserver.h" |
22 #include "webrtc/base/platform_thread.h" | 22 #include "webrtc/base/platform_thread.h" |
23 #include "webrtc/base/stringutils.h" | 23 #include "webrtc/base/stringutils.h" |
24 #include "webrtc/base/timeutils.h" | 24 #include "webrtc/base/timeutils.h" |
25 #include "webrtc/base/trace_event.h" | 25 #include "webrtc/base/trace_event.h" |
26 | 26 |
27 #if defined(WEBRTC_MAC) | |
28 #include "webrtc/base/maccocoathreadhelper.h" | |
29 #include "webrtc/base/scoped_autorelease_pool.h" | |
30 #endif | |
31 | |
32 namespace rtc { | 27 namespace rtc { |
33 | 28 |
34 ThreadManager* ThreadManager::Instance() { | 29 ThreadManager* ThreadManager::Instance() { |
35 RTC_DEFINE_STATIC_LOCAL(ThreadManager, thread_manager, ()); | 30 RTC_DEFINE_STATIC_LOCAL(ThreadManager, thread_manager, ()); |
36 return &thread_manager; | 31 return &thread_manager; |
37 } | 32 } |
38 | 33 |
39 // static | 34 // static |
40 Thread* Thread::Current() { | 35 Thread* Thread::Current() { |
41 return ThreadManager::Instance()->CurrentThread(); | 36 return ThreadManager::Instance()->CurrentThread(); |
42 } | 37 } |
43 | 38 |
44 #if defined(WEBRTC_POSIX) | 39 #if defined(WEBRTC_POSIX) |
| 40 #if !defined(WEBRTC_MAC) |
45 ThreadManager::ThreadManager() { | 41 ThreadManager::ThreadManager() { |
46 pthread_key_create(&key_, nullptr); | 42 pthread_key_create(&key_, nullptr); |
47 #ifndef NO_MAIN_THREAD_WRAPPING | 43 #ifndef NO_MAIN_THREAD_WRAPPING |
48 WrapCurrentThread(); | 44 WrapCurrentThread(); |
49 #endif | 45 #endif |
50 #if defined(WEBRTC_MAC) | |
51 // This is necessary to alert the cocoa runtime of the fact that | |
52 // we are running in a multithreaded environment. | |
53 InitCocoaMultiThreading(); | |
54 #endif | |
55 } | 46 } |
56 | 47 |
57 ThreadManager::~ThreadManager() { | 48 ThreadManager::~ThreadManager() { |
58 #if defined(WEBRTC_MAC) | |
59 // This is called during exit, at which point apparently no NSAutoreleasePools | |
60 // are available; but we might still need them to do cleanup (or we get the | |
61 // "no autoreleasepool in place, just leaking" warning when exiting). | |
62 ScopedAutoreleasePool pool; | |
63 #endif | |
64 UnwrapCurrentThread(); | 49 UnwrapCurrentThread(); |
65 pthread_key_delete(key_); | 50 pthread_key_delete(key_); |
66 } | 51 } |
| 52 #endif |
67 | 53 |
68 Thread *ThreadManager::CurrentThread() { | 54 Thread *ThreadManager::CurrentThread() { |
69 return static_cast<Thread *>(pthread_getspecific(key_)); | 55 return static_cast<Thread *>(pthread_getspecific(key_)); |
70 } | 56 } |
71 | 57 |
72 void ThreadManager::SetCurrentThread(Thread *thread) { | 58 void ThreadManager::SetCurrentThread(Thread *thread) { |
73 pthread_setspecific(key_, thread); | 59 pthread_setspecific(key_, thread); |
74 } | 60 } |
75 #endif | 61 #endif |
76 | 62 |
(...skipping 29 matching lines...) Expand all Loading... |
106 } | 92 } |
107 | 93 |
108 void ThreadManager::UnwrapCurrentThread() { | 94 void ThreadManager::UnwrapCurrentThread() { |
109 Thread* t = CurrentThread(); | 95 Thread* t = CurrentThread(); |
110 if (t && !(t->IsOwned())) { | 96 if (t && !(t->IsOwned())) { |
111 t->UnwrapCurrent(); | 97 t->UnwrapCurrent(); |
112 delete t; | 98 delete t; |
113 } | 99 } |
114 } | 100 } |
115 | 101 |
116 struct ThreadInit { | |
117 Thread* thread; | |
118 Runnable* runnable; | |
119 }; | |
120 | |
121 Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls() | 102 Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls() |
122 : thread_(Thread::Current()), | 103 : thread_(Thread::Current()), |
123 previous_state_(thread_->SetAllowBlockingCalls(false)) { | 104 previous_state_(thread_->SetAllowBlockingCalls(false)) { |
124 } | 105 } |
125 | 106 |
126 Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() { | 107 Thread::ScopedDisallowBlockingCalls::~ScopedDisallowBlockingCalls() { |
127 RTC_DCHECK(thread_->IsCurrent()); | 108 RTC_DCHECK(thread_->IsCurrent()); |
128 thread_->SetAllowBlockingCalls(previous_state_); | 109 thread_->SetAllowBlockingCalls(previous_state_); |
129 } | 110 } |
130 | 111 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 | 272 |
292 // static | 273 // static |
293 void Thread::AssertBlockingIsAllowedOnCurrentThread() { | 274 void Thread::AssertBlockingIsAllowedOnCurrentThread() { |
294 #if !defined(NDEBUG) | 275 #if !defined(NDEBUG) |
295 Thread* current = Thread::Current(); | 276 Thread* current = Thread::Current(); |
296 RTC_DCHECK(!current || current->blocking_calls_allowed_); | 277 RTC_DCHECK(!current || current->blocking_calls_allowed_); |
297 #endif | 278 #endif |
298 } | 279 } |
299 | 280 |
300 // static | 281 // static |
| 282 #if !defined(WEBRTC_MAC) |
301 #if defined(WEBRTC_WIN) | 283 #if defined(WEBRTC_WIN) |
302 DWORD WINAPI Thread::PreRun(LPVOID pv) { | 284 DWORD WINAPI Thread::PreRun(LPVOID pv) { |
303 #else | 285 #else |
304 void* Thread::PreRun(void* pv) { | 286 void* Thread::PreRun(void* pv) { |
305 #endif | 287 #endif |
306 ThreadInit* init = static_cast<ThreadInit*>(pv); | 288 ThreadInit* init = static_cast<ThreadInit*>(pv); |
307 ThreadManager::Instance()->SetCurrentThread(init->thread); | 289 ThreadManager::Instance()->SetCurrentThread(init->thread); |
308 rtc::SetCurrentThreadName(init->thread->name_.c_str()); | 290 rtc::SetCurrentThreadName(init->thread->name_.c_str()); |
309 #if defined(WEBRTC_MAC) | |
310 // Make sure the new thread has an autoreleasepool | |
311 ScopedAutoreleasePool pool; | |
312 #endif | |
313 if (init->runnable) { | 291 if (init->runnable) { |
314 init->runnable->Run(init->thread); | 292 init->runnable->Run(init->thread); |
315 } else { | 293 } else { |
316 init->thread->Run(); | 294 init->thread->Run(); |
317 } | 295 } |
318 delete init; | 296 delete init; |
319 #ifdef WEBRTC_WIN | 297 #ifdef WEBRTC_WIN |
320 return 0; | 298 return 0; |
321 #else | 299 #else |
322 return nullptr; | 300 return nullptr; |
323 #endif | 301 #endif |
324 } | 302 } |
| 303 #endif |
325 | 304 |
326 void Thread::Run() { | 305 void Thread::Run() { |
327 ProcessMessages(kForever); | 306 ProcessMessages(kForever); |
328 } | 307 } |
329 | 308 |
330 bool Thread::IsOwned() { | 309 bool Thread::IsOwned() { |
331 return owned_; | 310 return owned_; |
332 } | 311 } |
333 | 312 |
334 void Thread::Stop() { | 313 void Thread::Stop() { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 *smsg.ready = true; | 450 *smsg.ready = true; |
472 smsg.thread->socketserver()->WakeUp(); | 451 smsg.thread->socketserver()->WakeUp(); |
473 continue; | 452 continue; |
474 } | 453 } |
475 ++iter; | 454 ++iter; |
476 } | 455 } |
477 | 456 |
478 MessageQueue::Clear(phandler, id, removed); | 457 MessageQueue::Clear(phandler, id, removed); |
479 } | 458 } |
480 | 459 |
| 460 #if !defined(WEBRTC_MAC) |
481 bool Thread::ProcessMessages(int cmsLoop) { | 461 bool Thread::ProcessMessages(int cmsLoop) { |
482 int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); | 462 int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); |
483 int cmsNext = cmsLoop; | 463 int cmsNext = cmsLoop; |
484 | 464 |
485 while (true) { | 465 while (true) { |
486 #if defined(WEBRTC_MAC) | |
487 // see: http://developer.apple.com/library/mac/#documentation/Cocoa/Referenc
e/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html | |
488 // Each thread is supposed to have an autorelease pool. Also for event loops | |
489 // like this, autorelease pool needs to be created and drained/released | |
490 // for each cycle. | |
491 ScopedAutoreleasePool pool; | |
492 #endif | |
493 Message msg; | 466 Message msg; |
494 if (!Get(&msg, cmsNext)) | 467 if (!Get(&msg, cmsNext)) |
495 return !IsQuitting(); | 468 return !IsQuitting(); |
496 Dispatch(&msg); | 469 Dispatch(&msg); |
497 | 470 |
498 if (cmsLoop != kForever) { | 471 if (cmsLoop != kForever) { |
499 cmsNext = static_cast<int>(TimeUntil(msEnd)); | 472 cmsNext = static_cast<int>(TimeUntil(msEnd)); |
500 if (cmsNext < 0) | 473 if (cmsNext < 0) |
501 return true; | 474 return true; |
502 } | 475 } |
503 } | 476 } |
504 } | 477 } |
| 478 #endif |
505 | 479 |
506 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, | 480 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, |
507 bool need_synchronize_access) { | 481 bool need_synchronize_access) { |
508 if (running()) | 482 if (running()) |
509 return false; | 483 return false; |
510 | 484 |
511 #if defined(WEBRTC_WIN) | 485 #if defined(WEBRTC_WIN) |
512 if (need_synchronize_access) { | 486 if (need_synchronize_access) { |
513 // We explicitly ask for no rights other than synchronization. | 487 // We explicitly ask for no rights other than synchronization. |
514 // This gives us the best chance of succeeding. | 488 // This gives us the best chance of succeeding. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
553 if (SUCCEEDED(hr)) { | 527 if (SUCCEEDED(hr)) { |
554 Thread::Run(); | 528 Thread::Run(); |
555 CoUninitialize(); | 529 CoUninitialize(); |
556 } else { | 530 } else { |
557 LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr; | 531 LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr; |
558 } | 532 } |
559 } | 533 } |
560 #endif | 534 #endif |
561 | 535 |
562 } // namespace rtc | 536 } // namespace rtc |
OLD | NEW |