1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2020 corydoras@ridiculousfish.com
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# The test scenario is from:
31# Bug 246385 - SIGCHLD dropped if generated while blocked in sigfastblock
32# https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246385
33# Fixed by r360940
34
35. ../default.cfg
36
37cat > /tmp/sigfastblock2.c <<EOF
38#include <assert.h>
39#include <fcntl.h>
40#include <limits.h>
41#include <signal.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <string.h>
46
47#include <sys/types.h>
48#include <sys/wait.h>
49#include <sys/time.h>
50
51static int pipes[2];
52
53static void assert_noerr(int res)
54{
55    if (res < 0)
56    {
57        fprintf(stderr, "error: %s", strerror(res));
58        exit(EXIT_FAILURE);
59    }
60}
61
62static void sigchld_handler(int sig)
63{
64    // Write a byte to the write end of pipes.
65    (void)sig;
66    char c = 0;
67    ssize_t amt = write(pipes[1], &c, 1);
68    if (amt < 0)
69    {
70        perror("write");
71        exit(EXIT_FAILURE);
72    }
73}
74
75static pid_t spawn_child()
76{
77    pid_t pid = fork();
78    assert_noerr(pid);
79    if (pid == 0)
80    {
81        _exit(0);
82    }
83    return pid;
84}
85
86int main(void)
87{
88    // Install SIGCHLD handler with SA_RESTART.
89    struct sigaction chld_act = {};
90    sigemptyset(&chld_act.sa_mask);
91    chld_act.sa_handler = &sigchld_handler;
92    chld_act.sa_flags = SA_RESTART;
93    assert_noerr(sigaction(SIGCHLD, &chld_act, NULL));
94
95    // Make our self-pipes.
96    assert_noerr(pipe(pipes));
97
98    // Spawn and reap children in a loop.
99    for (;;)
100    {
101        // Spawn a child.
102        pid_t child = spawn_child();
103        assert(child >= 0 && "Invalid pid");
104
105        // Wait for the SIGCHLD handler to write to us.
106        for (;;)
107        {
108            char buf[PIPE_BUF];
109	    alarm(5);
110            ssize_t amt = read(pipes[0], buf, sizeof buf);
111            if (amt >= 0)
112                break;
113	    alarm(0);
114        }
115
116        // Reap it.
117        int status = 0;
118        int pid_res = waitpid(child, &status, WUNTRACED | WCONTINUED);
119        assert(pid_res == child && "Unexpected pid");
120    }
121
122    return 0;
123}
124EOF
125mycc -o /tmp/sigfastblock2 -Wall -Wextra /tmp/sigfastblock2.c -lpthread ||
126    exit 1
127
128timeout 5m /tmp/sigfastblock2; s=$?
129[ $s -eq 124 ] && s=0
130
131rm -f /tmp/sigfastblock2 /tmp/sigfastblock2.c
132exit $s
133