#include <sys/cdefs.h>
__RCSID("$NetBSD: t_cancellation.c,v 1.4 2025/04/05 11:22:32 riastradh Exp $");
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/msg.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <aio.h>
#include <atf-c.h>
#include <fcntl.h>
#include <mqueue.h>
#include <paths.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <string.h>
#include <termios.h>
#include <threads.h>
#include <time.h>
#include <unistd.h>
#include "cancelpoint.h"
#include "h_macros.h"
static const char *
c11thrd_err(int error)
{
static char buf[32];
switch (error) {
case thrd_busy: return "thrd_busy";
case thrd_nomem: return "thrd_nomem";
case thrd_success: return "thrd_success";
case thrd_timedout: return "thrd_timedout";
default:
snprintf(buf, sizeof(buf), "thrd_%d", error);
return buf;
}
}
#define RT(x) do \
{ \
int RT_rv = (x); \
ATF_REQUIRE_MSG(RT_rv == 0, "%s: %d (%s)", \
#x, RT_rv, c11thrd_err(RT_rv)); \
} while (0)
pthread_barrier_t bar;
bool cleanup_done;
static void *
emptythread(void *cookie)
{
return NULL;
}
static int
emptythrd(void *cookie)
{
return 123;
}
static void
cleanup_pthread_join(void *cookie)
{
pthread_t *tp = cookie;
void *result;
RZ(pthread_join(*tp, &result));
ATF_CHECK_MSG(result == NULL, "result=%p", result);
}
static void
cleanup_thrd_join(void *cookie)
{
thrd_t *tp = cookie;
int result;
RT(thrd_join(*tp, &result));
ATF_CHECK_MSG(result == 123, "result=%d", result);
}
static void
cleanup_msgid(void *cookie)
{
int *msgidp = cookie;
RL(msgctl(*msgidp, IPC_RMID, NULL));
}
static int
acceptsetup(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_STREAM, 0));
RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun)));
RL(listen(sock, 1));
return sock;
}
static void
cancelpoint_accept(void)
{
const int sock = acceptsetup();
cancelpointready();
RL(accept(sock, NULL, NULL));
}
static void
cancelpoint_accept4(void)
{
const int sock = acceptsetup();
cancelpointready();
RL(accept4(sock, NULL, NULL, O_CLOEXEC));
}
static void
cancelpoint_aio_suspend(void)
{
int fd[2];
char buf[32];
struct aiocb aio = {
.aio_offset = 0,
.aio_buf = buf,
.aio_nbytes = sizeof(buf),
.aio_fildes = -1,
};
const struct aiocb *const aiolist[] = { &aio };
RL(pipe(fd));
aio.aio_fildes = fd[0];
RL(aio_read(&aio));
cancelpointready();
RL(aio_suspend(aiolist, __arraycount(aiolist), NULL));
}
static void
cancelpoint_clock_nanosleep(void)
{
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
cancelpointready();
RL(clock_nanosleep(CLOCK_MONOTONIC, 0, &t, NULL));
}
static void
cancelpoint_close(void)
{
int fd;
RL(fd = open("/dev/null", O_RDWR));
cancelpointready();
RL(close(fd));
}
static void
cancelpoint_cnd_timedwait(void)
{
cnd_t cnd;
mtx_t mtx;
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RT(cnd_init(&cnd));
RT(mtx_init(&mtx, mtx_plain));
cancelpointready();
RT(mtx_lock(&mtx));
RT(cnd_timedwait(&cnd, &mtx, &t));
RT(mtx_unlock(&mtx));
}
static void
cancelpoint_cnd_wait(void)
{
cnd_t cnd;
mtx_t mtx;
RT(cnd_init(&cnd));
RT(mtx_init(&mtx, mtx_plain));
cancelpointready();
RT(mtx_lock(&mtx));
RT(cnd_wait(&cnd, &mtx));
RT(mtx_unlock(&mtx));
}
static void
cancelpoint_connect(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_STREAM, 0));
cancelpointready();
RL(connect(sock, (const struct sockaddr *)&sun, sizeof(sun)));
}
static void
cancelpoint_creat(void)
{
cancelpointready();
RL(creat("file", 0666));
}
static void
cancelpoint_fcntl_F_SETLKW(void)
{
int fd;
struct flock fl = {
.l_start = 0,
.l_len = 0,
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
};
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(fcntl(fd, F_SETLKW, &fl));
}
static void
cancelpoint_fcntl_F_OFD_SETLKW(void)
{
#ifdef F_OFD_SETLKW
int fd;
struct flock fl = {
.l_start = 0,
.l_len = 0,
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
};
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(fcntl(fd, F_OFD_SETLKW, &fl));
#else
atf_tc_expect_fail("PR kern/59241: POSIX.1-2024:"
" OFD-owned file locks");
atf_tc_fail("no F_OFD_SETLKW");
#endif
}
static void
cancelpoint_fdatasync(void)
{
int fd;
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(fdatasync(fd));
}
static void
cancelpoint_fsync(void)
{
int fd;
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(fsync(fd));
}
static void
cancelpoint_kevent(void)
{
int kq;
struct kevent ev;
EV_SET(&ev, SIGUSR1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE,
0, 0, 0);
RL(kq = kqueue());
RL(kevent(kq, &ev, 1, NULL, 1, &(const struct timespec){0,0}));
cancelpointready();
RL(kevent(kq, NULL, 0, &ev, 1, NULL));
}
static void
cancelpoint_lockf_F_LOCK(void)
{
int fd;
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(lockf(fd, F_LOCK, 0));
}
static void
cancelpoint_mq_receive(void)
{
mqd_t mq;
char buf[32];
RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL));
cancelpointready();
RL(mq_receive(mq, buf, sizeof(buf), NULL));
}
static void
cancelpoint_mq_send(void)
{
mqd_t mq;
char buf[32] = {0};
RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL));
cancelpointready();
RL(mq_send(mq, buf, sizeof(buf), 0));
}
static void
cancelpoint_mq_timedreceive(void)
{
mqd_t mq;
char buf[32];
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL));
cancelpointready();
RL(mq_timedreceive(mq, buf, sizeof(buf), NULL, &t));
}
static void
cancelpoint_mq_timedsend(void)
{
mqd_t mq;
char buf[32] = {0};
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL));
cancelpointready();
RL(mq_timedsend(mq, buf, sizeof(buf), 0, &t));
}
static void
cancelpoint_msgrcv(void)
{
int msgid;
char buf[32];
RL(msgid = msgget(IPC_PRIVATE, IPC_CREAT));
pthread_cleanup_push(&cleanup_msgid, &msgid);
cancelpointready();
RL(msgrcv(msgid, buf, sizeof(buf), 0, 0));
pthread_cleanup_pop(1);
}
static void
cancelpoint_msgsnd(void)
{
int msgid;
char buf[32] = {0};
RL(msgid = msgget(IPC_PRIVATE, IPC_CREAT));
pthread_cleanup_push(&cleanup_msgid, &msgid);
cancelpointready();
RL(msgsnd(msgid, buf, sizeof(buf), 0));
pthread_cleanup_pop(1);
}
static void
cancelpoint_msync(void)
{
const unsigned long pagesize = sysconf(_SC_PAGESIZE);
int fd;
void *map;
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
RL(ftruncate(fd, pagesize));
REQUIRE_LIBC(map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0),
MAP_FAILED);
cancelpointready();
RL(msync(map, pagesize, MS_SYNC));
}
static void
cancelpoint_nanosleep(void)
{
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
cancelpointready();
RL(nanosleep(&t, NULL));
}
static void
cancelpoint_open(void)
{
cancelpointready();
RL(open("file", O_RDWR));
}
static void
cancelpoint_openat(void)
{
cancelpointready();
RL(openat(AT_FDCWD, "file", O_RDWR));
}
static void
cancelpoint_pause(void)
{
cancelpointready();
RL(pause());
}
static void
cancelpoint_poll(void)
{
int fd[2];
struct pollfd pfd;
RL(pipe(fd));
pfd.fd = fd[0];
pfd.events = POLLIN;
cancelpointready();
RL(poll(&pfd, 1, 1000));
}
static void
cancelpoint_posix_close(void)
{
#if 0
int fd;
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(posix_close(fd, POSIX_CLOSE_RESTART));
#else
atf_tc_expect_fail("PR kern/58929: POSIX.1-2024 compliance:"
" posix_close, POSIX_CLOSE_RESTART");
atf_tc_fail("no posix_close");
#endif
}
static void
cancelpoint_ppoll(void)
{
int fd[2];
struct pollfd pfd;
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RL(pipe(fd));
pfd.fd = fd[0];
pfd.events = POLLIN;
cancelpointready();
RL(ppoll(&pfd, 1, &t, NULL));
}
static void
cancelpoint_pread(void)
{
int fd;
char buf[1];
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(pread(fd, buf, sizeof(buf), 1));
}
static void
cancelpoint_pselect(void)
{
int fd[2];
fd_set readfd;
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
FD_ZERO(&readfd);
RL(pipe(fd));
FD_SET(fd[0], &readfd);
cancelpointready();
RL(pselect(fd[0] + 1, &readfd, NULL, NULL, &t, NULL));
}
static void
cancelpoint_pthread_cond_clockwait(void)
{
#if 0
pthread_cond_t cond;
pthread_mutex_t mutex;
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RZ(pthread_cond_init(&cond, NULL));
RZ(pthread_mutex_init(&mutex, NULL));
cancelpointready();
RZ(pthread_mutex_lock(&mutex));
RZ(pthread_cond_clockwait(&cond, &mutex, CLOCK_MONOTONIC, &t));
RZ(pthread_mutex_unlock(&mutex));
#else
atf_tc_expect_fail("PR lib/59142: POSIX.1-2024:"
" pthread_cond_clockwait and company");
atf_tc_fail("no posix_cond_clockwait");
#endif
}
static void
cancelpoint_pthread_cond_timedwait(void)
{
pthread_cond_t cond;
pthread_mutex_t mutex;
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RZ(pthread_cond_init(&cond, NULL));
RZ(pthread_mutex_init(&mutex, NULL));
cancelpointready();
RZ(pthread_mutex_lock(&mutex));
RZ(pthread_cond_timedwait(&cond, &mutex, &t));
RZ(pthread_mutex_unlock(&mutex));
}
static void
cancelpoint_pthread_cond_wait(void)
{
pthread_cond_t cond;
pthread_mutex_t mutex;
RZ(pthread_cond_init(&cond, NULL));
RZ(pthread_mutex_init(&mutex, NULL));
cancelpointready();
RZ(pthread_mutex_lock(&mutex));
RZ(pthread_cond_wait(&cond, &mutex));
RZ(pthread_mutex_unlock(&mutex));
}
static void
cancelpoint_pthread_join(void)
{
pthread_t t;
RZ(pthread_create(&t, NULL, &emptythread, NULL));
pthread_cleanup_push(&cleanup_pthread_join, &t);
cancelpointready();
RZ(pthread_join(t, NULL));
pthread_cleanup_pop(0);
}
static void
cancelpoint_pthread_testcancel(void)
{
cancelpointready();
pthread_testcancel();
}
static void
cancelpoint_pwrite(void)
{
int fd;
char buf[1] = {0};
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(pwrite(fd, buf, sizeof(buf), 1));
}
static void
cancelpoint_read(void)
{
int fd;
char buf[1];
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(read(fd, buf, sizeof(buf)));
}
static void
cancelpoint_readv(void)
{
int fd;
char buf[1];
struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(readv(fd, &iov, 1));
}
static void
cancelpoint_recv(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
char buf[1];
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0));
RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun)));
cancelpointready();
RL(recv(sock, buf, sizeof(buf), 0));
}
static void
cancelpoint_recvfrom(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
char buf[1];
struct sockaddr_storage ss;
socklen_t len = sizeof(ss);
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0));
RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun)));
cancelpointready();
RL(recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&ss, &len));
}
static void
cancelpoint_recvmsg(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
char buf[1];
struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0));
RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun)));
cancelpointready();
RL(recvmsg(sock, &msg, 0));
}
static void
cancelpoint_select(void)
{
int fd[2];
fd_set readfd;
struct timeval t = {.tv_sec = 1, .tv_usec = 0};
FD_ZERO(&readfd);
RL(pipe(fd));
FD_SET(fd[0], &readfd);
cancelpointready();
RL(select(fd[0] + 1, &readfd, NULL, NULL, &t));
}
static void
cancelpoint_send(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
char buf[1] = {0};
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0));
RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun)));
cancelpointready();
RL(send(sock, buf, sizeof(buf), 0));
}
static void
cancelpoint_sendto(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
char buf[1] = {0};
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0));
cancelpointready();
RL(sendto(sock, buf, sizeof(buf), 0, (const struct sockaddr *)&sun,
sizeof(sun)));
}
static void
cancelpoint_sendmsg(void)
{
struct sockaddr_un sun = { .sun_family = AF_LOCAL };
int sock;
char buf[1] = {0};
struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
struct msghdr msg = {
.msg_name = (struct sockaddr *)&sun,
.msg_namelen = sizeof(sun),
.msg_iov = &iov,
.msg_iovlen = 1,
};
strncpy(sun.sun_path, "sock", sizeof(sun.sun_path));
RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0));
cancelpointready();
RL(sendmsg(sock, &msg, 0));
}
static void
cancelpoint_sigsuspend(void)
{
sigset_t mask, omask;
RL(sigfillset(&mask));
RL(sigprocmask(SIG_BLOCK, &mask, &omask));
cancelpointready();
RL(sigsuspend(&omask));
}
static void
cancelpoint_sigtimedwait(void)
{
sigset_t mask, omask;
siginfo_t info;
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
RL(sigfillset(&mask));
RL(sigprocmask(SIG_BLOCK, &mask, &omask));
cancelpointready();
RL(sigtimedwait(&omask, &info, &t));
}
static void
cancelpoint_sigwait(void)
{
sigset_t mask, omask;
int sig;
RL(sigfillset(&mask));
RL(sigprocmask(SIG_BLOCK, &mask, &omask));
cancelpointready();
RL(sigwait(&omask, &sig));
}
static void
cancelpoint_sigwaitinfo(void)
{
sigset_t mask, omask;
siginfo_t info;
RL(sigfillset(&mask));
RL(sigprocmask(SIG_BLOCK, &mask, &omask));
cancelpointready();
RL(sigwaitinfo(&omask, &info));
}
static void
cancelpoint_sleep(void)
{
cancelpointready();
(void)sleep(1);
}
static void
cancelpoint_tcdrain(void)
{
int hostfd, appfd;
char *pts;
RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY));
RL(grantpt(hostfd));
RL(unlockpt(hostfd));
REQUIRE_LIBC(pts = ptsname(hostfd), NULL);
RL(appfd = open(pts, O_RDWR|O_NOCTTY));
cancelpointready();
RL(tcdrain(appfd));
}
static void
cancelpoint_thrd_join(void)
{
thrd_t t;
RT(thrd_create(&t, &emptythrd, NULL));
pthread_cleanup_push(&cleanup_thrd_join, &t);
cancelpointready();
RT(thrd_join(t, NULL));
pthread_cleanup_pop(0);
}
static void
cancelpoint_thrd_sleep(void)
{
struct timespec t = {.tv_sec = 1, .tv_nsec = 0};
cancelpointready();
RT(thrd_sleep(&t, NULL));
}
static void
cancelpoint_wait(void)
{
cancelpointready();
RL(wait(NULL));
}
static void
cancelpoint_waitid(void)
{
cancelpointready();
RL(waitid(P_ALL, 0, NULL, 0));
}
static void
cancelpoint_waitpid(void)
{
cancelpointready();
RL(waitpid(-1, NULL, 0));
}
static void
cancelpoint_write(void)
{
int fd;
char buf[1] = {0};
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(write(fd, buf, sizeof(buf)));
}
static void
cancelpoint_writev(void)
{
int fd;
char buf[1] = {0};
struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) };
RL(fd = open("file", O_RDWR|O_CREAT, 0666));
cancelpointready();
RL(writev(fd, &iov, 1));
}
TEST_CANCELPOINT(cancelpoint_accept, __nothing)
TEST_CANCELPOINT(cancelpoint_accept4, __nothing)
TEST_CANCELPOINT(cancelpoint_aio_suspend, __nothing)
TEST_CANCELPOINT(cancelpoint_clock_nanosleep, __nothing)
TEST_CANCELPOINT(cancelpoint_close, __nothing)
TEST_CANCELPOINT(cancelpoint_cnd_timedwait, __nothing)
TEST_CANCELPOINT(cancelpoint_cnd_wait, __nothing)
TEST_CANCELPOINT(cancelpoint_connect, __nothing)
TEST_CANCELPOINT(cancelpoint_creat, __nothing)
TEST_CANCELPOINT(cancelpoint_fcntl_F_SETLKW, __nothing)
TEST_CANCELPOINT(cancelpoint_fcntl_F_OFD_SETLKW, __nothing)
TEST_CANCELPOINT(cancelpoint_fdatasync, __nothing)
TEST_CANCELPOINT(cancelpoint_fsync, __nothing)
TEST_CANCELPOINT(cancelpoint_kevent, __nothing)
TEST_CANCELPOINT(cancelpoint_lockf_F_LOCK, __nothing)
TEST_CANCELPOINT(cancelpoint_mq_receive, __nothing)
TEST_CANCELPOINT(cancelpoint_mq_send, __nothing)
TEST_CANCELPOINT(cancelpoint_mq_timedreceive, __nothing)
TEST_CANCELPOINT(cancelpoint_mq_timedsend, __nothing)
TEST_CANCELPOINT(cancelpoint_msgrcv, __nothing)
TEST_CANCELPOINT(cancelpoint_msgsnd, __nothing)
TEST_CANCELPOINT(cancelpoint_msync, __nothing)
TEST_CANCELPOINT(cancelpoint_nanosleep, __nothing)
TEST_CANCELPOINT(cancelpoint_open, __nothing)
TEST_CANCELPOINT(cancelpoint_openat, __nothing)
TEST_CANCELPOINT(cancelpoint_pause, __nothing)
TEST_CANCELPOINT(cancelpoint_poll, __nothing)
TEST_CANCELPOINT(cancelpoint_posix_close, __nothing)
TEST_CANCELPOINT(cancelpoint_ppoll, __nothing)
TEST_CANCELPOINT(cancelpoint_pread, __nothing)
TEST_CANCELPOINT(cancelpoint_pselect, __nothing)
TEST_CANCELPOINT(cancelpoint_pthread_cond_clockwait, __nothing)
TEST_CANCELPOINT(cancelpoint_pthread_cond_timedwait, __nothing)
TEST_CANCELPOINT(cancelpoint_pthread_cond_wait, __nothing)
TEST_CANCELPOINT(cancelpoint_pthread_join, __nothing)
TEST_CANCELPOINT(cancelpoint_pthread_testcancel, __nothing)
TEST_CANCELPOINT(cancelpoint_pwrite, __nothing)
TEST_CANCELPOINT(cancelpoint_read, __nothing)
TEST_CANCELPOINT(cancelpoint_readv, __nothing)
TEST_CANCELPOINT(cancelpoint_recv, __nothing)
TEST_CANCELPOINT(cancelpoint_recvfrom, __nothing)
TEST_CANCELPOINT(cancelpoint_recvmsg, __nothing)
TEST_CANCELPOINT(cancelpoint_select, __nothing)
TEST_CANCELPOINT(cancelpoint_send, __nothing)
TEST_CANCELPOINT(cancelpoint_sendto, __nothing)
TEST_CANCELPOINT(cancelpoint_sendmsg, __nothing)
TEST_CANCELPOINT(cancelpoint_sigsuspend, __nothing)
TEST_CANCELPOINT(cancelpoint_sigtimedwait, __nothing)
TEST_CANCELPOINT(cancelpoint_sigwait, __nothing)
TEST_CANCELPOINT(cancelpoint_sigwaitinfo, __nothing)
TEST_CANCELPOINT(cancelpoint_sleep, __nothing)
TEST_CANCELPOINT(cancelpoint_tcdrain, __nothing)
TEST_CANCELPOINT(cancelpoint_thrd_join, __nothing)
TEST_CANCELPOINT(cancelpoint_thrd_sleep, __nothing)
TEST_CANCELPOINT(cancelpoint_wait, __nothing)
TEST_CANCELPOINT(cancelpoint_waitid, __nothing)
TEST_CANCELPOINT(cancelpoint_waitpid, __nothing)
TEST_CANCELPOINT(cancelpoint_write, __nothing)
TEST_CANCELPOINT(cancelpoint_writev, __nothing)
ATF_TC(cleanuppop0);
ATF_TC_HEAD(cleanuppop0, tc)
{
atf_tc_set_md_var(tc, "descr", "Test pthread_cleanup_pop(0)");
}
ATF_TC_BODY(cleanuppop0, tc)
{
pthread_cleanup_push(&cleanup, &cleanup_done);
pthread_cleanup_pop(0);
ATF_CHECK(!cleanup_done);
}
ATF_TC(cleanuppop1);
ATF_TC_HEAD(cleanuppop1, tc)
{
atf_tc_set_md_var(tc, "descr", "Test pthread_cleanup_pop(1)");
}
ATF_TC_BODY(cleanuppop1, tc)
{
pthread_cleanup_push(&cleanup, &cleanup_done);
pthread_cleanup_pop(1);
ATF_CHECK(cleanup_done);
}
static void *
cancelself_async(void *cookie)
{
int *n = cookie;
RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
pthread_cleanup_push(&cleanup, &cleanup_done);
*n = 1;
RZ(pthread_cancel(pthread_self()));
*n = 2;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
pthread_testcancel();
*n = 3;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
pthread_testcancel();
*n = 4;
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(cancelself_async);
ATF_TC_HEAD(cancelself_async, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test pthread_cancel(pthread_self()) async");
}
ATF_TC_BODY(cancelself_async, tc)
{
int n = 0;
pthread_t t;
RZ(pthread_create(&t, NULL, &cancelself_async, &n));
alarm(1);
RZ(pthread_join(t, NULL));
atf_tc_expect_fail("lib/59135: PTHREAD_CANCEL_ASYNCHRONOUS"
" doesn't do much");
ATF_CHECK_MSG(n == 1, "n=%d", n);
atf_tc_expect_pass();
ATF_CHECK(cleanup_done);
}
static void *
cancelself_deferred(void *cookie)
{
int *n = cookie;
pthread_cleanup_push(&cleanup, &cleanup_done);
*n = 1;
RZ(pthread_cancel(pthread_self()));
*n = 2;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
*n = 3;
pthread_testcancel();
*n = 4;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
*n = 5;
pthread_testcancel();
*n = 6;
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(cancelself_deferred);
ATF_TC_HEAD(cancelself_deferred, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test pthread_cancel(pthread_self()) deferred");
}
ATF_TC_BODY(cancelself_deferred, tc)
{
int n = 0;
pthread_t t;
RZ(pthread_create(&t, NULL, &cancelself_deferred, &n));
alarm(1);
RZ(pthread_join(t, NULL));
ATF_CHECK_MSG(n == 5, "n=%d", n);
ATF_CHECK(cleanup_done);
}
static void *
defaults(void *cookie)
{
int state, type;
fprintf(stderr, "created thread\n");
RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state));
RZ(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &type));
ATF_CHECK_MSG(state == PTHREAD_CANCEL_ENABLE,
"state=%d PTHREAD_CANCEL_ENABLE=%d PTHREAD_CANCEL_DISABLE=%d",
state, PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE);
ATF_CHECK_MSG(type == PTHREAD_CANCEL_DEFERRED,
"type=%d"
" PTHREAD_CANCEL_DEFERRED=%d PTHREAD_CANCEL_ASYNCHRONOUS=%d",
type, PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS);
return NULL;
}
ATF_TC(defaults);
ATF_TC_HEAD(defaults, tc)
{
atf_tc_set_md_var(tc, "descr", "Test default cancelability");
}
ATF_TC_BODY(defaults, tc)
{
pthread_t t;
fprintf(stderr, "initial thread\n");
(void)defaults(NULL);
RZ(pthread_create(&t, NULL, &defaults, NULL));
alarm(1);
RZ(pthread_join(t, NULL));
}
static void *
disable_enable(void *cookie)
{
int *n = cookie;
pthread_cleanup_push(&cleanup, &cleanup_done);
*n = 1;
pthread_testcancel();
*n = 2;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
*n = 3;
(void)pthread_barrier_wait(&bar);
*n = 4;
pthread_testcancel();
*n = 5;
(void)pthread_barrier_wait(&bar);
*n = 6;
pthread_testcancel();
*n = 7;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
*n = 8;
pthread_testcancel();
*n = 9;
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(disable_enable);
ATF_TC_HEAD(disable_enable, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test disabling and re-enabling cancellation");
}
ATF_TC_BODY(disable_enable, tc)
{
int n = 0;
pthread_t t;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, &disable_enable, &n));
(void)pthread_barrier_wait(&bar);
RZ(pthread_cancel(t));
(void)pthread_barrier_wait(&bar);
alarm(1);
RZ(pthread_join(t, NULL));
ATF_CHECK_MSG(n == 8, "n=%d", n);
ATF_CHECK(cleanup_done);
}
static void *
notestcancel_loop_async(void *cookie)
{
RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
pthread_cleanup_push(&cleanup, &cleanup_done);
(void)pthread_barrier_wait(&bar);
for (;;)
__insn_barrier();
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(notestcancel_loop_async);
ATF_TC_HEAD(notestcancel_loop_async, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test nothing in a loop with PTHREAD_CANCEL_ASYNCHRONOUS");
}
ATF_TC_BODY(notestcancel_loop_async, tc)
{
pthread_t t;
void *result;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, ¬estcancel_loop_async, NULL));
(void)pthread_barrier_wait(&bar);
RZ(pthread_cancel(t));
atf_tc_expect_signal(SIGALRM, "lib/59135: PTHREAD_CANCEL_ASYNCHRONOUS"
" doesn't do much");
alarm(1);
RZ(pthread_join(t, &result));
ATF_CHECK_MSG(result == PTHREAD_CANCELED,
"result=%p PTHREAD_CANCELED=%p", result, PTHREAD_CANCELED);
ATF_CHECK(cleanup_done);
}
static void *
disable_enable_async(void *cookie)
{
int *n = cookie;
pthread_cleanup_push(&cleanup, &cleanup_done);
RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
*n = 1;
pthread_testcancel();
*n = 2;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
*n = 3;
(void)pthread_barrier_wait(&bar);
*n = 4;
pthread_testcancel();
*n = 5;
(void)pthread_barrier_wait(&bar);
*n = 6;
pthread_testcancel();
*n = 7;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
*n = 8;
pthread_testcancel();
*n = 9;
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(disable_enable_async);
ATF_TC_HEAD(disable_enable_async, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test disabling and re-enabling cancellation when asynchronous");
}
ATF_TC_BODY(disable_enable_async, tc)
{
int n = 0;
pthread_t t;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, &disable_enable_async, &n));
(void)pthread_barrier_wait(&bar);
RZ(pthread_cancel(t));
(void)pthread_barrier_wait(&bar);
alarm(1);
RZ(pthread_join(t, NULL));
ATF_CHECK_MSG(n == 7, "n=%d", n);
ATF_CHECK(cleanup_done);
}
static void *
disable_enable_setcanceltype_async(void *cookie)
{
int *n = cookie;
pthread_cleanup_push(&cleanup, &cleanup_done);
*n = 1;
pthread_testcancel();
*n = 2;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL));
*n = 3;
(void)pthread_barrier_wait(&bar);
*n = 4;
pthread_testcancel();
*n = 5;
(void)pthread_barrier_wait(&bar);
*n = 6;
pthread_testcancel();
*n = 7;
RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
*n = 8;
pthread_testcancel();
*n = 9;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
*n = 10;
pthread_testcancel();
*n = 11;
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(disable_enable_setcanceltype_async);
ATF_TC_HEAD(disable_enable_setcanceltype_async, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test disabling cancellation, setting it async, and re-enabling");
}
ATF_TC_BODY(disable_enable_setcanceltype_async, tc)
{
int n = 0;
pthread_t t;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, &disable_enable_setcanceltype_async, &n));
(void)pthread_barrier_wait(&bar);
RZ(pthread_cancel(t));
(void)pthread_barrier_wait(&bar);
alarm(1);
RZ(pthread_join(t, NULL));
ATF_CHECK_MSG(n == 9, "n=%d", n);
ATF_CHECK(cleanup_done);
}
static void *
setcanceltype_async(void *cookie)
{
int *n = cookie;
pthread_cleanup_push(&cleanup, &cleanup_done);
*n = 1;
pthread_testcancel();
*n = 2;
(void)pthread_barrier_wait(&bar);
*n = 3;
(void)pthread_barrier_wait(&bar);
*n = 4;
RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,
NULL));
*n = 5;
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(setcanceltype_async);
ATF_TC_HEAD(setcanceltype_async, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test disabling cancellation, setting it async, and re-enabling");
}
ATF_TC_BODY(setcanceltype_async, tc)
{
int n = 0;
pthread_t t;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, &setcanceltype_async, &n));
(void)pthread_barrier_wait(&bar);
RZ(pthread_cancel(t));
(void)pthread_barrier_wait(&bar);
alarm(1);
RZ(pthread_join(t, NULL));
ATF_CHECK_MSG(n == 4, "n=%d", n);
ATF_CHECK(cleanup_done);
}
static void
sighandler(int signo)
{
int state;
RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state));
RZ(pthread_setcancelstate(state, NULL));
}
static void *
sigsafecancelstate(void *cookie)
{
atomic_ulong *n = cookie;
char name[128];
pthread_cleanup_push(&cleanup, &cleanup_done);
REQUIRE_LIBC(signal(SIGUSR1, &sighandler), SIG_ERR);
(void)pthread_barrier_wait(&bar);
while (atomic_load_explicit(n, memory_order_relaxed) != 0) {
RZ(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL));
RZ(pthread_getname_np(pthread_self(), name, sizeof(name)));
RZ(pthread_setname_np(pthread_self(), "%s", name));
}
pthread_cleanup_pop(1);
return NULL;
}
ATF_TC(sigsafecancelstate);
ATF_TC_HEAD(sigsafecancelstate, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test pthread_setcancelstate async-signal-safety");
}
ATF_TC_BODY(sigsafecancelstate, tc)
{
pthread_t t;
atomic_ulong n = 10000;
void *result;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, &sigsafecancelstate, &n));
(void)pthread_barrier_wait(&bar);
while (atomic_load_explicit(&n, memory_order_relaxed)) {
pthread_kill(t, SIGUSR1);
atomic_store_explicit(&n,
atomic_load_explicit(&n, memory_order_relaxed) - 1,
memory_order_relaxed);
}
alarm(1);
RZ(pthread_join(t, &result));
ATF_CHECK_MSG(result == NULL, "result=%p", result);
ATF_CHECK(cleanup_done);
}
static void *
testcancel_loop(void *cookie)
{
pthread_cleanup_push(&cleanup, &cleanup_done);
(void)pthread_barrier_wait(&bar);
for (;;)
pthread_testcancel();
pthread_cleanup_pop(0);
return NULL;
}
ATF_TC(testcancel_loop);
ATF_TC_HEAD(testcancel_loop, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test pthread_testcancel in a loop");
}
ATF_TC_BODY(testcancel_loop, tc)
{
pthread_t t;
void *result;
RZ(pthread_barrier_init(&bar, NULL, 2));
RZ(pthread_create(&t, NULL, &testcancel_loop, NULL));
(void)pthread_barrier_wait(&bar);
RZ(pthread_cancel(t));
alarm(1);
RZ(pthread_join(t, &result));
ATF_CHECK_MSG(result == PTHREAD_CANCELED,
"result=%p PTHREAD_CANCELED=%p", result, PTHREAD_CANCELED);
ATF_CHECK(cleanup_done);
}
ATF_TP_ADD_TCS(tp)
{
ADD_TEST_CANCELPOINT(cancelpoint_accept);
ADD_TEST_CANCELPOINT(cancelpoint_accept4);
ADD_TEST_CANCELPOINT(cancelpoint_aio_suspend);
ADD_TEST_CANCELPOINT(cancelpoint_clock_nanosleep);
ADD_TEST_CANCELPOINT(cancelpoint_close);
ADD_TEST_CANCELPOINT(cancelpoint_cnd_timedwait);
ADD_TEST_CANCELPOINT(cancelpoint_cnd_wait);
ADD_TEST_CANCELPOINT(cancelpoint_connect);
ADD_TEST_CANCELPOINT(cancelpoint_creat);
ADD_TEST_CANCELPOINT(cancelpoint_fcntl_F_SETLKW);
ADD_TEST_CANCELPOINT(cancelpoint_fcntl_F_OFD_SETLKW);
ADD_TEST_CANCELPOINT(cancelpoint_fdatasync);
ADD_TEST_CANCELPOINT(cancelpoint_fsync);
ADD_TEST_CANCELPOINT(cancelpoint_kevent);
ADD_TEST_CANCELPOINT(cancelpoint_lockf_F_LOCK);
ADD_TEST_CANCELPOINT(cancelpoint_mq_receive);
ADD_TEST_CANCELPOINT(cancelpoint_mq_send);
ADD_TEST_CANCELPOINT(cancelpoint_mq_timedreceive);
ADD_TEST_CANCELPOINT(cancelpoint_mq_timedsend);
ADD_TEST_CANCELPOINT(cancelpoint_msgrcv);
ADD_TEST_CANCELPOINT(cancelpoint_msgsnd);
ADD_TEST_CANCELPOINT(cancelpoint_msync);
ADD_TEST_CANCELPOINT(cancelpoint_nanosleep);
ADD_TEST_CANCELPOINT(cancelpoint_open);
ADD_TEST_CANCELPOINT(cancelpoint_openat);
ADD_TEST_CANCELPOINT(cancelpoint_pause);
ADD_TEST_CANCELPOINT(cancelpoint_poll);
ADD_TEST_CANCELPOINT(cancelpoint_posix_close);
ADD_TEST_CANCELPOINT(cancelpoint_ppoll);
ADD_TEST_CANCELPOINT(cancelpoint_pread);
ADD_TEST_CANCELPOINT(cancelpoint_pselect);
ADD_TEST_CANCELPOINT(cancelpoint_pthread_cond_clockwait);
ADD_TEST_CANCELPOINT(cancelpoint_pthread_cond_timedwait);
ADD_TEST_CANCELPOINT(cancelpoint_pthread_cond_wait);
ADD_TEST_CANCELPOINT(cancelpoint_pthread_join);
ADD_TEST_CANCELPOINT(cancelpoint_pthread_testcancel);
ADD_TEST_CANCELPOINT(cancelpoint_pwrite);
ADD_TEST_CANCELPOINT(cancelpoint_read);
ADD_TEST_CANCELPOINT(cancelpoint_readv);
ADD_TEST_CANCELPOINT(cancelpoint_recv);
ADD_TEST_CANCELPOINT(cancelpoint_recvfrom);
ADD_TEST_CANCELPOINT(cancelpoint_recvmsg);
ADD_TEST_CANCELPOINT(cancelpoint_select);
ADD_TEST_CANCELPOINT(cancelpoint_send);
ADD_TEST_CANCELPOINT(cancelpoint_sendto);
ADD_TEST_CANCELPOINT(cancelpoint_sendmsg);
ADD_TEST_CANCELPOINT(cancelpoint_sigsuspend);
ADD_TEST_CANCELPOINT(cancelpoint_sigtimedwait);
ADD_TEST_CANCELPOINT(cancelpoint_sigwait);
ADD_TEST_CANCELPOINT(cancelpoint_sigwaitinfo);
ADD_TEST_CANCELPOINT(cancelpoint_sleep);
ADD_TEST_CANCELPOINT(cancelpoint_tcdrain);
ADD_TEST_CANCELPOINT(cancelpoint_thrd_join);
ADD_TEST_CANCELPOINT(cancelpoint_thrd_sleep);
ADD_TEST_CANCELPOINT(cancelpoint_wait);
ADD_TEST_CANCELPOINT(cancelpoint_waitid);
ADD_TEST_CANCELPOINT(cancelpoint_waitpid);
ADD_TEST_CANCELPOINT(cancelpoint_write);
ADD_TEST_CANCELPOINT(cancelpoint_writev);
ATF_TP_ADD_TC(tp, cleanuppop0);
ATF_TP_ADD_TC(tp, cleanuppop1);
ATF_TP_ADD_TC(tp, cancelself_async);
ATF_TP_ADD_TC(tp, cancelself_deferred);
ATF_TP_ADD_TC(tp, defaults);
ATF_TP_ADD_TC(tp, disable_enable);
ATF_TP_ADD_TC(tp, disable_enable_async);
ATF_TP_ADD_TC(tp, disable_enable_setcanceltype_async);
ATF_TP_ADD_TC(tp, setcanceltype_async);
ATF_TP_ADD_TC(tp, notestcancel_loop_async);
ATF_TP_ADD_TC(tp, sigsafecancelstate);
ATF_TP_ADD_TC(tp, testcancel_loop);
return atf_no_error();
}