/* * Copyright (c) 2023 Meta * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include ZTEST(signal, test_sigemptyset) { sigset_t set; for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { set.sig[i] = -1; } zassert_ok(sigemptyset(&set)); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], 0u, "set.sig[%d] is not empty: 0x%lx", i, set.sig[i]); } } ZTEST(signal, test_sigfillset) { sigset_t set = (sigset_t){0}; zassert_ok(sigfillset(&set)); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], -1, "set.sig[%d] is not filled: 0x%lx", i, set.sig[i]); } } ZTEST(signal, test_sigaddset_oor) { sigset_t set = (sigset_t){0}; zassert_equal(sigaddset(&set, -1), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); zassert_equal(sigaddset(&set, 0), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); zassert_equal(sigaddset(&set, _NSIG), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); } ZTEST(signal, test_sigaddset) { int signo; sigset_t set = (sigset_t){0}; sigset_t target = (sigset_t){0}; signo = SIGHUP; zassert_ok(sigaddset(&set, signo)); WRITE_BIT(target.sig[0], signo, 1); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } signo = SIGSYS; zassert_ok(sigaddset(&set, signo)); WRITE_BIT(target.sig[0], signo, 1); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } signo = SIGRTMIN; /* >=32, will be in the second sig set for 32bit */ zassert_ok(sigaddset(&set, signo)); #ifdef CONFIG_64BIT WRITE_BIT(target.sig[0], signo, 1); #else /* 32BIT */ WRITE_BIT(target.sig[1], (signo)-BITS_PER_LONG, 1); #endif for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } signo = SIGRTMAX; zassert_ok(sigaddset(&set, signo)); WRITE_BIT(target.sig[signo / BITS_PER_LONG], signo % BITS_PER_LONG, 1); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } } ZTEST(signal, test_sigdelset_oor) { sigset_t set = (sigset_t){0}; zassert_equal(sigdelset(&set, -1), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); zassert_equal(sigdelset(&set, 0), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); zassert_equal(sigdelset(&set, _NSIG), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); } ZTEST(signal, test_sigdelset) { int signo; sigset_t set = (sigset_t){0}; sigset_t target = (sigset_t){0}; signo = SIGHUP; zassert_ok(sigdelset(&set, signo)); WRITE_BIT(target.sig[0], signo, 0); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } signo = SIGSYS; zassert_ok(sigdelset(&set, signo)); WRITE_BIT(target.sig[0], signo, 0); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } signo = SIGRTMIN; /* >=32, will be in the second sig set for 32bit */ zassert_ok(sigdelset(&set, signo)); #ifdef CONFIG_64BIT WRITE_BIT(target.sig[0], signo, 0); #else /* 32BIT */ WRITE_BIT(target.sig[1], (signo)-BITS_PER_LONG, 0); #endif for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } signo = SIGRTMAX; zassert_ok(sigdelset(&set, signo)); WRITE_BIT(target.sig[signo / BITS_PER_LONG], signo % BITS_PER_LONG, 0); for (int i = 0; i < ARRAY_SIZE(set.sig); i++) { zassert_equal(set.sig[i], target.sig[i], "set.sig[%d of %d] has content: %lx, expected %lx", i, ARRAY_SIZE(set.sig) - 1, set.sig[i], target.sig[i]); } } ZTEST(signal, test_sigismember_oor) { sigset_t set = {0}; zassert_equal(sigismember(&set, -1), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); zassert_equal(sigismember(&set, 0), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); zassert_equal(sigismember(&set, _NSIG), -1, "rc should be -1"); zassert_equal(errno, EINVAL, "errno should be %s", "EINVAL"); } ZTEST(signal, test_sigismember) { sigset_t set = (sigset_t){0}; #ifdef CONFIG_64BIT set.sig[0] = BIT(SIGHUP) | BIT(SIGSYS) | BIT(SIGRTMIN); #else /* 32BIT */ set.sig[0] = BIT(SIGHUP) | BIT(SIGSYS); set.sig[1] = BIT((SIGRTMIN)-BITS_PER_LONG); #endif WRITE_BIT(set.sig[SIGRTMAX / BITS_PER_LONG], SIGRTMAX % BITS_PER_LONG, 1); zassert_equal(sigismember(&set, SIGHUP), 1, "%s expected to be member", "SIGHUP"); zassert_equal(sigismember(&set, SIGSYS), 1, "%s expected to be member", "SIGSYS"); zassert_equal(sigismember(&set, SIGRTMIN), 1, "%s expected to be member", "SIGRTMIN"); zassert_equal(sigismember(&set, SIGRTMAX), 1, "%s expected to be member", "SIGRTMAX"); zassert_equal(sigismember(&set, SIGKILL), 0, "%s not expected to be member", "SIGKILL"); zassert_equal(sigismember(&set, SIGTERM), 0, "%s not expected to be member", "SIGTERM"); } ZTEST(signal, test_signal_strsignal) { /* Using -INT_MAX here because compiler resolves INT_MIN to (-2147483647 - 1) */ char buf[sizeof("RT signal -" STRINGIFY(INT_MAX))] = {0}; zassert_mem_equal(strsignal(-1), "Invalid signal", sizeof("Invalid signal")); zassert_mem_equal(strsignal(0), "Invalid signal", sizeof("Invalid signal")); zassert_mem_equal(strsignal(_NSIG), "Invalid signal", sizeof("Invalid signal")); zassert_mem_equal(strsignal(30), "Signal 30", sizeof("Signal 30")); snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMIN - SIGRTMIN); zassert_mem_equal(strsignal(SIGRTMIN), buf, strlen(buf)); snprintf(buf, sizeof(buf), "RT signal %d", SIGRTMAX - SIGRTMIN); zassert_mem_equal(strsignal(SIGRTMAX), buf, strlen(buf)); #ifdef CONFIG_POSIX_SIGNAL_STRING_DESC zassert_mem_equal(strsignal(SIGHUP), "Hangup", sizeof("Hangup")); zassert_mem_equal(strsignal(SIGSYS), "Bad system call", sizeof("Bad system call")); #else zassert_mem_equal(strsignal(SIGHUP), "Signal 1", sizeof("Signal 1")); zassert_mem_equal(strsignal(SIGSYS), "Signal 31", sizeof("Signal 31")); #endif } typedef int (*sigmask_fn)(int how, const sigset_t *set, sigset_t *oset); static void *test_sigmask_entry(void *arg) { /* for clarity */ #define SIG_GETMASK SIG_SETMASK enum { NEW, OLD, }; static sigset_t set[2]; const int invalid_how = 0x9a2ba9e; sigmask_fn sigmask = arg; /* invalid how results in EINVAL */ zassert_equal(sigmask(invalid_how, NULL, NULL), EINVAL); zassert_equal(sigmask(invalid_how, &set[NEW], &set[OLD]), EINVAL); /* verify setting / getting masks */ zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); zassert_ok(sigfillset(&set[OLD])); zassert_ok(sigmask(SIG_GETMASK, NULL, &set[OLD])); zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD])); zassert_ok(sigfillset(&set[NEW])); zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[OLD])); zassert_ok(sigmask(SIG_GETMASK, NULL, &set[OLD])); zassert_mem_equal(&set[OLD], &set[NEW], sizeof(set[OLD])); /* start with an empty mask */ zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); /* verify SIG_BLOCK: expect (SIGUSR1 | SIGUSR2 | SIGHUP) */ zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR1)); zassert_ok(sigmask(SIG_BLOCK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR2)); zassert_ok(sigaddset(&set[NEW], SIGHUP)); zassert_ok(sigmask(SIG_BLOCK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[OLD])); zassert_ok(sigaddset(&set[OLD], SIGUSR1)); zassert_ok(sigaddset(&set[OLD], SIGUSR2)); zassert_ok(sigaddset(&set[OLD], SIGHUP)); zassert_ok(sigmask(SIG_GETMASK, NULL, &set[NEW])); zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW])); /* start with full mask */ zassert_ok(sigfillset(&set[NEW])); zassert_ok(sigmask(SIG_SETMASK, &set[NEW], NULL)); /* verify SIG_UNBLOCK: expect ~(SIGUSR1 | SIGUSR2 | SIGHUP) */ zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR1)); zassert_ok(sigmask(SIG_UNBLOCK, &set[NEW], NULL)); zassert_ok(sigemptyset(&set[NEW])); zassert_ok(sigaddset(&set[NEW], SIGUSR2)); zassert_ok(sigaddset(&set[NEW], SIGHUP)); zassert_ok(sigmask(SIG_UNBLOCK, &set[NEW], NULL)); zassert_ok(sigfillset(&set[OLD])); zassert_ok(sigdelset(&set[OLD], SIGUSR1)); zassert_ok(sigdelset(&set[OLD], SIGUSR2)); zassert_ok(sigdelset(&set[OLD], SIGHUP)); zassert_ok(sigmask(SIG_GETMASK, NULL, &set[NEW])); zassert_mem_equal(&set[NEW], &set[OLD], sizeof(set[NEW])); return NULL; } ZTEST(signal, test_pthread_sigmask) { pthread_t th; zassert_ok(pthread_create(&th, NULL, test_sigmask_entry, pthread_sigmask)); zassert_ok(pthread_join(th, NULL)); } ZTEST(signal, test_sigprocmask) { if (IS_ENABLED(CONFIG_MULTITHREADING)) { if (!IS_ENABLED(CONFIG_ASSERT)) { zassert_not_ok(sigprocmask(SIG_SETMASK, NULL, NULL)); zassert_equal(errno, ENOSYS); } } else { pthread_t th; zassert_ok(pthread_create(&th, NULL, test_sigmask_entry, sigprocmask)); zassert_ok(pthread_join(th, NULL)); } } static void before(void *arg) { ARG_UNUSED(arg); if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) { /* skip redundant testing if there is no thread pool / heap allocation */ ztest_test_skip(); } } ZTEST_SUITE(signal, NULL, NULL, before, NULL, NULL);