diff options
Diffstat (limited to 'regress')
-rw-r--r-- | regress/sys/kern/Makefile | 4 | ||||
-rw-r--r-- | regress/sys/kern/sigprof/Makefile | 10 | ||||
-rw-r--r-- | regress/sys/kern/sigprof/sigprof.c | 132 |
3 files changed, 144 insertions, 2 deletions
diff --git a/regress/sys/kern/Makefile b/regress/sys/kern/Makefile index 65ca6859d5b..77df15b6c47 100644 --- a/regress/sys/kern/Makefile +++ b/regress/sys/kern/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.60 2013/01/03 17:43:34 bluhm Exp $ +# $OpenBSD: Makefile,v 1.61 2013/10/07 15:52:17 jsing Exp $ SUBDIR+= __syscall accept dup2 dup2_self exec_self execve exit extent SUBDIR+= fchdir @@ -10,7 +10,7 @@ SUBDIR+= main-thread-exited SUBDIR+= mmap mmap2 mmap3 mmap-fail #SUBDIR+= mquery SUBDIR+= nanosleep noexec pread preadv ptmget pty pwrite pwritev rcvtimeo -SUBDIR+= rlimit-file signal signal-stress sigsuspend +SUBDIR+= rlimit-file signal signal-stress sigprof sigsuspend SUBDIR+= sosplice SUBDIR+= syscall sysvmsg sysvsem SUBDIR+= sysvshm unalign unfdpass wait diff --git a/regress/sys/kern/sigprof/Makefile b/regress/sys/kern/sigprof/Makefile new file mode 100644 index 00000000000..0062d7e5b66 --- /dev/null +++ b/regress/sys/kern/sigprof/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 2013/10/07 15:52:18 jsing Exp $ + +PROG= sigprof + +LIBPTHREAD= /usr/lib/libpthread.a + +LDADD+= -lpthread +DPADD+= ${LIBPTHREAD} + +.include <bsd.regress.mk> diff --git a/regress/sys/kern/sigprof/sigprof.c b/regress/sys/kern/sigprof/sigprof.c new file mode 100644 index 00000000000..9848c96580e --- /dev/null +++ b/regress/sys/kern/sigprof/sigprof.c @@ -0,0 +1,132 @@ +/* $OpenBSD: sigprof.c,v 1.1 2013/10/07 15:52:18 jsing Exp $ */ +/* + * Copyright (c) 2013 Joel Sing <jsing@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Test that profiling signals are delivered to the thread whose execution + * consumed the CPU time and resulted in the profiling timer expiring. + * Inspired by a problem report test case from Russ Cox <rsc@golang.org>. + */ + +#include <err.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> + +#define NTHREADS 4 +#define NSIGNALS 100 +#define NSIGTOTAL (NTHREADS * NSIGNALS) +#define NMINSIG ((NSIGNALS * 75) / 100) + +void handler(int); +void *spinloop(void *); + +pthread_t threads[NTHREADS + 1]; +int sigcount[NTHREADS + 1]; +volatile int sigtotal; +volatile int done; + +void +handler(int sig) +{ + pthread_t self; + int i; + + /* + * pthread_self() is not required to be async-signal-safe, however + * the OpenBSD implementation currently is. + */ + self = pthread_self(); + + for (i = 0; i <= NTHREADS; i++) + if (threads[i] == self) + sigcount[i]++; + + if (++sigtotal >= NSIGTOTAL) + done = 1; +} + +void * +spinloop(void *arg) +{ + while (!done) + ; + + pthread_exit(NULL); +} + +int +main(int argc, char **argv) +{ + struct sigaction sa; + struct itimerval it; + int i; + + bzero(&sa, sizeof(sa)); + sa.sa_handler = handler; + sa.sa_flags = SA_RESTART; + sigfillset(&sa.sa_mask); + sigaction(SIGPROF, &sa, 0); + + threads[0] = pthread_self(); + for (i = 1; i <= NTHREADS; i++) + if (pthread_create(&threads[i], NULL, spinloop, NULL) != 0) + err(1, "pthread_create"); + + bzero(&it, sizeof(it)); + it.it_interval.tv_usec = 10000; + it.it_value = it.it_interval; + setitimer(ITIMER_PROF, &it, NULL); + + for (i = 1; i <= NTHREADS; i++) + if (pthread_join(threads[i], NULL) != 0) + err(1, "pthread_join"); + + bzero(&it, sizeof(it)); + setitimer(ITIMER_PROF, &it, NULL); + + fprintf(stderr, "total profiling signals: %d\n", sigtotal); + fprintf(stderr, "minimum signals per thread: %d\n", NMINSIG); + fprintf(stderr, "main thread - %d\n", sigcount[0]); + for (i = 1; i <= NTHREADS; i++) + fprintf(stderr, "thread %d - %d\n", i, sigcount[i]); + + if (sigtotal < NSIGTOTAL) + errx(1, "insufficient profiling signals (%d < %d)", + sigtotal, NSIGTOTAL); + + /* + * The main thread is effectively sleeping and should have received + * almost no profiling signals. Allow a small tolerance. + */ + if (sigcount[0] > ((NSIGNALS * 10) / 100)) + errx(1, "main thread received too many signals (%d)", + sigcount[0]); + + /* + * Ensure that the kernel delivered the profiling signals to the + * thread that consumed the CPU time. In an ideal world each thread + * would have received equal CPU time and an equal number of signals. + * In the less than ideal world we'll just settle for a percentage. + */ + for (i = 1; i <= NTHREADS; i++) + if (sigcount[i] < NMINSIG) + errx(1, "thread %d received only %d signals (%d < %d)", + i, sigcount[i], sigcount[i], NMINSIG); + + return 0; +} |