| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 | /* * 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_AIO__)# include <aio.h>#elseSTUB(aio_suspend, (void *p, int n, const void *p2))#endif#if defined(__UCLIBC_STROPTS__)# include <stropts.h>#elseSTUB(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))#endifint 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))#ifdef __UCLIBC_SUSV3_LEGACY__MAKE_CANCEL_THREAD_FUNC(usleep, (0))#endifMAKE_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);#ifdef __UCLIBC_SUSV3_LEGACY__	ret += TEST_FUNC(usleep);#endif	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;}
 |