-
Notifications
You must be signed in to change notification settings - Fork 369
Expand file tree
/
Copy pathWindowsJNAAffinity.java
More file actions
152 lines (130 loc) · 4.91 KB
/
WindowsJNAAffinity.java
File metadata and controls
152 lines (130 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
* Copyright 2013-2026 chronicle.software; SPDX-License-Identifier: Apache-2.0
*/
package net.openhft.affinity.impl;
import com.sun.jna.*;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.LongByReference;
import net.openhft.affinity.IAffinity;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.BitSet;
/**
* Implementation of {@link net.openhft.affinity.IAffinity} based on JNA call of
* sched_SetThreadAffinityMask/GetProcessAffinityMask from Windows 'kernel32' library. Applicable for
* most windows platforms
* <p> *
*
* @author andre.monteiro
*/
public enum WindowsJNAAffinity implements IAffinity {
INSTANCE;
public static final boolean LOADED;
private static final Logger LOGGER = LoggerFactory.getLogger(WindowsJNAAffinity.class);
private static final ThreadLocal<BitSet> currentAffinity = new ThreadLocal<>();
static {
boolean loaded = false;
try {
INSTANCE.getAffinity();
loaded = true;
} catch (UnsatisfiedLinkError e) {
LOGGER.warn("Unable to load jna library", e);
}
LOADED = loaded;
}
private final ThreadLocal<Integer> THREAD_ID = new ThreadLocal<>();
@Override
public BitSet getAffinity() {
BitSet bitSet = currentAffinity.get();
if (bitSet != null)
return bitSet;
BitSet longs = getAffinity0();
return longs != null ? longs : new BitSet();
}
@Override
public void setAffinity(final BitSet affinity) {
final CLibrary lib = CLibrary.INSTANCE;
WinDef.DWORD aff;
long[] longs = affinity.toLongArray();
switch (longs.length) {
case 0:
aff = new WinDef.DWORD(0);
break;
case 1:
aff = new WinDef.DWORD(longs[0]);
break;
default:
throw new IllegalArgumentException("Windows API does not support more than 64 CPUs for thread affinity");
}
int pid = getTid();
try {
lib.SetThreadAffinityMask(handle(pid), aff);
} catch (LastErrorException e) {
throw new IllegalStateException("SetThreadAffinityMask((" + pid + ") , &(" + affinity + ") ) errorNo=" + e.getErrorCode(), e);
}
BitSet affinity2 = getAffinity0();
assert affinity2 != null;
if (!affinity2.intersects(affinity)) {
LoggerFactory.getLogger(WindowsJNAAffinity.class).warn("Tried to set affinity to {} but was {} you may have insufficient access rights", affinity, affinity2);
}
currentAffinity.set((BitSet) affinity.clone());
}
@Nullable
private BitSet getAffinity0() {
final CLibrary lib = CLibrary.INSTANCE;
final LongByReference cpuset1 = new LongByReference(0);
final LongByReference cpuset2 = new LongByReference(0);
try {
final int ret = lib.GetProcessAffinityMask(handle(-1), cpuset1, cpuset2);
// Successful result is positive, according to the docs
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683213%28v=vs.85%29.aspx
if (ret <= 0) {
throw new IllegalStateException("GetProcessAffinityMask(( -1 ), &(" + cpuset1 + "), &(" + cpuset2 + ") ) return " + ret);
}
long[] longs = new long[1];
longs[0] = cpuset1.getValue();
return BitSet.valueOf(longs);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
return null;
}
private WinNT.HANDLE handle(int pid) {
return new WinNT.HANDLE(new Pointer(pid));
}
public int getTid() {
final CLibrary lib = CLibrary.INSTANCE;
try {
return lib.GetCurrentThread();
} catch (LastErrorException e) {
throw new IllegalStateException("GetCurrentThread( ) errorNo=" + e.getErrorCode(), e);
}
}
@Override
public int getCpu() {
return -1;
}
@Override
public int getProcessId() {
return Kernel32.INSTANCE.GetCurrentProcessId();
}
@Override
public int getThreadId() {
Integer tid = THREAD_ID.get();
if (tid == null)
THREAD_ID.set(tid = Kernel32.INSTANCE.GetCurrentThreadId());
return tid;
}
/**
* @author BegemoT
*/
private interface CLibrary extends Library {
CLibrary INSTANCE = Native.load("kernel32", CLibrary.class);
int GetProcessAffinityMask(final WinNT.HANDLE pid, final PointerType lpProcessAffinityMask, final PointerType lpSystemAffinityMask) throws LastErrorException;
void SetThreadAffinityMask(final WinNT.HANDLE pid, final WinDef.DWORD lpProcessAffinityMask) throws LastErrorException;
int GetCurrentThread() throws LastErrorException;
}
}