/*
* Copyright (C) 2014 RoboVM AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.robovm.rt;
import static org.junit.Assert.*;
import org.junit.Test;
import org.robovm.rt.Signals.InstallSignalsCallback;
import org.robovm.rt.bro.Bro;
import org.robovm.rt.bro.annotation.Bridge;
import org.robovm.rt.bro.annotation.Callback;
import org.robovm.rt.bro.annotation.Library;
import org.robovm.rt.bro.annotation.Pointer;
/**
* Tests {@link Signals}.
*/
@Library("c")
public class SignalsTest {
static {
Bro.bind(SignalsTest.class);
}
private static final int SIGBUS = 10;
private static final int SIGSEGV = 11;
private static Object nullObj;
private static long oldHandlerSigbus;
private static long oldHandlerSigsegv;
private void triggerSOE() {
triggerSOE();
}
@Bridge native static int sigaction(int sig, @Pointer long act, @Pointer long oact);
@Bridge native static @Pointer long signal(int sig, @Pointer long func);
@Bridge native static int raise(int sig);
@Callback static void handler(int signum, @Pointer long info, @Pointer long context) {
// Dummy
}
private static long currentHandler(int sig) {
long h = signal(sig, 0);
signal(sig, h);
return h;
}
@Test
public void testInstallSignals() throws Exception {
// This is hard to test properly without generating a fatal signal and
// kill the process. We just make sure that NPE/SOE works fine after
// installSignals() has been called and that the handlers aren't the
// original non-chaining once and aren't handler().
final long handlerPtr = VM.getCallbackMethodImpl(SignalsTest.class.getDeclaredMethod("handler", int.class, long.class, long.class));
long oldSigactionSigbus = VM.malloc(512);
long oldSigactionSigsegv = VM.malloc(512);
try {
if (sigaction(SIGBUS, 0, oldSigactionSigbus) != 0) {
fail("sigaction");
}
if (sigaction(SIGSEGV, 0, oldSigactionSigsegv) != 0) {
fail("sigaction");
}
try {
Signals.installSignals(new InstallSignalsCallback() {
@Override
public void install() {
if (Bro.IS_DARWIN) {
oldHandlerSigbus = signal(SIGBUS, handlerPtr);
}
oldHandlerSigsegv = signal(SIGSEGV, handlerPtr);
}
});
// Make sure NPEs and SOEs still work properly
try {
nullObj.hashCode();
fail("NullPointerException expected");
} catch (NullPointerException e) {
}
try {
triggerSOE();
fail("StackOverflowError expected");
} catch (StackOverflowError e) {
}
if (Bro.IS_DARWIN) {
assertNotEquals(handlerPtr, currentHandler(SIGBUS));
assertNotEquals(oldHandlerSigbus, currentHandler(SIGBUS));
}
assertNotEquals(handlerPtr, currentHandler(SIGSEGV));
assertNotEquals(oldHandlerSigsegv, currentHandler(SIGSEGV));
try {
Signals.installSignals(new InstallSignalsCallback() {
@Override
public void install() {
}
});
fail("IllegalStateException expected");
} catch (IllegalStateException e) {
}
} finally {
sigaction(SIGBUS, oldSigactionSigbus, 0);
sigaction(SIGSEGV, oldSigactionSigsegv, 0);
}
} finally {
VM.free(oldSigactionSigbus);
VM.free(oldSigactionSigsegv);
}
}
}