package com.oracle.svm.core.windows;
import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.FromAlias;
import static org.graalvm.nativeimage.c.function.CFunction.Transition.NO_TRANSITION;
import java.util.Hashtable;
import org.graalvm.nativeimage.ImageInfo;
import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.jdk.Jvm;
import com.oracle.svm.core.jdk.Package_jdk_internal_misc;
import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport;
import com.oracle.svm.core.jdk.RuntimeSupport;
import com.oracle.svm.core.thread.JavaThreads;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.core.windows.headers.WinBase;
@TargetClass(classNameProvider = Package_jdk_internal_misc.class, className = "Signal")
final class Target_jdk_internal_misc_Signal {
@Alias @RecomputeFieldValue(kind = FromAlias)
private static Hashtable<?, ?> handlers = new Hashtable<>(4);
@Alias @RecomputeFieldValue(kind = FromAlias)
private static Hashtable<?, ?> signals = new Hashtable<>(4);
@Alias
static native void dispatch(int number);
@Substitute
private static long handle0(int sig, long nativeH) {
if (ImageInfo.isSharedLibrary()) {
throw new IllegalArgumentException("Installing signal handlers is not allowed for native-image shared libraries.");
}
if (!PlatformNativeLibrarySupport.singleton().isFirstIsolate()) {
throw new IllegalArgumentException("Only the first isolate can install signal handlers, as signal handling is global for the process.");
}
SignalDispatcher.ensureInitialized();
return Jvm.JVM_RegisterSignal(sig, WordFactory.pointer(nativeH)).rawValue();
}
}
class SignalDispatcher implements Runnable {
private static final int NEAR_MAX_PRIORITY = Thread.MAX_PRIORITY - 1;
private static final Thread signalDispatcherThread;
static {
signalDispatcherThread = new Thread(JavaThreads.singleton().systemGroup,
new SignalDispatcher(), "Signal Dispatcher");
signalDispatcherThread.setPriority(NEAR_MAX_PRIORITY);
signalDispatcherThread.setDaemon(true);
}
@Override
public void run() {
while (true) {
int sig = osSignalWait();
if (sig == osSigexitnumPd()) {
return;
} else {
Target_jdk_internal_misc_Signal.dispatch(sig);
}
}
}
@CFunction("os__signal_wait")
private static native int osSignalWait();
@CFunction(value = "os__sigexitnum_pd", transition = NO_TRANSITION)
private static native int osSigexitnumPd();
static void ensureInitialized() {
if (signalDispatcherThread.getState() == Thread.State.NEW) {
if (!jdkMiscSignalInit()) {
VMError.shouldNotReachHere("Native state initialization for jdk.internal.misc.Signal failed with error code: 0x" +
Integer.toUnsignedString(WinBase.GetLastError(), 16).toUpperCase());
}
RuntimeSupport.getRuntimeSupport().addTearDownHook(SignalDispatcher::osTerminateSignalThread);
signalDispatcherThread.start();
}
}
@CFunction(value = "jdk_misc_signal_init", transition = NO_TRANSITION)
private static native boolean jdkMiscSignalInit();
@CFunction(value = "os__terminate_signal_thread", transition = NO_TRANSITION)
private static native void osTerminateSignalThread();
}