1152186Sdavidxu/* $FreeBSD$ */
2197965Skib#include <sys/types.h>
3197965Skib#include <sys/wait.h>
4197965Skib#include <err.h>
5197965Skib#include <errno.h>
6152186Sdavidxu#include <signal.h>
7152186Sdavidxu#include <stdio.h>
8197965Skib#include <stdlib.h>
9197965Skib#include <unistd.h>
10152186Sdavidxu
11152186Sdavidxuint stop_received;
12152186Sdavidxuint exit_received;
13152186Sdavidxuint cont_received;
14152186Sdavidxu
15197965Skibvoid
16197965Skibjob_handler(int sig, siginfo_t *si, void *ctx)
17152186Sdavidxu{
18152186Sdavidxu	int status;
19152186Sdavidxu	int ret;
20152186Sdavidxu
21152186Sdavidxu	if (si->si_code == CLD_STOPPED) {
22197965Skib		printf("%d: stop received\n", si->si_pid);
23152186Sdavidxu		stop_received = 1;
24152186Sdavidxu		kill(si->si_pid, SIGCONT);
25152186Sdavidxu	} else if (si->si_code == CLD_EXITED) {
26197965Skib		printf("%d: exit received\n", si->si_pid);
27152186Sdavidxu		ret = waitpid(si->si_pid, &status, 0);
28152186Sdavidxu		if (ret == -1)
29152186Sdavidxu			errx(1, "waitpid");
30152186Sdavidxu		if (!WIFEXITED(status))
31152186Sdavidxu			errx(1, "!WIFEXITED(status)");
32152186Sdavidxu		exit_received = 1;
33152186Sdavidxu	} else if (si->si_code == CLD_CONTINUED) {
34197965Skib		printf("%d: cont received\n", si->si_pid);
35152186Sdavidxu		cont_received = 1;
36152186Sdavidxu	}
37152186Sdavidxu}
38152186Sdavidxu
39197965Skibvoid
40197965Skibjob_control_test(void)
41152186Sdavidxu{
42152186Sdavidxu	struct sigaction sa;
43152186Sdavidxu	pid_t pid;
44152186Sdavidxu	int count = 10;
45152186Sdavidxu
46152186Sdavidxu	sigemptyset(&sa.sa_mask);
47152186Sdavidxu	sa.sa_flags = SA_SIGINFO;
48152186Sdavidxu	sa.sa_sigaction = job_handler;
49152186Sdavidxu	sigaction(SIGCHLD, &sa, NULL);
50152186Sdavidxu	stop_received = 0;
51152186Sdavidxu	cont_received = 0;
52152186Sdavidxu	exit_received = 0;
53197965Skib	fflush(stdout);
54152186Sdavidxu	pid = fork();
55152186Sdavidxu	if (pid == 0) {
56197965Skib		printf("child %d\n", getpid());
57152186Sdavidxu		kill(getpid(), SIGSTOP);
58197965Skib		sleep(2);
59152186Sdavidxu		exit(1);
60152186Sdavidxu	}
61152186Sdavidxu
62152186Sdavidxu	while (!(cont_received && stop_received && exit_received)) {
63152186Sdavidxu		sleep(1);
64152186Sdavidxu		if (--count == 0)
65152186Sdavidxu			break;
66152186Sdavidxu	}
67152186Sdavidxu	if (!(cont_received && stop_received && exit_received))
68152186Sdavidxu		errx(1, "job signals lost");
69152186Sdavidxu
70152186Sdavidxu	printf("job control test OK.\n");
71152186Sdavidxu}
72152186Sdavidxu
73197965Skibvoid
74197965Skibrtsig_handler(int sig, siginfo_t *si, void *ctx)
75152186Sdavidxu{
76152186Sdavidxu}
77152186Sdavidxu
78197965Skibint
79197965Skibmain()
80152186Sdavidxu{
81152186Sdavidxu	struct sigaction sa;
82152186Sdavidxu	sigset_t set;
83152186Sdavidxu	union sigval val;
84152186Sdavidxu
85152186Sdavidxu	/* test job control with empty signal queue */
86152186Sdavidxu	job_control_test();
87152186Sdavidxu
88152186Sdavidxu	/* now full fill signal queue in kernel */
89152186Sdavidxu	sigemptyset(&sa.sa_mask);
90152186Sdavidxu	sa.sa_flags = SA_SIGINFO;
91152186Sdavidxu	sa.sa_sigaction = rtsig_handler;
92152186Sdavidxu	sigaction(SIGRTMIN, &sa, NULL);
93152186Sdavidxu	sigemptyset(&set);
94152186Sdavidxu	sigaddset(&set, SIGRTMIN);
95152186Sdavidxu	sigprocmask(SIG_BLOCK, &set, NULL);
96152186Sdavidxu	val.sival_int = 1;
97152186Sdavidxu	while (sigqueue(getpid(), SIGRTMIN, val))
98152186Sdavidxu		;
99152186Sdavidxu
100152186Sdavidxu	/* signal queue is fully filled, test the job control again. */
101152186Sdavidxu	job_control_test();
102152186Sdavidxu	return (0);
103152186Sdavidxu}
104