summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Guenther <guenther@cvs.openbsd.org>2013-06-21 06:47:21 +0000
committerPhilip Guenther <guenther@cvs.openbsd.org>2013-06-21 06:47:21 +0000
commit9fd81a0e33aa45db36dc88769d12aef5c6d75fc8 (patch)
treefb7ab180e88a35d3f3e2913ca3e956546c722601
parent18f0593eba6ee930bb1ad9ad4c452fb8a7fb1bbd (diff)
Add earlysig test to check whether the pthread fork() wrapper
has a critical section where getting a signal causes a hang. Based on otto@ earlysig kernel regress; suggested by miod@
-rw-r--r--regress/lib/libpthread/Makefile5
-rw-r--r--regress/lib/libpthread/earlysig/Makefile5
-rw-r--r--regress/lib/libpthread/earlysig/earlysig.c87
3 files changed, 95 insertions, 2 deletions
diff --git a/regress/lib/libpthread/Makefile b/regress/lib/libpthread/Makefile
index 2cdd9958cb0..9358149c4d3 100644
--- a/regress/lib/libpthread/Makefile
+++ b/regress/lib/libpthread/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.42 2013/03/25 08:03:18 guenther Exp $
+# $OpenBSD: Makefile,v 1.43 2013/06/21 06:47:20 guenther Exp $
# disabled because it requires a buggy behavior that uthread had:
# dup2_race
@@ -12,7 +12,8 @@
# blocked_fifo
SUBDIR= barrier blocked_shutdown \
- cancel cancel2 close close_race closefrom cwd errno execve fork \
+ cancel cancel2 close close_race closefrom cwd earlysig \
+ errno execve fork \
group malloc_duel netdb pcap poll preemption preemption_float \
pthread_atfork pthread_cond_timedwait pthread_create \
pthread_join pthread_kill pthread_mutex \
diff --git a/regress/lib/libpthread/earlysig/Makefile b/regress/lib/libpthread/earlysig/Makefile
new file mode 100644
index 00000000000..f18ead884e9
--- /dev/null
+++ b/regress/lib/libpthread/earlysig/Makefile
@@ -0,0 +1,5 @@
+# $OpenBSD: Makefile,v 1.1 2013/06/21 06:47:20 guenther Exp $
+
+PROG= earlysig
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libpthread/earlysig/earlysig.c b/regress/lib/libpthread/earlysig/earlysig.c
new file mode 100644
index 00000000000..e65caaad53f
--- /dev/null
+++ b/regress/lib/libpthread/earlysig/earlysig.c
@@ -0,0 +1,87 @@
+/* $OpenBSD: earlysig.c,v 1.1 2013/06/21 06:47:20 guenther Exp $ */
+
+/*
+ * Public domain. 2005, Otto Moerbeek; 2013, Philip Guenther
+ *
+ * Try to create the case where a signal is delivered to a process before
+ * the pthread fork() wrapper can unlock the ld.so bind lock.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void dohup(int signo)
+{
+ struct utsname name;
+ uname(&name); /* anything that'll require binding */
+}
+
+void *tmain(void *arg)
+{
+ return (arg);
+}
+
+int
+main()
+{
+ pthread_t tid;
+ pid_t pid, rpid;
+ int r, status;
+
+ if (signal(SIGHUP, dohup) == SIG_ERR)
+ err(1, "signal");
+
+ /* make sure the thread library is fully active */
+ if ((r = pthread_create(&tid, NULL, tmain, NULL)))
+ errx(1, "pthread_create: %s", strerror(r));
+ pthread_join(tid, NULL);
+
+ /* make sure kill() and all the symbols in fork() are bound */
+ kill(0, 0);
+ if ((pid = fork()) <= 0) {
+ if (pid == -1)
+ err(1, "fork");
+ _exit(0);
+ }
+ if (waitpid(pid, &status, 0) == -1)
+ err(1, "waitpid");
+
+
+ switch(pid = fork()) {
+ case -1:
+ err(1, "fork");
+ break;
+ case 0:
+ sleep(2);
+ _exit(0);
+ default:
+ kill(pid, SIGHUP);
+ sleep(3);
+ if ((rpid = waitpid(pid, &status, WNOHANG)) == -1)
+ err(1, "waitpid");
+ if (rpid == 0) {
+ /* took too long */
+ kill(pid, SIGKILL);
+ if (waitpid(pid, &status, 0) == -1)
+ err(1, "waitpid");
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ exit(0);
+ else if (WIFEXITED(status))
+ errx(1, "child exited with status %d",
+ WEXITSTATUS(status));
+ else if (WTERMSIG(status) == SIGKILL)
+ errx(1, "failed: child hung");
+ errx(1, "child killed by signal %d", WTERMSIG(status));
+ }
+}