NDK 可以处理信号吗?
Can NDK handle signals?
这是一个对照实验,显示 NDK 无法处理主机设法处理的 SIGUSR1:https://github.com/champignoom/TestNDKBug。但是从我发现的任何文档中都不能明显看出 NDK 无法处理信号。
有人知道这里发生了什么吗?
repo 基本上是一个简单的 C 实验的包装器,可以为设备和主机编译,其中唯一的工作线程应该在其 10 次迭代的第 5 次被 SIGUSR1 中断:
#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
循环未在设备上中断:
...
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)
...
但在主机上被中断了(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
我们将不胜感激。
注意:AttachCurrentThread
/DetachCurrentThread
经测试与本实验无关。
事实证明,SIGUSR1 默认情况下被阻止,尽管没有被处理。
只需在 pthread_create
之前解锁 SIGUSR1 即可。
这是一个对照实验,显示 NDK 无法处理主机设法处理的 SIGUSR1:https://github.com/champignoom/TestNDKBug。但是从我发现的任何文档中都不能明显看出 NDK 无法处理信号。
有人知道这里发生了什么吗?
repo 基本上是一个简单的 C 实验的包装器,可以为设备和主机编译,其中唯一的工作线程应该在其 10 次迭代的第 5 次被 SIGUSR1 中断:
#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
循环未在设备上中断:
...
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)
...
但在主机上被中断了(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
我们将不胜感激。
注意:AttachCurrentThread
/DetachCurrentThread
经测试与本实验无关。
事实证明,SIGUSR1 默认情况下被阻止,尽管没有被处理。
只需在 pthread_create
之前解锁 SIGUSR1 即可。