Skip to content
Permalink
Browse files
Replace more static Locks with CheckedLocks in WTF / WebCore
https://bugs.webkit.org/show_bug.cgi?id=226040

Reviewed by Darin Adler.

Replace more static Locks with CheckedLocks so that we can benefit from Clang Thread Safety Analysis.

Source/WebCore:

* Modules/indexeddb/server/IDBSerializationContext.cpp:
(WebCore::IDBServer::IDBSerializationContext::getOrCreateForCurrentThread):
(WebCore::IDBServer::IDBSerializationContext::~IDBSerializationContext):
* Modules/mediastream/RTCDataChannel.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::RTCDataChannel::detach):
(WebCore::RTCDataChannel::removeFromDataChannelLocalMapIfNeeded):
(WebCore::RTCDataChannel::handlerFromIdentifier):
* Modules/webdatabase/Database.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::Database::Database):
(WebCore::Database::performOpenAndVerify):
(WebCore::Database::closeDatabase):
(WebCore::Database::getCachedVersion const):
(WebCore::Database::setCachedVersion):
* Modules/webgpu/WebGPUDevice.cpp:
(WebCore::WebGPUDevice::instancesLock):
(WebCore::WebGPUDevice::~WebGPUDevice):
* Modules/webgpu/WebGPUDevice.h:
* Modules/webgpu/WebGPUPipeline.cpp:
(WebCore::WebGPUPipeline::instancesLock):
(WebCore::WebGPUPipeline::WebGPUPipeline):
(WebCore::WebGPUPipeline::~WebGPUPipeline):
* Modules/webgpu/WebGPUPipeline.h:
* Modules/websockets/WebSocket.cpp:
(WebCore::WebSocket::WebSocket):
(WebCore::WebSocket::~WebSocket):
(WebCore::WebSocket::allActiveWebSocketsLock):
* Modules/websockets/WebSocket.h:
* bridge/objc/WebScriptObject.mm:
(WebCore::getJSWrapper):
(WebCore::addJSWrapper):
(WebCore::removeJSWrapper):
(WebCore::removeJSWrapperIfRetainCountOne):
* crypto/CryptoAlgorithmRegistry.cpp:
(WebCore::CryptoAlgorithmRegistry::singleton):
(WebCore::CryptoAlgorithmRegistry::identifier):
(WebCore::CryptoAlgorithmRegistry::name):
(WebCore::CryptoAlgorithmRegistry::create):
(WebCore::CryptoAlgorithmRegistry::registerAlgorithm):
* crypto/CryptoAlgorithmRegistry.h:
* dom/MessagePort.cpp:
(WebCore::MessagePort::deref const):
(WebCore::MessagePort::isExistingMessagePortLocallyReachable):
(WebCore::MessagePort::notifyMessageAvailable):
(WebCore::MessagePort::MessagePort):
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::contextIdentifier const):
(WebCore::ScriptExecutionContext::removeFromContextsMap):
(WebCore::ScriptExecutionContext::~ScriptExecutionContext):
(WebCore::ScriptExecutionContext::postTaskTo):
* html/canvas/CanvasRenderingContext.cpp:
(WebCore::CanvasRenderingContext::instancesLock):
(WebCore::CanvasRenderingContext::CanvasRenderingContext):
(WebCore::CanvasRenderingContext::~CanvasRenderingContext):
* html/canvas/CanvasRenderingContext.h:
* html/canvas/WebGLProgram.cpp:
(WebCore::WebGLProgram::instancesLock):
(WebCore::WebGLProgram::WebGLProgram):
(WebCore::WebGLProgram::~WebGLProgram):
* html/canvas/WebGLProgram.h:
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::~WebGLRenderingContextBase):
* inspector/InspectorCanvas.cpp:
(WebCore::InspectorCanvas::canvasElement const):
(WebCore:: const):
* inspector/agents/InspectorCanvasAgent.cpp:
(WebCore::InspectorCanvasAgent::enable):
* inspector/agents/InspectorNetworkAgent.cpp:
(WebCore::InspectorNetworkAgent::enable):
(WebCore::InspectorNetworkAgent::webSocketForRequestId):
* inspector/agents/InspectorNetworkAgent.h:
* inspector/agents/page/PageNetworkAgent.cpp:
* inspector/agents/page/PageNetworkAgent.h:
* inspector/agents/worker/WorkerNetworkAgent.cpp:
* inspector/agents/worker/WorkerNetworkAgent.h:
* page/SecurityPolicy.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::SecurityPolicy::isAccessAllowed):
(WebCore::SecurityPolicy::addOriginAccessAllowlistEntry):
(WebCore::SecurityPolicy::removeOriginAccessAllowlistEntry):
(WebCore::SecurityPolicy::resetOriginAccessAllowlists):
(WebCore::SecurityPolicy::allowAccessTo):
* page/cocoa/ResourceUsageThreadCocoa.mm:
(WebCore::ResourceUsageThread::platformCollectCPUData):
* page/linux/ResourceUsageThreadLinux.cpp:
(WebCore::ResourceUsageThread::platformCollectCPUData):
* platform/GenericTaskQueue.cpp:
(WebCore::TaskDispatcher<Timer>::postTask):
(WebCore::TaskDispatcher<Timer>::sharedTimerFired):
(WebCore::TaskDispatcher<Timer>::pendingDispatchers):
(WebCore::TaskDispatcher<Timer>::dispatchOneTask):
* platform/GenericTaskQueue.h:
* platform/LegacySchemeRegistry.cpp:
(WebCore::allBuiltinSchemes):
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsLocal):
(WebCore::LegacySchemeRegistry::removeURLSchemeRegisteredAsLocal):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsHandledBySchemeHandler):
(WebCore::LegacySchemeRegistry::schemeIsHandledBySchemeHandler):
(WebCore::LegacySchemeRegistry::shouldTreatURLSchemeAsLocal):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsNoAccess):
(WebCore::LegacySchemeRegistry::shouldTreatURLSchemeAsNoAccess):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsDisplayIsolated):
(WebCore::LegacySchemeRegistry::shouldTreatURLSchemeAsDisplayIsolated):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsSecure):
(WebCore::LegacySchemeRegistry::shouldTreatURLSchemeAsSecure):
(WebCore::LegacySchemeRegistry::canDisplayOnlyIfCanRequest):
(WebCore::LegacySchemeRegistry::registerAsCanDisplayOnlyIfCanRequest):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy):
(WebCore::LegacySchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy):
(WebCore::LegacySchemeRegistry::schemeShouldBypassContentSecurityPolicy):
(WebCore::LegacySchemeRegistry::registerURLSchemeAsCachePartitioned):
(WebCore::LegacySchemeRegistry::shouldPartitionCacheForURLScheme):
* platform/audio/mac/FFTFrameMac.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::FFTFrame::fftSetupForSize):
* platform/graphics/MediaPlayer.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::installedMediaEngines):
(WebCore::MediaPlayer::resetMediaEngines):
* platform/ios/QuickLook.mm:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::removeQLPreviewConverterForURL):
(WebCore::addQLPreviewConverterWithFileForURL):
* platform/ios/WebSQLiteDatabaseTrackerClient.mm:
(WTF_REQUIRES_LOCK):
(+[WebDatabaseTransactionBackgroundTaskController startBackgroundTask]):
(+[WebDatabaseTransactionBackgroundTaskController endBackgroundTask]):
* platform/network/mac/UTIUtilities.mm:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::UTIFromMIMEType):
* platform/sql/SQLiteDatabase.cpp:
(WebCore::WTF_GUARDED_BY_LOCK):
(WebCore::SQLiteDatabase::setIsDatabaseOpeningForbidden):
(WebCore::SQLiteDatabase::open):
* platform/sql/SQLiteDatabaseTracker.cpp:
(WebCore::SQLiteDatabaseTracker::WTF_GUARDED_BY_LOCK):
(WebCore::SQLiteDatabaseTracker::setClient):
(WebCore::SQLiteDatabaseTracker::incrementTransactionInProgressCount):
(WebCore::SQLiteDatabaseTracker::decrementTransactionInProgressCount):
(WebCore::SQLiteDatabaseTracker::hasTransactionInProgress):
* platform/text/TextEncodingRegistry.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::newTextCodec):
(WebCore::atomCanonicalTextEncodingName):
* workers/WorkerGlobalScope.cpp:
(WebCore::WTF_REQUIRES_LOCK):
(WebCore::WorkerGlobalScope::WorkerGlobalScope):
(WebCore::WorkerGlobalScope::~WorkerGlobalScope):
(WebCore::WorkerGlobalScope::releaseMemoryInWorkers):
* workers/WorkerOrWorkletThread.cpp:
(WebCore::WorkerOrWorkletThread::workerOrWorkletThreadsLock):
(WebCore::WorkerOrWorkletThread::WorkerOrWorkletThread):
(WebCore::WorkerOrWorkletThread::~WorkerOrWorkletThread):
(WebCore::WorkerOrWorkletThread::releaseFastMallocFreeMemoryInAllThreads):
* workers/WorkerOrWorkletThread.h:

Source/WTF:

* wtf/Threading.cpp:
(WTF::Thread::allThreadsLock):
(WTF::Thread::create):
(WTF::Thread::didExit):
* wtf/Threading.h:
* wtf/URL.cpp:
(WTF::WTF_REQUIRES_LOCK):
(WTF::registerDefaultPortForProtocolForTesting):
(WTF::clearDefaultPortForProtocolMapForTesting):
(WTF::defaultPortForProtocol):
* wtf/cf/LanguageCF.cpp:
(WTF::WTF_REQUIRES_LOCK):
(WTF::platformLanguageDidChange):
(WTF::platformUserPreferredLanguages):
* wtf/text/StringView.cpp:
(WTF::StringView::invalidate):
(WTF::StringView::adoptUnderlyingString):
(WTF::StringView::setUnderlyingString):
* wtf/unicode/icu/CollatorICU.cpp:
(WTF::Collator::Collator):
(WTF::Collator::~Collator):


Canonical link: https://commits.webkit.org/238018@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@277880 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
cdumez committed May 21, 2021
1 parent 60e69e9 commit 3559a772ecafeb29939eb9e5a3bdae8261f33dad
Showing 52 changed files with 542 additions and 323 deletions.
@@ -1,3 +1,34 @@
2021-05-21 Chris Dumez <cdumez@apple.com>

Replace more static Locks with CheckedLocks in WTF / WebCore
https://bugs.webkit.org/show_bug.cgi?id=226040

Reviewed by Darin Adler.

Replace more static Locks with CheckedLocks so that we can benefit from Clang Thread Safety Analysis.

* wtf/Threading.cpp:
(WTF::Thread::allThreadsLock):
(WTF::Thread::create):
(WTF::Thread::didExit):
* wtf/Threading.h:
* wtf/URL.cpp:
(WTF::WTF_REQUIRES_LOCK):
(WTF::registerDefaultPortForProtocolForTesting):
(WTF::clearDefaultPortForProtocolMapForTesting):
(WTF::defaultPortForProtocol):
* wtf/cf/LanguageCF.cpp:
(WTF::WTF_REQUIRES_LOCK):
(WTF::platformLanguageDidChange):
(WTF::platformUserPreferredLanguages):
* wtf/text/StringView.cpp:
(WTF::StringView::invalidate):
(WTF::StringView::adoptUnderlyingString):
(WTF::StringView::setUnderlyingString):
* wtf/unicode/icu/CollatorICU.cpp:
(WTF::Collator::Collator):
(WTF::Collator::~Collator):

2021-05-21 Chris Dumez <cdumez@apple.com>

Use CheckedLock more in cases where we try-lock
@@ -41,6 +41,8 @@

namespace WTF {

CheckedLock Thread::s_allThreadsLock;

static Optional<size_t> stackSize(ThreadType threadType)
{
// Return the stack size for the created thread based on its type.
@@ -91,7 +93,7 @@ struct Thread::NewThreadContext : public ThreadSafeRefCounted<NewThreadContext>
#endif
};

HashSet<Thread*>& Thread::allThreads(const LockHolder&)
HashSet<Thread*>& Thread::allThreads()
{
static LazyNeverDestroyed<HashSet<Thread*>> allThreads;
static std::once_flag onceKey;
@@ -101,10 +103,9 @@ HashSet<Thread*>& Thread::allThreads(const LockHolder&)
return allThreads;
}

Lock& Thread::allThreadsMutex()
CheckedLock& Thread::allThreadsLock()
{
static Lock mutex;
return mutex;
return s_allThreadsLock;
}

const char* Thread::normalizeThreadName(const char* threadName)
@@ -218,9 +219,9 @@ Ref<Thread> Thread::create(const char* name, Function<void()>&& entryPoint, Thre
// called Thread::didExit to unregister itself from allThreads. Registering such a thread will register a stale thread pointer to allThreads, which will not be removed
// even after Thread is destroyed. Register a thread only when it has not unregistered itself from allThreads yet.
{
auto locker = holdLock(allThreadsMutex());
Locker locker { allThreadsLock() };
if (!thread->m_didUnregisterFromAllThreads)
allThreads(locker).add(thread.ptr());
allThreads().add(thread.ptr());
}

ASSERT(!thread->stack().isEmpty());
@@ -244,8 +245,8 @@ static bool shouldRemoveThreadFromThreadGroup()
void Thread::didExit()
{
{
auto locker = holdLock(allThreadsMutex());
allThreads(locker).remove(this);
Locker locker { allThreadsLock() };
allThreads().remove(this);
m_didUnregisterFromAllThreads = true;
}

@@ -33,6 +33,7 @@
#include <mutex>
#include <stdint.h>
#include <wtf/Atomics.h>
#include <wtf/CheckedLock.h>
#include <wtf/Expected.h>
#include <wtf/FastTLS.h>
#include <wtf/Function.h>
@@ -116,8 +117,8 @@ class Thread : public ThreadSafeRefCounted<Thread> {
static Thread& current();

// Set of all WTF::Thread created threads.
WTF_EXPORT_PRIVATE static HashSet<Thread*>& allThreads(const LockHolder&);
WTF_EXPORT_PRIVATE static Lock& allThreadsMutex();
WTF_EXPORT_PRIVATE static HashSet<Thread*>& allThreads() WTF_REQUIRES_LOCK(allThreadsLock());
WTF_EXPORT_PRIVATE static CheckedLock& allThreadsLock() WTF_RETURNS_LOCK(s_allThreadsLock);

WTF_EXPORT_PRIVATE unsigned numberOfThreadGroups();

@@ -328,6 +329,8 @@ class Thread : public ThreadSafeRefCounted<Thread> {
static Thread* currentMayBeNull();
#endif

static CheckedLock s_allThreadsLock;

JoinableState m_joinableState { Joinable };
bool m_isShuttingDown : 1;
bool m_didExit : 1;
@@ -30,6 +30,7 @@
#include "URLParser.h"
#include <stdio.h>
#include <unicode/uidna.h>
#include <wtf/CheckedLock.h>
#include <wtf/HashMap.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/PrintStream.h>
@@ -267,16 +268,16 @@ static void assertProtocolIsGood(StringView protocol)

#endif

static Lock defaultPortForProtocolMapForTestingLock;
static CheckedLock defaultPortForProtocolMapForTestingLock;

using DefaultPortForProtocolMapForTesting = HashMap<String, uint16_t>;
static DefaultPortForProtocolMapForTesting*& defaultPortForProtocolMapForTesting()
static DefaultPortForProtocolMapForTesting*& defaultPortForProtocolMapForTesting() WTF_REQUIRES_LOCK(defaultPortForProtocolMapForTestingLock)
{
static DefaultPortForProtocolMapForTesting* defaultPortForProtocolMap;
return defaultPortForProtocolMap;
}

static DefaultPortForProtocolMapForTesting& ensureDefaultPortForProtocolMapForTesting()
static DefaultPortForProtocolMapForTesting& ensureDefaultPortForProtocolMapForTesting() WTF_REQUIRES_LOCK(defaultPortForProtocolMapForTestingLock)
{
DefaultPortForProtocolMapForTesting*& defaultPortForProtocolMap = defaultPortForProtocolMapForTesting();
if (!defaultPortForProtocolMap)
@@ -286,25 +287,26 @@ static DefaultPortForProtocolMapForTesting& ensureDefaultPortForProtocolMapForTe

void registerDefaultPortForProtocolForTesting(uint16_t port, const String& protocol)
{
auto locker = holdLock(defaultPortForProtocolMapForTestingLock);
Locker locker { defaultPortForProtocolMapForTestingLock };
ensureDefaultPortForProtocolMapForTesting().add(protocol, port);
}

void clearDefaultPortForProtocolMapForTesting()
{
auto locker = holdLock(defaultPortForProtocolMapForTestingLock);
Locker locker { defaultPortForProtocolMapForTestingLock };
if (auto* map = defaultPortForProtocolMapForTesting())
map->clear();
}

Optional<uint16_t> defaultPortForProtocol(StringView protocol)
{
if (auto* overrideMap = defaultPortForProtocolMapForTesting()) {
auto locker = holdLock(defaultPortForProtocolMapForTestingLock);
ASSERT(overrideMap); // No need to null check again here since overrideMap cannot become null after being non-null.
auto iterator = overrideMap->find(protocol.toStringWithoutCopying());
if (iterator != overrideMap->end())
return iterator->value;
{
Locker locker { defaultPortForProtocolMapForTestingLock };
if (auto* overrideMap = defaultPortForProtocolMapForTesting()) {
auto iterator = overrideMap->find(protocol.toStringWithoutCopying());
if (iterator != overrideMap->end())
return iterator->value;
}
}
return URLParser::defaultPortForProtocol(protocol);
}
@@ -30,15 +30,15 @@
#include <mutex>
#include <unicode/uloc.h>
#include <wtf/Assertions.h>
#include <wtf/Lock.h>
#include <wtf/CheckedLock.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/RetainPtr.h>
#include <wtf/spi/cf/CFBundleSPI.h>
#include <wtf/text/WTFString.h>

namespace WTF {

static Lock preferredLanguagesMutex;
static CheckedLock preferredLanguagesLock;

#if PLATFORM(MAC)
static void languagePreferencesDidChange(CFNotificationCenterRef, void*, CFStringRef, const void*, CFDictionaryRef)
@@ -47,7 +47,7 @@ static void languagePreferencesDidChange(CFNotificationCenterRef, void*, CFStrin
}
#endif

static Vector<String>& preferredLanguages()
static Vector<String>& preferredLanguages() WTF_REQUIRES_LOCK(preferredLanguagesLock)
{
static LazyNeverDestroyed<Vector<String>> languages;
static std::once_flag onceKey;
@@ -91,7 +91,7 @@ static String httpStyleLanguageCode(CFStringRef language)
void platformLanguageDidChange()
{
{
auto locker = holdLock(preferredLanguagesMutex);
Locker locker { preferredLanguagesLock };
preferredLanguages().clear();
}
}
@@ -108,7 +108,7 @@ void listenForLanguageChangeNotifications()

Vector<String> platformUserPreferredLanguages()
{
auto locker = holdLock(preferredLanguagesMutex);
Locker locker { preferredLanguagesLock };
Vector<String>& userPreferredLanguages = preferredLanguages();

if (userPreferredLanguages.isEmpty()) {
@@ -30,8 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unicode/ubrk.h>
#include <unicode/unorm2.h>
#include <wtf/ASCIICType.h>
#include <wtf/CheckedLock.h>
#include <wtf/HashMap.h>
#include <wtf/Lock.h>
#include <wtf/Optional.h>
#include <wtf/text/StringToIntegerConversion.h>
#include <wtf/text/TextBreakIterator.h>
@@ -360,23 +360,19 @@ StringView::UnderlyingString::UnderlyingString(const StringImpl& string)
{
}

static Lock underlyingStringsMutex;
static CheckedLock underlyingStringsLock;

static HashMap<const StringImpl*, StringView::UnderlyingString*>& underlyingStrings()
static HashMap<const StringImpl*, StringView::UnderlyingString*>& underlyingStrings() WTF_REQUIRES_LOCK(underlyingStringsLock)
{
static LazyNeverDestroyed<HashMap<const StringImpl*, StringView::UnderlyingString*>> map;
static std::once_flag onceKey;
std::call_once(onceKey, [&] {
map.construct();
});
static NeverDestroyed<HashMap<const StringImpl*, StringView::UnderlyingString*>> map;
return map;
}

void StringView::invalidate(const StringImpl& stringToBeDestroyed)
{
UnderlyingString* underlyingString;
{
auto locker = holdLock(underlyingStringsMutex);
Locker locker { underlyingStringsLock };
underlyingString = underlyingStrings().take(&stringToBeDestroyed);
if (!underlyingString)
return;
@@ -393,7 +389,7 @@ bool StringView::underlyingStringIsValid() const
void StringView::adoptUnderlyingString(UnderlyingString* underlyingString)
{
if (m_underlyingString) {
auto locker = holdLock(underlyingStringsMutex);
Locker locker { underlyingStringsLock };
if (!--m_underlyingString->refCount) {
if (m_underlyingString->isValid) {
underlyingStrings().remove(&m_underlyingString->string);
@@ -410,7 +406,7 @@ void StringView::setUnderlyingString(const StringImpl* string)
if (!string)
underlyingString = nullptr;
else {
auto locker = holdLock(underlyingStringsMutex);
Locker locker { underlyingStringsLock };
auto result = underlyingStrings().add(string, nullptr);
if (result.isNewEntry)
result.iterator->value = new UnderlyingString(*string);
@@ -425,7 +421,7 @@ void StringView::setUnderlyingString(const StringView& otherString)
{
UnderlyingString* underlyingString = otherString.m_underlyingString;
if (underlyingString) {
// It's safe to inc the refCount here without locking underlyingStringsMutex
// It's safe to inc the refCount here without locking underlyingStringsLock
// because UnderlyingString::refCount is a std::atomic_uint, and we're
// guaranteed that the StringView we're copying it from will at least
// have 1 ref on it, thereby keeping it alive regardless of what other
@@ -35,7 +35,7 @@

#include <mutex>
#include <unicode/ucol.h>
#include <wtf/Lock.h>
#include <wtf/CheckedLock.h>
#include <wtf/text/StringView.h>

#if OS(DARWIN) && USE(CF)
@@ -45,12 +45,11 @@

namespace WTF {

static UCollator* cachedCollator;
static CheckedLock cachedCollatorLock;
static UCollator* cachedCollator WTF_GUARDED_BY_LOCK(cachedCollatorLock);
static char* cachedCollatorLocale;
static bool cachedCollatorShouldSortLowercaseFirst;

static Lock cachedCollatorMutex;

#if !(OS(DARWIN) && USE(CF))

static inline const char* resolveDefaultLocale(const char* locale)
@@ -106,7 +105,7 @@ Collator::Collator(const char* locale, bool shouldSortLowercaseFirst)
UErrorCode status = U_ZERO_ERROR;

{
auto locker = holdLock(cachedCollatorMutex);
Locker locker { cachedCollatorLock };
if (cachedCollator && localesMatch(cachedCollatorLocale, locale) && cachedCollatorShouldSortLowercaseFirst == shouldSortLowercaseFirst) {
m_collator = cachedCollator;
m_locale = cachedCollatorLocale;
@@ -136,7 +135,7 @@ Collator::Collator(const char* locale, bool shouldSortLowercaseFirst)

Collator::~Collator()
{
auto locker = holdLock(cachedCollatorMutex);
Locker locker { cachedCollatorLock };
if (cachedCollator) {
ucol_close(cachedCollator);
fastFree(cachedCollatorLocale);

0 comments on commit 3559a77

Please sign in to comment.