Rename AtomicString to AtomString
[WebKit.git] / Source / WebCore / platform / ios / wak / WebCoreThread.mm
index 10bd779..195408d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2018 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #import "config.h"
 #import "WebCoreThread.h"
 
-#if PLATFORM(IOS)
+#if PLATFORM(IOS_FAMILY)
 
 #import "CommonVM.h"
 #import "FloatingPointEnvironment.h"
+#import "Logging.h"
 #import "RuntimeApplicationChecks.h"
 #import "ThreadGlobalData.h"
 #import "WAKWindow.h"
+#import "WKUtilities.h"
 #import "WebCoreThreadInternal.h"
 #import "WebCoreThreadMessage.h"
 #import "WebCoreThreadRun.h"
-#import "WKUtilities.h"
-
-#import <runtime/InitializeThreading.h>
-#import <runtime/JSLock.h>
+#import <Foundation/NSInvocation.h>
+#import <JavaScriptCore/InitializeThreading.h>
+#import <JavaScriptCore/JSLock.h>
+#import <libkern/OSAtomic.h>
+#import <objc/runtime.h>
 #import <wtf/Assertions.h>
 #import <wtf/MainThread.h>
+#import <wtf/RecursiveLockAdapter.h>
 #import <wtf/RunLoop.h>
+#import <wtf/ThreadSpecific.h>
 #import <wtf/Threading.h>
-#import <wtf/text/AtomicString.h>
-
-#import <Foundation/NSInvocation.h>
-#import <libkern/OSAtomic.h>
-#import <objc/runtime.h>
+#import <wtf/spi/cocoa/objcSPI.h>
+#import <wtf/text/AtomString.h>
 
 #define LOG_MESSAGES 0
 #define LOG_WEB_LOCK 0
 #define LOG_RELEASES 0
 
 #define DistantFuture   (86400.0 * 2000 * 365.2425 + 86400.0)   // same as +[NSDate distantFuture]
-#define MaxArgCount         5
-#define DrawWaitInterval     10
-#define DelegateWaitInterval 10
 
-static void _WebThreadAutoLock(void);
-static bool _WebTryThreadLock(bool shouldTry);
+static const constexpr Seconds DelegateWaitInterval { 10_s };
+
+static void _WebThreadAutoLock();
+static void _WebThreadLock();
 static void _WebThreadLockFromAnyThread(bool shouldLog);
-static void _WebThreadUnlock(void);
+static void _WebThreadUnlock();
 
 @interface NSObject(ForwardDeclarations)
 -(void)_webcore_releaseOnWebThread;
@@ -73,29 +74,19 @@ static void _WebThreadUnlock(void);
 @implementation NSObject(WebCoreThreadAdditions)
 
 - (void)releaseOnMainThread {
-    if ([NSThread isMainThread]) {
+    if ([NSThread isMainThread])
         [self release];
-    } else {
+    else
         [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
-    }
 }
 
 @end
 
-typedef void *NSAutoreleasePoolMark;
-#ifdef __cplusplus
-extern "C" {
-#endif
-extern NSAutoreleasePoolMark NSPushAutoreleasePool(unsigned ignored);
-extern void NSPopAutoreleasePool(NSAutoreleasePoolMark token);
-#ifdef __cplusplus
-}
-#endif
-
-static int WebTimedConditionLock (pthread_cond_t *condition, pthread_mutex_t *lock, CFAbsoluteTime interval);
+static RecursiveLock webLock;
+static Lock webThreadReleaseLock;
+static RecursiveLock webCoreReleaseLock;
 
-static pthread_mutex_t webLock;
-static NSAutoreleasePoolMark autoreleasePoolMark;
+static void* autoreleasePoolMark;
 static CFRunLoopRef webThreadRunLoop;
 static NSRunLoop* webThreadNSRunLoop;
 static pthread_t webThread;
@@ -103,23 +94,22 @@ static BOOL isWebThreadLocked;
 static BOOL webThreadStarted;
 static unsigned webThreadLockCount;
 
-static NSAutoreleasePoolMark savedAutoreleasePoolMark;
+static void* savedAutoreleasePoolMark;
 static BOOL isNestedWebThreadRunLoop;
 typedef enum {
     PushOrPopAutoreleasePool,
     IgnoreAutoreleasePool
 } AutoreleasePoolOperation;
 
-static pthread_mutex_t WebThreadReleaseLock = PTHREAD_MUTEX_INITIALIZER;
 static CFRunLoopSourceRef WebThreadReleaseSource;
 static CFMutableArrayRef WebThreadReleaseObjArray;
 
 static void MainThreadAdoptAndRelease(id obj);
 
-static pthread_mutex_t delegateLock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t delegateCondition = PTHREAD_COND_INITIALIZER;
-static NSInvocation *delegateInvocation;
-static CFRunLoopSourceRef delegateSource = NULL;
+static Lock delegateLock;
+static StaticCondition delegateCondition;
+static NSInvocationdelegateInvocation;
+static CFRunLoopSourceRef delegateSource = nullptr;
 static BOOL delegateHandled;
 #if LOG_MAIN_THREAD_LOCKING
 static BOOL sendingDelegateMessage;
@@ -127,35 +117,32 @@ static BOOL sendingDelegateMessage;
 
 static CFRunLoopObserverRef mainRunLoopAutoUnlockObserver;
 
-static pthread_mutex_t startupLock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t startupCondition = PTHREAD_COND_INITIALIZER;
+static Lock startupLock;
+static StaticCondition startupCondition;
 
-static WebThreadContext *webThreadContext;
-static pthread_key_t threadContextKey;
+static WebThreadContext* webThreadContext;
 static unsigned mainThreadLockCount;
 static unsigned otherThreadLockCount;
 static unsigned sMainThreadModalCount;
 
 WEBCORE_EXPORT volatile bool webThreadShouldYield;
 
-static pthread_mutex_t WebCoreReleaseLock;
 static void WebCoreObjCDeallocOnWebThreadImpl(id self, SEL _cmd);
 static void WebCoreObjCDeallocWithWebThreadLock(Class cls);
 static void WebCoreObjCDeallocWithWebThreadLockImpl(id self, SEL _cmd);
 
-static NSMutableArray *sAsyncDelegates = nil;
+static NSMutableArraysAsyncDelegates = nil;
 
-static CFStringRef delegateSourceRunLoopMode;
+WEBCORE_EXPORT volatile unsigned webThreadDelegateMessageScopeCount = 0;
 
-static inline void SendMessage(NSInvocation *invocation)
+static inline void SendMessage(NSInvocationinvocation)
 {
     [invocation invoke];
     MainThreadAdoptAndRelease(invocation);
 }
 
-static void HandleDelegateSource(void *info)
+static void HandleDelegateSource(void*)
 {
-    UNUSED_PARAM(info);
     ASSERT(!WebThreadIsCurrent());
 
 #if LOG_MAIN_THREAD_LOCKING
@@ -164,81 +151,86 @@ static void HandleDelegateSource(void *info)
 
     _WebThreadAutoLock();
 
-    int result = pthread_mutex_lock(&delegateLock);
-    ASSERT_WITH_MESSAGE(result == 0, "delegate lock failed with code:%d", result);
+    {
+        auto locker = holdLock(delegateLock);
 
 #if LOG_MESSAGES
-    if ([[delegateInvocation target] isKindOfClass:[NSNotificationCenter class]]) {
-        id argument0;
-        [delegateInvocation getArgument:&argument0 atIndex:0];
-        NSLog(@"notification receive: %@", argument0);
-    } else {
-        NSLog(@"delegate receive: %@", NSStringFromSelector([delegateInvocation selector]));
-    }
+        if ([[delegateInvocation target] isKindOfClass:[NSNotificationCenter class]]) {
+            id argument0;
+            [delegateInvocation getArgument:&argument0 atIndex:0];
+            NSLog(@"notification receive: %@", argument0);
+        } else
+            NSLog(@"delegate receive: %@", NSStringFromSelector([delegateInvocation selector]));
 #endif
 
-    SendMessage(delegateInvocation);
+        SendMessage(delegateInvocation);
 
-    delegateHandled = YES;
-    pthread_cond_signal(&delegateCondition);
-
-    result = pthread_mutex_unlock(&delegateLock);
-    ASSERT_WITH_MESSAGE(result == 0, "delegate unlock failed with code:%d", result);
+        delegateHandled = YES;
+        delegateCondition.notifyOne();
+    }
 
 #if LOG_MAIN_THREAD_LOCKING
     sendingDelegateMessage = NO;
 #endif
 }
 
-static void SendDelegateMessage(NSInvocation *invocation)
+class WebThreadDelegateMessageScope {
+public:
+    WebThreadDelegateMessageScope() { ++webThreadDelegateMessageScopeCount; }
+    ~WebThreadDelegateMessageScope()
+    {
+        ASSERT(webThreadDelegateMessageScopeCount);
+        --webThreadDelegateMessageScopeCount;
+    }
+};
+
+static void SendDelegateMessage(NSInvocation* invocation)
 {
-    if (WebThreadIsCurrent()) {
-        ASSERT(delegateSource);
-        int result = pthread_mutex_lock(&delegateLock);
-        ASSERT_WITH_MESSAGE(result == 0, "delegate lock failed with code:%d", result);
+    if (!WebThreadIsCurrent()) {
+        SendMessage(invocation);
+        return;
+    }
+
+    ASSERT(delegateSource);
+    delegateLock.lock();
 
-        delegateInvocation = invocation;
-        delegateHandled = NO;
+    delegateInvocation = invocation;
+    delegateHandled = NO;
 
 #if LOG_MESSAGES
-        if ([[delegateInvocation target] isKindOfClass:[NSNotificationCenter class]]) {
-            id argument0;
-            [delegateInvocation getArgument:&argument0 atIndex:0];
-            NSLog(@"notification send: %@", argument0);
-        } else {
-            NSLog(@"delegate send: %@", NSStringFromSelector([delegateInvocation selector]));
-        }
+    if ([[delegateInvocation target] isKindOfClass:[NSNotificationCenter class]]) {
+        id argument0;
+        [delegateInvocation getArgument:&argument0 atIndex:0];
+        NSLog(@"notification send: %@", argument0);
+    } else
+        NSLog(@"delegate send: %@", NSStringFromSelector([delegateInvocation selector]));
 #endif
 
-        {
-            // Code block created to scope JSC::JSLock::DropAllLocks outside of WebThreadLock()
-            JSC::JSLock::DropAllLocks dropAllLocks(WebCore::commonVM());
-            _WebThreadUnlock();
-
-            CFRunLoopSourceSignal(delegateSource);
-            CFRunLoopWakeUp(CFRunLoopGetMain());
-
-            while (!delegateHandled) {
-                if (WebTimedConditionLock(&delegateCondition, &delegateLock, DelegateWaitInterval) != 0) {
-                    id delegateInformation;
-                    if ([[delegateInvocation target] isKindOfClass:[NSNotificationCenter class]])
-                        [delegateInvocation getArgument:&delegateInformation atIndex:0];
-                    else
-                        delegateInformation = NSStringFromSelector([delegateInvocation selector]);
-        
-                    CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());
-                    NSLog(@"%s: delegate (%@) failed to return after waiting %d seconds. main run loop mode: %@", __PRETTY_FUNCTION__, delegateInformation, DelegateWaitInterval, mode);
-                    if (mode)
-                        CFRelease(mode);
-                }
-            }
-            result = pthread_mutex_unlock(&delegateLock);
+    {
+        WebThreadDelegateMessageScope delegateScope;
+        // Code block created to scope JSC::JSLock::DropAllLocks outside of WebThreadLock()
+        JSC::JSLock::DropAllLocks dropAllLocks(WebCore::commonVM());
+        _WebThreadUnlock();
 
-            ASSERT_WITH_MESSAGE(result == 0, "delegate unlock failed with code:%d", result);
-            _WebTryThreadLock(false);
+        CFRunLoopSourceSignal(delegateSource);
+        CFRunLoopWakeUp(CFRunLoopGetMain());
+
+        while (!delegateHandled) {
+            if (!delegateCondition.waitFor(delegateLock, DelegateWaitInterval)) {
+                id delegateInformation;
+                if ([[delegateInvocation target] isKindOfClass:[NSNotificationCenter class]])
+                    [delegateInvocation getArgument:&delegateInformation atIndex:0];
+                else
+                    delegateInformation = NSStringFromSelector([delegateInvocation selector]);
+    
+                CFStringRef mode = CFRunLoopCopyCurrentMode(CFRunLoopGetMain());
+                NSLog(@"%s: delegate (%@) failed to return after waiting %f seconds. main run loop mode: %@", __PRETTY_FUNCTION__, delegateInformation, DelegateWaitInterval.seconds(), mode);
+                if (mode)
+                    CFRelease(mode);
+            }
         }
-    } else {
-        SendMessage(invocation);
+        delegateLock.unlock();
+        _WebThreadLock();
     }
 }
 
@@ -257,7 +249,7 @@ void WebThreadRunOnMainThread(void(^delegateBlock)())
     dispatch_sync(dispatch_get_main_queue(), delegateBlockCopy);
     Block_release(delegateBlockCopy);
 
-    _WebTryThreadLock(false);
+    _WebThreadLock();
 }
 
 static void MainThreadAdoptAndRelease(id obj)
@@ -286,31 +278,13 @@ void WebThreadAdoptAndRelease(id obj)
     NSLog(@"Release send [main thread]: %@", obj);
 #endif        
 
-    int result = pthread_mutex_lock(&WebThreadReleaseLock);
-    ASSERT_WITH_MESSAGE(result == 0, "Release lock failed with code:%d", result);
+    auto locker = holdLock(webThreadReleaseLock);
 
     if (WebThreadReleaseObjArray == nil)
-        WebThreadReleaseObjArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
+        WebThreadReleaseObjArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, nullptr);
     CFArrayAppendValue(WebThreadReleaseObjArray, obj);
     CFRunLoopSourceSignal(WebThreadReleaseSource);
     CFRunLoopWakeUp(webThreadRunLoop);
-
-    result = pthread_mutex_unlock(&WebThreadReleaseLock);    
-    ASSERT_WITH_MESSAGE(result == 0, "Release unlock failed with code:%d", result);
-}
-
-static inline void lockWebCoreReleaseLock()
-{
-    int lockcode = pthread_mutex_lock(&WebCoreReleaseLock);
-#pragma unused (lockcode)
-    ASSERT_WITH_MESSAGE(lockcode == 0, "WebCoreReleaseLock lock failed with code:%d", lockcode);
-}
-
-static inline void unlockWebCoreReleaseLock()
-{
-    int lockcode = pthread_mutex_unlock(&WebCoreReleaseLock);
-#pragma unused (lockcode)
-    ASSERT_WITH_MESSAGE(lockcode == 0, "WebCoreReleaseLock unlock failed with code:%d", lockcode);
 }
 
 void WebCoreObjCDeallocOnWebThread(Class cls)
@@ -365,65 +339,57 @@ void WebCoreObjCDeallocWithWebThreadLock(Class cls)
     method_exchangeImplementations(releaseMethod, class_getInstanceMethod(cls, webThreadLockReleaseSEL));
 }
 
-void WebCoreObjCDeallocOnWebThreadImpl(id self, SEL _cmd)
+void WebCoreObjCDeallocOnWebThreadImpl(id self, SEL)
 {
-    UNUSED_PARAM(_cmd);
-    if (!WebThreadIsEnabled())
+    if (!WebThreadIsEnabled()) {
         [self _webcore_releaseOnWebThread];
-    else {
-        lockWebCoreReleaseLock();
-        if ([self retainCount] == 1) {
-            // This is the only reference retaining the object, so we can
-            // safely release the WebCoreReleaseLock now.
-            unlockWebCoreReleaseLock();
-            if (WebThreadIsCurrent())
-                [self _webcore_releaseOnWebThread];
-            else
-                WebThreadAdoptAndRelease(self);
-        } else {
+        return;
+    }
+
+    {
+        auto locker = holdLock(webCoreReleaseLock);
+        if ([self retainCount] != 1) {
             // This is not the only reference retaining the object, so another
             // thread could also call release - hold the lock whilst calling
             // release to avoid a race condition.
             [self _webcore_releaseOnWebThread];
-            unlockWebCoreReleaseLock();
+            return;
         }
+        // This is the only reference retaining the object, so we can
+        // safely release the webCoreReleaseLock now.
     }
+    if (WebThreadIsCurrent())
+        [self _webcore_releaseOnWebThread];
+    else
+        WebThreadAdoptAndRelease(self);
 }
 
-void WebCoreObjCDeallocWithWebThreadLockImpl(id self, SEL _cmd)
+void WebCoreObjCDeallocWithWebThreadLockImpl(id self, SEL)
 {
-    UNUSED_PARAM(_cmd);
-    lockWebCoreReleaseLock();
+    auto locker = holdLock(webCoreReleaseLock);
     if (WebThreadIsLockedOrDisabled() || 1 != [self retainCount])
         [self _webcore_releaseWithWebThreadLock];
     else
         WebThreadAdoptAndRelease(self);
-    unlockWebCoreReleaseLock();
 }
 
-static void HandleWebThreadReleaseSource(void *info)
+static void HandleWebThreadReleaseSource(void*)
 {
-    UNUSED_PARAM(info);
     ASSERT(WebThreadIsCurrent());
 
-    int result = pthread_mutex_lock(&WebThreadReleaseLock);
-    ASSERT_WITH_MESSAGE(result == 0, "Release lock failed with code:%d", result);
-
-    CFMutableArrayRef objects = NULL;
-    if (CFArrayGetCount(WebThreadReleaseObjArray)) {
-        objects = CFArrayCreateMutableCopy(NULL, 0, WebThreadReleaseObjArray);
-        CFArrayRemoveAllValues(WebThreadReleaseObjArray);
+    CFMutableArrayRef objects = nullptr;
+    {
+        auto locker = holdLock(webThreadReleaseLock);
+        if (CFArrayGetCount(WebThreadReleaseObjArray)) {
+            objects = CFArrayCreateMutableCopy(nullptr, 0, WebThreadReleaseObjArray);
+            CFArrayRemoveAllValues(WebThreadReleaseObjArray);
+        }
     }
 
-    result = pthread_mutex_unlock(&WebThreadReleaseLock);
-    ASSERT_WITH_MESSAGE(result == 0, "Release unlock failed with code:%d", result);
-
     if (!objects)
         return;
 
-    unsigned count = CFArrayGetCount(objects);
-    unsigned i;
-    for (i = 0; i < count; i++) {
+    for (unsigned i = 0, count = CFArrayGetCount(objects); i < count; ++i) {
         id obj = (id)CFArrayGetValueAtIndex(objects, i);
 #if LOG_RELEASES
         NSLog(@"Release recv [web thread] : %@", obj);
@@ -434,13 +400,13 @@ static void HandleWebThreadReleaseSource(void *info)
     CFRelease(objects);
 }
 
-void WebThreadCallDelegate(NSInvocation *invocation)
+void WebThreadCallDelegate(NSInvocationinvocation)
 {
     // NSInvocation released in SendMessage()
     SendDelegateMessage([invocation retain]);
 }
 
-void WebThreadPostNotification(NSString *name, id object, id userInfo)
+void WebThreadPostNotification(NSStringname, id object, id userInfo)
 {
     if (pthread_main_np())
         [[NSNotificationCenter defaultCenter] postNotificationName:name object:object userInfo:userInfo];
@@ -451,7 +417,7 @@ void WebThreadPostNotification(NSString *name, id object, id userInfo)
     }
 }
 
-void WebThreadCallDelegateAsync(NSInvocation *invocation)
+void WebThreadCallDelegateAsync(NSInvocationinvocation)
 {
     ASSERT(invocation);
     if (WebThreadIsCurrent())
@@ -461,12 +427,12 @@ void WebThreadCallDelegateAsync(NSInvocation *invocation)
 }
 
 // Note: despite the name, returns an autoreleased object.
-NSInvocation *WebThreadMakeNSInvocation(id target, SEL selector)
+NSInvocationWebThreadMakeNSInvocation(id target, SEL selector)
 {
-    NSMethodSignature *signature = [target methodSignatureForSelector:selector];
+    NSMethodSignaturesignature = [target methodSignatureForSelector:selector];
     ASSERT(signature);
     if (signature) {
-        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
+        NSInvocationinvocation = [NSInvocation invocationWithMethodSignature:signature];
         [invocation setSelector:selector];
         [invocation setTarget:target];
         [invocation retainArguments];
@@ -475,14 +441,11 @@ NSInvocation *WebThreadMakeNSInvocation(id target, SEL selector)
     return nil;
 }
 
-static void MainRunLoopAutoUnlock(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *context)
+static void MainRunLoopAutoUnlock(CFRunLoopObserverRef, CFRunLoopActivity, void*)
 {
-    UNUSED_PARAM(observer);
-    UNUSED_PARAM(activity);
-    UNUSED_PARAM(context);
     ASSERT(!WebThreadIsCurrent());
 
-    if (sMainThreadModalCount != 0)
+    if (sMainThreadModalCount)
         return;
     
     CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), mainRunLoopAutoUnlockObserver, kCFRunLoopCommonModes);
@@ -494,18 +457,18 @@ static void _WebThreadAutoLock(void)
 {
     ASSERT(!WebThreadIsCurrent());
 
-    if (mainThreadLockCount == 0) {
+    if (!mainThreadLockCount) {
         CFRunLoopAddObserver(CFRunLoopGetCurrent(), mainRunLoopAutoUnlockObserver, kCFRunLoopCommonModes);    
-        _WebTryThreadLock(false);
+        _WebThreadLock();
         CFRunLoopWakeUp(CFRunLoopGetMain());
     }
 }
 
 static void WebRunLoopLockInternal(AutoreleasePoolOperation poolOperation)
 {
-    _WebTryThreadLock(false);
+    _WebThreadLock();
     if (poolOperation == PushOrPopAutoreleasePool)
-        autoreleasePoolMark = NSPushAutoreleasePool(0);
+        autoreleasePoolMark = objc_autoreleasePoolPush();
     isWebThreadLocked = YES;
 }
 
@@ -519,16 +482,14 @@ static void WebRunLoopUnlockInternal(AutoreleasePoolOperation poolOperation)
     }
 
     if (poolOperation == PushOrPopAutoreleasePool)
-        NSPopAutoreleasePool(autoreleasePoolMark);
+        objc_autoreleasePoolPop(autoreleasePoolMark);
 
     _WebThreadUnlock();
     isWebThreadLocked = NO;
 }
 
-static void WebRunLoopLock(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *context)
+static void WebRunLoopLock(CFRunLoopObserverRef, CFRunLoopActivity activity, void*)
 {
-    UNUSED_PARAM(observer);
-    UNUSED_PARAM(context);
     ASSERT(WebThreadIsCurrent());
     ASSERT_UNUSED(activity, activity == kCFRunLoopAfterWaiting || activity == kCFRunLoopBeforeTimers || activity == kCFRunLoopBeforeSources);
 
@@ -539,10 +500,8 @@ static void WebRunLoopLock(CFRunLoopObserverRef observer, CFRunLoopActivity acti
     WebRunLoopLockInternal(PushOrPopAutoreleasePool);
 }
 
-static void WebRunLoopUnlock(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *context)
+static void WebRunLoopUnlock(CFRunLoopObserverRef, CFRunLoopActivity activity, void*)
 {
-    UNUSED_PARAM(observer);
-    UNUSED_PARAM(context);
     ASSERT(WebThreadIsCurrent());
     ASSERT_UNUSED(activity, activity == kCFRunLoopBeforeWaiting || activity == kCFRunLoopExit);
     ASSERT(!mainThreadLockCount);
@@ -552,22 +511,19 @@ static void WebRunLoopUnlock(CFRunLoopObserverRef observer, CFRunLoopActivity ac
     WebRunLoopUnlockInternal(PushOrPopAutoreleasePool);
 }
 
-static void MainRunLoopUnlockGuard(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *context)
+static void MainRunLoopUnlockGuard(CFRunLoopObserverRef observer, CFRunLoopActivity activity, voidcontext)
 {
-    UNUSED_PARAM(observer);
-    UNUSED_PARAM(activity);
-    UNUSED_PARAM(context);
     ASSERT(!WebThreadIsCurrent());
 
     // We shouldn't have the web lock at this point.  However, MobileMail sometimes
     // get to a state where the main thread has web lock but it didn't release it on last
     // runloop exit, and web thread gets stuck at waiting for the lock. If this happens,
     // we need to help release the lock.  See <rdar://problem/8005192>.
-    if (mainThreadLockCount != 0 && sMainThreadModalCount == 0) {
+    if (mainThreadLockCount && !sMainThreadModalCount) {
         NSLog(@"WARNING: Main thread didn't release the lock at last runloop exit!");
 
         MainRunLoopAutoUnlock(observer, activity, context);
-        if (mainThreadLockCount != 0)
+        if (mainThreadLockCount)
             mainThreadLockCount = 0;
     }
 }
@@ -614,41 +570,20 @@ void WebRunLoopDisableNested()
     isNestedWebThreadRunLoop = NO;
 }
 
-static void FreeThreadContext(void *threadContext)
-{
-    if (threadContext != NULL)
-       free(threadContext);
-}
-
-static void InitThreadContextKey()
-{
-    int error = pthread_key_create(&threadContextKey, FreeThreadContext);
-    if (error)
-        CRASH();
-}
-
-static WebThreadContext *CurrentThreadContext(void)
+static ThreadSpecific<WebThreadContext, WTF::CanBeGCThread::True>* threadContext;
+static WebThreadContext* CurrentThreadContext()
 {
-    static pthread_once_t initControl = PTHREAD_ONCE_INIT; 
-    pthread_once(&initControl, InitThreadContextKey);    
-
-    WebThreadContext *threadContext = (WebThreadContext*)pthread_getspecific(threadContextKey);
-    if (threadContext == NULL) {
-        threadContext = (WebThreadContext *)calloc(sizeof(WebThreadContext), 1);
-        pthread_setspecific(threadContextKey, threadContext);
-    }        
-    return threadContext;
+    static std::once_flag flag;
+    std::call_once(flag, [] {
+        threadContext = new ThreadSpecific<WebThreadContext, WTF::CanBeGCThread::True>();
+    });
+    return *threadContext;
 }
 
-static
-#ifndef __llvm__
-NO_RETURN
-#endif
-void *RunWebThread(void *arg)
+static void* RunWebThread(void*)
 {
     FloatingPointEnvironment::singleton().propagateMainThreadEnvironment();
 
-    UNUSED_PARAM(arg);
     // WTF::initializeMainThread() needs to be called before JSC::initializeThreading() since the
     // code invoked by the latter needs to know if it's running on the WebThread. See
     // <rdar://problem/8502487>.
@@ -658,7 +593,6 @@ void *RunWebThread(void *arg)
     
     // Make sure that the WebThread and the main thread share the same ThreadGlobalData objects.
     WebCore::threadGlobalData().setWebCoreThreadData();
-    initializeWebThreadIdentifier();
 
 #if HAVE(PTHREAD_SETNAME_NP)
     pthread_setname_np("WebThread");
@@ -668,49 +602,46 @@ void *RunWebThread(void *arg)
     webThreadRunLoop = CFRunLoopGetCurrent();
     webThreadNSRunLoop = [[NSRunLoop currentRunLoop] retain];
 
-    CFRunLoopObserverRef webRunLoopLockObserverRef = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeTimers|kCFRunLoopBeforeSources|kCFRunLoopAfterWaiting, YES, 0, WebRunLoopLock, NULL);
+    CFRunLoopObserverRef webRunLoopLockObserverRef = CFRunLoopObserverCreate(nullptr, kCFRunLoopBeforeTimers | kCFRunLoopBeforeSources | kCFRunLoopAfterWaiting, YES, 0, WebRunLoopLock, nullptr);
     CFRunLoopAddObserver(webThreadRunLoop, webRunLoopLockObserverRef, kCFRunLoopCommonModes);
     CFRelease(webRunLoopLockObserverRef);
     
     WebThreadInitRunQueue();
 
     // We must have the lock when CA paints in the web thread. CA commits at 2000000 so we use larger order number than that to free the lock.
-    CFRunLoopObserverRef webRunLoopUnlockObserverRef = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting|kCFRunLoopExit, YES, 2500000, WebRunLoopUnlock, NULL);    
+    CFRunLoopObserverRef webRunLoopUnlockObserverRef = CFRunLoopObserverCreate(nullptr, kCFRunLoopBeforeWaiting | kCFRunLoopExit, YES, 2500000, WebRunLoopUnlock, nullptr);    
     CFRunLoopAddObserver(webThreadRunLoop, webRunLoopUnlockObserverRef, kCFRunLoopCommonModes);
     CFRelease(webRunLoopUnlockObserverRef);    
 
-    CFRunLoopSourceContext ReleaseSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HandleWebThreadReleaseSource};
-    WebThreadReleaseSource = CFRunLoopSourceCreate(NULL, -1, &ReleaseSourceContext);
+    CFRunLoopSourceContext ReleaseSourceContext = {0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, HandleWebThreadReleaseSource};
+    WebThreadReleaseSource = CFRunLoopSourceCreate(nullptr, -1, &ReleaseSourceContext);
     CFRunLoopAddSource(webThreadRunLoop, WebThreadReleaseSource, kCFRunLoopDefaultMode);
 
-    int result = pthread_mutex_lock(&startupLock);
-    ASSERT_WITH_MESSAGE(result == 0, "startup lock failed with code:%d", result);
-
-    result = pthread_cond_signal(&startupCondition);
-    ASSERT_WITH_MESSAGE(result == 0, "startup signal failed with code:%d", result);
-
-    result = pthread_mutex_unlock(&startupLock);
-    ASSERT_WITH_MESSAGE(result == 0, "startup unlock failed with code:%d", result);
+    {
+        LockHolder locker(startupLock);
+        startupCondition.notifyOne();
+    }
 
     while (1)
         CFRunLoopRunInMode(kCFRunLoopDefaultMode, DistantFuture, true);
 
-#ifdef __llvm__
-    return NULL;
-#endif  
+    return nullptr;
 }
 
 static void StartWebThread()
 {
     webThreadStarted = TRUE;
 
+    // ThreadGlobalData touches AtomString, which requires Threading initialization.
+    WTF::initializeThreading();
+
+    // Initialize AtomString on the main thread.
+    WTF::AtomString::init();
+
     // Initialize ThreadGlobalData on the main UI thread so that the WebCore thread
     // can later set it's thread-specific data to point to the same objects.
     WebCore::ThreadGlobalData& unused = WebCore::threadGlobalData();
-    (void)unused;
-
-    // Initialize AtomicString on the main thread.
-    WTF::AtomicString::init();
+    UNUSED_PARAM(unused);
 
     RunLoop::initializeMainRunLoop();
 
@@ -718,31 +649,18 @@ static void StartWebThread()
     WebCoreObjCDeallocOnWebThread([WAKWindow class]);
     WebCoreObjCDeallocWithWebThreadLock([WAKView class]);
 
-    pthread_mutexattr_t mattr;
-    pthread_mutexattr_init(&mattr);
-    pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
-    pthread_mutex_init(&webLock, &mattr);
-    pthread_mutexattr_destroy(&mattr);            
-
-    pthread_mutexattr_t mutex_attr;
-    pthread_mutexattr_init(&mutex_attr);
-    pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);    
-    pthread_mutex_init(&WebCoreReleaseLock, &mutex_attr);
-    pthread_mutexattr_destroy(&mutex_attr);
-
     CFRunLoopRef runLoop = CFRunLoopGetCurrent();
-    CFRunLoopSourceContext delegateSourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, HandleDelegateSource};
-    delegateSource = CFRunLoopSourceCreate(NULL, 0, &delegateSourceContext);
+    CFRunLoopSourceContext delegateSourceContext = {0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, HandleDelegateSource};
+    delegateSource = CFRunLoopSourceCreate(nullptr, 0, &delegateSourceContext);
+
     // We shouldn't get delegate callbacks while scrolling, but there might be
     // one outstanding when we start.  Add the source for all common run loop
     // modes so we don't block the web thread while scrolling.
-    if (!delegateSourceRunLoopMode)
-        delegateSourceRunLoopMode = kCFRunLoopCommonModes;
-    CFRunLoopAddSource(runLoop, delegateSource, delegateSourceRunLoopMode);
+    CFRunLoopAddSource(runLoop, delegateSource, kCFRunLoopCommonModes);
 
     sAsyncDelegates = [[NSMutableArray alloc] init];
 
-    mainRunLoopAutoUnlockObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting | kCFRunLoopExit, YES, 3000001, MainRunLoopAutoUnlock, NULL);
+    mainRunLoopAutoUnlockObserver = CFRunLoopObserverCreate(nullptr, kCFRunLoopBeforeWaiting | kCFRunLoopExit, YES, 3000001, MainRunLoopAutoUnlock, nullptr);
 
     pthread_attr_t tattr;
     pthread_attr_init(&tattr);
@@ -750,47 +668,31 @@ static void StartWebThread()
     // The web thread is a secondary thread, and secondary threads are usually given
     // a 512 kb stack, but we need more space in order to have room for the JavaScriptCore
     // reentrancy limit. This limit works on both the simulator and the device.
-    pthread_attr_setstacksize(&tattr, 200 * 4096);
+    pthread_attr_setstacksize(&tattr, 800 * KB);
 
-    struct sched_param param;
-    pthread_attr_getschedparam(&tattr, &param);
-    param.sched_priority--;
-    pthread_attr_setschedparam(&tattr, &param);
+    pthread_attr_set_qos_class_np(&tattr, QOS_CLASS_USER_INTERACTIVE, -10);
 
     // Wait for the web thread to startup completely before we continue.
-    int result = pthread_mutex_lock(&startupLock);
-    ASSERT_WITH_MESSAGE(result == 0, "startup lock failed with code:%d", result);
-
-    // Propagate the mainThread's fenv to workers & the web thread.
-    FloatingPointEnvironment::singleton().saveMainThreadEnvironment();
-
-    pthread_create(&webThread, &tattr, RunWebThread, NULL);
-    pthread_attr_destroy(&tattr);
+    {
+        LockHolder locker(startupLock);
 
-    result = pthread_cond_wait(&startupCondition, &startupLock);
-    ASSERT_WITH_MESSAGE(result == 0, "startup wait failed with code:%d", result);
+        // Propagate the mainThread's fenv to workers & the web thread.
+        FloatingPointEnvironment::singleton().saveMainThreadEnvironment();
 
-    result = pthread_mutex_unlock(&startupLock);
-    ASSERT_WITH_MESSAGE(result == 0, "startup unlock failed with code:%d", result);
+        pthread_create(&webThread, &tattr, RunWebThread, nullptr);
+        pthread_attr_destroy(&tattr);
 
-    initializeApplicationUIThreadIdentifier();
-}
+        startupCondition.wait(startupLock);
+    }
 
-static int WebTimedConditionLock (pthread_cond_t *condition, pthread_mutex_t *lock, CFAbsoluteTime interval)
-{
-    struct timespec time;
-    CFAbsoluteTime at = CFAbsoluteTimeGetCurrent() + interval;
-    time.tv_sec = (time_t)(floor(at) + kCFAbsoluteTimeIntervalSince1970);
-    time.tv_nsec = (int32_t)((at - floor(at)) * 1000000000.0);        
-    return pthread_cond_timedwait(condition, lock, &time);
+    initializeApplicationUIThread();
 }
 
-
 #if LOG_WEB_LOCK || LOG_MAIN_THREAD_LOCKING
 static unsigned lockCount;
 #endif
 
-static bool _WebTryThreadLock(bool shouldTry)
+static void _WebThreadLock()
 {
     // Suspend the web thread if the main thread is trying to lock.
     bool onMainThread = pthread_main_np();
@@ -800,47 +702,30 @@ static bool _WebTryThreadLock(bool shouldTry)
         NSLog(@"%s, %p: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...", __PRETTY_FUNCTION__, CurrentThreadContext());
         CRASH();
     }
-        
-            
-    int result;
-    bool busy = false;
-    if (shouldTry) {
-        result = pthread_mutex_trylock(&webLock);
-        if (result == EBUSY) {
-            busy = true;
-        } else
-            ASSERT_WITH_MESSAGE(result == 0, "try web lock failed with code:%d", result);
-    }
-    else {
-        result = pthread_mutex_lock(&webLock);
-        ASSERT_WITH_MESSAGE(result == 0, "web lock failed with code:%d", result);
-    }
-    
-    if (!busy) {
+
+    webLock.lock();
+
 #if LOG_WEB_LOCK || LOG_MAIN_THREAD_LOCKING
-        lockCount++;
+    lockCount++;
 #if LOG_WEB_LOCK
-        NSLog(@"lock   %d, web-thread: %d", lockCount, WebThreadIsCurrent());
+    NSLog(@"lock   %d, web-thread: %d", lockCount, WebThreadIsCurrent());
 #endif
 #endif
-        if (onMainThread) {
-            ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
-            webThreadShouldYield = false;
-            mainThreadLockCount++;
+    if (onMainThread) {
+        ASSERT(CFRunLoopGetCurrent() == CFRunLoopGetMain());
+        webThreadShouldYield = false;
+        mainThreadLockCount++;
 #if LOG_MAIN_THREAD_LOCKING
-            if (!sendingDelegateMessage && lockCount == 1)
-                NSLog(@"Main thread locking outside of delegate messages.");
+        if (!sendingDelegateMessage && lockCount == 1)
+            NSLog(@"Main thread locking outside of delegate messages.");
 #endif
-        } else {
-            webThreadLockCount++;
-            if (webThreadLockCount > 1) {
-                NSLog(@"%s, %p: Multiple locks on web thread not allowed! Please file a bug. Crashing now...", __PRETTY_FUNCTION__, CurrentThreadContext());
-                CRASH();
-            }
+    } else {
+        webThreadLockCount++;
+        if (webThreadLockCount > 1) {
+            NSLog(@"%s, %p: Multiple locks on web thread not allowed! Please file a bug. Crashing now...", __PRETTY_FUNCTION__, CurrentThreadContext());
+            CRASH();
         }
     }
-    
-    return !busy;
 }
 
 void WebThreadLock(void)
@@ -856,12 +741,12 @@ void WebThreadUnlock(void)
     ASSERT(!WebThreadIsCurrent());
 }
 
-void WebThreadLockFromAnyThread()
+void WebThreadLockFromAnyThread(void)
 {
     _WebThreadLockFromAnyThread(true);
 }
     
-void WebThreadLockFromAnyThreadNoLog()
+void WebThreadLockFromAnyThreadNoLog(void)
 {
     _WebThreadLockFromAnyThread(false);
 }
@@ -878,14 +763,14 @@ static void _WebThreadLockFromAnyThread(bool shouldLog)
     if (shouldLog)
         NSLog(@"%s, %p: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.", __PRETTY_FUNCTION__, CurrentThreadContext());
 
-    pthread_mutex_lock(&webLock);
-    
+    webLock.lock();
+
     // This used for any thread other than the web thread.
     otherThreadLockCount++;
     webThreadShouldYield = false;
 }
 
-void WebThreadUnlockFromAnyThread()
+void WebThreadUnlockFromAnyThread(void)
 {
     if (!webThreadStarted)
         return;
@@ -896,22 +781,20 @@ void WebThreadUnlockFromAnyThread()
     
     ASSERT(otherThreadLockCount);
     otherThreadLockCount--;
-    
-    int result;
-    result = pthread_mutex_unlock(&webLock); 
-    ASSERT_WITH_MESSAGE(result == 0, "web unlock failed with code:%d", result);
+
+    webLock.unlock();
 }
 
-void WebThreadUnlockGuardForMail()
+void WebThreadUnlockGuardForMail(void)
 {
     ASSERT(!WebThreadIsCurrent());
 
-    CFRunLoopObserverRef mainRunLoopUnlockGuardObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopEntry, YES, 0, MainRunLoopUnlockGuard, NULL);
+    CFRunLoopObserverRef mainRunLoopUnlockGuardObserver = CFRunLoopObserverCreate(nullptr, kCFRunLoopEntry, YES, 0, MainRunLoopUnlockGuard, nullptr);
     CFRunLoopAddObserver(CFRunLoopGetMain(), mainRunLoopUnlockGuardObserver, kCFRunLoopCommonModes);
     CFRelease(mainRunLoopUnlockGuardObserver);
 }
 
-void _WebThreadUnlock(void)
+void _WebThreadUnlock()
 {
 #if LOG_WEB_LOCK || LOG_MAIN_THREAD_LOCKING
     lockCount--;
@@ -921,26 +804,25 @@ void _WebThreadUnlock(void)
 #endif
     
     if (!WebThreadIsCurrent()) {
-        ASSERT(mainThreadLockCount != 0);
+        ASSERT(mainThreadLockCount);
         mainThreadLockCount--;
     } else {    
         webThreadLockCount--;
         webThreadShouldYield = false;
     }
-    
-    int result;
-    result = pthread_mutex_unlock(&webLock); 
-    ASSERT_WITH_MESSAGE(result == 0, "web unlock failed with code:%d", result);    
+
+    webLock.unlock();
 }
 
 bool WebThreadIsLocked(void)
 {
     if (WebThreadIsCurrent())
         return webThreadLockCount;
-    else if (pthread_main_np())
+
+    if (pthread_main_np())
         return mainThreadLockCount;
-    else
-        return otherThreadLockCount;
+
+    return otherThreadLockCount;
 }
 
 bool WebThreadIsLockedOrDisabled(void)
@@ -963,7 +845,7 @@ void WebThreadLockPopModal(void)
         return;
     
     ASSERT(WebThreadIsLocked());
-    ASSERT(sMainThreadModalCount != 0);
+    ASSERT(sMainThreadModalCount);
     --sMainThreadModalCount;
 }
 
@@ -987,23 +869,21 @@ NSRunLoop* WebThreadNSRunLoop(void)
     return [NSRunLoop currentRunLoop];
 }
 
-WebThreadContext *WebThreadCurrentContext(void)
+WebThreadContextWebThreadCurrentContext(void)
 {
     return CurrentThreadContext();
 }
 
-void WebThreadSetDelegateSourceRunLoopMode(CFStringRef mode)
-{
-    ASSERT(!webThreadStarted);
-    delegateSourceRunLoopMode = mode;
-}
-
 void WebThreadEnable(void)
 {
     RELEASE_ASSERT_WITH_MESSAGE(!WebCore::IOSApplication::isWebProcess(), "The WebProcess should never run a Web Thread");
+    if (WebCore::IOSApplication::isSpringBoard()) {
+        using WebCore::LogThreading;
+        RELEASE_LOG_FAULT(Threading, "SpringBoard enabled WebThread.");
+    }
 
-    static pthread_once_t initControl = PTHREAD_ONCE_INIT;
-    pthread_once(&initControl, StartWebThread);
+    static std::once_flag flag;
+    std::call_once(flag, StartWebThread);
 }
 
 bool WebThreadIsEnabled(void)
@@ -1021,4 +901,4 @@ bool WebThreadNotCurrent(void)
     return webThreadStarted && !pthread_equal(webThread, pthread_self());
 }
 
-#endif // PLATFORM(IOS)
+#endif // PLATFORM(IOS_FAMILY)