diff options
Diffstat (limited to 'test/pthread/cancellation-points.c')
| -rw-r--r-- | test/pthread/cancellation-points.c | 280 | 
1 files changed, 280 insertions, 0 deletions
diff --git a/test/pthread/cancellation-points.c b/test/pthread/cancellation-points.c new file mode 100644 index 000000000..3fe49fcaa --- /dev/null +++ b/test/pthread/cancellation-points.c @@ -0,0 +1,280 @@ +/* + * Make sure functions marked as cancellation points actually are. + * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_05 + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <features.h> +#include <sys/ipc.h> +#include <sys/mman.h> +#include <sys/msg.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <mqueue.h> +#include <poll.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> + +/* take care of optional things ... */ +#define STUB(func, args) static void func args { sleep(0); } +#if !defined(__UCLIBC__) || defined(__UCLIBC_AIO__) +# include <aio.h> +#else +STUB(aio_suspend, (void *p, int n, const void *p2)) +#endif +#if !defined(__UCLIBC__) || defined(__UCLIBC_STROPTS__) +# include <stropts.h> +#else +STUB(getmsg, (int f, void *p, void *p2, void *p3)) +STUB(getpmsg, (int f, void *p, void *p2, void *p3, void *p4)) +STUB(putmsg, (int f, void *p, void *p2, void *p3)) +STUB(putpmsg, (int f, void *p, void *p2, void *p3, void *p4)) +#endif +#if defined(__UCLIBC__) +STUB(clock_nanosleep, (int i, int f, const void *p, void *p2)) +#endif + +int cnt; +bool ready; + +void cancel_timeout(int sig) +{ +	ready = false; +} +void cancel_thread_cleanup(void *arg) +{ +	ready = false; +} + +/* some funcs need some help as they wont take NULL args ... */ +const struct timespec zero_sec = { .tv_sec = 0, .tv_nsec = 0 }; + +sem_t sem; +void help_sem_setup(void) +{ +	if (sem_init(&sem, 0, 1) == -1) { +		perror("sem_init() failed"); +		exit(-1); +	} +} + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex; +void help_pthread_setup(void) +{ +	pthread_mutex_init(&mutex, NULL); +	pthread_mutex_lock(&mutex); +} + +/* the pthread function that will call the cancellable function over and over */ +#define _MAKE_CANCEL_THREAD_FUNC_EX(func, sysfunc, args, setup) \ +void *cancel_thread_##func(void *arg) \ +{ \ +	if (pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) { \ +		perror("unable to set cancel type to deferred; something is seriously broken"); \ +		exit(-1); \ +	} \ +	pthread_cleanup_push(cancel_thread_cleanup, NULL); \ +	setup; \ +	ready = true; \ +	while (ready) \ +		sysfunc args; \ +	pthread_cleanup_pop(1); \ +	return NULL; \ +} +#define MAKE_CANCEL_THREAD_FUNC_RE(func, sysfunc, args) _MAKE_CANCEL_THREAD_FUNC_EX(func, sysfunc, args, (void)0) +#define MAKE_CANCEL_THREAD_FUNC_EX(func, args, setup)   _MAKE_CANCEL_THREAD_FUNC_EX(func, func, args, setup) +#define MAKE_CANCEL_THREAD_FUNC(func, args)             _MAKE_CANCEL_THREAD_FUNC_EX(func, func, args, (void)0) + +MAKE_CANCEL_THREAD_FUNC(accept, (-1, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(aio_suspend, (NULL, 0, &zero_sec)) +MAKE_CANCEL_THREAD_FUNC(clock_nanosleep, (0, 0, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(close, (-1)) +MAKE_CANCEL_THREAD_FUNC(connect, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(creat, ("", 0)) +MAKE_CANCEL_THREAD_FUNC(fcntl, (0, F_SETLKW, NULL)) +MAKE_CANCEL_THREAD_FUNC(fdatasync, (-1)) +MAKE_CANCEL_THREAD_FUNC(fsync, (0)) +MAKE_CANCEL_THREAD_FUNC(getmsg, (-1, NULL, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(getpmsg, (-1, NULL, NULL, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(lockf, (-1, F_TEST, 0)) +MAKE_CANCEL_THREAD_FUNC(mq_receive, (0, NULL, 0, NULL)) +MAKE_CANCEL_THREAD_FUNC(mq_send, (0, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(mq_timedreceive, (0, NULL, 0, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(mq_timedsend, (0, NULL, 0, 0, NULL)) +MAKE_CANCEL_THREAD_FUNC(msgrcv, (-1, NULL, 0, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(msgsnd, (-1, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(msync, (NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(nanosleep, (NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(open, ("", 0)) +MAKE_CANCEL_THREAD_FUNC(pause, ()) +MAKE_CANCEL_THREAD_FUNC(poll, (NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(pread, (-1, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(pselect, (0, NULL, NULL, NULL, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC_EX(pthread_cond_timedwait, (&cond, &mutex, &zero_sec), help_pthread_setup()) +MAKE_CANCEL_THREAD_FUNC_EX(pthread_cond_wait, (&cond, &mutex), help_pthread_setup()) +/*MAKE_CANCEL_THREAD_FUNC_EX(pthread_join, (0, NULL))*/ +MAKE_CANCEL_THREAD_FUNC(pthread_testcancel, ()) +MAKE_CANCEL_THREAD_FUNC(putmsg, (-1, NULL, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(putpmsg, (-1, NULL, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(pwrite, (-1, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(read, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(readv, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(recv, (-1, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(recvfrom, (-1, NULL, 0, 0, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(recvmsg, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(select, (0, NULL, NULL, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC_EX(sem_timedwait, (&sem, &zero_sec), help_sem_setup()) +MAKE_CANCEL_THREAD_FUNC_EX(sem_wait, (&sem), help_sem_setup()) +MAKE_CANCEL_THREAD_FUNC(send, (-1, NULL, 0, 0)) +MAKE_CANCEL_THREAD_FUNC(sendmsg, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(sendto, (-1, NULL, 0, 0, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(sigpause, (0)) +MAKE_CANCEL_THREAD_FUNC(sigsuspend, (NULL)) +MAKE_CANCEL_THREAD_FUNC(sigtimedwait, (NULL, NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(sigwait, (NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(sigwaitinfo, (NULL, NULL)) +MAKE_CANCEL_THREAD_FUNC(sleep, (0)) +MAKE_CANCEL_THREAD_FUNC(system, ("")) +MAKE_CANCEL_THREAD_FUNC(tcdrain, (-1)) +MAKE_CANCEL_THREAD_FUNC(usleep, (0)) +MAKE_CANCEL_THREAD_FUNC(wait, (NULL)) +MAKE_CANCEL_THREAD_FUNC(waitid, (0, 0, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(waitpid, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(write, (-1, NULL, 0)) +MAKE_CANCEL_THREAD_FUNC(writev, (-1, NULL, 0)) + +/* test a few variations that should not cancel ... */ +MAKE_CANCEL_THREAD_FUNC_RE(fcntl_another, fcntl, (0, F_GETFD)) + +/* main test that creates thread, cancels it, etc... */ +int _test_func(const char *func_name, void *(*func)(void*), const int should_cancel) +{ +	int ret; +	pthread_t cancel_thread_id; + +	++cnt; + +	printf("testing %-30s ", func_name); + +	printf("."); +	if (signal(SIGALRM, cancel_timeout) == SIG_ERR) { +		perror("unable to bind SIGALRM"); +		exit(-1); +	} + +	printf("."); +	ready = false; +	pthread_create(&cancel_thread_id, NULL, func, NULL); + +	printf("."); +	while (!ready) +		sched_yield(); + +	printf("."); +	if (pthread_cancel(cancel_thread_id)) { +		perror("unable to cancel thread"); +		exit(-1); +	} + +	printf("."); +	alarm(5); +	while (ready) +		sched_yield(); + +	printf("."); +	ret = (!!!alarm(0) == should_cancel); + +	if (ret) +		printf(" failed ;(\n"); +	else +		printf(" OK!\n"); + +	return ret; +} +#define TEST_FUNC(f)    _test_func(#f, cancel_thread_##f, 1) +#define TEST_FUNC_RE(f) _test_func(#f, cancel_thread_##f, 0) + +int main(int argc, char *argv[]) +{ +	int ret = 0; +	setbuf(stdout, NULL); +	cnt = 0; + +	ret += TEST_FUNC(accept); +	ret += TEST_FUNC(aio_suspend); +	ret += TEST_FUNC(clock_nanosleep); +	ret += TEST_FUNC(close); +	ret += TEST_FUNC(connect); +	ret += TEST_FUNC(creat); +	ret += TEST_FUNC(fcntl); +	ret += TEST_FUNC(fdatasync); +	ret += TEST_FUNC(fsync); +	ret += TEST_FUNC(getmsg); +	ret += TEST_FUNC(getpmsg); +	ret += TEST_FUNC(lockf); +	ret += TEST_FUNC(mq_receive); +	ret += TEST_FUNC(mq_send); +	ret += TEST_FUNC(mq_timedreceive); +	ret += TEST_FUNC(mq_timedsend); +	ret += TEST_FUNC(msgrcv); +	ret += TEST_FUNC(msgsnd); +	ret += TEST_FUNC(msync); +	ret += TEST_FUNC(nanosleep); +	ret += TEST_FUNC(open); +	ret += TEST_FUNC(pause); +	ret += TEST_FUNC(poll); +	ret += TEST_FUNC(pread); +	ret += TEST_FUNC(pselect); +	ret += TEST_FUNC(pthread_cond_timedwait); +	ret += TEST_FUNC(pthread_cond_wait); +	/*ret += TEST_FUNC(pthread_join);*/ +	ret += TEST_FUNC(pthread_testcancel); +	ret += TEST_FUNC(putmsg); +	ret += TEST_FUNC(putpmsg); +	ret += TEST_FUNC(pwrite); +	ret += TEST_FUNC(read); +	ret += TEST_FUNC(readv); +	ret += TEST_FUNC(recv); +	ret += TEST_FUNC(recvfrom); +	ret += TEST_FUNC(recvmsg); +	ret += TEST_FUNC(select); +	ret += TEST_FUNC(sem_timedwait); +	ret += TEST_FUNC(sem_wait); +	ret += TEST_FUNC(send); +	ret += TEST_FUNC(sendmsg); +	ret += TEST_FUNC(sendto); +	ret += TEST_FUNC(sigpause); +	ret += TEST_FUNC(sigsuspend); +	ret += TEST_FUNC(sigtimedwait); +	ret += TEST_FUNC(sigwait); +	ret += TEST_FUNC(sigwaitinfo); +	ret += TEST_FUNC(sleep); +	ret += TEST_FUNC(system); +	ret += TEST_FUNC(tcdrain); +	ret += TEST_FUNC(usleep); +	ret += TEST_FUNC(wait); +	ret += TEST_FUNC(waitid); +	ret += TEST_FUNC(waitpid); +	ret += TEST_FUNC(write); +	ret += TEST_FUNC(writev); + +	ret += TEST_FUNC_RE(fcntl_another); + +	if (ret) +		printf("!!! %i / %i tests failed\n", ret, cnt); + +	return ret; +}  | 
