Skip to content

Commit 4ada7ab

Browse files
committed
Fix handling of affinity lock when specific CPU is requested. Fixes OpenHFT#43.
1 parent 9a9926e commit 4ada7ab

4 files changed

Lines changed: 47 additions & 10 deletions

File tree

affinity/src/main/java/net/openhft/affinity/AffinityLock.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class AffinityLock implements Closeable {
4646
public static final BitSet RESERVED_AFFINITY;
4747
private static final Logger LOGGER = LoggerFactory.getLogger(AffinityLock.class);
4848
private static final LockInventory LOCK_INVENTORY;
49+
static final int ANY_CPU = -1;
4950

5051
static {
5152
int processors = Runtime.getRuntime().availableProcessors();
@@ -164,7 +165,7 @@ public static AffinityLock acquireCore() {
164165
* @return A handle for an affinity lock.
165166
*/
166167
public static AffinityLock acquireLock(boolean bind) {
167-
return acquireLock(bind, -1, AffinityStrategies.ANY);
168+
return acquireLock(bind, ANY_CPU, AffinityStrategies.ANY);
168169
}
169170

170171

@@ -190,7 +191,7 @@ public static AffinityLock acquireLock(int cpuId) {
190191
* @return A handle for an affinity lock.
191192
*/
192193
public static AffinityLock acquireCore(boolean bind) {
193-
return acquireCore(bind, -1, AffinityStrategies.ANY);
194+
return acquireCore(bind, ANY_CPU, AffinityStrategies.ANY);
194195
}
195196

196197
private static AffinityLock acquireLock(boolean bind, int cpuId, @NotNull AffinityStrategy... strategies) {

affinity/src/main/java/net/openhft/affinity/LockInventory.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,24 +83,33 @@ public final synchronized void set(CpuLayout cpuLayout) {
8383
}
8484

8585
public final synchronized AffinityLock acquireLock(boolean bind, int cpuId, AffinityStrategy... strategies) {
86+
final boolean specificCpuRequested = !isAnyCpu(cpuId);
87+
if (specificCpuRequested && cpuId != 0) {
88+
final AffinityLock required = logicalCoreLocks[cpuId];
89+
if (required.canReserve() && anyStrategyMatches(cpuId, cpuId, strategies)) {
90+
updateLockForCurrentThread(bind, required, false);
91+
return required;
92+
}
93+
}
8694

95+
LOGGER.warn("Unable to acquire lock on CPU {} for thread {}, trying to find another CPU",
96+
cpuId, Thread.currentThread());
8797

8898
for (AffinityStrategy strategy : strategies) {
8999
// consider all processors except cpu 0 which is usually used by the OS.
90100
// if you have only one core, this library is not appropriate in any case.
91101
for (int i = logicalCoreLocks.length - 1; i > 0; i--) {
92102
AffinityLock al = logicalCoreLocks[i];
93-
if (al.canReserve() && (cpuId < 0 || strategy.matches(cpuId, al.cpuId()))) {
94-
al.assignCurrentThread(bind, false);
95-
LockCheck.updateCpu(al.cpuId());
103+
if (al.canReserve() && (isAnyCpu(cpuId) || strategy.matches(cpuId, al.cpuId()))) {
104+
updateLockForCurrentThread(bind, al, false);
96105
return al;
97106
}
98107
}
99108
}
100109

101110
LOGGER.warn("No reservable CPU for {}", Thread.currentThread());
102111

103-
return newLock(-1, false, false);
112+
return newLock(AffinityLock.ANY_CPU, false, false);
104113
}
105114

106115
public final synchronized AffinityLock acquireCore(boolean bind, int cpuId, AffinityStrategy... strategies) {
@@ -112,8 +121,7 @@ public final synchronized AffinityLock acquireCore(boolean bind, int cpuId, Affi
112121
continue LOOP;
113122

114123
final AffinityLock al = als[0];
115-
al.assignCurrentThread(bind, true);
116-
LockCheck.updateCpu(al.cpuId());
124+
updateLockForCurrentThread(bind, al, true);
117125
return al;
118126
}
119127
}
@@ -196,4 +204,22 @@ private void releaseAffinityLock(final Thread t, final AffinityLock al, final St
196204
LOGGER.warn("Failed to delete lock file at " + lockFilePath);
197205
}
198206
}
207+
208+
private static boolean anyStrategyMatches(final int cpuOne, final int cpuTwo, final AffinityStrategy[] strategies) {
209+
for (AffinityStrategy strategy : strategies) {
210+
if (strategy.matches(cpuOne, cpuTwo)) {
211+
return true;
212+
}
213+
}
214+
return false;
215+
}
216+
217+
private static boolean isAnyCpu(final int cpuId) {
218+
return cpuId == AffinityLock.ANY_CPU;
219+
}
220+
221+
private static void updateLockForCurrentThread(final boolean bind, final AffinityLock al, final boolean b) {
222+
al.assignCurrentThread(bind, b);
223+
LockCheck.updateCpu(al.cpuId());
224+
}
199225
}

affinity/src/main/java/net/openhft/affinity/NonForkingAffinityLock.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static AffinityLock acquireCore() {
6868
* @return A handle for an affinity lock.
6969
*/
7070
public static AffinityLock acquireLock(boolean bind) {
71-
return acquireLock(bind, -1, AffinityStrategies.ANY);
71+
return acquireLock(bind, AffinityLock.ANY_CPU, AffinityStrategies.ANY);
7272
}
7373

7474
/**
@@ -80,7 +80,7 @@ public static AffinityLock acquireLock(boolean bind) {
8080
* @return A handle for an affinity lock.
8181
*/
8282
public static AffinityLock acquireCore(boolean bind) {
83-
return acquireCore(bind, -1, AffinityStrategies.ANY);
83+
return acquireCore(bind, AffinityLock.ANY_CPU, AffinityStrategies.ANY);
8484
}
8585

8686
private static AffinityLock acquireLock(boolean bind, int cpuId, @NotNull AffinityStrategy... strategies) {

affinity/src/test/java/net/openhft/affinity/AffinityLockTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import static org.junit.Assert.assertEquals;
3434
import static org.junit.Assert.assertNotSame;
3535
import static org.junit.Assert.assertThat;
36+
import static org.junit.Assume.assumeTrue;
3637

3738
/**
3839
* @author peter.lawrey
@@ -222,6 +223,15 @@ public void run() {
222223
displayStatus();
223224
}
224225

226+
@Test
227+
public void shouldReturnLockForSpecifiedCpu() {
228+
assumeTrue(Runtime.getRuntime().availableProcessors() > 3);
229+
230+
try (final AffinityLock affinityLock = AffinityLock.acquireLock(2)) {
231+
assertThat(affinityLock.cpuId(), is(2));
232+
}
233+
}
234+
225235
@Test
226236
public void lockFilesShouldBeRemovedOnRelease() {
227237
final AffinityLock lock = AffinityLock.acquireLock();

0 commit comments

Comments
 (0)