+vfork
fork
sig
skodic
-vfork
clone
leaderkill
childthread
+sigkill_rain
+wait_must_be_interruptible
# $Id$
#
-all: vfork fork sig skodic clone leaderkill childthread
+all: \
+ vfork fork sig skodic clone leaderkill childthread \
+ sigkill_rain wait_must_be_interruptible
leaderkill: LDFLAGS += -pthread
childthread: LDFLAGS += -pthread
clean distclean:
- rm -f clone vfork fork sig leaderkill *.o core
+ rm -f *.o core \
+ vfork fork sig skodic clone leaderkill childthread \
+ sigkill_rain wait_must_be_interruptible
--- /dev/null
+To run a test:
+* Run make
+* Run resulting executable(s) under strace
+* Check strace output and/or program's output and exitcode
+
+To add a new test:
+* Add its .c source to this dir
+* Add it to "all" and "clean" targets in Makefile
+* Add it to .gitignore file
+
+Please spend some time making your testcase understandable.
+For example, it may print an explanation how it should be used
+(which strace options to use, and what to look for in strace output).
+
+If possible, make it so that your testcase detects error/bug
+it is intended to test for, and prints error message and exits with 1
+if the bug is detected, instead of relying on user to peruse strace output.
+/* for CLONE_foo: */
+#define _GNU_SOURCE 1
+
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
-/* This test is not yet added to Makefile */
-
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <signal.h>
-
#include <sys/types.h>
#include <sys/socket.h>
+#include <stdio.h>
static const struct sockaddr sa;
int pid;
sigset_t set;
+ printf(
+"Please run me under 'strace -f -oLOG', and examine LOG file for incorrect\n"
+"decoding of interrupted syscalls: grep for 'sendto', '??" /* anti-trigraph gap */ "?', 'unavailable'.\n"
+"Pass number of iterations in argv[1] (default: 999).\n"
+ );
+
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, NULL);
*/
switch (loops & 1) {
case 0:
- break; /* intentional empty */
+ break; /* intentionally empty */
case 1:
sendto(-1, "Hello cruel world", 17, 0, &sa, sizeof(sa));
break;
--- /dev/null
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <stdio.h>
+
+/* Expected order is:
+ * Child signals parent
+ * Parent got signal
+ * Child will exit now
+ *
+ * The bug we test for: under strace -f, last two lines are swapped
+ * because wait syscall is suspended by strace and thus can't be interrupted.
+ */
+
+static const char msg1[] = "Child signals parent\n";
+static const char msg2[] = "Parent got signal\n";
+static const char msg3[] = "Child will exit now\n";
+
+static void handler(int s)
+{
+ write(1, msg2, sizeof(msg2)-1);
+}
+
+static void test()
+{
+ /* Note: in Linux, signal() installs handler with SA_RESTART flag,
+ * therefore wait will be restarted.
+ */
+ signal(SIGALRM, handler);
+
+ if (fork() == 0) {
+ /* child */
+ sleep(1);
+ write(1, msg1, sizeof(msg1)-1);
+ kill(getppid(), SIGALRM);
+ sleep(1);
+ write(1, msg3, sizeof(msg3)-1);
+ _exit(0);
+ }
+
+ /* parent */
+ wait(NULL);
+ _exit(0);
+}
+
+int main()
+{
+ char buf1[80];
+ char buf2[80];
+ char buf3[80];
+ int pipefd[2];
+
+ printf("Please run me under 'strace -f'\n");
+
+ pipe(pipefd);
+
+ if (fork() == 0) {
+ if (pipefd[1] != 1) {
+ dup2(pipefd[1], 1);
+ close(pipefd[1]);
+ }
+ test();
+ }
+
+ if (pipefd[0] != 0) {
+ dup2(pipefd[0], 0);
+ close(pipefd[0]);
+ }
+ fgets(buf1, 80, stdin); printf("%s", buf1);
+ fgets(buf2, 80, stdin); printf("%s", buf2);
+ fgets(buf3, 80, stdin); printf("%s", buf3);
+
+ if (strcmp(buf1, msg1) != 0
+ || strcmp(buf2, msg2) != 0
+ || strcmp(buf3, msg3) != 0
+ ) {
+ printf("ERROR! Expected order:\n%s%s%s", msg1, msg2, msg3);
+ return 1;
+ }
+ printf("Good: wait seems to be correctly interrupted by signals\n");
+ return 0;
+}