@@ -17,12 +17,12 @@ import JavaKit
1717typealias JavaVMPointer = UnsafeMutablePointer < JavaVM ? >
1818
1919public final class JavaVirtualMachine : @unchecked Sendable {
20+ /// The JNI version that we depend on.
21+ static let jniVersion = JNI_VERSION_1_6
22+
2023 /// The Java virtual machine instance.
2124 private let jvm : JavaVMPointer
2225
23- /// The JNI environment for the JVM.
24- public let environment : JNIEnvironment
25-
2626 /// Initialize a new Java virtual machine instance.
2727 ///
2828 /// - Parameters:
@@ -41,7 +41,7 @@ public final class JavaVirtualMachine: @unchecked Sendable {
4141 var jvm : JavaVMPointer ? = nil
4242 var environment : UnsafeMutableRawPointer ? = nil
4343 var vmArgs = JavaVMInitArgs ( )
44- vmArgs. version = JNI_VERSION_1_6
44+ vmArgs. version = JavaVirtualMachine . jniVersion
4545 vmArgs. ignoreUnrecognized = jboolean ( ignoreUnrecognized ? JNI_TRUE : JNI_FALSE)
4646
4747 // Construct the complete list of VM options.
@@ -80,7 +80,6 @@ public final class JavaVirtualMachine: @unchecked Sendable {
8080 }
8181
8282 self . jvm = jvm!
83- self . environment = environment!. assumingMemoryBound ( to: JNIEnv ? . self)
8483 }
8584
8685 deinit {
@@ -89,10 +88,55 @@ public final class JavaVirtualMachine: @unchecked Sendable {
8988 fatalError ( " Failed to destroy the JVM. " )
9089 }
9190 }
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+ }
92134}
93135
94136extension JavaVirtualMachine {
95137 enum VMError : Error {
96138 case failedToCreateVM
139+ case failedToAttachThread
140+ case failedToDetachThread
97141 }
98142}
0 commit comments