| 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) |
| 461 // Note that these methods have a separate implementation for mac and ios |
| 462 // defined in webrtc/base/thread_darwin.mm. |
| 481 bool Thread::ProcessMessages(int cmsLoop) { | 463 bool Thread::ProcessMessages(int cmsLoop) { |
| 482 int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); | 464 int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); |
| 483 int cmsNext = cmsLoop; | 465 int cmsNext = cmsLoop; |
| 484 | 466 |
| 485 while (true) { | 467 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; | 468 Message msg; |
| 494 if (!Get(&msg, cmsNext)) | 469 if (!Get(&msg, cmsNext)) |
| 495 return !IsQuitting(); | 470 return !IsQuitting(); |
| 496 Dispatch(&msg); | 471 Dispatch(&msg); |
| 497 | 472 |
| 498 if (cmsLoop != kForever) { | 473 if (cmsLoop != kForever) { |
| 499 cmsNext = static_cast<int>(TimeUntil(msEnd)); | 474 cmsNext = static_cast<int>(TimeUntil(msEnd)); |
| 500 if (cmsNext < 0) | 475 if (cmsNext < 0) |
| 501 return true; | 476 return true; |
| 502 } | 477 } |
| 503 } | 478 } |
| 504 } | 479 } |
| 480 #endif |
| 505 | 481 |
| 506 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, | 482 bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, |
| 507 bool need_synchronize_access) { | 483 bool need_synchronize_access) { |
| 508 if (running()) | 484 if (running()) |
| 509 return false; | 485 return false; |
| 510 | 486 |
| 511 #if defined(WEBRTC_WIN) | 487 #if defined(WEBRTC_WIN) |
| 512 if (need_synchronize_access) { | 488 if (need_synchronize_access) { |
| 513 // We explicitly ask for no rights other than synchronization. | 489 // We explicitly ask for no rights other than synchronization. |
| 514 // This gives us the best chance of succeeding. | 490 // 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)) { | 529 if (SUCCEEDED(hr)) { |
| 554 Thread::Run(); | 530 Thread::Run(); |
| 555 CoUninitialize(); | 531 CoUninitialize(); |
| 556 } else { | 532 } else { |
| 557 LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr; | 533 LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr; |
| 558 } | 534 } |
| 559 } | 535 } |
| 560 #endif | 536 #endif |
| 561 | 537 |
| 562 } // namespace rtc | 538 } // namespace rtc |
| OLD | NEW |