Skip to content

Commit f4818ea

Browse files
authored
Merge pull request #19289 from mikeash/thread-local-storage-dedicated-keys
[Runtime][Stdlib] Use dedicated thread-local storage keys when possible.
2 parents e6a5aca + 29ff3de commit f4818ea

File tree

10 files changed

+255
-162
lines changed

10 files changed

+255
-162
lines changed

stdlib/public/SwiftShims/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(sources
1313
SwiftStddef.h
1414
SwiftStdint.h
1515
System.h
16+
ThreadLocalStorage.h
1617
UnicodeShims.h
1718
Visibility.h
1819

stdlib/public/SwiftShims/LibcShims.h

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -189,35 +189,6 @@ double lgamma_r(double x, int *psigngam);
189189
long double lgammal_r(long double x, int *psigngam);
190190
#endif // defined(__APPLE__)
191191

192-
// TLS - thread local storage
193-
194-
#if defined(__linux__)
195-
# if defined(__ANDROID__)
196-
typedef int __swift_thread_key_t;
197-
# else
198-
typedef unsigned int __swift_thread_key_t;
199-
# endif
200-
#elif defined(__FreeBSD__)
201-
typedef int __swift_thread_key_t;
202-
#elif defined(_WIN32)
203-
typedef unsigned long __swift_thread_key_t;
204-
#elif defined(__HAIKU__)
205-
typedef int __swift_thread_key_t;
206-
#else
207-
typedef unsigned long __swift_thread_key_t;
208-
#endif
209-
210-
SWIFT_RUNTIME_STDLIB_INTERNAL
211-
int _stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key,
212-
void (* _Nullable destructor)(void * _Nullable));
213-
214-
SWIFT_RUNTIME_STDLIB_INTERNAL
215-
void * _Nullable _stdlib_thread_getspecific(__swift_thread_key_t key);
216-
217-
SWIFT_RUNTIME_STDLIB_INTERNAL
218-
int _stdlib_thread_setspecific(__swift_thread_key_t key,
219-
const void * _Nullable value);
220-
221192
#ifdef __cplusplus
222193
}} // extern "C", namespace swift
223194
#endif
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===--- ThreadLocalStorage.h - Wrapper for thread-local storage. --*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_STDLIB_SHIMS_THREADLOCALSTORAGE_H
14+
#define SWIFT_STDLIB_SHIMS_THREADLOCALSTORAGE_H
15+
16+
#include "Visibility.h"
17+
18+
SWIFT_RUNTIME_STDLIB_INTERNAL
19+
void * _Nonnull _swift_stdlib_threadLocalStorageGet(void);
20+
21+
#endif // SWIFT_STDLIB_SHIMS_THREADLOCALSTORAGE_H

stdlib/public/SwiftShims/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module SwiftShims {
1313
header "SwiftStddef.h"
1414
header "SwiftStdint.h"
1515
header "System.h"
16+
header "ThreadLocalStorage.h"
1617
header "UnicodeShims.h"
1718
header "Visibility.h"
1819
export *

stdlib/public/core/ThreadLocalStorage.swift

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,8 @@ internal struct _ThreadLocalStorage {
6464
internal static func getPointer()
6565
-> UnsafeMutablePointer<_ThreadLocalStorage>
6666
{
67-
let tlsRawPtr = _stdlib_thread_getspecific(_tlsKey)
68-
if _fastPath(tlsRawPtr != nil) {
69-
return tlsRawPtr._unsafelyUnwrappedUnchecked.assumingMemoryBound(
70-
to: _ThreadLocalStorage.self)
71-
}
72-
73-
return _initializeThreadLocalStorage()
67+
return _swift_stdlib_threadLocalStorageGet().assumingMemoryBound(
68+
to: _ThreadLocalStorage.self)
7469
}
7570

7671
internal static func getUBreakIterator(
@@ -105,23 +100,10 @@ internal func _destroyTLS(_ ptr: UnsafeMutableRawPointer?) {
105100
#endif
106101
}
107102

108-
// Lazily created global key for use with pthread TLS
109-
internal let _tlsKey: __swift_thread_key_t = {
110-
let sentinelValue = __swift_thread_key_t.max
111-
var key: __swift_thread_key_t = sentinelValue
112-
let success = _stdlib_thread_key_create(&key, _destroyTLS)
113-
_sanityCheck(success == 0, "somehow failed to create TLS key")
114-
_sanityCheck(key != sentinelValue, "Didn't make a new key")
115-
return key
116-
}()
117-
118-
@inline(never)
119-
internal func _initializeThreadLocalStorage()
103+
@_silgen_name("_stdlib_createTLS")
104+
internal func _createThreadLocalStorage()
120105
-> UnsafeMutablePointer<_ThreadLocalStorage>
121106
{
122-
_sanityCheck(_stdlib_thread_getspecific(_tlsKey) == nil,
123-
"already initialized")
124-
125107
// Create and initialize one.
126108
var err = __swift_stdlib_U_ZERO_ERROR
127109
let newUBreakIterator = __swift_stdlib_ubrk_open(
@@ -136,7 +118,5 @@ internal func _initializeThreadLocalStorage()
136118
tlsPtr.initialize(
137119
to: _ThreadLocalStorage(_uBreakIterator: newUBreakIterator)
138120
)
139-
let success = _stdlib_thread_setspecific(_tlsKey, tlsPtr)
140-
_sanityCheck(success == 0, "setspecific failed")
141121
return tlsPtr
142122
}

stdlib/public/runtime/Exclusivity.cpp

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,43 +14,15 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "swift/Basic/Lazy.h"
1718
#include "swift/Runtime/Config.h"
1819
#include "swift/Runtime/Debug.h"
1920
#include "swift/Runtime/Exclusivity.h"
2021
#include "swift/Runtime/Metadata.h"
22+
#include "ThreadLocalStorage.h"
2123
#include <memory>
2224
#include <stdio.h>
2325

24-
// Pick an implementation strategy.
25-
#ifndef SWIFT_EXCLUSIVITY_USE_THREADLOCAL
26-
27-
// If we're using Clang, and Clang claims not to support thread_local,
28-
// it must be because we're on a platform that doesn't support it.
29-
// Use pthreads.
30-
// Workaround: has_feature(cxx_thread_local) is wrong on two old Apple
31-
// simulators. clang thinks thread_local works there, but it doesn't.
32-
#if TARGET_OS_SIMULATOR && !TARGET_RT_64_BIT && \
33-
((TARGET_OS_IOS && __IPHONE_OS_VERSION_MIN_REQUIRED__ < 100000) || \
34-
(TARGET_OS_WATCH && __WATCHOS_OS_VERSION_MIN_REQUIRED__ < 30000))
35-
// 32-bit iOS 9 simulator or 32-bit watchOS 2 simulator - use pthreads
36-
# define SWIFT_EXCLUSIVITY_USE_THREADLOCAL 0
37-
# define SWIFT_EXCLUSIVITY_USE_PTHREAD_SPECIFIC 1
38-
#elif __clang__ && !__has_feature(cxx_thread_local)
39-
// clang without thread_local support - use pthreads
40-
# define SWIFT_EXCLUSIVITY_USE_THREADLOCAL 0
41-
# define SWIFT_EXCLUSIVITY_USE_PTHREAD_SPECIFIC 1
42-
#else
43-
// Use thread_local
44-
# define SWIFT_EXCLUSIVITY_USE_THREADLOCAL 1
45-
# define SWIFT_EXCLUSIVITY_USE_PTHREAD_SPECIFIC 0
46-
#endif
47-
48-
#endif
49-
50-
#if SWIFT_EXCLUSIVITY_USE_PTHREAD_SPECIFIC
51-
#include <pthread.h>
52-
#endif
53-
5426
// Pick a return-address strategy
5527
#if __GNUC__
5628
#define get_return_address() __builtin_return_address(0)
@@ -277,46 +249,63 @@ class AccessSet {
277249
// Each of these cases should define a function with this prototype:
278250
// AccessSets &getAllSets();
279251

280-
#if SWIFT_EXCLUSIVITY_USE_THREADLOCAL
281-
// Use direct language support for thread-locals.
252+
#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC
253+
// Use the reserved TSD key if possible.
254+
255+
static AccessSet &getAccessSet() {
256+
AccessSet *set = static_cast<AccessSet*>(
257+
SWIFT_THREAD_GETSPECIFIC(SWIFT_EXCLUSIVITY_TLS_KEY));
258+
if (set)
259+
return *set;
260+
261+
static OnceToken_t setupToken;
262+
SWIFT_ONCE_F(setupToken, [](void *) {
263+
pthread_key_init_np(SWIFT_EXCLUSIVITY_TLS_KEY, [](void *pointer) {
264+
delete static_cast<AccessSet*>(pointer);
265+
});
266+
}, nullptr);
267+
268+
set = new AccessSet();
269+
SWIFT_THREAD_SETSPECIFIC(SWIFT_EXCLUSIVITY_TLS_KEY, set);
270+
return *set;
271+
}
272+
273+
#elif SWIFT_TLS_HAS_THREADLOCAL
274+
// Second choice is direct language support for thread-locals.
282275

283-
static_assert(LLVM_ENABLE_THREADS, "LLVM_THREAD_LOCAL will use a global?");
284276
static LLVM_THREAD_LOCAL AccessSet ExclusivityAccessSet;
285277

286278
static AccessSet &getAccessSet() {
287279
return ExclusivityAccessSet;
288280
}
289281

290-
#elif SWIFT_EXCLUSIVITY_USE_PTHREAD_SPECIFIC
291-
// Use pthread_getspecific.
282+
#else
283+
// Use the platform thread-local data API.
292284

293-
static pthread_key_t createAccessSetPthreadKey() {
294-
pthread_key_t key;
295-
int result = pthread_key_create(&key, [](void *pointer) {
285+
static __swift_thread_key_t createAccessSetThreadKey() {
286+
__swift_thread_key_t key;
287+
int result = SWIFT_THREAD_KEY_CREATE(&key, [](void *pointer) {
296288
delete static_cast<AccessSet*>(pointer);
297289
});
298290

299291
if (result != 0) {
300-
fatalError(0, "couldn't create pthread key for exclusivity: %s\n",
292+
fatalError(0, "couldn't create thread key for exclusivity: %s\n",
301293
strerror(result));
302294
}
303295
return key;
304296
}
305297

306298
static AccessSet &getAccessSet() {
307-
static pthread_key_t key = createAccessSetPthreadKey();
299+
static __swift_thread_key_t key = createAccessSetThreadKey();
308300

309-
AccessSet *set = static_cast<AccessSet*>(pthread_getspecific(key));
301+
AccessSet *set = static_cast<AccessSet*>(SWIFT_THREAD_GETSPECIFIC(key));
310302
if (!set) {
311303
set = new AccessSet();
312-
pthread_setspecific(key, set);
304+
SWIFT_THREAD_SETSPECIFIC(key, set);
313305
}
314306
return *set;
315307
}
316308

317-
/** An access set accessed via pthread_get_specific. *************************/
318-
#else
319-
#error No implementation chosen for exclusivity!
320309
#endif
321310

322311
/// Begin tracking a dynamic access.
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===--- ThreadLocalStorage.h - Thread-local storage interface. --*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_RUNTIME_THREADLOCALSTORAGE_H
14+
#define SWIFT_RUNTIME_THREADLOCALSTORAGE_H
15+
16+
#include "llvm/Support/Compiler.h"
17+
#include "swift/Runtime/Config.h"
18+
19+
// Depending on the target, we may be able to use dedicated TSD keys or
20+
// thread_local variables. When dedicated TSD keys aren't available,
21+
// wrap the target's API for thread-local data for things that don't want
22+
// to use thread_local.
23+
24+
// On Apple platforms, we have dedicated TSD keys.
25+
#if defined(__APPLE__)
26+
# define SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC 1
27+
#endif
28+
29+
// If we're using Clang, and Clang claims not to support thread_local,
30+
// it must be because we're on a platform that doesn't support it.
31+
#if __clang__ && !__has_feature(cxx_thread_local)
32+
// No thread_local.
33+
#else
34+
// Otherwise, we do have thread_local.
35+
# define SWIFT_TLS_HAS_THREADLOCAL 1
36+
static_assert(LLVM_ENABLE_THREADS, "LLVM_THREAD_LOCAL will use a global?");
37+
#endif
38+
39+
#if SWIFT_TLS_HAS_RESERVED_PTHREAD_SPECIFIC
40+
// Use reserved TSD keys.
41+
# if __has_include(<pthread/tsd_private.h>)
42+
# include <pthread/tsd_private.h>
43+
# else
44+
// We still need to use the SPI for setting the destructor, so declare it here.
45+
extern "C" int pthread_key_init_np(int key, void (*destructor)(void *));
46+
# endif
47+
48+
// If the keys are not available from the header, define them ourselves. The values match
49+
// what tsd_private.h provides.
50+
# ifndef __PTK_FRAMEWORK_SWIFT_KEY0
51+
# define __PTK_FRAMEWORK_SWIFT_KEY0 100
52+
# endif
53+
# ifndef __PTK_FRAMEWORK_SWIFT_KEY1
54+
# define __PTK_FRAMEWORK_SWIFT_KEY1 101
55+
# endif
56+
57+
# define SWIFT_EXCLUSIVITY_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY0
58+
# define SWIFT_STDLIB_TLS_KEY __PTK_FRAMEWORK_SWIFT_KEY1
59+
60+
#endif
61+
62+
// If the reserved key path didn't already provide get/setspecific macros,
63+
// wrap the platform's APIs.
64+
#ifndef SWIFT_THREAD_GETSPECIFIC
65+
66+
// Pick the right typedef for the key.
67+
# if defined(__linux__)
68+
# if defined(__ANDROID__)
69+
typedef int __swift_thread_key_t;
70+
# else
71+
typedef unsigned int __swift_thread_key_t;
72+
# endif
73+
# elif defined(__FreeBSD__)
74+
typedef int __swift_thread_key_t;
75+
# elif defined(_WIN32)
76+
typedef unsigned long __swift_thread_key_t;
77+
# elif defined(__HAIKU__)
78+
typedef int __swift_thread_key_t;
79+
# else
80+
typedef unsigned long __swift_thread_key_t;
81+
# endif
82+
83+
# if defined(_WIN32) && !defined(__CYGWIN__)
84+
// Windows has its own flavor of API.
85+
# include <io.h>
86+
# define WIN32_LEAN_AND_MEAN
87+
# include <Windows.h>
88+
static_assert(std::is_same<__swift_thread_key_t, DWORD>::value,
89+
"__swift_thread_key_t is not a DWORD");
90+
91+
# if defined(_M_IX86)
92+
typedef stdcall void (*__swift_thread_key_destructor)(void *)
93+
# else
94+
typedef void (*__swift_thread_key_destructor)(void *)
95+
# endif
96+
97+
static inline
98+
_stdlib_thread_key_create(__swift_thread_key_t * _Nonnull key,
99+
__swift_thread_key_destructor _Nullable destructor) {
100+
*key = FlsAlloc(destroyTLS_CCAdjustmentThunk);
101+
return *key != FLS_OUT_OF_INDEXES;
102+
}
103+
104+
# define SWIFT_THREAD_KEY_CREATE _stdlib_thread_key_create
105+
# define SWIFT_THREAD_GETSPECIFIC FlsGetValue
106+
# define SWIFT_THREAD_SETSPECIFIC(key, value) (FlsSetValue(key, value) == TRUE)
107+
108+
# else
109+
// Otherwise use the pthread API.
110+
# include <pthread.h>
111+
# define SWIFT_THREAD_KEY_CREATE pthread_key_create
112+
# define SWIFT_THREAD_GETSPECIFIC pthread_getspecific
113+
# define SWIFT_THREAD_SETSPECIFIC pthread_setspecific
114+
# endif
115+
#endif
116+
117+
#endif // SWIFT_RUNTIME_THREADLOCALSTORAGE_H

stdlib/public/stubs/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(swift_stubs_sources
55
KeyPaths.cpp
66
LibcShims.cpp
77
Stubs.cpp
8+
ThreadLocalStorage.cpp
89
MathStubs.cpp
910
)
1011
set(swift_stubs_objc_sources

0 commit comments

Comments
 (0)