1/*
2   This test makes sure the thread exit notification signals don't
3   interfere with the stack growth signals.
4
5   Thread death notifications are sent as RT signals, which are
6   queued.  In general, these notifications are ignored, since they're
7   only used by the main thread if it has exited and is still waiting
8   for the rest to exit.
9
10   The system has a finite limit to the number of RT signals which can
11   be queued (typically 1024), and beyond that it stops queueing
12   siginfo.  We rely on getting SIGSEGVs with siginfo information to
13   grow the stack.  If we don't get the siginfo, then it just looks
14   like the program crashed.
15
16   The extra complication in this test is making sure that the
17   unwanted signals are discarded while the main thread is blocked in
18   a syscall.  So, to check this, main creates a new process, which
19   attempts to grow the stack once all the threads have been created
20   and exited.  main() itself is blocked waiting for the child
21   process.
22
23   Oh, and this test also makes sure that thread resources are cleaned
24   up properly.
25 */
26#include <pthread.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <signal.h>
32#include <sys/wait.h>
33
34static int grower;
35
36static void handler(int sig)
37{
38}
39
40static void *thr(void *v)
41{
42	return 0;
43}
44
45#define FRAME 4096
46
47static void grow(int depth)
48{
49	volatile char frame[FRAME];
50
51	memset((char *)frame, 0xff, sizeof(frame));
52
53	if (depth > 1)
54		grow(depth-1);
55}
56
57static void *maker(void *v)
58{
59	int i;
60
61	sleep(1);
62
63	/* Create lots of threads */
64	printf("creating threads...\n");
65	for(i = 0; i < 1300; i++) {
66		pthread_t t;
67		int ret;
68
69		if (i % 100 == 0)
70			printf("%d...\n", i);
71
72		ret = pthread_create(&t, NULL, thr, NULL);
73		if (ret) {
74			printf("pthread_create failed: %s\n", strerror(ret));
75			exit(1);
76		}
77
78		ret = pthread_join(t, NULL);
79		if (ret) {
80			printf("pthread_join failed: %s\n", strerror(ret));
81			exit(1);
82		}
83	}
84
85	kill(grower, SIGUSR1);
86
87	return NULL;
88}
89
90int main()
91{
92	pthread_t pth;
93	sigset_t mask;
94	int status;
95	struct sigaction sa;
96
97	sigemptyset(&mask);
98	sigaddset(&mask, SIGCHLD);
99	sigprocmask(SIG_BLOCK, &mask, NULL);
100
101	sa.sa_handler = handler;
102	sa.sa_flags = 0;
103	sigfillset(&sa.sa_mask);
104	sigaction(SIGUSR1, &sa, NULL);
105
106	grower = fork();
107
108	if (grower == -1) {
109		perror("fork");
110		exit(1);
111	}
112
113	if (grower == 0) {
114		pause();	/* child - wait for SIGUSR1 */
115		grow(10);
116		printf("stack grew OK\n");
117		exit(0);
118	}
119
120	pthread_create(&pth, NULL, maker, NULL);
121
122	/* wait for child */
123	if (waitpid(grower, &status, 0) != grower)
124		printf("FAILED\n");
125	else if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
126		printf("PASS: child OK\n");
127	else
128		printf("FAILED: exit status=%d\n", status);
129
130	pthread_join(pth, NULL);
131
132	return 0;
133}
134