package com.oracle.svm.core.posix;
import static com.oracle.svm.core.posix.headers.Signal.SignalEnum.SIGKILL;
import static com.oracle.svm.core.posix.headers.Signal.SignalEnum.SIGTERM;
import java.nio.file.Files;
import java.nio.file.Path;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.nativeimage.c.function.CEntryPointLiteral;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
import org.graalvm.word.PointerBase;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.BaseProcessPropertiesSupport;
import com.oracle.svm.core.posix.headers.Dlfcn;
import com.oracle.svm.core.posix.headers.LibC;
import com.oracle.svm.core.posix.headers.Signal;
import com.oracle.svm.core.posix.headers.Stdlib;
import com.oracle.svm.core.posix.headers.Unistd;
public abstract class PosixProcessPropertiesSupport extends BaseProcessPropertiesSupport {
@Override
public long getProcessID() {
return PosixUtils.getpid();
}
@Override
public long getProcessID(Process process) {
return PosixUtils.getpid(process);
}
@Override
public boolean destroy(long processID) {
return Signal.kill(Math.toIntExact(processID), SIGTERM.getCValue()) == 0;
}
@Override
public boolean destroyForcibly(long processID) {
return Signal.kill(Math.toIntExact(processID), SIGKILL.getCValue()) == 0;
}
@Override
public boolean isAlive(long processID) {
return Signal.kill(Math.toIntExact(processID), 0) == 0;
}
@Override
public int waitForProcessExit(long processID) {
return PosixUtils.waitForProcessExit(Math.toIntExact(processID));
}
@Override
public String getObjectFile(String symbol) {
return getObjectPathDefiningSymbol(symbol);
}
@Override
public String getObjectFile(CEntryPointLiteral<?> symbol) {
return getObjectPathDefiningAddress(symbol.getFunctionPointer());
}
@Override
public String setLocale(String category, String locale) {
return PosixUtils.setLocale(category, locale);
}
@Override
public void exec(Path executable, String[] args) {
if (!Files.isExecutable(executable)) {
throw new RuntimeException("Path " + executable + " does not point to executable file");
}
try (CTypeConversion.CCharPointerHolder pathHolder = CTypeConversion.toCString(executable.toString());
CTypeConversion.CCharPointerPointerHolder argvHolder = CTypeConversion.toCStrings(args)) {
if (Unistd.execv(pathHolder.get(), argvHolder.get()) != 0) {
String msg = PosixUtils.lastErrorString("Executing " + executable + " with arguments " + String.join(" ", args) + " failed");
throw new RuntimeException(msg);
}
}
}
static String getObjectPathDefiningSymbol(String symbol) {
try (CTypeConversion.CCharPointerHolder symbolHolder = CTypeConversion.toCString(symbol)) {
PointerBase symbolAddress = Dlfcn.dlsym(Dlfcn.RTLD_DEFAULT(), symbolHolder.get());
if (symbolAddress.isNull()) {
return null;
}
return getObjectPathDefiningAddress(symbolAddress);
}
}
static String getObjectPathDefiningAddress(PointerBase symbolAddress) {
Dlfcn.Dl_info info = StackValue.get(Dlfcn.Dl_info.class);
if (Dlfcn.dladdr(symbolAddress, info) == 0) {
return null;
}
CCharPointer realpath = Stdlib.realpath(info.dli_fname(), WordFactory.nullPointer());
if (realpath.isNull()) {
return null;
}
try {
return CTypeConversion.toJavaString(realpath);
} finally {
LibC.free(realpath);
}
}
protected static String realpath(String path) {
try (CCharPointerHolder pathHolder = CTypeConversion.toCString(path)) {
final CCharPointer realpathPointer = Stdlib.realpath(pathHolder.get(), WordFactory.nullPointer());
if (realpathPointer.isNull()) {
return null;
} else {
final String result = CTypeConversion.toJavaString(realpathPointer);
LibC.free(realpathPointer);
return result;
}
}
}
}