Home | History | Annotate | Download | only in tests
      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 
     34 static int grower;
     35 
     36 static void handler(int sig)
     37 {
     38 }
     39 
     40 static void *thr(void *v)
     41 {
     42 	return 0;
     43 }
     44 
     45 #define FRAME 4096
     46 
     47 static 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 
     57 static 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 
     90 int 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