1
+ /*
2
+ * Copyright (c) 2025 derreisende77.
3
+ * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
1
19
package mediathek.tool.affinity
2
20
3
- import com.sun.jna.Native
4
- import com.sun.jna.Pointer
5
- import com.sun.jna.platform.win32.Kernel32
6
- import com.sun.jna.platform.win32.WinNT.HANDLE
7
21
import org.apache.logging.log4j.LogManager
8
- import java.util.*
22
+ import java.lang.foreign.*
23
+ import java.lang.invoke.MethodHandle
9
24
10
25
class WindowsAffinity : IAffinity {
11
26
override fun setDesiredCpuAffinity (numCpus : Int ) {
12
- val pid = - 1 // current process
13
- val bitSet = BitSet ()
14
- bitSet[0 ] = numCpus
15
- val affinity = bitSet.stream()
16
- .takeWhile { i: Int -> i < java.lang.Long .SIZE }
17
- .mapToLong { i: Int -> 1L shl i }
18
- .reduce(0 ) { a: Long , b: Long -> a or b }
19
- val affinityMask = affinity.toInt()
20
- val instance = Native .load(" Kernel32" , AffinityKernel ::class .java)
21
- val result = instance.SetProcessAffinityMask (HANDLE (Pointer (pid.toLong())), affinityMask)
22
- if (result) {
23
- logger.info(" CPU affinity was set successfully." )
24
- logger.trace(" Available processors: {}" , Runtime .getRuntime().availableProcessors())
25
- } else logger.warn(" Failed to set CPU affinity." )
26
- }
27
+ require(numCpus in 1 .. 64 ) { " numCpus must be between 1 and 64" }
28
+
29
+ val affinityMask = (0 until numCpus).fold(0L ) { acc, i -> acc or (1L shl i) }
30
+
31
+ Linker .nativeLinker().let { linker ->
32
+ val symbolLookup = SymbolLookup .loaderLookup()
33
+
34
+ val getCurrentProcess: MethodHandle = linker.downcallHandle(
35
+ symbolLookup.find(" GetCurrentProcess" ).orElseThrow(),
36
+ FunctionDescriptor .of(ValueLayout .ADDRESS )
37
+ )
38
+
39
+ val setAffinity: MethodHandle = linker.downcallHandle(
40
+ symbolLookup.find(" SetProcessAffinityMask" ).orElseThrow(),
41
+ FunctionDescriptor .of(ValueLayout .JAVA_INT , ValueLayout .ADDRESS , ValueLayout .JAVA_LONG )
42
+ )
43
+
44
+ val processHandle = getCurrentProcess.invoke() as MemorySegment
45
+ val result = setAffinity.invoke(processHandle, affinityMask) as Int
27
46
28
- private interface AffinityKernel : Kernel32 {
29
- fun SetProcessAffinityMask (hProcess : HANDLE ? , dwProcessAffinityMask : Int ): Boolean
47
+ if (result != 0 ) {
48
+ logger.info(" CPU affinity was set successfully to mask: 0x${affinityMask.toString(16 )} " )
49
+ logger.trace(" Available processors: {}" , Runtime .getRuntime().availableProcessors())
50
+ } else {
51
+ logger.warn(" Failed to set CPU affinity." )
52
+ }
53
+ }
30
54
}
31
55
32
56
companion object {
33
57
private val logger = LogManager .getLogger()
34
58
}
35
- }
59
+ }
0 commit comments