diff options
| author | Carmelo Amoroso <carmelo.amoroso@st.com> | 2008-04-25 17:30:17 +0000 |
|---|---|---|
| committer | Carmelo Amoroso <carmelo.amoroso@st.com> | 2008-04-25 17:30:17 +0000 |
| commit | d847043c266e211ceaee0c222928537d40cf9409 (patch) | |
| tree | 261f12336fb21742a024a2e4c8b8bda458cf7443 /test/pthread | |
| parent | ffb45327c079ec3d37af737e161ec9e784de0ebf (diff) | |
| download | uClibc-alpine-d847043c266e211ceaee0c222928537d40cf9409.tar.bz2 uClibc-alpine-d847043c266e211ceaee0c222928537d40cf9409.tar.xz | |
STEP 12: synch librt directory
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Diffstat (limited to 'test/pthread')
| -rw-r--r-- | test/pthread/Makefile | 2 | ||||
| -rw-r--r-- | test/pthread/cancellation-points.c | 280 | ||||
| -rw-r--r-- | test/pthread/ex1.c | 2 | ||||
| -rw-r--r-- | test/pthread/ex2.c | 10 | ||||
| -rw-r--r-- | test/pthread/ex4.c | 6 | ||||
| -rw-r--r-- | test/pthread/ex5.c | 10 | ||||
| -rw-r--r-- | test/pthread/ex6.c | 2 | ||||
| -rw-r--r-- | test/pthread/ex7.c | 10 | ||||
| -rw-r--r-- | test/pthread/tst-too-many-cleanups.c | 104 |
9 files changed, 406 insertions, 20 deletions
diff --git a/test/pthread/Makefile b/test/pthread/Makefile index 560a424cb..ef924ad1a 100644 --- a/test/pthread/Makefile +++ b/test/pthread/Makefile @@ -4,3 +4,5 @@ include ../Test.mak EXTRA_LDFLAGS := -lpthread + +LDFLAGS_cancellation-points := -lrt 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; +} diff --git a/test/pthread/ex1.c b/test/pthread/ex1.c index a1b24c31a..4d9de03d8 100644 --- a/test/pthread/ex1.c +++ b/test/pthread/ex1.c @@ -7,7 +7,7 @@ #include <unistd.h> #include "pthread.h" -void *process(void * arg) +static void *process(void * arg) { int i; printf("Starting process %s\n", (char *)arg); diff --git a/test/pthread/ex2.c b/test/pthread/ex2.c index 70cb6b398..98bd4b347 100644 --- a/test/pthread/ex2.c +++ b/test/pthread/ex2.c @@ -20,7 +20,7 @@ struct prodcons { /* Initialize a buffer */ -void init(struct prodcons * b) +static void init(struct prodcons * b) { pthread_mutex_init(&b->lock, NULL); pthread_cond_init(&b->notempty, NULL); @@ -31,7 +31,7 @@ void init(struct prodcons * b) /* Store an integer in the buffer */ -void put(struct prodcons * b, int data) +static void put(struct prodcons * b, int data) { pthread_mutex_lock(&b->lock); /* Wait until buffer is not full */ @@ -50,7 +50,7 @@ void put(struct prodcons * b, int data) /* Read and remove an integer from the buffer */ -int get(struct prodcons * b) +static int get(struct prodcons * b) { int data; pthread_mutex_lock(&b->lock); @@ -75,7 +75,7 @@ int get(struct prodcons * b) struct prodcons buffer; -void * producer(void * data) +static void * producer(void * data) { int n; for (n = 0; n < 10000; n++) { @@ -86,7 +86,7 @@ void * producer(void * data) return NULL; } -void * consumer(void * data) +static void * consumer(void * data) { int d; while (1) { diff --git a/test/pthread/ex4.c b/test/pthread/ex4.c index 11a09f013..cf4cf1d69 100644 --- a/test/pthread/ex4.c +++ b/test/pthread/ex4.c @@ -14,7 +14,7 @@ #if 0 -char * str_accumulate(char * s) +static char * str_accumulate(char * s) { static char accu[1024] = { 0 }; strcat(accu, s); @@ -40,7 +40,7 @@ static void str_alloc_destroy_accu(void * accu); /* Thread-safe version of str_accumulate */ -char * str_accumulate(const char * s) +static char * str_accumulate(const char * s) { char * accu; @@ -81,7 +81,7 @@ static void str_alloc_destroy_accu(void * accu) /* Test program */ -void * process(void * arg) +static void * process(void * arg) { char * res; res = str_accumulate("Result of "); diff --git a/test/pthread/ex5.c b/test/pthread/ex5.c index 475de0e0c..7a293eb01 100644 --- a/test/pthread/ex5.c +++ b/test/pthread/ex5.c @@ -19,7 +19,7 @@ struct prodcons { /* Initialize a buffer */ -void init(struct prodcons * b) +static void init(struct prodcons * b) { sem_init(&b->sem_write, 0, BUFFER_SIZE - 1); sem_init(&b->sem_read, 0, 0); @@ -29,7 +29,7 @@ void init(struct prodcons * b) /* Store an integer in the buffer */ -void put(struct prodcons * b, int data) +static void put(struct prodcons * b, int data) { /* Wait until buffer is not full */ sem_wait(&b->sem_write); @@ -43,7 +43,7 @@ void put(struct prodcons * b, int data) /* Read and remove an integer from the buffer */ -int get(struct prodcons * b) +static int get(struct prodcons * b) { int data; /* Wait until buffer is not empty */ @@ -64,7 +64,7 @@ int get(struct prodcons * b) struct prodcons buffer; -void * producer(void * data) +static void * producer(void * data) { int n; for (n = 0; n < 10000; n++) { @@ -75,7 +75,7 @@ void * producer(void * data) return NULL; } -void * consumer(void * data) +static void * consumer(void * data) { int d; while (1) { diff --git a/test/pthread/ex6.c b/test/pthread/ex6.c index 15914ce85..bb96ca5fa 100644 --- a/test/pthread/ex6.c +++ b/test/pthread/ex6.c @@ -4,7 +4,7 @@ #include <pthread.h> #include <unistd.h> -void * +static void * test_thread (void *v_param) { return NULL; diff --git a/test/pthread/ex7.c b/test/pthread/ex7.c index bda2ca9eb..9cf30aa19 100644 --- a/test/pthread/ex7.c +++ b/test/pthread/ex7.c @@ -22,12 +22,12 @@ typedef struct { event_t main_event; -void * +static void * test_thread (void *ms_param) { unsigned long status = 0; event_t foo; - struct timespec time; + struct timespec timeout; struct timeval now; long ms = (long) ms_param; @@ -39,13 +39,13 @@ test_thread (void *ms_param) /* set the time out value */ printf("waiting %ld ms ...\n", ms); gettimeofday(&now, NULL); - time.tv_sec = now.tv_sec + ms/1000 + (now.tv_usec + (ms%1000)*1000)/1000000; - time.tv_nsec = ((now.tv_usec + (ms%1000)*1000) % 1000000) * 1000; + timeout.tv_sec = now.tv_sec + ms/1000 + (now.tv_usec + (ms%1000)*1000)/1000000; + timeout.tv_nsec = ((now.tv_usec + (ms%1000)*1000) % 1000000) * 1000; /* Just use this to test the time out. The cond var is never signaled. */ pthread_mutex_lock(&foo.mutex); while (foo.flag == 0 && status != ETIMEDOUT) { - status = pthread_cond_timedwait(&foo.cond, &foo.mutex, &time); + status = pthread_cond_timedwait(&foo.cond, &foo.mutex, &timeout); } pthread_mutex_unlock(&foo.mutex); diff --git a/test/pthread/tst-too-many-cleanups.c b/test/pthread/tst-too-many-cleanups.c new file mode 100644 index 000000000..7828c5036 --- /dev/null +++ b/test/pthread/tst-too-many-cleanups.c @@ -0,0 +1,104 @@ +/* + * This illustrates the bug where the cleanup function + * of a thread may be called too many times. + * + * main thread: + * - grab mutex + * - spawn thread1 + * - go to sleep + * thread1: + * - register cleanup handler via pthread_cleanup_push() + * - try to grab mutex and sleep + * main: + * - kill thread1 + * - go to sleep + * thread1 cleanup handler: + * - try to grab mutex and sleep + * main: + * - kill thread1 + * - go to sleep + * thread1 cleanup handler: + * - wrongly called again + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <assert.h> +#include <unistd.h> + +#define warn(fmt, args...) fprintf(stderr, "[%p] " fmt, (void*)pthread_self(), ## args) +#define warnf(fmt, args...) warn("%s:%i: " fmt, __FUNCTION__, __LINE__, ## args) + +int ok_to_kill_thread; + +static void thread_killed(void *arg); + +static void *KillMeThread(void *thread_par) +{ + pthread_t pthread_id; + + warnf("Starting child thread\n"); + + pthread_id = pthread_self(); + pthread_cleanup_push(thread_killed, (void *)pthread_id); + + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + /* main code */ + warnf("please kill me now\n"); + while (1) { + ok_to_kill_thread = 1; + sleep(1); + } + + pthread_cleanup_pop(0); + + return 0; +} + +static void thread_killed(void *arg) +{ + static int num_times_called = 0; + + warnf("killing %p [cnt=%i]\n", arg, ++num_times_called); + assert(num_times_called == 1); + + /* pick any cancellation endpoint, sleep() will do just fine */ + while (1) { + warnf("sleeping in cancellation endpoint ...\n"); + sleep(1); + } + + warnf("done cleaning up\n"); +} + +int main(int argc, char *argv[]) +{ + int count = 3; + pthread_t app_pthread_id; + + /* need to tweak this test a bit to play nice with signals and LT */ + return 0; + + ok_to_kill_thread = 0; + + pthread_create(&app_pthread_id, NULL, KillMeThread, NULL); + + warnf("waiting for thread to prepare itself\n"); + while (!ok_to_kill_thread) + sleep(1); + + while (count--) { + warnf("killing thread\n"); + pthread_cancel(app_pthread_id); + sleep(3); + } + + return 0; +} |
