From 61abe1582915fb25fe3f231d7d2c9a174c0e3e6b Mon Sep 17 00:00:00 2001 From: kthelgason Date: Wed, 29 Mar 2017 02:32:36 -0700 Subject: [PATCH] Add Darwin thread.h implementation. Due to quirks of the Cocoa runtime several platform-specific fixes were in place. See the deleted files maccocoathreadhelper and scoped_autorelease_pool for examples. There is no way to do a stack-based RAII autoreleasepool that is compatible with ARC, and autoreleasepool blocks can't be used with c++. The solution was to separate out the implementation of some methods in thread.h to an ObjC++ file for Darwin platforms, allowing us to get rid of the helper classes and enable ARC everywhere. BUG=webrtc:6412 Review-Url: https://codereview.webrtc.org/2784483002 Cr-Commit-Position: refs/heads/master@{#17436} --- webrtc/BUILD.gn | 1 - webrtc/base/BUILD.gn | 5 +- webrtc/base/maccocoathreadhelper.h | 27 -------- webrtc/base/maccocoathreadhelper.mm | 41 ------------ webrtc/base/scoped_autorelease_pool.h | 59 ---------------- webrtc/base/scoped_autorelease_pool.mm | 25 ------- webrtc/base/thread.cc | 40 +++-------- webrtc/base/thread.h | 5 ++ webrtc/base/thread_darwin.mm | 93 ++++++++++++++++++++++++++ 9 files changed, 107 insertions(+), 189 deletions(-) delete mode 100644 webrtc/base/maccocoathreadhelper.h delete mode 100644 webrtc/base/maccocoathreadhelper.mm delete mode 100644 webrtc/base/scoped_autorelease_pool.h delete mode 100644 webrtc/base/scoped_autorelease_pool.mm create mode 100644 webrtc/base/thread_darwin.mm diff --git a/webrtc/BUILD.gn b/webrtc/BUILD.gn index 5ac31323b0..a10b953cd7 100644 --- a/webrtc/BUILD.gn +++ b/webrtc/BUILD.gn @@ -33,7 +33,6 @@ config("common_inherited_config") { "FEATURE_ENABLE_VOICEMAIL", "EXPAT_RELATIVE_PATH", "GTEST_RELATIVE_PATH", - "NO_MAIN_THREAD_WRAPPING", "NO_SOUND_SYSTEM", "WEBRTC_CHROMIUM_BUILD", ] diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn index 7514b07c8d..3d0a3f42f1 100644 --- a/webrtc/base/BUILD.gn +++ b/webrtc/base/BUILD.gn @@ -544,11 +544,8 @@ rtc_static_library("rtc_base") { if (is_ios || is_mac) { sources += [ - "maccocoathreadhelper.h", - "maccocoathreadhelper.mm", "macifaddrs_converter.cc", - "scoped_autorelease_pool.h", - "scoped_autorelease_pool.mm", + "thread_darwin.mm", ] } diff --git a/webrtc/base/maccocoathreadhelper.h b/webrtc/base/maccocoathreadhelper.h deleted file mode 100644 index 255d081cec..0000000000 --- a/webrtc/base/maccocoathreadhelper.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2008 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Helper function for using Cocoa with Posix threads. This header should be -// included from C/C++ files that want to use some Cocoa functionality without -// using the .mm extension (mostly for files that are compiled on multiple -// platforms). - -#ifndef WEBRTC_BASE_MACCOCOATHREADHELPER_H__ -#define WEBRTC_BASE_MACCOCOATHREADHELPER_H__ - -namespace rtc { - -// Cocoa must be "put into multithreading mode" before Cocoa functionality can -// be used on POSIX threads. This function does that. -void InitCocoaMultiThreading(); - -} // namespace rtc - -#endif // WEBRTC_BASE_MACCOCOATHREADHELPER_H__ diff --git a/webrtc/base/maccocoathreadhelper.mm b/webrtc/base/maccocoathreadhelper.mm deleted file mode 100644 index 70d920de39..0000000000 --- a/webrtc/base/maccocoathreadhelper.mm +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2007 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ -// Helper function for using Cocoa with Posix threading. - -#import - -#import "webrtc/base/maccocoathreadhelper.h" - -#include "webrtc/base/checks.h" - -namespace rtc { - -// Cocoa must be "put into multithreading mode" before Cocoa functionality can -// be used on POSIX threads. The way to do that is to spawn one thread that may -// immediately exit. -void InitCocoaMultiThreading() { - if ([NSThread isMultiThreaded] == NO) { - // The sole purpose of this autorelease pool is to avoid a console - // message on Leopard that tells us we're autoreleasing the thread - // with no autorelease pool in place. - // Doing NSAutoreleasePool* hack = [[NSAutoreleasePool alloc] init]; - // causes unused variable error. - NSAutoreleasePool* hack; - hack = [[NSAutoreleasePool alloc] init]; - [NSThread detachNewThreadSelector:@selector(class) - toTarget:[NSObject class] - withObject:nil]; - [hack drain]; - } - - RTC_DCHECK([NSThread isMultiThreaded]); -} - -} // namespace rtc diff --git a/webrtc/base/scoped_autorelease_pool.h b/webrtc/base/scoped_autorelease_pool.h deleted file mode 100644 index 2e0a2042db..0000000000 --- a/webrtc/base/scoped_autorelease_pool.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2008 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Automatically initialize and and free an autoreleasepool. Never allocate -// an instance of this class using "new" - that will result in a compile-time -// error. Only use it as a stack object. -// -// Note: NSAutoreleasePool docs say that you should not normally need to -// declare an NSAutoreleasePool as a member of an object - but there's nothing -// that indicates it will be a problem, as long as the stack lifetime of the -// pool exactly matches the stack lifetime of the object. - -#ifndef WEBRTC_BASE_SCOPED_AUTORELEASE_POOL_H__ -#define WEBRTC_BASE_SCOPED_AUTORELEASE_POOL_H__ - -#if defined(WEBRTC_MAC) - -#include "webrtc/base/constructormagic.h" - -// This header may be included from Obj-C files or C++ files. -#ifdef __OBJC__ -@class NSAutoreleasePool; -#else -class NSAutoreleasePool; -#endif - -namespace rtc { - -class ScopedAutoreleasePool { - public: - ScopedAutoreleasePool(); - ~ScopedAutoreleasePool(); - - private: - // Declaring private overrides of new and delete here enforces the "only use - // as a stack object" discipline. - // - // Note: new is declared as "throw()" to get around a gcc warning about new - // returning null, but this method will never get called and therefore will - // never actually throw any exception. - void* operator new(size_t size) throw() { return nullptr; } - void operator delete (void* ptr) {} - - NSAutoreleasePool* pool_; - - RTC_DISALLOW_COPY_AND_ASSIGN(ScopedAutoreleasePool); -}; - -} // namespace rtc - -#endif // WEBRTC_MAC -#endif // WEBRTC_BASE_SCOPED_AUTORELEASE_POOL_H__ diff --git a/webrtc/base/scoped_autorelease_pool.mm b/webrtc/base/scoped_autorelease_pool.mm deleted file mode 100644 index 4176aad0e9..0000000000 --- a/webrtc/base/scoped_autorelease_pool.mm +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2008 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#import - -#import "webrtc/base/scoped_autorelease_pool.h" - -namespace rtc { - -ScopedAutoreleasePool::ScopedAutoreleasePool() { - pool_ = [[NSAutoreleasePool alloc] init]; -} - -ScopedAutoreleasePool::~ScopedAutoreleasePool() { - [pool_ drain]; -} - -} // namespace rtc diff --git a/webrtc/base/thread.cc b/webrtc/base/thread.cc index a7db4184c5..66542bb3d9 100644 --- a/webrtc/base/thread.cc +++ b/webrtc/base/thread.cc @@ -24,11 +24,6 @@ #include "webrtc/base/timeutils.h" #include "webrtc/base/trace_event.h" -#if defined(WEBRTC_MAC) -#include "webrtc/base/maccocoathreadhelper.h" -#include "webrtc/base/scoped_autorelease_pool.h" -#endif - namespace rtc { ThreadManager* ThreadManager::Instance() { @@ -42,28 +37,19 @@ Thread* Thread::Current() { } #if defined(WEBRTC_POSIX) +#if !defined(WEBRTC_MAC) ThreadManager::ThreadManager() { pthread_key_create(&key_, nullptr); #ifndef NO_MAIN_THREAD_WRAPPING WrapCurrentThread(); #endif -#if defined(WEBRTC_MAC) - // This is necessary to alert the cocoa runtime of the fact that - // we are running in a multithreaded environment. - InitCocoaMultiThreading(); -#endif } ThreadManager::~ThreadManager() { -#if defined(WEBRTC_MAC) - // This is called during exit, at which point apparently no NSAutoreleasePools - // are available; but we might still need them to do cleanup (or we get the - // "no autoreleasepool in place, just leaking" warning when exiting). - ScopedAutoreleasePool pool; -#endif UnwrapCurrentThread(); pthread_key_delete(key_); } +#endif Thread *ThreadManager::CurrentThread() { return static_cast(pthread_getspecific(key_)); @@ -113,11 +99,6 @@ void ThreadManager::UnwrapCurrentThread() { } } -struct ThreadInit { - Thread* thread; - Runnable* runnable; -}; - Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls() : thread_(Thread::Current()), previous_state_(thread_->SetAllowBlockingCalls(false)) { @@ -298,6 +279,7 @@ void Thread::AssertBlockingIsAllowedOnCurrentThread() { } // static +#if !defined(WEBRTC_MAC) #if defined(WEBRTC_WIN) DWORD WINAPI Thread::PreRun(LPVOID pv) { #else @@ -306,10 +288,6 @@ void* Thread::PreRun(void* pv) { ThreadInit* init = static_cast(pv); ThreadManager::Instance()->SetCurrentThread(init->thread); rtc::SetCurrentThreadName(init->thread->name_.c_str()); -#if defined(WEBRTC_MAC) - // Make sure the new thread has an autoreleasepool - ScopedAutoreleasePool pool; -#endif if (init->runnable) { init->runnable->Run(init->thread); } else { @@ -322,6 +300,7 @@ void* Thread::PreRun(void* pv) { return nullptr; #endif } +#endif void Thread::Run() { ProcessMessages(kForever); @@ -478,18 +457,14 @@ void Thread::Clear(MessageHandler* phandler, MessageQueue::Clear(phandler, id, removed); } +#if !defined(WEBRTC_MAC) +// Note that these methods have a separate implementation for mac and ios +// defined in webrtc/base/thread_darwin.mm. bool Thread::ProcessMessages(int cmsLoop) { int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); int cmsNext = cmsLoop; while (true) { -#if defined(WEBRTC_MAC) - // see: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html - // Each thread is supposed to have an autorelease pool. Also for event loops - // like this, autorelease pool needs to be created and drained/released - // for each cycle. - ScopedAutoreleasePool pool; -#endif Message msg; if (!Get(&msg, cmsNext)) return !IsQuitting(); @@ -502,6 +477,7 @@ bool Thread::ProcessMessages(int cmsLoop) { } } } +#endif bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager, bool need_synchronize_access) { diff --git a/webrtc/base/thread.h b/webrtc/base/thread.h index 5751df385c..398063d263 100644 --- a/webrtc/base/thread.h +++ b/webrtc/base/thread.h @@ -238,6 +238,11 @@ class LOCKABLE Thread : public MessageQueue { friend class ScopedDisallowBlockingCalls; private: + struct ThreadInit { + Thread* thread; + Runnable* runnable; + }; + #if defined(WEBRTC_WIN) static DWORD WINAPI PreRun(LPVOID context); #else diff --git a/webrtc/base/thread_darwin.mm b/webrtc/base/thread_darwin.mm new file mode 100644 index 0000000000..5bcc5c8c06 --- /dev/null +++ b/webrtc/base/thread_darwin.mm @@ -0,0 +1,93 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/base/thread.h" + +#import + +#include "webrtc/base/platform_thread.h" + +/* + * This file contains platform-specific implementations for several + * methods in rtc::Thread. + */ + +namespace { +void InitCocoaMultiThreading() { + if ([NSThread isMultiThreaded] == NO) { + // The sole purpose of this autorelease pool is to avoid a console + // message on Leopard that tells us we're autoreleasing the thread + // with no autorelease pool in place. + @autoreleasepool { + [NSThread detachNewThreadSelector:@selector(class) + toTarget:[NSObject class] + withObject:nil]; + } + } + + RTC_DCHECK([NSThread isMultiThreaded]); +} +} + +namespace rtc { + +ThreadManager::ThreadManager() { + pthread_key_create(&key_, nullptr); +#ifndef NO_MAIN_THREAD_WRAPPING + WrapCurrentThread(); +#endif + // This is necessary to alert the cocoa runtime of the fact that + // we are running in a multithreaded environment. + InitCocoaMultiThreading(); +} + +ThreadManager::~ThreadManager() { + @autoreleasepool { + UnwrapCurrentThread(); + pthread_key_delete(key_); + } +} + +// static +void* Thread::PreRun(void* pv) { + ThreadInit* init = static_cast(pv); + ThreadManager::Instance()->SetCurrentThread(init->thread); + rtc::SetCurrentThreadName(init->thread->name_.c_str()); + @autoreleasepool { + if (init->runnable) { + init->runnable->Run(init->thread); + } else { + init->thread->Run(); + } + } + delete init; + return nullptr; +} + +bool Thread::ProcessMessages(int cmsLoop) { + int64_t msEnd = (kForever == cmsLoop) ? 0 : TimeAfter(cmsLoop); + int cmsNext = cmsLoop; + + while (true) { + @autoreleasepool { + Message msg; + if (!Get(&msg, cmsNext)) + return !IsQuitting(); + Dispatch(&msg); + + if (cmsLoop != kForever) { + cmsNext = static_cast(TimeUntil(msEnd)); + if (cmsNext < 0) + return true; + } + } + } +} +} // namespace rtc