@@ -17,12 +17,12 @@ import JavaKit
17
17
typealias JavaVMPointer = UnsafeMutablePointer < JavaVM ? >
18
18
19
19
public final class JavaVirtualMachine : @unchecked Sendable {
20
+ /// The JNI version that we depend on.
21
+ static let jniVersion = JNI_VERSION_1_6
22
+
20
23
/// The Java virtual machine instance.
21
24
private let jvm : JavaVMPointer
22
25
23
- /// The JNI environment for the JVM.
24
- public let environment : JNIEnvironment
25
-
26
26
/// Initialize a new Java virtual machine instance.
27
27
///
28
28
/// - Parameters:
@@ -41,7 +41,7 @@ public final class JavaVirtualMachine: @unchecked Sendable {
41
41
var jvm : JavaVMPointer ? = nil
42
42
var environment : UnsafeMutableRawPointer ? = nil
43
43
var vmArgs = JavaVMInitArgs ( )
44
- vmArgs. version = JNI_VERSION_1_6
44
+ vmArgs. version = JavaVirtualMachine . jniVersion
45
45
vmArgs. ignoreUnrecognized = jboolean ( ignoreUnrecognized ? JNI_TRUE : JNI_FALSE)
46
46
47
47
// Construct the complete list of VM options.
@@ -80,7 +80,6 @@ public final class JavaVirtualMachine: @unchecked Sendable {
80
80
}
81
81
82
82
self . jvm = jvm!
83
- self . environment = environment!. assumingMemoryBound ( to: JNIEnv ? . self)
84
83
}
85
84
86
85
deinit {
@@ -89,10 +88,55 @@ public final class JavaVirtualMachine: @unchecked Sendable {
89
88
fatalError ( " Failed to destroy the JVM. " )
90
89
}
91
90
}
91
+
92
+ /// Produce the JNI environment for the active thread, attaching this
93
+ /// thread to the JVM if it isn't already.
94
+ ///
95
+ /// - Parameter
96
+ /// - asDaemon: Whether this thread should be treated as a daemon
97
+ /// thread in the Java Virtual Machine.
98
+ public func environment( asDaemon: Bool = false ) throws -> JNIEnvironment {
99
+ // Check whether this thread is already attached. If so, return the
100
+ // corresponding environment.
101
+ var environment : UnsafeMutableRawPointer ? = nil
102
+ let getEnvResult = jvm. pointee!. pointee. GetEnv (
103
+ jvm,
104
+ & environment,
105
+ JavaVirtualMachine . jniVersion
106
+ )
107
+ if getEnvResult == JNI_OK, let environment {
108
+ return environment. assumingMemoryBound ( to: JNIEnv ? . self)
109
+ }
110
+
111
+ // Attach the current thread to the JVM.
112
+ let attachResult : jint
113
+ if asDaemon {
114
+ attachResult = jvm. pointee!. pointee. AttachCurrentThreadAsDaemon ( jvm, & environment, nil )
115
+ } else {
116
+ attachResult = jvm. pointee!. pointee. AttachCurrentThread ( jvm, & environment, nil )
117
+ }
118
+
119
+ if attachResult == JNI_OK, let environment {
120
+ return environment. assumingMemoryBound ( to: JNIEnv ? . self)
121
+ }
122
+
123
+ throw VMError . failedToAttachThread
124
+ }
125
+
126
+ /// Detach the current thread from the Java Virtual Machine. All Java
127
+ /// threads waiting for this thread to die are notified.
128
+ public func detachCurrentThread( ) throws {
129
+ let result = jvm. pointee!. pointee. DetachCurrentThread ( jvm)
130
+ if result != JNI_OK {
131
+ throw VMError . failedToDetachThread
132
+ }
133
+ }
92
134
}
93
135
94
136
extension JavaVirtualMachine {
95
137
enum VMError : Error {
96
138
case failedToCreateVM
139
+ case failedToAttachThread
140
+ case failedToDetachThread
97
141
}
98
142
}
0 commit comments