Introduce posix tests package

This commit is contained in:
Justine Tunney 2023-11-12 05:41:30 -08:00
parent 48bd3d85df
commit f7cad70da1
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
8 changed files with 453 additions and 0 deletions

View file

@ -221,6 +221,7 @@ include third_party/nsync/testing/testing.mk
include libc/testlib/testlib.mk include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk include tool/viz/lib/vizlib.mk
include tool/args/args.mk include tool/args/args.mk
include test/posix/test.mk
include test/tool/args/test.mk include test/tool/args/test.mk
include third_party/linenoise/linenoise.mk include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk include third_party/maxmind/maxmind.mk

115
test/posix/mask_test.c Normal file
View file

@ -0,0 +1,115 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
volatile sig_atomic_t cpu_signal_received = 0;
volatile sig_atomic_t io_signal_received = 0;
// Declare thread IDs
pthread_t cpu_thread_id;
pthread_t io_thread_id;
void signal_handler(int signum) {
// Set the flag to indicate the signal was received
if (pthread_equal(pthread_self(), cpu_thread_id)) {
cpu_signal_received = 1;
} else if (pthread_equal(pthread_self(), io_thread_id)) {
io_signal_received = 1;
}
}
void *cpu_bound_task(void *arg) {
// Unblock SIGUSR1 for this thread
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
// Simulate CPU-bound work
while (!cpu_signal_received) {
// Busy-wait loop
}
return NULL;
}
void *io_bound_task(void *arg) {
// Unblock SIGUSR1 for this thread
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
// Simulate I/O-bound work
sleep(1); // Use sleep to simulate waiting for I/O
return NULL;
}
int main() {
// Install the signal handler
struct sigaction sa;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
// Failed to install signal handler
exit(1);
}
// Block SIGUSR1 in the main thread
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
// Failed to set signal mask
exit(2);
}
// Create the CPU-bound and I/O-bound threads
if (pthread_create(&cpu_thread_id, NULL, &cpu_bound_task, NULL) != 0) {
// Failed to create the CPU-bound thread
exit(3);
}
if (pthread_create(&io_thread_id, NULL, &io_bound_task, NULL) != 0) {
// Failed to create the I/O-bound thread
exit(4);
}
/* sleep(1); */
// Raise the signal for both threads
pthread_kill(cpu_thread_id, SIGUSR1);
pthread_kill(io_thread_id, SIGUSR1);
// Wait for both threads to finish
pthread_join(cpu_thread_id, NULL);
pthread_join(io_thread_id, NULL);
// Check if both threads received the signal
if (cpu_signal_received && io_signal_received) {
// Both signals were successfully caught
exit(0);
} else {
// One or both signals were not caught
exit(5);
}
}

View file

@ -0,0 +1,79 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
volatile sig_atomic_t signal_handled_count;
void reentrant_signal_handler(int signum) {
// waste stack memory to test raise() won't recurse
volatile char burn_stack[3500];
burn_stack[3000] = 0;
burn_stack[0] = 3;
// Increment the count to indicate the signal was handled
if (++signal_handled_count == 10000) return;
// Re-raise the signal to test reentrancy
raise(signum | burn_stack[3000]);
}
void *child_thread_func(void *arg) {
// Send SIGUSR2 to the main thread
pthread_kill(*((pthread_t *)arg), SIGUSR2);
return NULL;
}
int main() {
pthread_t main_thread_id = pthread_self();
pthread_t child_thread;
struct sigaction sa;
// Install the signal handler for SIGUSR2
sa.sa_handler = reentrant_signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR2, &sa, NULL) == -1) {
exit(1); // Failed to install signal handler
}
// Create the child thread
if (pthread_create(&child_thread, NULL, &child_thread_func,
&main_thread_id) != 0) {
exit(2); // Failed to create child thread
}
// Wait for the signal to be handled
while (signal_handled_count < 10000) {
// Busy wait
}
// Wait for child thread to finish
pthread_join(child_thread, NULL);
// Check if the signal was handled reentrantly
if (signal_handled_count == 10000) {
exit(0); // Success
} else {
exit(3); // The signal was not handled twice as expected
}
}

View file

@ -0,0 +1,39 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include <signal.h>
volatile int gotsig;
void OnSig(int sig) {
gotsig = sig;
}
int main() {
struct sigaction sa;
sa.sa_handler = OnSig;
sa.sa_flags = SA_RESETHAND;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, 0)) return 1;
if (sigaction(SIGUSR1, 0, &sa)) return 2;
if (sa.sa_handler != OnSig) return 3;
if (raise(SIGUSR1)) return 4;
if (gotsig != SIGUSR1) return 5;
if (sigaction(SIGUSR1, 0, &sa)) return 6;
if (sa.sa_handler != SIG_DFL) return 7;
}

104
test/posix/sigchld_test.c Normal file
View file

@ -0,0 +1,104 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <spawn.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <ucontext.h>
#include <unistd.h>
// clang-format off
// sh -c 'build/bootstrap/make.com -j8 V=1 o//test/posix/sigchld_test.com.runs'
// clang-format on
void Assert(const char *file, int line, bool ok) {
sigset_t ss;
if (!ok) {
sigfillset(&ss);
sigprocmask(SIG_BLOCK, &ss, 0);
fprintf(stderr, "%s:%d: assertion failed\n", file, line);
_exit(1);
}
}
#define FL __FILE__, __LINE__
#define ASSERT_TRUE(got) Assert(FL, got)
#define EXPECT_TRUE(got) Assert(FL, got)
#define EXPECT_EQ(want, got) Assert(FL, (want) == (got))
#define ASSERT_EQ(want, got) Assert(FL, (want) == (got))
#define EXPECT_NE(donotwant, got) Assert(FL, (donotwant) != (got))
#define ASSERT_SYS(err, want, got) \
errno = 0, Assert(FL, (want) == (got)), Assert(FL, (err) == errno)
#define EXPECT_SYS(err, want, got) \
errno = 0, Assert(FL, (want) == (got)), Assert(FL, (err) == errno)
int sigchld_pid;
volatile bool sigchld_got_signal;
// 1. Test SIGCHLD is delivered due to lack of waiters.
// 2. Test wait4() returns ECHILD when nothing remains.
// 3. Test wait4() failing doesn't clobber *ws and *ru.
// 4. Check information passed in siginfo and ucontext.
void OnSigchld(int sig, siginfo_t *si, void *arg) {
int ws;
struct rusage ru;
ucontext_t *ctx = arg;
EXPECT_NE(-1, wait4(sigchld_pid, &ws, 0, &ru));
EXPECT_SYS(ECHILD, -1, wait4(sigchld_pid, &ws, 0, &ru));
EXPECT_TRUE(WIFEXITED(ws));
EXPECT_EQ(42, WEXITSTATUS(ws));
EXPECT_EQ(SIGCHLD, sig);
EXPECT_EQ(SIGCHLD, si->si_signo);
EXPECT_EQ(CLD_EXITED, si->si_code);
EXPECT_EQ(sigchld_pid, si->si_pid);
EXPECT_EQ(getuid(), si->si_uid);
EXPECT_NE(NULL, ctx);
sigchld_got_signal = true;
}
int main(int argc, char *argv[]) {
const char *startup = getenv("EXITCODE");
if (startup) exit(atoi(startup));
struct sigaction newsa, oldsa;
sigset_t oldmask, blocksigchld, unblockall;
char *prog = argv[0];
char *args[] = {prog, NULL};
char *envs[] = {"EXITCODE=42", NULL};
newsa.sa_flags = SA_SIGINFO;
newsa.sa_sigaction = OnSigchld;
sigemptyset(&newsa.sa_mask);
ASSERT_SYS(0, 0, sigaction(SIGCHLD, &newsa, &oldsa));
sigemptyset(&blocksigchld);
sigaddset(&blocksigchld, SIGCHLD);
ASSERT_SYS(0, 0, sigprocmask(SIG_BLOCK, &blocksigchld, &oldmask));
EXPECT_EQ(0, posix_spawn(&sigchld_pid, prog, NULL, NULL, args, envs));
sigemptyset(&unblockall);
EXPECT_SYS(EINTR, -1, sigsuspend(&unblockall));
EXPECT_TRUE(sigchld_got_signal);
EXPECT_SYS(0, 0, sigaction(SIGCHLD, &oldsa, 0));
ASSERT_SYS(0, 0, sigprocmask(SIG_SETMASK, &oldmask, 0));
}

55
test/posix/signal_test.c Normal file
View file

@ -0,0 +1,55 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include <signal.h>
#include <stdlib.h>
volatile sig_atomic_t signal_received = 0;
void signal_handler(int signum) {
// Set the flag to indicate the signal was received
signal_received = 1;
}
int main() {
// Install the signal handler
struct sigaction sa;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
// Failed to install signal handler
exit(1);
}
// Raise the signal
if (raise(SIGUSR1) != 0) {
// Failed to raise signal
exit(2);
}
// Check if the signal was received
if (signal_received == 1) {
// Signal was successfully caught
exit(0);
} else {
// Signal was not caught
exit(3);
}
}

59
test/posix/test.mk Normal file
View file

@ -0,0 +1,59 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += TEST_POSIX
TEST_POSIX_SRCS := \
$(wildcard test/posix/*.c)
TEST_POSIX_SRCS_TEST = \
$(filter %_test.c,$(TEST_POSIX_SRCS))
TEST_POSIX_OBJS = \
$(TEST_POSIX_SRCS:%.c=o/$(MODE)/%.o)
TEST_POSIX_COMS = \
$(TEST_POSIX_SRCS_TEST:%.c=o/$(MODE)/%.com)
TEST_POSIX_BINS = \
$(TEST_POSIX_COMS) \
$(TEST_POSIX_COMS:%=%.dbg)
TEST_POSIX_TESTS = \
$(TEST_POSIX_SRCS_TEST:%.c=o/$(MODE)/%.com.ok)
TEST_POSIX_CHECKS = \
$(TEST_POSIX_SRCS_TEST:%.c=o/$(MODE)/%.com.runs)
TEST_POSIX_DIRECTDEPS = \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_MEM \
LIBC_PROC \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_SYSV \
LIBC_THREAD
TEST_POSIX_DEPS := \
$(call uniq,$(foreach x,$(TEST_POSIX_DIRECTDEPS),$($(x))))
o/$(MODE)/test/posix/posix.pkg: \
$(TEST_POSIX_OBJS) \
$(foreach x,$(TEST_POSIX_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/test/posix/%.com.dbg: \
$(TEST_POSIX_DEPS) \
o/$(MODE)/test/posix/%.o \
o/$(MODE)/test/posix/posix.pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
$(TEST_POSIX_OBJS): private CFLAGS += -isystem isystem/
.PHONY: o/$(MODE)/test/posix
o/$(MODE)/test/posix: \
$(TEST_POSIX_BINS) \
$(TEST_POSIX_CHECKS)

View file

@ -5,4 +5,5 @@
o/$(MODE)/test: o/$(MODE)/test/dsp \ o/$(MODE)/test: o/$(MODE)/test/dsp \
o/$(MODE)/test/libc \ o/$(MODE)/test/libc \
o/$(MODE)/test/net \ o/$(MODE)/test/net \
o/$(MODE)/test/posix \
o/$(MODE)/test/tool o/$(MODE)/test/tool