summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--regress/sys/kern/Makefile4
-rw-r--r--regress/sys/kern/sigprof/Makefile10
-rw-r--r--regress/sys/kern/sigprof/sigprof.c132
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;
+}