1/* $FreeBSD$ */
2#include <sys/types.h>
3#include <sys/wait.h>
4#include <err.h>
5#include <errno.h>
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10
11int stop_received;
12int exit_received;
13int cont_received;
14
15void
16job_handler(int sig, siginfo_t *si, void *ctx)
17{
18	int status;
19	int ret;
20
21	if (si->si_code == CLD_STOPPED) {
22		printf("%d: stop received\n", si->si_pid);
23		stop_received = 1;
24		kill(si->si_pid, SIGCONT);
25	} else if (si->si_code == CLD_EXITED) {
26		printf("%d: exit received\n", si->si_pid);
27		ret = waitpid(si->si_pid, &status, 0);
28		if (ret == -1)
29			errx(1, "waitpid");
30		if (!WIFEXITED(status))
31			errx(1, "!WIFEXITED(status)");
32		exit_received = 1;
33	} else if (si->si_code == CLD_CONTINUED) {
34		printf("%d: cont received\n", si->si_pid);
35		cont_received = 1;
36	}
37}
38
39void
40job_control_test(void)
41{
42	struct sigaction sa;
43	pid_t pid;
44	int count = 10;
45
46	sigemptyset(&sa.sa_mask);
47	sa.sa_flags = SA_SIGINFO;
48	sa.sa_sigaction = job_handler;
49	sigaction(SIGCHLD, &sa, NULL);
50	stop_received = 0;
51	cont_received = 0;
52	exit_received = 0;
53	fflush(stdout);
54	pid = fork();
55	if (pid == 0) {
56		printf("child %d\n", getpid());
57		kill(getpid(), SIGSTOP);
58		sleep(2);
59		exit(1);
60	}
61
62	while (!(cont_received && stop_received && exit_received)) {
63		sleep(1);
64		if (--count == 0)
65			break;
66	}
67	if (!(cont_received && stop_received && exit_received))
68		errx(1, "job signals lost");
69
70	printf("job control test OK.\n");
71}
72
73void
74rtsig_handler(int sig, siginfo_t *si, void *ctx)
75{
76}
77
78int
79main()
80{
81	struct sigaction sa;
82	sigset_t set;
83	union sigval val;
84
85	/* test job control with empty signal queue */
86	job_control_test();
87
88	/* now full fill signal queue in kernel */
89	sigemptyset(&sa.sa_mask);
90	sa.sa_flags = SA_SIGINFO;
91	sa.sa_sigaction = rtsig_handler;
92	sigaction(SIGRTMIN, &sa, NULL);
93	sigemptyset(&set);
94	sigaddset(&set, SIGRTMIN);
95	sigprocmask(SIG_BLOCK, &set, NULL);
96	val.sival_int = 1;
97	while (sigqueue(getpid(), SIGRTMIN, val))
98		;
99
100	/* signal queue is fully filled, test the job control again. */
101	job_control_test();
102	return (0);
103}
104