Skip to content

Commit 28fb69f

Browse files
authored
Detach from any threads we have attached to. (#173)
1 parent c6545d7 commit 28fb69f

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

Sources/JavaKit/JavaKitVM/JavaVirtualMachine.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public final class JavaVirtualMachine: @unchecked Sendable {
2424
/// The JNI version that we depend on.
2525
static let jniVersion = JNI_VERSION_1_6
2626

27+
/// Thread-local storage to detach from thread on exit
28+
private static let destroyTLS = ThreadLocalStorage { _ in
29+
try? JavaVirtualMachine.shared().detachCurrentThread()
30+
}
31+
2732
/// The Java virtual machine instance.
2833
private let jvm: JavaVMPointer
2934

@@ -146,12 +151,14 @@ extension JavaVirtualMachine {
146151
throw attachError
147152
}
148153

154+
JavaVirtualMachine.destroyTLS.set(environment!)
155+
149156
return environment!.assumingMemoryBound(to: JNIEnv?.self)
150157
}
151158

152159
/// Detach the current thread from the Java Virtual Machine. All Java
153160
/// threads waiting for this thread to die are notified.
154-
public func detachCurrentThread() throws {
161+
func detachCurrentThread() throws {
155162
if let resultError = VMError(fromJNIError: jvm.pointee!.pointee.DetachCurrentThread(jvm)) {
156163
throw resultError
157164
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#if canImport(Darwin)
16+
import Darwin
17+
#elseif canImport(Bionic)
18+
import Bionic
19+
#elseif canImport(Glibc)
20+
import Glibc
21+
#elseif canImport(Musl)
22+
import Musl
23+
#elseif canImport(WinSDK)
24+
import WinSDK
25+
#endif
26+
27+
#if !(canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl) || canImport(WinSDK))
28+
private var _globalTlsValue: UnsafeMutableRawPointer?
29+
#endif
30+
31+
package struct ThreadLocalStorage: ~Copyable {
32+
#if canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl)
33+
private typealias PlatformKey = pthread_key_t
34+
#elseif canImport(WinSDK)
35+
private typealias PlatformKey = DWORD
36+
#else
37+
private typealias PlatformKey = Void
38+
#endif
39+
40+
#if canImport(Darwin)
41+
package typealias Value = UnsafeMutableRawPointer
42+
#else
43+
package typealias Value = UnsafeMutableRawPointer?
44+
#endif
45+
46+
package typealias OnThreadExit = @convention(c) (_: Value) -> ()
47+
48+
#if canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl)
49+
private var _key: PlatformKey
50+
#elseif canImport(WinSDK)
51+
private let _key: PlatformKey
52+
#endif
53+
54+
package init(onThreadExit: OnThreadExit) {
55+
#if canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl)
56+
_key = 0
57+
pthread_key_create(&_key, onThreadExit)
58+
#elseif canImport(WinSDK)
59+
key = FlsAlloc(onThreadExit)
60+
#endif
61+
}
62+
63+
package func get() -> UnsafeMutableRawPointer? {
64+
#if canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl)
65+
pthread_getspecific(_key)
66+
#elseif canImport(WinSDK)
67+
FlsGetValue(_key)
68+
#else
69+
_globalTlsValue
70+
#endif
71+
}
72+
73+
package func set(_ value: Value) {
74+
#if canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl)
75+
pthread_setspecific(_key, value)
76+
#elseif canImport(WinSDK)
77+
FlsSetValue(_key, value)
78+
#else
79+
_globalTlsValue = value
80+
#endif
81+
}
82+
83+
deinit {
84+
#if canImport(Darwin) || canImport(Bionic) || canImport(Glibc) || canImport(Musl)
85+
pthread_key_delete(_key)
86+
#elseif canImport(WinSDK)
87+
FlsFree(_key)
88+
#endif
89+
}
90+
}

0 commit comments

Comments
 (0)