114b7815fSDavid Xu #include <sys/types.h>
214b7815fSDavid Xu #include <sys/wait.h>
3eb9de28fSKonstantin Belousov #include <err.h>
4eb9de28fSKonstantin Belousov #include <errno.h>
5eb9de28fSKonstantin Belousov #include <signal.h>
6eb9de28fSKonstantin Belousov #include <stdio.h>
7eb9de28fSKonstantin Belousov #include <stdlib.h>
8eb9de28fSKonstantin Belousov #include <unistd.h>
914b7815fSDavid Xu 
1014b7815fSDavid Xu int stop_received;
1114b7815fSDavid Xu int exit_received;
1214b7815fSDavid Xu int cont_received;
1314b7815fSDavid Xu 
14eb9de28fSKonstantin Belousov void
job_handler(int sig,siginfo_t * si,void * ctx)15eb9de28fSKonstantin Belousov job_handler(int sig, siginfo_t *si, void *ctx)
1614b7815fSDavid Xu {
1714b7815fSDavid Xu 	int status;
1814b7815fSDavid Xu 	int ret;
1914b7815fSDavid Xu 
2014b7815fSDavid Xu 	if (si->si_code == CLD_STOPPED) {
21eb9de28fSKonstantin Belousov 		printf("%d: stop received\n", si->si_pid);
2214b7815fSDavid Xu 		stop_received = 1;
2314b7815fSDavid Xu 		kill(si->si_pid, SIGCONT);
2414b7815fSDavid Xu 	} else if (si->si_code == CLD_EXITED) {
25eb9de28fSKonstantin Belousov 		printf("%d: exit received\n", si->si_pid);
2614b7815fSDavid Xu 		ret = waitpid(si->si_pid, &status, 0);
2714b7815fSDavid Xu 		if (ret == -1)
2814b7815fSDavid Xu 			errx(1, "waitpid");
2914b7815fSDavid Xu 		if (!WIFEXITED(status))
3014b7815fSDavid Xu 			errx(1, "!WIFEXITED(status)");
3114b7815fSDavid Xu 		exit_received = 1;
3214b7815fSDavid Xu 	} else if (si->si_code == CLD_CONTINUED) {
33eb9de28fSKonstantin Belousov 		printf("%d: cont received\n", si->si_pid);
3414b7815fSDavid Xu 		cont_received = 1;
3514b7815fSDavid Xu 	}
3614b7815fSDavid Xu }
3714b7815fSDavid Xu 
38eb9de28fSKonstantin Belousov void
job_control_test(void)39eb9de28fSKonstantin Belousov job_control_test(void)
4014b7815fSDavid Xu {
4114b7815fSDavid Xu 	struct sigaction sa;
4214b7815fSDavid Xu 	pid_t pid;
4314b7815fSDavid Xu 	int count = 10;
4414b7815fSDavid Xu 
4514b7815fSDavid Xu 	sigemptyset(&sa.sa_mask);
4614b7815fSDavid Xu 	sa.sa_flags = SA_SIGINFO;
4714b7815fSDavid Xu 	sa.sa_sigaction = job_handler;
4814b7815fSDavid Xu 	sigaction(SIGCHLD, &sa, NULL);
4914b7815fSDavid Xu 	stop_received = 0;
5014b7815fSDavid Xu 	cont_received = 0;
5114b7815fSDavid Xu 	exit_received = 0;
52eb9de28fSKonstantin Belousov 	fflush(stdout);
5314b7815fSDavid Xu 	pid = fork();
5414b7815fSDavid Xu 	if (pid == 0) {
55eb9de28fSKonstantin Belousov 		printf("child %d\n", getpid());
5614b7815fSDavid Xu 		kill(getpid(), SIGSTOP);
57eb9de28fSKonstantin Belousov 		sleep(2);
5814b7815fSDavid Xu 		exit(1);
5914b7815fSDavid Xu 	}
6014b7815fSDavid Xu 
6114b7815fSDavid Xu 	while (!(cont_received && stop_received && exit_received)) {
6214b7815fSDavid Xu 		sleep(1);
6314b7815fSDavid Xu 		if (--count == 0)
6414b7815fSDavid Xu 			break;
6514b7815fSDavid Xu 	}
6614b7815fSDavid Xu 	if (!(cont_received && stop_received && exit_received))
6714b7815fSDavid Xu 		errx(1, "job signals lost");
6814b7815fSDavid Xu 
6914b7815fSDavid Xu 	printf("job control test OK.\n");
7014b7815fSDavid Xu }
7114b7815fSDavid Xu 
72eb9de28fSKonstantin Belousov void
rtsig_handler(int sig,siginfo_t * si,void * ctx)73eb9de28fSKonstantin Belousov rtsig_handler(int sig, siginfo_t *si, void *ctx)
7414b7815fSDavid Xu {
7514b7815fSDavid Xu }
7614b7815fSDavid Xu 
77eb9de28fSKonstantin Belousov int
main()78eb9de28fSKonstantin Belousov main()
7914b7815fSDavid Xu {
8014b7815fSDavid Xu 	struct sigaction sa;
8114b7815fSDavid Xu 	sigset_t set;
8214b7815fSDavid Xu 	union sigval val;
8314b7815fSDavid Xu 
8414b7815fSDavid Xu 	/* test job control with empty signal queue */
8514b7815fSDavid Xu 	job_control_test();
8614b7815fSDavid Xu 
8714b7815fSDavid Xu 	/* now full fill signal queue in kernel */
8814b7815fSDavid Xu 	sigemptyset(&sa.sa_mask);
8914b7815fSDavid Xu 	sa.sa_flags = SA_SIGINFO;
9014b7815fSDavid Xu 	sa.sa_sigaction = rtsig_handler;
9114b7815fSDavid Xu 	sigaction(SIGRTMIN, &sa, NULL);
9214b7815fSDavid Xu 	sigemptyset(&set);
9314b7815fSDavid Xu 	sigaddset(&set, SIGRTMIN);
9414b7815fSDavid Xu 	sigprocmask(SIG_BLOCK, &set, NULL);
9514b7815fSDavid Xu 	val.sival_int = 1;
9614b7815fSDavid Xu 	while (sigqueue(getpid(), SIGRTMIN, val))
9714b7815fSDavid Xu 		;
9814b7815fSDavid Xu 
9914b7815fSDavid Xu 	/* signal queue is fully filled, test the job control again. */
10014b7815fSDavid Xu 	job_control_test();
10114b7815fSDavid Xu 	return (0);
10214b7815fSDavid Xu }
103