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}
This commit is contained in:
kthelgason 2017-03-29 02:32:36 -07:00 committed by Commit bot
parent 0f0a849cba
commit 61abe15829
9 changed files with 107 additions and 189 deletions

View File

@ -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",
]

View File

@ -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",
]
}

View File

@ -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__

View File

@ -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 <Foundation/Foundation.h>
#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

View File

@ -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__

View File

@ -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 <Foundation/Foundation.h>
#import "webrtc/base/scoped_autorelease_pool.h"
namespace rtc {
ScopedAutoreleasePool::ScopedAutoreleasePool() {
pool_ = [[NSAutoreleasePool alloc] init];
}
ScopedAutoreleasePool::~ScopedAutoreleasePool() {
[pool_ drain];
}
} // namespace rtc

View File

@ -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<Thread *>(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<ThreadInit*>(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) {

View File

@ -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

View File

@ -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 <Foundation/Foundation.h>
#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<ThreadInit*>(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<int>(TimeUntil(msEnd));
if (cmsNext < 0)
return true;
}
}
}
}
} // namespace rtc