Skip to content

Java9 fixes #181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions affinity/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@
<profile>
<id>make-c</id>
<activation>
<os>
<family>linux</family>
<arch>!arm</arch>
</os>
<property>
<name>!dontMake</name>
</property>
Expand Down
49 changes: 43 additions & 6 deletions affinity/src/main/java/net/openhft/affinity/BootClassPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
Expand All @@ -39,21 +41,56 @@ enum BootClassPath {
private static Set<String> getResourcesOnBootClasspath() {
final Logger logger = LoggerFactory.getLogger(BootClassPath.class);
final Set<String> resources = new HashSet<>();

final String bootClassPath = System.getProperty("sun.boot.class.path", "");
logger.trace("Boot class-path is: {}", bootClassPath);
if (!bootClassPath.isEmpty()) {
logger.trace("Boot class-path is: {}", bootClassPath);

final String pathSeparator = System.getProperty("path.separator");
logger.trace("Path separator is: '{}'", pathSeparator);
final String pathSeparator = File.pathSeparator;
logger.trace("Path separator is: '{}'", pathSeparator);

final String[] pathElements = bootClassPath.split(pathSeparator);
final String[] pathElements = bootClassPath.split(pathSeparator);

for (final String pathElement : pathElements) {
resources.addAll(findResources(Paths.get(pathElement), logger));
for (final String pathElement : pathElements) {
resources.addAll(findResources(Paths.get(pathElement), logger));
}
} else {
resources.addAll(findResourcesInJrt(logger));
}

return resources;
}

private static Set<String> findResourcesInJrt(final Logger logger) {
final Set<String> jrtResources = new HashSet<>();
try {
FileSystem fs;
try {
fs = FileSystems.getFileSystem(URI.create("jrt:/"));
} catch (FileSystemNotFoundException | ProviderNotFoundException e) {
fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap());
}
final Path modules = fs.getPath("/modules");
Files.walkFileTree(modules, new SimpleFileVisitor<Path>() {
@Override
public @NotNull FileVisitResult visitFile(final @NotNull Path file,
final @NotNull BasicFileAttributes attrs) throws IOException {
if (file.getFileName().toString().endsWith(".class")) {
Path relative = modules.relativize(file);
if (relative.getNameCount() > 1) {
Path classPath = relative.subpath(1, relative.getNameCount());
jrtResources.add(classPath.toString());
}
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
logger.warn("Error walking jrt filesystem", e);
}
return jrtResources;
}

private static Set<String> findResources(final Path path, final Logger logger) {
if (!Files.exists(path)) {
return Collections.emptySet();
Expand Down
8 changes: 5 additions & 3 deletions affinity/src/main/java/net/openhft/affinity/LockCheck.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package net.openhft.affinity;

import net.openhft.affinity.impl.Utilities;
import net.openhft.affinity.lockchecker.FileLockBasedLockChecker;
import net.openhft.affinity.lockchecker.LockChecker;
import org.slf4j.Logger;
Expand All @@ -39,9 +40,7 @@ public enum LockCheck {
private static final LockChecker lockChecker = FileLockBasedLockChecker.getInstance();

public static long getPID() {
String processName =
java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
return Long.parseLong(processName.split("@")[0]);
return Utilities.currentProcessId();
}

static boolean canOSSupportOperation() {
Expand Down Expand Up @@ -79,6 +78,9 @@ private synchronized static boolean isLockFree(int id) {
}

public static int getProcessForCpu(int core) throws IOException {
if (!canOSSupportOperation())
return EMPTY_PID;

String meta = lockChecker.getMetaInfo(core);

if (meta != null && !meta.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.util.BitSet;

/**
Expand All @@ -48,8 +47,7 @@ public int getCpu() {

@Override
public int getProcessId() {
final String name = ManagementFactory.getRuntimeMXBean().getName();
return Integer.parseInt(name.split("@")[0]);
return Utilities.currentProcessId();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.util.BitSet;

/**
Expand Down Expand Up @@ -55,8 +54,7 @@ public int getCpu() {

@Override
public int getProcessId() {
final String name = ManagementFactory.getRuntimeMXBean().getName();
return Integer.parseInt(name.split("@")[0]);
return Utilities.currentProcessId();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.util.BitSet;

/**
Expand Down Expand Up @@ -55,8 +54,7 @@ public int getCpu() {

@Override
public int getProcessId() {
final String name = ManagementFactory.getRuntimeMXBean().getName();
return Integer.parseInt(name.split("@")[0]);
return Utilities.currentProcessId();
}

@Override
Expand Down
26 changes: 26 additions & 0 deletions affinity/src/main/java/net/openhft/affinity/impl/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,30 @@ private static boolean is64Bit0() {
systemProp = System.getProperty("java.vm.version");
return systemProp != null && systemProp.contains("_64");
}

/**
* Returns the current process id. Uses {@code ProcessHandle} when running
* on Java&nbsp;9 or later and falls back to parsing
* {@code RuntimeMXBean#getName()} on earlier versions.
*
* @return the process id or {@code -1} if it cannot be determined
*/
public static int currentProcessId() {
try {
// Java 9+ provides ProcessHandle which has a pid() method.
Class<?> phClass = Class.forName("java.lang.ProcessHandle");
Object current = phClass.getMethod("current").invoke(null);
long pid = (Long) phClass.getMethod("pid").invoke(current);
return (int) pid;
} catch (Throwable ignored) {
// ignore and fallback to the pre-Java 9 approach
}

try {
String name = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
return Integer.parseInt(name.split("@")[0]);
} catch (Throwable e) {
return -1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ public void setAffinity(final BitSet affinity) {
throw new IllegalStateException("SetThreadAffinityMask((" + pid + ") , &(" + affinity + ") ) errorNo=" + e.getErrorCode(), e);
}
BitSet affinity2 = getAffinity0();
if (!affinity2.equals(affinity)) {
LoggerFactory.getLogger(WindowsJNAAffinity.class).warn("Tried to set affinity to " + affinity + " but was " + affinity2 + " you may have insufficient access rights");
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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import net.openhft.affinity.impl.Utilities;
import net.openhft.affinity.impl.VanillaCpuLayout;
import net.openhft.chronicle.testframework.Waiters;
import org.hamcrest.MatcherAssert;
import org.junit.Test;
import org.slf4j.Logger;
Expand Down Expand Up @@ -334,19 +335,17 @@ public void acquireLockWithoutBindingDoesNotChangeAffinity() {

@Test
public void testTooHighCpuId() {
AffinityLock lock = AffinityLock.acquireLock(123456);
assertFalse(lock.isBound());
assertFalse(AffinityLock.acquireLock(123456).isBound());
}

@Test
public void testNegativeCpuId() {
AffinityLock lock = AffinityLock.acquireLock(-1);
assertFalse(lock.isBound());
assertFalse(AffinityLock.acquireLock(-1).isBound());
}

@Test
public void testTooHighCpuId2() {
AffinityLock lock = AffinityLock.acquireLock(new int[]{-1, 123456});
AffinityLock lock = AffinityLock.acquireLock(new int[]{123456});
assertFalse(lock.isBound());
}

Expand All @@ -365,10 +364,7 @@ public void bindingTwoThreadsToSameCpuThrows() throws InterruptedException {
});
t.start();

while (!lock.isBound()) {
//noinspection BusyWait
Thread.sleep(10);
}
Waiters.waitForCondition("Waiting for lock to be bound", lock::isBound, 1000);

try {
lock.bind();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
public class BootClassPathTest {
@Test
public void shouldDetectClassesOnClassPath() {
if (!System.getProperty("java.version").startsWith("1.8"))
return;
assertTrue(BootClassPath.INSTANCE.has("java.lang.Thread"));
assertTrue(BootClassPath.INSTANCE.has("java.lang.Runtime"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,37 @@ public void shouldNotBlowUpIfPidFileIsEmpty() throws Exception {

LockCheck.isCpuFree(cpu);
}

@Test
public void lockFileDeletedWhileHeld() throws Exception {
cpu++;

Assert.assertTrue(LockCheck.isCpuFree(cpu));
LockCheck.updateCpu(cpu, 0);

File lockFile = lockChecker.doToFile(cpu);
Assert.assertTrue(lockFile.exists());

Assert.assertTrue("Could not delete lock file", lockFile.delete());
Assert.assertFalse(lockFile.exists());

Assert.assertFalse("CPU should remain locked despite missing file", LockCheck.isCpuFree(cpu));
Assert.assertEquals(LockCheck.getPID(), LockCheck.getProcessForCpu(cpu));

LockCheck.releaseLock(cpu);

Assert.assertTrue("Lock should be free after release", LockCheck.isCpuFree(cpu));
LockCheck.updateCpu(cpu, 0);

lockFile = lockChecker.doToFile(cpu);
Assert.assertTrue("Lock file should be recreated", lockFile.exists());
}

@Test
public void getProcessForCpuReturnsEmptyPidWhenNoFile() throws IOException {
int freeCpu = 99;
File lockFile = lockChecker.doToFile(freeCpu);
Assert.assertFalse(lockFile.exists());
Assert.assertEquals(Integer.MIN_VALUE, LockCheck.getProcessForCpu(freeCpu));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public void testPidOnLinux() {
Assert.assertTrue(LockCheck.isProcessRunning(LockCheck.getPID()));
}

@Test
public void testNegativePidOnLinux() {
Assert.assertFalse(LockCheck.isProcessRunning(-1));
}

@Test
public void testReplace() throws IOException {
cpu++;
Expand Down