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}
diff --git a/webrtc/BUILD.gn b/webrtc/BUILD.gn
index 5ac3132..a10b953 100644
--- a/webrtc/BUILD.gn
+++ b/webrtc/BUILD.gn
@@ -33,7 +33,6 @@
"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 7514b07..3d0a3f4 100644
--- a/webrtc/base/BUILD.gn
+++ b/webrtc/base/BUILD.gn
@@ -544,11 +544,8 @@
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 255d081..0000000
--- 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 70d920d..0000000
--- 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 <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
diff --git a/webrtc/base/scoped_autorelease_pool.h b/webrtc/base/scoped_autorelease_pool.h
deleted file mode 100644
index 2e0a204..0000000
--- 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 4176aad..0000000
--- 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 <Foundation/Foundation.h>
-
-#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 a7db418..66542bb 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 @@
}
#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 @@
}
}
-struct ThreadInit {
- Thread* thread;
- Runnable* runnable;
-};
-
Thread::ScopedDisallowBlockingCalls::ScopedDisallowBlockingCalls()
: thread_(Thread::Current()),
previous_state_(thread_->SetAllowBlockingCalls(false)) {
@@ -298,6 +279,7 @@
}
// static
+#if !defined(WEBRTC_MAC)
#if defined(WEBRTC_WIN)
DWORD WINAPI Thread::PreRun(LPVOID pv) {
#else
@@ -306,10 +288,6 @@
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 @@
return nullptr;
#endif
}
+#endif
void Thread::Run() {
ProcessMessages(kForever);
@@ -478,18 +457,14 @@
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 @@
}
}
}
+#endif
bool Thread::WrapCurrentWithThreadManager(ThreadManager* thread_manager,
bool need_synchronize_access) {
diff --git a/webrtc/base/thread.h b/webrtc/base/thread.h
index 5751df3..398063d 100644
--- a/webrtc/base/thread.h
+++ b/webrtc/base/thread.h
@@ -238,6 +238,11 @@
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 0000000..5bcc5c8
--- /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 <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