Issue
Here's a controlled experiment showing that NDK fails to handle SIGUSR1 which the host manages to handle: https://github.com/champignoom/TestNDKBug. But it's not evident from any documentation I could find that the NDK could not handle signals.
Does anyone have an idea of what is happening here?
The repo is basically a wrapper around a simple experiment in C that can be compiled both for the device and for the host, where the only worker thread is supposed to be interrupted by SIGUSR1 at the 5th of its 10 iterations:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <signal.h>
#ifdef TEST_HOST
#define printlog(...) fprintf(stderr, __VA_ARGS__)
#else
#include <jni.h>
#include <android/log.h>
#define printlog(...) __android_log_print(ANDROID_LOG_DEBUG, "TestNDKBug", __VA_ARGS__)
#endif
static const struct timespec DURATION = { .tv_sec = 0, .tv_nsec = 200LL*1000*1000 };
static const struct timespec DURATION5 = { .tv_sec = 1, .tv_nsec = 0 };
static void *do_thread(void *_arg) {
for (int i=0; i<10; ++i) {
printlog("loop %d\n", i);
if (nanosleep(&DURATION, NULL)) {
perror("nanosleep thread");
}
}
return NULL;
}
static void signal_handler(int _sig) {
fprintf(stderr, "signal received\n");
pthread_exit(NULL);
}
void do_main() {
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_restorer = NULL;
sa.sa_sigaction = NULL;
sa.sa_handler = signal_handler;
if (sigemptyset(&sa.sa_mask)) {
perror("sigemptyset");
exit(1);
}
if (sigaction(SIGUSR1, &sa, NULL)) {
perror("sigaction");
exit(1);
}
pthread_t pid;
if (pthread_create(&pid, NULL, do_thread, NULL)) {
perror("pthread_create");
exit(1);
}
if (nanosleep(&DURATION5, NULL)) {
perror("nanosleep main");
}
if (pthread_kill(pid, SIGUSR1)) {
perror("pthread_kill");
exit(1);
}
if (pthread_join(pid, NULL)) {
perror("pthread_join");
}
}
#ifdef TEST_HOST
int main() {
do_main();
return 0;
}
#else
JNIEXPORT void JNICALL
Java_com_champignoom_testndkbug_NDKWrapper_run_1native(JNIEnv *env, jclass clazz) {
do_main();
}
#endif
The loop was not interrupted on the device:
...
2021-02-08 15:36:48.273 21420-21454/com.champignoom.testndkbug I/TestRunner: started: test(com.champignoom.testndkbug.InstrumentedTest)
2021-02-08 15:36:48.279 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 0
2021-02-08 15:36:48.479 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 1
2021-02-08 15:36:48.679 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 2
2021-02-08 15:36:48.880 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 3
2021-02-08 15:36:49.082 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 4
2021-02-08 15:36:49.283 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 5
2021-02-08 15:36:49.483 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 6
2021-02-08 15:36:49.684 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 7
2021-02-08 15:36:49.885 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 8
2021-02-08 15:36:50.085 21420-21456/com.champignoom.testndkbug D/TestNDKBug: loop 9
2021-02-08 15:36:50.286 21420-21454/com.champignoom.testndkbug I/TestRunner: finished: test(com.champignoom.testndkbug.InstrumentedTest)
...
but was interrupted on the host (gcc -DTEST_HOST app/src/main/cpp/native-lib.c -lpthread -std=gnu11 -o ./test-ndk-bug && ./test-ndk-bug
):
loop 0
loop 1
loop 2
loop 3
loop 4
signal received
Any help will be appreciated.
NB: AttachCurrentThread
/DetachCurrentThread
are tested to be irrelevant for this experiment.
Solution
Turns out that SIGUSR1 is by default blocked, although not handled.
Simply unblock SIGUSR1 before pthread_create
and it works.
Answered By - Sylvain Hubert
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.