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