diff options
Diffstat (limited to 'test/nptl')
-rw-r--r-- | test/nptl/tst-clock.c | 124 | ||||
-rw-r--r-- | test/nptl/tst-clock_nanosleep.c | 58 | ||||
-rw-r--r-- | test/nptl/tst-cpuclock1.c | 307 | ||||
-rw-r--r-- | test/nptl/tst-cpuclock2.c | 332 | ||||
-rw-r--r-- | test/nptl/tst-cputimer1.c | 68 | ||||
-rw-r--r-- | test/nptl/tst-cputimer2.c | 83 | ||||
-rw-r--r-- | test/nptl/tst-cputimer3.c | 130 | ||||
-rw-r--r-- | test/nptl/tst-mqueue.h | 84 | ||||
-rw-r--r-- | test/nptl/tst-mqueue1.c | 416 | ||||
-rw-r--r-- | test/nptl/tst-mqueue2.c | 477 | ||||
-rw-r--r-- | test/nptl/tst-mqueue3.c | 244 | ||||
-rw-r--r-- | test/nptl/tst-mqueue4.c | 288 | ||||
-rw-r--r-- | test/nptl/tst-mqueue5.c | 1014 | ||||
-rw-r--r-- | test/nptl/tst-mqueue6.c | 305 | ||||
-rw-r--r-- | test/nptl/tst-mqueue7.c | 109 | ||||
-rw-r--r-- | test/nptl/tst-mqueue8.c | 266 | ||||
-rw-r--r-- | test/nptl/tst-mqueue9.c | 92 | ||||
-rw-r--r-- | test/nptl/tst-timer2.c | 65 | ||||
-rw-r--r-- | test/nptl/tst-timer3.c | 86 | ||||
-rw-r--r-- | test/nptl/tst-timer4.c | 648 | ||||
-rw-r--r-- | test/nptl/tst-timer5.c | 38 |
21 files changed, 5234 insertions, 0 deletions
diff --git a/test/nptl/tst-clock.c b/test/nptl/tst-clock.c new file mode 100644 index 000000000..f2f18874a --- /dev/null +++ b/test/nptl/tst-clock.c @@ -0,0 +1,124 @@ +/* Test program for POSIX clock_* functions. + Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <string.h> +#include <time.h> + + +/* We want to see output immediately. */ +#define STDOUT_UNBUFFERED + +/* We expect to run at least 10 seconds. */ +#define TIMEOUT 15 + +static int +clock_test (clockid_t cl) +{ + struct timespec old_ts; + struct timespec ts; + struct timespec waitit; + int result = 0; + int i; + + memset (&ts, '\0', sizeof ts); + + waitit.tv_sec = 0; + waitit.tv_nsec = 500000000; + + /* Get and print resolution of the clock. */ + if (clock_getres (cl, &ts) == 0) + { + if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) + { + printf ("clock %d: nanosecond value of resolution wrong\n", cl); + result = 1; + } + else + printf ("clock %d: resolution = %ld.%09ld secs\n", + cl, ts.tv_sec, ts.tv_nsec); + } + else + { + printf ("clock %d: cannot get resolution\n", cl); + result = 1; + } + + memset (&ts, '\0', sizeof ts); + memset (&old_ts, '\0', sizeof old_ts); + + /* Next get the current time value a few times. */ + for (i = 0; i < 10; ++i) + { + if (clock_gettime (cl, &ts) == 0) + { + if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) + { + printf ("clock %d: nanosecond value of time wrong (try %d)\n", + cl, i); + result = 1; + } + else + { + printf ("clock %d: time = %ld.%09ld secs\n", + cl, ts.tv_sec, ts.tv_nsec); + + if (memcmp (&ts, &old_ts, sizeof ts) == 0) + { + printf ("clock %d: time hasn't changed (try %d)\n", cl, i); + result = 1; + + old_ts = ts; + } + } + } + else + { + printf ("clock %d: cannot get time (try %d)\n", cl, i); + result = 1; + } + + /* Wait a bit before the next iteration. */ + nanosleep (&waitit, NULL); + } + + return result; +} + +static int +do_test (void) +{ + clockid_t cl; + int result; + + result = clock_test (CLOCK_REALTIME); + + if (clock_getcpuclockid (0, &cl) == 0) + /* XXX It's not yet a bug when this fails. */ + clock_test (cl); + else + printf("CPU clock unavailble, skipping test\n"); + + return result; +} +#define TEST_FUNCTION do_test () + + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock_nanosleep.c b/test/nptl/tst-clock_nanosleep.c new file mode 100644 index 000000000..98a8b5f57 --- /dev/null +++ b/test/nptl/tst-clock_nanosleep.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + + +/* Test that clock_nanosleep() does sleep. */ +static int +do_test (void) +{ + /* Current time. */ + struct timeval tv1; + (void) gettimeofday (&tv1, NULL); + + struct timespec ts; + ts.tv_sec = 1; + ts.tv_nsec = 0; + TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts)); + + /* At least one second must have passed. */ + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + tv2.tv_sec -= tv1.tv_sec; + tv2.tv_usec -= tv1.tv_usec; + if (tv2.tv_usec < 0) + --tv2.tv_sec; + + if (tv2.tv_sec < 1) + { + puts ("clock_nanosleep didn't sleep long enough"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cpuclock1.c b/test/nptl/tst-cpuclock1.c new file mode 100644 index 000000000..024df6314 --- /dev/null +++ b/test/nptl/tst-cpuclock1.c @@ -0,0 +1,307 @@ +/* Test program for process CPU clocks. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +/* This function is intended to rack up both user and system time. */ +static void +chew_cpu (void) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); + } +} + +static int +do_test (void) +{ + int result = 0; + clockid_t cl; + int e; + pid_t dead_child, child; + + /* Fork a child and let it die, to give us a PID known not be valid + (assuming PIDs don't wrap around during the test). */ + { + dead_child = fork (); + if (dead_child == 0) + _exit (0); + if (dead_child < 0) + { + perror ("fork"); + return 1; + } + int x; + if (wait (&x) != dead_child) + { + perror ("wait"); + return 2; + } + } + + /* POSIX says we should get ESRCH for this. */ + e = clock_getcpuclockid (dead_child, &cl); + if (e != ENOSYS && e != ESRCH && e != EPERM) + { + printf ("clock_getcpuclockid on dead PID %d => %s\n", + dead_child, strerror (e)); + result = 1; + } + + /* Now give us a live child eating up CPU time. */ + child = fork (); + if (child == 0) + { + chew_cpu (); + _exit (1); + } + if (child < 0) + { + perror ("fork"); + return 1; + } + + e = clock_getcpuclockid (child, &cl); + if (e == EPERM) + { + puts ("clock_getcpuclockid does not support other processes"); + goto done; + } + if (e != 0) + { + printf ("clock_getcpuclockid on live PID %d => %s\n", + child, strerror (e)); + result = 1; + goto done; + } + + const clockid_t child_clock = cl; + struct timespec res; + if (clock_getres (child_clock, &res) < 0) + { + printf ("clock_getres on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d clock %lx resolution %lu.%.9lu\n", + child, (unsigned long int) child_clock, res.tv_sec, res.tv_nsec); + + struct timespec before, after; + if (clock_gettime (child_clock, &before) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d before sleep => %lu.%.9lu\n", + child, before.tv_sec, before.tv_nsec); + + struct timespec sleeptime = { .tv_nsec = 500000000 }; + nanosleep (&sleeptime, NULL); + + if (clock_gettime (child_clock, &after) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d after sleep => %lu.%.9lu\n", + child, after.tv_sec, after.tv_nsec); + + struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec, + .tv_nsec = after.tv_nsec - before.tv_nsec }; + if (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + if (diff.tv_sec != 0 + || diff.tv_nsec > 600000000 + || diff.tv_nsec < 100000000) + { + printf ("before - after %lu.%.9lu outside reasonable range\n", + diff.tv_sec, diff.tv_nsec); + result = 1; + } + + sleeptime.tv_nsec = 100000000; + e = clock_nanosleep (child_clock, 0, &sleeptime, NULL); + if (e == EINVAL || e == ENOTSUP || e == ENOSYS) + { + printf ("clock_nanosleep not supported for other process clock: %s\n", + strerror (e)); + } + else if (e != 0) + { + printf ("clock_nanosleep on other process clock: %s\n", strerror (e)); + result = 1; + } + else + { + struct timespec afterns; + if (clock_gettime (child_clock, &afterns) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + } + else + { + struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec, + .tv_nsec = afterns.tv_nsec - after.tv_nsec }; + if (d.tv_nsec < 0) + { + --d.tv_sec; + d.tv_nsec += 1000000000; + } + if (d.tv_sec > 0 + || d.tv_nsec < sleeptime.tv_nsec + || d.tv_nsec > sleeptime.tv_nsec * 2) + { + printf ("nanosleep time %lu.%.9lu outside reasonable range\n", + d.tv_sec, d.tv_nsec); + result = 1; + } + } + } + + if (kill (child, SIGKILL) != 0) + { + perror ("kill"); + result = 2; + goto done; + } + + /* Wait long enough to let the child finish dying. */ + + sleeptime.tv_nsec = 200000000; + nanosleep (&sleeptime, NULL); + + struct timespec dead; + if (clock_gettime (child_clock, &dead) < 0) + { + printf ("clock_gettime on dead PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("dead PID %d => %lu.%.9lu\n", + child, dead.tv_sec, dead.tv_nsec); + + diff.tv_sec = dead.tv_sec - after.tv_sec; + diff.tv_nsec = dead.tv_nsec - after.tv_nsec; + if (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + if (diff.tv_sec != 0 || diff.tv_nsec > 200000000) + { + printf ("dead - after %lu.%.9lu outside reasonable range\n", + diff.tv_sec, diff.tv_nsec); + result = 1; + } + + /* Now reap the child and verify that its clock is no longer valid. */ + { + int x; + if (waitpid (child, &x, 0) != child) + { + perror ("waitpid"); + result = 1; + } + } + + if (clock_gettime (child_clock, &dead) == 0) + { + printf ("clock_gettime on reaped PID %d clock %lx => %lu%.9lu\n", + child, (unsigned long int) child_clock, + dead.tv_sec, dead.tv_nsec); + result = 1; + } + else + { + if (errno != EINVAL) + result = 1; + printf ("clock_gettime on reaped PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + } + + if (clock_getres (child_clock, &dead) == 0) + { + printf ("clock_getres on reaped PID %d clock %lx => %lu%.9lu\n", + child, (unsigned long int) child_clock, + dead.tv_sec, dead.tv_nsec); + result = 1; + } + else + { + if (errno != EINVAL) + result = 1; + printf ("clock_getres on reaped PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + } + + return result; + + done: + { + if (kill (child, SIGKILL) != 0 && errno != ESRCH) + { + perror ("kill"); + return 2; + } + int x; + if (waitpid (child, &x, 0) != child && errno != ECHILD) + { + perror ("waitpid"); + return 2; + } + } + + return result; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cpuclock2.c b/test/nptl/tst-cpuclock2.c new file mode 100644 index 000000000..d1621f3d0 --- /dev/null +++ b/test/nptl/tst-cpuclock2.c @@ -0,0 +1,332 @@ +/* Test program for process and thread CPU clocks. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> + +#if (_POSIX_THREADS - 0) <= 0 + +# define TEST_FUNCTION 0 + +#else + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> + +static pthread_barrier_t barrier; + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + pthread_barrier_wait (&barrier); + + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static unsigned long long int +tsdiff (const struct timespec *before, const struct timespec *after) +{ + struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec, + .tv_nsec = after->tv_nsec - before->tv_nsec }; + while (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + return diff.tv_sec * 1000000000ULL + diff.tv_nsec; +} + +static unsigned long long int +test_nanosleep (clockid_t clock, const char *which, + const struct timespec *before, int *bad) +{ + const struct timespec sleeptime = { .tv_nsec = 100000000 }; + int e = clock_nanosleep (clock, 0, &sleeptime, NULL); + if (e == EINVAL || e == ENOTSUP || e == ENOSYS) + { + printf ("clock_nanosleep not supported for %s CPU clock: %s\n", + which, strerror (e)); + return 0; + } + if (e != 0) + { + printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e)); + *bad = 1; + return 0; + } + + struct timespec after; + if (clock_gettime (clock, &after) < 0) + { + printf ("clock_gettime on %s CPU clock %lx => %s\n", + which, (unsigned long int) clock, strerror (errno)); + *bad = 1; + return 0; + } + + unsigned long long int diff = tsdiff (before, &after); + if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2) + { + printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n", + which, diff); + *bad = 1; + return diff; + } + + struct timespec sleeptimeabs = sleeptime; + sleeptimeabs.tv_sec += after.tv_sec; + sleeptimeabs.tv_nsec += after.tv_nsec; + while (sleeptimeabs.tv_nsec > 1000000000) + { + ++sleeptimeabs.tv_sec; + sleeptimeabs.tv_nsec -= 1000000000; + } + e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL); + if (e != 0) + { + printf ("absolute clock_nanosleep on %s CPU clock: %s\n", + which, strerror (e)); + *bad = 1; + return diff; + } + + struct timespec afterabs; + if (clock_gettime (clock, &afterabs) < 0) + { + printf ("clock_gettime on %s CPU clock %lx => %s\n", + which, (unsigned long int) clock, strerror (errno)); + *bad = 1; + return diff; + } + + unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs); + if (sleepdiff > sleeptime.tv_nsec) + { + printf ("\ +absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n", + which, sleepdiff); + *bad = 1; + } + + unsigned long long int diffabs = tsdiff (&after, &afterabs); + if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2) + { + printf ("\ +absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n", + which, diffabs); + *bad = 1; + } + + return diff + diffabs; +} + + + +static int +do_test (void) +{ + int result = 0; + clockid_t process_clock, th_clock, my_thread_clock; + int e; + pthread_t th; + + e = clock_getcpuclockid (0, &process_clock); + if (e != 0) + { + printf ("clock_getcpuclockid on self => %s\n", strerror (e)); + return 1; + } + + e = pthread_getcpuclockid (pthread_self (), &my_thread_clock); + if (e != 0) + { + printf ("pthread_getcpuclockid on self => %s\n", strerror (e)); + return 1; + } + + /* This is a kludge. This test fails if the semantics of thread and + process clocks are wrong. The old code using hp-timing without kernel + support has bogus semantics if there are context switches. We don't + fail to report failure when the proper functionality is not available + in the kernel. It so happens that Linux kernels without correct CPU + clock support also lack CPU timer support, so we use use that to guess + that we are using the bogus code and not test it. */ + timer_t t; + if (timer_create (my_thread_clock, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + puts ("No support for CPU clocks with good semantics, skipping test"); + return 0; + } + timer_delete (t); + + + pthread_barrier_init (&barrier, NULL, 2); + + e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + return 1; + } + + e = pthread_getcpuclockid (th, &th_clock); + if (e == ENOENT || e == ENOSYS || e == ENOTSUP) + { + puts ("pthread_getcpuclockid does not support other threads"); + return 1; + } + + pthread_barrier_wait (&barrier); + + struct timespec res; + if (clock_getres (th_clock, &res) < 0) + { + printf ("clock_getres on thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + result = 1; + return 1; + } + printf ("live thread clock %lx resolution %lu.%.9lu\n", + (unsigned long int) th_clock, res.tv_sec, res.tv_nsec); + + struct timespec process_before, process_after; + if (clock_gettime (process_clock, &process_before) < 0) + { + printf ("clock_gettime on process clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + + struct timespec before, after; + if (clock_gettime (th_clock, &before) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("live thread before sleep => %lu.%.9lu\n", + before.tv_sec, before.tv_nsec); + + struct timespec me_before, me_after; + if (clock_gettime (my_thread_clock, &me_before) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("self thread before sleep => %lu.%.9lu\n", + me_before.tv_sec, me_before.tv_nsec); + + struct timespec sleeptime = { .tv_nsec = 500000000 }; + nanosleep (&sleeptime, NULL); + + if (clock_gettime (th_clock, &after) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("live thread after sleep => %lu.%.9lu\n", + after.tv_sec, after.tv_nsec); + + if (clock_gettime (process_clock, &process_after) < 0) + { + printf ("clock_gettime on process clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + + if (clock_gettime (my_thread_clock, &me_after) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("self thread after sleep => %lu.%.9lu\n", + me_after.tv_sec, me_after.tv_nsec); + + unsigned long long int th_diff = tsdiff (&before, &after); + unsigned long long int pdiff = tsdiff (&process_before, &process_after); + unsigned long long int my_diff = tsdiff (&me_before, &me_after); + + if (th_diff < 100000000 || th_diff > 600000000) + { + printf ("thread before - after %llu outside reasonable range\n", + th_diff); + result = 1; + } + + if (my_diff > 100000000) + { + printf ("self thread before - after %llu outside reasonable range\n", + my_diff); + result = 1; + } + + if (pdiff < th_diff) + { + printf ("process before - after %llu outside reasonable range (%llu)\n", + pdiff, th_diff); + result = 1; + } + + process_after.tv_nsec += test_nanosleep (th_clock, "thread", + &after, &result); + process_after.tv_nsec += test_nanosleep (process_clock, "process", + &process_after, &result); + test_nanosleep (CLOCK_PROCESS_CPUTIME_ID, + "PROCESS_CPUTIME_ID", &process_after, &result); + + pthread_cancel (th); + + e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL); + if (e != EINVAL) + { + printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n", + strerror (e)); + result = 1; + } + + return result; +} +# define TIMEOUT 8 +# define TEST_FUNCTION do_test () +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cputimer1.c b/test/nptl/tst-cputimer1.c new file mode 100644 index 000000000..8f5dd76cf --- /dev/null +++ b/test/nptl/tst-cputimer1.c @@ -0,0 +1,68 @@ +/* Tests for POSIX timer implementation using process CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> + +#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "process CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static int +setup_test (void) +{ + /* Test timers on our own process CPU clock by having a worker thread + eating CPU. First make sure we can make such timers at all. */ + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + pthread_t th; + int e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + exit (1); + } + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-cputimer2.c b/test/nptl/tst-cputimer2.c new file mode 100644 index 000000000..397d7998c --- /dev/null +++ b/test/nptl/tst-cputimer2.c @@ -0,0 +1,83 @@ +/* Tests for POSIX timer implementation using thread CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> + +static clockid_t worker_thread_clock; + +#define TEST_CLOCK worker_thread_clock +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "thread CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static int +setup_test (void) +{ + /* Test timers on a thread CPU clock by having a worker thread eating + CPU. First make sure we can make such timers at all. */ + + pthread_t th; + int e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + exit (1); + } + + e = pthread_getcpuclockid (th, &worker_thread_clock); + if (e == EPERM || e == ENOENT || e == ENOTSUP) + { + puts ("pthread_getcpuclockid does not support other threads"); + return 1; + } + if (e != 0) + { + printf ("pthread_getcpuclockid: %s\n", strerror (e)); + exit (1); + } + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-cputimer3.c b/test/nptl/tst-cputimer3.c new file mode 100644 index 000000000..056766a37 --- /dev/null +++ b/test/nptl/tst-cputimer3.c @@ -0,0 +1,130 @@ +/* Tests for POSIX timer implementation using another process's CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <signal.h> +#include <sys/wait.h> + +static clockid_t child_clock; + +#define TEST_CLOCK child_clock +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "other-process CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void +chew_cpu (void) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); + } +} + +static pid_t child; +static void +cleanup_child (void) +{ + if (child <= 0) + return; + if (kill (child, SIGKILL) < 0 && errno != ESRCH) + printf ("cannot kill child %d: %m\n", child); + else + { + int status; + errno = 0; + if (waitpid (child, &status, 0) != child) + printf ("waitpid %d: %m\n", child); + } +} +#define CLEANUP_HANDLER cleanup_child () + +static int +setup_test (void) +{ + /* Test timers on a process CPU clock by having a child process eating + CPU. First make sure we can make such timers at all. */ + + int pipefd[2]; + if (pipe (pipefd) < 0) + { + printf ("pipe: %m\n"); + exit (1); + } + + child = fork (); + + if (child == 0) + { + char c; + close (pipefd[1]); + if (read (pipefd[0], &c, 1) == 1) + chew_cpu (); + _exit (1); + } + + if (child < 0) + { + printf ("fork: %m\n"); + exit (1); + } + + atexit (&cleanup_child); + + close (pipefd[0]); + + int e = clock_getcpuclockid (child, &child_clock); + if (e == EPERM) + { + puts ("clock_getcpuclockid does not support other processes"); + return 1; + } + if (e != 0) + { + printf ("clock_getcpuclockid: %s\n", strerror (e)); + exit (1); + } + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + /* Get the child started chewing. */ + if (write (pipefd[1], "x", 1) != 1) + { + printf ("write to pipe: %m\n"); + return 1; + } + close (pipefd[1]); + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-mqueue.h b/test/nptl/tst-mqueue.h new file mode 100644 index 000000000..8e73be51c --- /dev/null +++ b/test/nptl/tst-mqueue.h @@ -0,0 +1,84 @@ +/* Common code for message queue passing tests. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <mqueue.h> +#include <search.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/uio.h> +#include <unistd.h> + +static int temp_mq_fd; + +/* Add temporary files in list. */ +static void +__attribute__ ((unused)) +add_temp_mq (const char *name) +{ + struct iovec iov[2]; + iov[0].iov_base = (char *) name; + iov[0].iov_len = strlen (name); + iov[1].iov_base = (char *) "\n"; + iov[1].iov_len = 1; + if (writev (temp_mq_fd, iov, 2) != iov[0].iov_len + 1) + printf ("Could not record temp mq filename %s\n", name); +} + +/* Delete all temporary message queues. */ +static void +do_cleanup (void) +{ + if (lseek (temp_mq_fd, 0, SEEK_SET) != 0) + return; + + FILE *f = fdopen (temp_mq_fd, "r"); + if (f == NULL) + return; + + char *line = NULL; + size_t n = 0; + ssize_t rets; + while ((rets = getline (&line, &n, f)) > 0) + { + if (line[rets - 1] != '\n') + continue; + + line[rets - 1] = '\0'; + mq_unlink (line); + } + fclose (f); +} + +static void +do_prepare (void) +{ + char name [] = "/tmp/tst-mqueueN.XXXXXX"; + temp_mq_fd = mkstemp (name); + if (temp_mq_fd == -1) + { + printf ("Could not create temporary file %s: %m\n", name); + exit (1); + } + unlink (name); +} + +#define PREPARE(argc, argv) do_prepare () +#define CLEANUP_HANDLER do_cleanup () diff --git a/test/nptl/tst-mqueue1.c b/test/nptl/tst-mqueue1.c new file mode 100644 index 000000000..c7ac81a2f --- /dev/null +++ b/test/nptl/tst-mqueue1.c @@ -0,0 +1,416 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static int +intcmp (const void *a, const void *b) +{ + if (*(unsigned char *)a < *(unsigned char *)b) + return 1; + if (*(unsigned char *)a > *(unsigned char *)b) + return -1; + return 0; +} + +static int +check_attrs (struct mq_attr *attr, int nonblock, long cnt) +{ + int result = 0; + + if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1) + { + printf ("attributes don't match those passed to mq_open\n" + "mq_maxmsg %ld, mq_msgsize %ld\n", + attr->mq_maxmsg, attr->mq_msgsize); + result = 1; + } + + if ((attr->mq_flags & O_NONBLOCK) != nonblock) + { + printf ("mq_flags %lx != %x\n", (attr->mq_flags & O_NONBLOCK), nonblock); + result = 1; + } + + if (attr->mq_curmsgs != cnt) + { + printf ("mq_curmsgs %ld != %ld\n", attr->mq_curmsgs, cnt); + result = 1; + } + + return result; +} + +static int +do_one_test (mqd_t q, const char *name, int nonblock) +{ + int result = 0; + + char v [] + = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 }; + + struct mq_attr attr; + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + if (mq_receive (q, &v[0], 1, NULL) != -1) + { + puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + --ts.tv_sec; + else + { + ts.tv_sec = time (NULL) - 1; + ts.tv_nsec = 0; + } + + int ret; + for (int i = 0; i < 10; ++i) + { + if (i & 1) + ret = mq_send (q, &v[i], 1, v[i] >> 4); + else + ret = mq_timedsend (q, &v[i], 1, v[i] >> 4, &ts); + + if (ret) + { + printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed"); + result = 1; + } + } + + ret = mq_timedsend (q, &v[10], 1, 8, &ts); + if (ret != -1) + { + puts ("mq_timedsend on full queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedsend on full queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_send (q, &v[10], 1, 8); + if (ret != -1) + { + puts ("mq_send on full non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_send on full non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 10); + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + result = 1; + } + else if (pid == 0) + { + result = 0; + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + q = mq_open (name, O_RDONLY | nonblock); + if (q == (mqd_t) -1) + { + printf ("mq_open in child failed: %m\n"); + exit (1); + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 10); + + unsigned char vr[11] = { }; + unsigned int prio; + ssize_t rets; + + if (mq_send (q, &v[0], 1, 1) != -1) + { + puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + for (int i = 0; i < 10; ++i) + { + if (i & 1) + rets = mq_receive (q, (char *) &vr[i], 1, &prio); + rets = mq_timedreceive (q, (char *) &vr[i], 1, &prio, &ts); + + if (rets != 1) + { + if (rets == -1) + printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed"); + else + printf ("mq_%sreceive returned %zd != 1\n", + (i & 1) ? "" : "timed", rets); + result = 1; + } + else if (prio != (unsigned int) vr[i] >> 4) + { + printf ("unexpected priority %x for value %02x\n", prio, + vr[i]); + result = 1; + } + } + + qsort (v, 10, 1, intcmp); + if (memcmp (v, vr, 10) != 0) + { + puts ("messages not received in expected order"); + result = 1; + } + + rets = mq_timedreceive (q, (char *) &vr[10], 1, &prio, &ts); + if (rets != -1) + { + puts ("mq_timedreceive on empty queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedreceive on empty queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_receive (q, (char *) &vr[10], 1, &prio); + if (ret != -1) + { + puts ("mq_receive on empty non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_receive on empty non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + exit (result); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed: %d\n", status); + result = 1; + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + return result; +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + result |= do_one_test (q, name, 0); + + mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK); + if (q2 == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + q2 = q; + result = 1; + } + else + { + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + q = q2; + result |= do_one_test (q, name, O_NONBLOCK); + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + { + attr.mq_flags ^= O_NONBLOCK; + + struct mq_attr attr2; + memset (&attr2, 0x55, sizeof (attr2)); + if (mq_setattr (q, &attr, &attr2) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK) + || attr.mq_maxmsg != attr2.mq_maxmsg + || attr.mq_msgsize != attr2.mq_msgsize + || attr.mq_curmsgs != 0 + || attr2.mq_curmsgs != 0) + { + puts ("mq_setattr returned unexpected values in *omqstat"); + result = 1; + } + else + { + result |= do_one_test (q, name, 0); + + if (mq_setattr (q, &attr2, NULL) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else + result |= do_one_test (q, name, O_NONBLOCK); + } + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_close (q) != -1) + { + puts ("second mq_close did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("second mq_close did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue2.c b/test/nptl/tst-mqueue2.c new file mode 100644 index 000000000..1948965c6 --- /dev/null +++ b/test/nptl/tst-mqueue2.c @@ -0,0 +1,477 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static void +alrm_handler (int sig) +{ +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with O_EXCL unexpectedly succeeded"); + result = 1; + } + else if (errno != EEXIST) + { + printf ("mq_open did not fail with EEXIST: %m\n"); + result = 1; + } + + char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3]; + snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ()); + + attr.mq_maxmsg = -2; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_maxmsg did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + attr.mq_maxmsg = 2; + attr.mq_msgsize = -56; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_msgsize unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_msgsize did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + char buf[3]; + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ts.tv_sec += 10; + else + { + ts.tv_sec = time (NULL) + 10; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0) + { + puts ("mq_timedreceive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_timedreceive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -1; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = 1000000000; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it = { .it_value = { .tv_sec = 1 } }; + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_receive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_nsec = 0; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + buf[0] = '6'; + buf[1] = '7'; + if (mq_send (q, buf, 2, 3) != 0 + || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0)) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q, buf, 3, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 4 || memcmp (buf, "8 ", 3) != 0) + { + printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + rets = mq_receive (q, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "67 ", 3) != 0) + { + printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + buf[0] = '2'; + buf[1] = '1'; + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + if ((mq_timedsend (q, buf, 2, 5, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0)) + || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec, + (mq_timedsend (q, buf, 1, 4, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0)))) + { + printf ("mq_timedsend failed: %m\n"); + result = 1; + } + + buf[0] = '-'; + ts.tv_nsec = 1000000001; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = -2; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with megatove tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_send (q, buf, 2, 8) == 0) + { + puts ("mq_send on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_send on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_sec += 10; + ts.tv_nsec = 0; + if (mq_timedsend (q, buf, 2, 7, &ts) == 0) + { + puts ("mq_timedsend on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedsend on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + rets = mq_timedreceive (q, buf, 2, &prio, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, &prio); + if (rets != 2) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 2\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "21 ", 3) != 0) + { + printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_receive (q, buf, 1, NULL) == 0) + { + puts ("mq_receive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_receive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -ts.tv_nsec; + rets = mq_timedreceive (q, buf, 2, NULL, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, NULL); + if (rets != 1) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 1\n", rets); + result = 1; + } + else if (memcmp (buf, "31 ", 3) != 0) + { + printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_send (q, "", 0, 2) != 0) + { + printf ("mq_send with msg_len 0 failed: %m\n"); + result = 1; + } + + rets = mq_receive (q, buf, 2, &prio); + if (rets) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 0\n", rets); + result = 1; + } + + long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX); + if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max) + { + if (mq_send (q, buf, 1, mq_prio_max) == 0) + { + puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_send with MQ_PRIO_MAX priority did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, mq_prio_max - 1) != 0) + { + printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n"); + result = 1; + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDWR); + if (q2 != (mqd_t) -1) + { + printf ("mq_open of unlinked %s without O_CREAT unexpectedly" + "succeeded\n", name); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_open of unlinked %s without O_CREAT did not fail with " + "ENOENT: %m\n", name); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, 2) == 0) + { + puts ("mq_send on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_getattr (q, &attr) == 0) + { + puts ("mq_getattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&attr, 0, sizeof (attr)); + if (mq_setattr (q, &attr, NULL) == 0) + { + puts ("mq_setattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1) + { + puts ("mq_unlink of non-existant message queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_unlink of non-existant message queue did not fail with " + "ENOENT: %m\n"); + result = 1; + } + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue3.c b/test/nptl/tst-mqueue3.c new file mode 100644 index 000000000..990e05728 --- /dev/null +++ b/test/nptl/tst-mqueue3.c @@ -0,0 +1,244 @@ +/* Test SIGEV_THREAD handling for POSIX message queues. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +static pid_t pid; +static mqd_t m; +static const char message[] = "hello"; + +# define MAXMSG 10 +# define MSGSIZE 10 +# define UNIQUE 42 + + +static void +fct (union sigval s) +{ + /* Put the mq in non-blocking mode. */ + struct mq_attr attr; + if (mq_getattr (m, &attr) != 0) + { + printf ("%s: mq_getattr failed: %m\n", __FUNCTION__); + exit (1); + } + attr.mq_flags |= O_NONBLOCK; + if (mq_setattr (m, &attr, NULL) != 0) + { + printf ("%s: mq_setattr failed: %m\n", __FUNCTION__); + exit (1); + } + + /* Check the values. */ + if (attr.mq_maxmsg != MAXMSG) + { + printf ("%s: mq_maxmsg wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_maxmsg, MAXMSG); + exit (1); + } + if (attr.mq_msgsize != MAXMSG) + { + printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_msgsize, MSGSIZE); + exit (1); + } + + /* Read the message. */ + char buf[attr.mq_msgsize]; + ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL)); + if (n != sizeof (message)) + { + printf ("%s: length of message wrong: is %zd, expected %zu\n", + __FUNCTION__, n, sizeof (message)); + exit (1); + } + if (memcmp (buf, message, sizeof (message)) != 0) + { + printf ("%s: message wrong: is \"%s\", expected \"%s\"\n", + __FUNCTION__, buf, message); + exit (1); + } + + exit (UNIQUE); +} + + +int +do_test (void) +{ + char tmpfname[] = "/tmp/tst-mqueue3-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b; + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + /* Name for the message queue. */ + char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)]; + snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld", + (long int) getpid ()); + + /* Create the message queue. */ + struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE }; + m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (m == -1) + { + if (errno == ENOSYS) + { + puts ("not implemented"); + return 0; + } + + puts ("mq_open failed"); + return 1; + } + + /* Unlink the message queue right away. */ + if (mq_unlink (mqname) != 0) + { + puts ("mq_unlink failed"); + return 1; + } + + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + if (pid == 0) + { + /* Request notification via thread. */ + struct sigevent ev; + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_value.sival_ptr = NULL; + ev.sigev_notify_attributes = NULL; + + /* Tell the kernel. */ + if (mq_notify (m,&ev) != 0) + { + puts ("mq_notify failed"); + exit (1); + } + + /* Tell the parent we are ready. */ + (void) pthread_barrier_wait (b); + + /* Make sure the process goes away eventually. */ + alarm (10); + + /* Do nothing forever. */ + while (1) + pause (); + } + + /* Wait for the child process to register to notification method. */ + (void) pthread_barrier_wait (b); + + /* Send the message. */ + if (mq_send (m, message, sizeof (message), 1) != 0) + { + kill (pid, SIGKILL); + puts ("mq_send failed"); + return 1; + } + + int r; + if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid) + { + kill (pid, SIGKILL); + puts ("waitpid failed"); + return 1; + } + + return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1; +} +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue4.c b/test/nptl/tst-mqueue4.c new file mode 100644 index 000000000..aa31706f8 --- /dev/null +++ b/test/nptl/tst-mqueue4.c @@ -0,0 +1,288 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX]; + char *p; + p = name + snprintf (name, sizeof (name), "/tst-mqueue4-%u", getpid ()); + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + *p = '.'; + memset (p + 1, 'x', NAME_MAX + 1 - (p - name)); + name[NAME_MAX + 1] = '\0'; + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open with NAME_MAX long name compoment failed with: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + name[NAME_MAX + 1] = 'x'; + name[NAME_MAX + 2] = '\0'; + q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with too long name component unexpectedly succeeded"); + mq_unlink (name); + mq_close (q2); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_open with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + if (mq_unlink (name) == 0) + { + puts ("mq_unlink with too long name component unexpectedly succeeded"); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_unlink with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + *p = '\0'; + attr.mq_maxmsg = 1; + attr.mq_msgsize = 3; + q2 = mq_open (name, O_CREAT | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_EXCL failed with %m\n"); + result = 1; + } + + char buf[3]; + strcpy (buf, "jk"); + if (mq_send (q, buf, 2, 4) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_send (q, buf + 1, 1, 5) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_getattr (q2, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 2) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedsend (q2, buf, 1, 1, &ts) == 0) + { + puts ("mq_timedsend unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedsend did not fail with ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDONLY, 0600); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + mqd_t q3 = mq_open (name, O_RDONLY, 0600); + if (q3 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q2, buf, 2, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "k ", 3) != 0) + { + printf ("mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_getattr (q3, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 1) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + rets = mq_receive (q3, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "jk ", 3) != 0) + { + printf ("mq_receive returned buf \"%c%c%c\" != \"jk \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q2, buf, 2, NULL, &ts) != -1) + { + puts ("mq_timedreceive on empty queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedreceive on empty queue did not fail with " + "ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue5.c b/test/nptl/tst-mqueue5.c new file mode 100644 index 000000000..97571da8a --- /dev/null +++ b/test/nptl/tst-mqueue5.c @@ -0,0 +1,1014 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 3 + +#if _POSIX_THREADS +# include <pthread.h> + +volatile int rtmin_cnt; +volatile pid_t rtmin_pid; +volatile uid_t rtmin_uid; +volatile int rtmin_code; +volatile union sigval rtmin_sigval; + +static void +rtmin_handler (int sig, siginfo_t *info, void *ctx) +{ + if (sig != SIGRTMIN) + abort (); + ++rtmin_cnt; + rtmin_pid = info->si_pid; + rtmin_uid = info->si_uid; + rtmin_code = info->si_code; + rtmin_sigval = info->si_value; +} + +#define mqsend(q) (mqsend) (q, __LINE__) +static int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +#define mqrecv(q) (mqrecv) (q, __LINE__) +static int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +struct thr_data +{ + const char *name; + pthread_barrier_t *b3; + mqd_t q; +}; + +static void * +thr (void *arg) +{ + pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3; + mqd_t q = ((struct thr_data *)arg)->q; + const char *name = ((struct thr_data *)arg)->name; + int result = 0; + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 0xdeadbeef) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (%d)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int, 0xdeadbeef); + result = 1; + } + + struct sigevent ev; + memset (&ev, 0x82, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + if (mq_notify (q, NULL) != 0) + { + printf ("second mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q4 = mq_open (name, O_RDONLY); + if (q4 == (mqd_t) -1) + { + printf ("mq_open in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q4, NULL) != 0) + { + printf ("mq_notify in thread (q4, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q4) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q5 = mq_open (name, O_WRONLY); + if (q5 == (mqd_t) -1) + { + printf ("mq_open O_WRONLY in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q5, NULL) != 0) + { + printf ("mq_notify in thread (q5, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q5) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + + return (void *) (long) result; +} + +static void +do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3, + mqd_t q) +{ + int result = 0; + + struct sigevent ev; + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which makes notification available. */ + + (void) pthread_barrier_wait (b2); + + rtmin_cnt = 0; + + if (mq_notify (q, &ev) != 0) + { + printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal in child caught too early"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify. */ + /* Parent calls mqsend (q), which makes notification available + and triggers a signal in the child. */ + /* Parent successfully calls mq_notify SIGEV_SIGNAL. */ + + (void) pthread_barrier_wait (b2); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_ptr != &ev) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_ptr %p (%p)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_ptr, &ev); + result = 1; + } + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Parent verifies caught SIGRTMIN. */ + + mqd_t q2 = mq_open (name, O_RDWR); + if (q2 == (mqd_t) -1) + { + printf ("mq_open in child failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent mq_open's another mqd_t for the same queue (q3). */ + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q2, &ev) != 0) + { + printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent successfully calls mq_notify { SIGEV_NONE } on q3. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &b2; + if (mq_notify (q, &ev) == 0) + { + puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mq_close on q3, which makes the queue available again for + notification. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x13, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in child (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + struct thr_data thr_data = { .name = name, .b3 = b3, .q = q }; + pthread_t th; + int ret = pthread_create (&th, NULL, thr, &thr_data); + if (ret) + { + errno = ret; + printf ("pthread_created failed with: %m\n"); + result = 1; + } + + /* Wait till thr calls mq_receive on the empty queue q and blocks on it. */ + sleep (1); + + memset (&ev, 0x5f, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 0xdeadbeef; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which should wake up mqrecv (q) + in the thread but no notification should be sent. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught while thr was blocked on mq_receive"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been received. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + memset (&ev, 0x6a, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = do_child; + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL), which should unregister the above + notification. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0x7b, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = thr; + if (mq_notify (q, &ev) != 0) + { + printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0xe1, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 127; + if (mq_notify (q, &ev) != 0) + { + printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + void *thr_ret; + ret = pthread_join (th, &thr_ret); + if (ret) + { + errno = ret; + printf ("pthread_join failed: %m\n"); + result = 1; + } + else if (thr_ret) + result = 1; + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + exit (result); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b2; + b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrier_t *b3; + b3 = b2 + 1; + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b2, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (b3, &a, 3) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + /* Implementation-defined behaviour, so don't fail, + just inform. */ + printf ("second mq_notify (q, NULL) failed with: %m\n"); + } + + struct sigaction sa = { .sa_sigaction = rtmin_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 26; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqsend (q); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != getpid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 26) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n", + rtmin_pid, getpid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int); + result = 1; + } + + ev.sigev_value.sival_int = 75; + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork () failed: %m\n"); + mq_unlink (name); + return 1; + } + + if (pid == 0) + do_child (name, b2, b3, q); + + /* Child unsuccessfully attempts to mq_notify. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify SIGEV_SIGNAL now. */ + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 15; + if (mq_notify (q, &ev) == 0) + { + puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child verifies caught SIGRTMIN signal. */ + /* Child calls mq_send (q) which triggers SIGRTMIN signal here. */ + + (void) pthread_barrier_wait (b2); + + /* Child mq_open's another mqd_t for the same queue (q2). */ + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != pid + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 15) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n", + rtmin_pid, pid, rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child calls mq_close on q2, which makes the queue available again for + notification. */ + + mqd_t q3 = mq_open (name, O_RDWR); + if (q3 == (mqd_t) -1) + { + printf ("mq_open q3 in parent failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x12, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q3, &ev) != 0) + { + printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_NONE } on q. */ + /* Child successfully calls mq_notify NULL on q. */ + + (void) pthread_barrier_wait (b2); + + /* Child creates new thread. */ + /* Thread blocks on mqrecv (q). */ + /* Child sleeps for 1sec so that thread has time to reach that point. */ + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been caught. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL). */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL). */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed with status %d\n", status); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue6.c b/test/nptl/tst-mqueue6.c new file mode 100644 index 000000000..5a76bb59f --- /dev/null +++ b/test/nptl/tst-mqueue6.c @@ -0,0 +1,305 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#if _POSIX_THREADS +# include <pthread.h> + +# define mqsend(q) (mqsend) (q, __LINE__) +static int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +# define mqrecv(q) (mqrecv) (q, __LINE__) +static int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +volatile int fct_cnt, fct_err; +size_t fct_guardsize; + +static void +fct (union sigval s) +{ + mqd_t q = *(mqd_t *) s.sival_ptr; + + pthread_attr_t nattr; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("pthread_getattr_np failed: %m\n"); + fct_err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &fct_guardsize); + if (ret) + { + errno = ret; + printf ("pthread_attr_getguardsize failed: %m\n"); + fct_err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + fct_err = 1; + } + } + + ++fct_cnt; + fct_err |= mqsend (q); +} + +# define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + fct_guardsize = 1; + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = (struct __pthread_attr_s *) &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + size_t ps = sysconf (_SC_PAGESIZE); + if (pthread_attr_setguardsize (&nattr, 32 * ps)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 0) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 1) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 0) + { + printf ("fct_guardsize %zd != 0\n", fct_guardsize); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 1) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 2) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 32 * ps) + { + printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_int = 0; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (fct_err) + result = 1; + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue7.c b/test/nptl/tst-mqueue7.c new file mode 100644 index 000000000..34222f834 --- /dev/null +++ b/test/nptl/tst-mqueue7.c @@ -0,0 +1,109 @@ +/* Test all open message queues descriptors are closed during exec*. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#define OPT_AFTEREXEC 20000 + +static mqd_t after_exec = (mqd_t) -1; + +#define CMDLINE_OPTIONS \ + { "after-exec", required_argument, NULL, OPT_AFTEREXEC }, + +#define CMDLINE_PROCESS \ + case OPT_AFTEREXEC: \ + after_exec = (mqd_t) strtoul (optarg, NULL, 0); \ + break; + +static int +do_after_exec (void) +{ + int result = 0; + + struct mq_attr attr; + if (mq_getattr (after_exec, &attr) == 0) + { + puts ("mq_getattr after exec unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr after exec did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +static int +do_test (int argc, char **argv) +{ + if (after_exec != (mqd_t) -1) + return do_after_exec (); + + char name[sizeof "/tst-mqueue7-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue7-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + else if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + return 1; + } + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + return 1; + } + + char after_exec_arg[sizeof "--after-exec=0x" + sizeof (long) * 3]; + snprintf (after_exec_arg, sizeof (after_exec_arg), + "--after-exec=0x%lx", (long) q); + + const char *newargv[argc + 2]; + for (int i = 1; i < argc; ++i) + newargv[i - 1] = argv[i]; + newargv[argc - 1] = "--direct"; + newargv[argc] = after_exec_arg; + newargv[argc + 1] = NULL; + + /* Verify that exec* has the effect of mq_close (q). */ + execv (newargv[0], (char * const *) newargv); + printf ("execv failed: %m\n"); + return 1; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue8.c b/test/nptl/tst-mqueue8.c new file mode 100644 index 000000000..7e902aa60 --- /dev/null +++ b/test/nptl/tst-mqueue8.c @@ -0,0 +1,266 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + +static pthread_barrier_t b; + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + +#define TF_MQ_RECEIVE 0L +#define TF_MQ_TIMEDRECEIVE 1L +#define TF_MQ_SEND 2L +#define TF_MQ_TIMEDSEND 3L + +static const char *names[] + = { "mq_receive", "mq_timedreceive", "mq_send", "mq_timedsend" }; + +static mqd_t q; +static struct timespec never; + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char c = ' '; + + switch ((long) arg) + { + case TF_MQ_SEND: + TEMP_FAILURE_RETRY (mq_send (q, &c, 1, 1)); + break; + case TF_MQ_TIMEDSEND: + TEMP_FAILURE_RETRY (mq_timedsend (q, &c, 1, 1, &never)); + break; + case TF_MQ_RECEIVE: + TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + break; + case TF_MQ_TIMEDRECEIVE: + TEMP_FAILURE_RETRY (mq_timedreceive (q, &c, 1, NULL, &never)); + break; + } + + pthread_cleanup_pop (0); + + printf ("tf: %s returned\n", names[(long) arg]); + + exit (1); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + char name[sizeof "/tst-mqueue8-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue8-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (clock_gettime (CLOCK_REALTIME, &never) == 0) + never.tv_sec += 100; + else + { + never.tv_sec = time (NULL) + 100; + never.tv_nsec = 0; + } + + int result = 0; + for (long l = TF_MQ_RECEIVE; l <= TF_MQ_TIMEDSEND; ++l) + { + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) l) != 0) + { + printf ("1st %s create failed\n", names[l]); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + result = 1; + continue; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + printf ("going to cancel %s in-time\n", names[l]); + if (pthread_cancel (th) != 0) + { + printf ("1st cancel of %s failed\n", names[l]); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("1st join of %s failed\n", names[l]); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("1st %s thread not canceled\n", names[l]); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("%s cleanup handler not called\n", names[l]); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("%s cleanup handler called more than once\n", names[l]); + result = 1; + continue; + } + + printf ("in-time %s cancellation succeeded\n", names[l]); + + cl_called = 0; + + if (pthread_create (&th, NULL, tf, (void *) l) != 0) + { + printf ("2nd %s create failed\n", names[l]); + result = 1; + continue; + } + + printf ("going to cancel %s early\n", names[l]); + if (pthread_cancel (th) != 0) + { + printf ("2nd cancel of %s failed\n", names[l]); + result = 1; + continue; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + result = 1; + continue; + } + + if (pthread_join (th, &status) != 0) + { + printf ("2nd join of %s failed\n", names[l]); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("2nd %s thread not canceled\n", names[l]); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("%s cleanup handler not called\n", names[l]); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("%s cleanup handler called more than once\n", names[l]); + result = 1; + continue; + } + + printf ("early %s cancellation succeeded\n", names[l]); + + if (l == TF_MQ_TIMEDRECEIVE) + { + /* mq_receive and mq_timedreceive are tested on empty mq. + For mq_send and mq_timedsend we need to make it full. + If this fails, there is no point in doing further testing. */ + char c = ' '; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + break; + } + } + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue9.c b/test/nptl/tst-mqueue9.c new file mode 100644 index 000000000..fb057d4ad --- /dev/null +++ b/test/nptl/tst-mqueue9.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + if (geteuid () != 0) + { + puts ("this test requires root"); + return 0; + } + + char name[sizeof "/tst-mqueue9-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue9-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + else + add_temp_mq (name); + + if (seteuid (1) != 0) + { + printf ("failed to seteuid (1): %m\n"); + mq_unlink (name); + return 0; + } + + int result = 0; + if (mq_unlink (name) == 0) + { + puts ("mq_unlink unexpectedly succeeded"); + result = 1; + } + else if (errno != EACCES) + { + printf ("mq_unlink did not fail with EACCES: %m\n"); + result = 1;; + } + + if (seteuid (0) != 0) + { + printf ("failed to seteuid (0): %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed with: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer2.c b/test/nptl/tst-timer2.c new file mode 100644 index 000000000..60026c1ef --- /dev/null +++ b/test/nptl/tst-timer2.c @@ -0,0 +1,65 @@ +/* Test for crashing bugs when trying to create too many timers. */ + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +void +thread (union sigval arg) +{ + puts ("Timeout"); +} + +int +do_test (void) +{ + int i, res; + timer_t timerId; + struct itimerspec itval; + struct sigevent sigev; + + itval.it_interval.tv_sec = 2; + itval.it_interval.tv_nsec = 0; + itval.it_value.tv_sec = 2; + itval.it_value.tv_nsec = 0; + + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_signo = SIGRTMIN; + sigev.sigev_notify_function = thread; + sigev.sigev_notify_attributes = 0; + sigev.sigev_value.sival_ptr = (void *) &timerId; + + for (i = 0; i < 100; i++) + { + printf ("cnt = %d\n", i); + + if (timer_create (CLOCK_REALTIME, &sigev, &timerId) < 0) + { + perror ("timer_create"); + continue; + } + + res = timer_settime (timerId, 0, &itval, NULL); + if (res < 0) + perror ("timer_settime"); + + res = timer_delete (timerId); + if (res < 0) + perror ("timer_delete"); + } + + return 0; +} + +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer3.c b/test/nptl/tst-timer3.c new file mode 100644 index 000000000..8113f6690 --- /dev/null +++ b/test/nptl/tst-timer3.c @@ -0,0 +1,86 @@ +/* Test for bogus per-thread deletion of timers. */ + +#include <stdio.h> +#include <error.h> +#include <time.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + + +/* Creating timers in another thread should work too. */ +static void * +do_timer_create (void *arg) +{ + struct sigevent *const sigev = arg; + timer_t *const timerId = sigev->sigev_value.sival_ptr; + if (timer_create (CLOCK_REALTIME, sigev, timerId) < 0) + { + printf ("timer_create: %m\n"); + return NULL; + } + return timerId; +} + + +static int +do_test (void) +{ + int i, res; + timer_t timerId; + struct itimerspec itval; + struct sigevent sigev; + + itval.it_interval.tv_sec = 2; + itval.it_interval.tv_nsec = 0; + itval.it_value.tv_sec = 2; + itval.it_value.tv_nsec = 0; + + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = SIGALRM; + sigev.sigev_value.sival_ptr = (void *) &timerId; + + for (i = 0; i < 100; i++) + { + printf ("cnt = %d\n", i); + + pthread_t thr; + res = pthread_create (&thr, NULL, &do_timer_create, &sigev); + if (res) + { + printf ("pthread_create: %s\n", strerror (res)); + continue; + } + void *val; + res = pthread_join (thr, &val); + if (res) + { + printf ("pthread_join: %s\n", strerror (res)); + continue; + } + if (val == NULL) + continue; + + res = timer_settime (timerId, 0, &itval, NULL); + if (res < 0) + printf ("timer_settime: %m\n"); + + res = timer_delete (timerId); + if (res < 0) + printf ("timer_delete: %m\n"); + } + + return 0; +} + +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer4.c b/test/nptl/tst-timer4.c new file mode 100644 index 000000000..edd8f712c --- /dev/null +++ b/test/nptl/tst-timer4.c @@ -0,0 +1,648 @@ +/* Tests for POSIX timer implementation. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004 + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + +# ifndef TEST_CLOCK +# define TEST_CLOCK CLOCK_REALTIME +# endif + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2; + +int thr1_cnt, thr1_err; +union sigval thr1_sigval; +struct timespec thr1_ts; + +static void +thr1 (union sigval sigval) +{ + pthread_mutex_lock (&lock); + thr1_err = clock_gettime (TEST_CLOCK, &thr1_ts); + if (thr1_cnt >= 5) + { + struct itimerspec it = { }; + thr1_err |= timer_settime (timer_thr1, 0, &it, NULL); + } + thr1_sigval = sigval; + ++thr1_cnt; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&lock); +} + +int thr2_cnt, thr2_err; +union sigval thr2_sigval; +size_t thr2_guardsize; +struct timespec thr2_ts; + +static void +thr2 (union sigval sigval) +{ + pthread_attr_t nattr; + int err = 0; + size_t guardsize = -1; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("*** pthread_getattr_np failed: %m\n"); + err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &guardsize); + if (ret) + { + errno = ret; + printf ("*** pthread_attr_getguardsize failed: %m\n"); + err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("*** pthread_attr_destroy failed"); + err = 1; + } + } + pthread_mutex_lock (&lock); + thr2_err = clock_gettime (TEST_CLOCK, &thr2_ts) | err; + if (thr2_cnt >= 5) + { + struct itimerspec it = { }; + thr2_err |= timer_settime (timer_thr2, 0, &it, NULL); + } + thr2_sigval = sigval; + ++thr2_cnt; + thr2_guardsize = guardsize; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&lock); +} + +volatile int sig1_cnt, sig1_err; +volatile union sigval sig1_sigval; +struct timespec sig1_ts; + +static void +sig1_handler (int sig, siginfo_t *info, void *ctx) +{ + int err = 0; + if (sig != SIGRTMIN) err |= 1 << 0; + if (info->si_signo != SIGRTMIN) err |= 1 << 1; + if (info->si_code != SI_TIMER) err |= 1 << 2; + if (clock_gettime (TEST_CLOCK, &sig1_ts) != 0) + err |= 1 << 3; + if (sig1_cnt >= 5) + { + struct itimerspec it = { }; + if (timer_settime (timer_sig1, 0, &it, NULL)) + err |= 1 << 4; + } + sig1_err |= err; + sig1_sigval = info->si_value; + ++sig1_cnt; +} + +volatile int sig2_cnt, sig2_err; +volatile union sigval sig2_sigval; +struct timespec sig2_ts; + +static void +sig2_handler (int sig, siginfo_t *info, void *ctx) +{ + int err = 0; + if (sig != SIGRTMIN + 1) err |= 1 << 0; + if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1; + if (info->si_code != SI_TIMER) err |= 1 << 2; + if (clock_gettime (TEST_CLOCK, &sig2_ts) != 0) + err |= 1 << 3; + if (sig2_cnt >= 5) + { + struct itimerspec it = { }; + if (timer_settime (timer_sig2, 0, &it, NULL)) + err |= 1 << 4; + } + sig2_err |= err; + sig2_sigval = info->si_value; + ++sig2_cnt; +} + +/* Check if end is later or equal to start + nsec. */ +static int +check_ts (const char *name, const struct timespec *start, + const struct timespec *end, long msec) +{ + struct timespec ts = *start; + + ts.tv_sec += msec / 1000000; + ts.tv_nsec += (msec % 1000000) * 1000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + if (end->tv_sec < ts.tv_sec + || (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec)) + { + printf ("\ +*** timer %s invoked too soon: %ld.%09ld instead of expected %ld.%09ld\n", + name, (long) end->tv_sec, end->tv_nsec, + (long) ts.tv_sec, ts.tv_nsec); + return 1; + } + else + return 0; +} + +#define TIMEOUT 15 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + +#ifdef TEST_CLOCK_MISSING + const char *missing = TEST_CLOCK_MISSING (TEST_CLOCK); + if (missing != NULL) + { + printf ("%s missing, skipping test\n", missing); + return 0; + } +#endif + + struct timespec ts; + if (clock_gettime (TEST_CLOCK, &ts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + else + printf ("clock_gettime returned timespec = { %ld, %ld }\n", + (long) ts.tv_sec, ts.tv_nsec); + + if (clock_getres (TEST_CLOCK, &ts) != 0) + { + printf ("*** clock_getres failed: %m\n"); + result = 1; + } + else + printf ("clock_getres returned timespec = { %ld, %ld }\n", + (long) ts.tv_sec, ts.tv_nsec); + + struct sigevent ev; + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (timer_create (TEST_CLOCK, &ev, &timer_none) != 0) + { + printf ("*** timer_create for timer_none failed: %m\n"); + return 1; + } + + struct sigaction sa = { .sa_sigaction = sig1_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + sa.sa_sigaction = sig2_handler; + sigaction (SIGRTMIN + 1, &sa, NULL); + + memset (&ev, 0x22, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (timer_create (TEST_CLOCK, &ev, &timer_sig1) != 0) + { + printf ("*** timer_create for timer_sig1 failed: %m\n"); + return 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN + 1; + ev.sigev_value.sival_int = 163; + if (timer_create (TEST_CLOCK, &ev, &timer_sig2) != 0) + { + printf ("*** timer_create for timer_sig2 failed: %m\n"); + return 1; + } + + memset (&ev, 0x44, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = thr1; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_ptr = &ev; + if (timer_create (TEST_CLOCK, &ev, &timer_thr1) != 0) + { + printf ("*** timer_create for timer_thr1 failed: %m\n"); + return 1; + } + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("*** pthread_attr_t setup failed"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = thr2; + ev.sigev_notify_attributes = (struct __pthread_attr_s *) &nattr; + ev.sigev_value.sival_int = 111; + if (timer_create (TEST_CLOCK, &ev, &timer_thr2) != 0) + { + printf ("*** timer_create for timer_thr2 failed: %m\n"); + return 1; + } + + int ret = timer_getoverrun (timer_thr1); + if (ret != 0) + { + if (ret == -1) + printf ("*** timer_getoverrun failed: %m\n"); + else + printf ("*** timer_getoverrun returned %d != 0\n", ret); + result = 1; + } + + struct itimerspec it; + it.it_value.tv_sec = 0; + it.it_value.tv_nsec = -26; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 0; + if (timer_settime (timer_sig1, 0, &it, NULL) == 0) + { + puts ("*** timer_settime with negative tv_nsec unexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("*** timer_settime with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000; + it.it_interval.tv_nsec = 1000000000; + if (timer_settime (timer_sig2, 0, &it, NULL) == 0) + { + puts ("\ +*** timer_settime with tv_nsec 1000000000 unexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("*** timer_settime with tv_nsec 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + +#if 0 + it.it_value.tv_nsec = 0; + it.it_interval.tv_nsec = -26; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("\ +!!! timer_settime with it_value 0 it_interval invalid failed: %m\n"); + /* FIXME: is this mandated by POSIX? + result = 1; */ + } + + it.it_interval.tv_nsec = 3000000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("\ +!!! timer_settime with it_value 0 it_interval invalid failed: %m\n"); + /* FIXME: is this mandated by POSIX? + result = 1; */ + } +#endif + + struct timespec startts; + if (clock_gettime (TEST_CLOCK, &startts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000000; + it.it_interval.tv_nsec = 0; + if (timer_settime (timer_none, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_none failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 200000000; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 300000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr2 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 400000000; + if (timer_settime (timer_sig1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_sig1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 500000000; + if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0) + { + printf ("*** timer_settime timer_sig2 failed: %m\n"); + result = 1; + } + + pthread_mutex_lock (&lock); + while (thr1_cnt == 0 || thr2_cnt == 0) + pthread_cond_wait (&cond, &lock); + pthread_mutex_unlock (&lock); + + while (sig1_cnt == 0 || sig2_cnt == 0) + { + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + + pthread_mutex_lock (&lock); + + if (thr1_cnt != 1) + { + printf ("*** thr1 not called exactly once, but %d times\n", thr1_cnt); + result = 1; + } + else if (thr1_err) + { + puts ("*** an error occurred in thr1"); + result = 1; + } + else if (thr1_sigval.sival_ptr != &ev) + { + printf ("*** thr1_sigval.sival_ptr %p != %p\n", + thr1_sigval.sival_ptr, &ev); + result = 1; + } + else if (check_ts ("thr1", &startts, &thr1_ts, 200000)) + result = 1; + + if (thr2_cnt != 1) + { + printf ("*** thr2 not called exactly once, but %d times\n", thr2_cnt); + result = 1; + } + else if (thr2_err) + { + puts ("*** an error occurred in thr2"); + result = 1; + } + else if (thr2_sigval.sival_int != 111) + { + printf ("*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int); + result = 1; + } + else if (check_ts ("thr2", &startts, &thr2_ts, 300000)) + result = 1; + else if (thr2_guardsize != 0) + { + printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize); + result = 1; + } + + pthread_mutex_unlock (&lock); + + if (sig1_cnt != 1) + { + printf ("*** sig1 not called exactly once, but %d times\n", sig1_cnt); + result = 1; + } + else if (sig1_err) + { + printf ("*** errors occurred in sig1 handler %x\n", sig1_err); + result = 1; + } + else if (sig1_sigval.sival_ptr != &ev) + { + printf ("*** sig1_sigval.sival_ptr %p != %p\n", + sig1_sigval.sival_ptr, &ev); + result = 1; + } + else if (check_ts ("sig1", &startts, &sig1_ts, 400000)) + result = 1; + + if (sig2_cnt != 1) + { + printf ("*** sig2 not called exactly once, but %d times\n", sig2_cnt); + result = 1; + } + else if (sig2_err) + { + printf ("*** errors occurred in sig2 handler %x\n", sig2_err); + result = 1; + } + else if (sig2_sigval.sival_int != 163) + { + printf ("*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int); + result = 1; + } + else if (check_ts ("sig2", &startts, &sig2_ts, 500000)) + result = 1; + + if (timer_gettime (timer_none, &it) != 0) + { + printf ("*** timer_gettime timer_none failed: %m\n"); + result = 1; + } + else if (it.it_value.tv_sec || it.it_value.tv_nsec + || it.it_interval.tv_sec || it.it_interval.tv_nsec) + { + printf ("\ +*** timer_gettime timer_none returned { %ld.%09ld, %ld.%09ld }\n", + (long) it.it_value.tv_sec, it.it_value.tv_nsec, + (long) it.it_interval.tv_sec, it.it_interval.tv_nsec); + result = 1; + } + + if (clock_gettime (TEST_CLOCK, &startts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + + it.it_value.tv_sec = 1; + it.it_value.tv_nsec = 0; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 100000000; + if (timer_settime (timer_none, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_none failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000000; + it.it_interval.tv_nsec = 200000000; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 200000000; + it.it_interval.tv_nsec = 300000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr2 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 300000000; + it.it_interval.tv_nsec = 400000000; + if (timer_settime (timer_sig1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_sig1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 400000000; + it.it_interval.tv_nsec = 500000000; + if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0) + { + printf ("*** timer_settime timer_sig2 failed: %m\n"); + result = 1; + } + + pthread_mutex_lock (&lock); + while (thr1_cnt < 6 || thr2_cnt < 6) + pthread_cond_wait (&cond, &lock); + pthread_mutex_unlock (&lock); + + while (sig1_cnt < 6 || sig2_cnt < 6) + { + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + + pthread_mutex_lock (&lock); + + if (thr1_err) + { + puts ("*** an error occurred in thr1"); + result = 1; + } + else if (check_ts ("thr1", &startts, &thr1_ts, 1100000 + 4 * 200000)) + result = 1; + + if (thr2_err) + { + puts ("*** an error occurred in thr2"); + result = 1; + } + else if (check_ts ("thr2", &startts, &thr2_ts, 1200000 + 4 * 300000)) + result = 1; + else if (thr2_guardsize != 0) + { + printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize); + result = 1; + } + + pthread_mutex_unlock (&lock); + + if (sig1_err) + { + printf ("*** errors occurred in sig1 handler %x\n", sig1_err); + result = 1; + } + else if (check_ts ("sig1", &startts, &sig1_ts, 1300000 + 4 * 400000)) + result = 1; + + if (sig2_err) + { + printf ("*** errors occurred in sig2 handler %x\n", sig2_err); + result = 1; + } + else if (check_ts ("sig2", &startts, &sig2_ts, 1400000 + 4 * 500000)) + result = 1; + + if (timer_gettime (timer_none, &it) != 0) + { + printf ("*** timer_gettime timer_none failed: %m\n"); + result = 1; + } + else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000) + { + printf ("\ +!!! second timer_gettime timer_none returned it_interval %ld.%09ld\n", + (long) it.it_interval.tv_sec, it.it_interval.tv_nsec); + /* FIXME: For now disabled. + result = 1; */ + } + + if (timer_delete (timer_none) != 0) + { + printf ("*** timer_delete for timer_none failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_sig1) != 0) + { + printf ("*** timer_delete for timer_sig1 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_sig2) != 0) + { + printf ("*** timer_delete for timer_sig2 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_thr1) != 0) + { + printf ("*** timer_delete for timer_thr1 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_thr2) != 0) + { + printf ("*** timer_delete for timer_thr2 failed: %m\n"); + result = 1; + } + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer5.c b/test/nptl/tst-timer5.c new file mode 100644 index 000000000..6466c8efc --- /dev/null +++ b/test/nptl/tst-timer5.c @@ -0,0 +1,38 @@ +/* Timer test using the monotonic clock. */ + +#include <time.h> +#include <unistd.h> + +#if defined CLOCK_MONOTONIC && defined _POSIX_MONOTONIC_CLOCK + +# define TEST_CLOCK CLOCK_MONOTONIC +# define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "CLOCK_MONOTONIC" : NULL) + +# include <stdio.h> + +static int +setup_test (void) +{ + if (sysconf (_SC_MONOTONIC_CLOCK) <= 0) + return 1; + + /* The user-level timers implementation doesn't support CLOCK_MONOTONIC, + even though sysconf claims it will. */ + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + return 0; +} + +# include "tst-timer4.c" + +#else +# define TEST_FUNCTION 0 +# include "../test-skeleton.c" +#endif |