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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "zdtmtst.h"
const char *test_doc = "Check for alternate signal stack";
const char *test_author = "Cyrill Gorcunov <gorcunov@openvz.org>";
#define TESTSIGSTKSZ 16384
static char stack_thread[TESTSIGSTKSZ + TEST_MSG_BUFFER_SIZE] __stack_aligned__;
static char stack_main[TESTSIGSTKSZ + TEST_MSG_BUFFER_SIZE] __stack_aligned__;
enum {
SAS_MAIN_OLD,
SAS_MAIN_NEW,
SAS_THRD_OLD,
SAS_THRD_NEW,
SAS_MAX
};
static stack_t sas_state[SAS_MAX];
static task_waiter_t t;
#define exit_group(code) syscall(__NR_exit_group, code)
#define gettid() syscall(__NR_gettid)
static int sascmp(stack_t *old, stack_t *new)
{
return old->ss_size != new->ss_size || old->ss_sp != new->ss_sp || old->ss_flags != new->ss_flags;
}
static void show_ss(char *prefix, stack_t *s)
{
test_msg("%20s: at %p (size %8zu flags %#2x)\n", prefix, s->ss_sp, s->ss_size, s->ss_flags);
}
void thread_sigaction(int signo, siginfo_t *info, void *context)
{
if (sigaltstack(NULL, &sas_state[SAS_THRD_NEW]))
pr_perror("thread sigaltstack");
show_ss("thread in sas", &sas_state[SAS_THRD_NEW]);
task_waiter_complete(&t, 2);
test_msg("Waiting in thread SAS\n");
task_waiter_wait4(&t, 3);
test_msg("Leaving thread SAS\n");
}
static void *thread_func(void *arg)
{
struct sigaction sa = {
.sa_sigaction = thread_sigaction,
.sa_flags = SA_RESTART | SA_ONSTACK,
};
sas_state[SAS_THRD_OLD] = (stack_t){
.ss_size = sizeof(stack_thread) - 8,
.ss_sp = stack_thread,
.ss_flags = 0,
};
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR2, &sa, NULL)) {
pr_perror("Can't set SIGUSR2 handler");
exit_group(-1);
}
task_waiter_wait4(&t, 1);
if (sigaltstack(&sas_state[SAS_THRD_OLD], NULL)) {
pr_perror("thread sigaltstack");
exit_group(-1);
}
syscall(__NR_tkill, gettid(), SIGUSR2);
return NULL;
}
void leader_sigaction(int signo, siginfo_t *info, void *context)
{
if (sigaltstack(NULL, &sas_state[SAS_MAIN_NEW]))
pr_perror("leader sigaltstack");
show_ss("leader in sas", &sas_state[SAS_MAIN_NEW]);
}
int main(int argc, char *argv[])
{
pthread_t thread;
struct sigaction sa = {
.sa_sigaction = leader_sigaction,
.sa_flags = SA_RESTART | SA_ONSTACK,
};
sas_state[SAS_MAIN_OLD] = (stack_t){
.ss_size = sizeof(stack_main) - 8,
.ss_sp = stack_main,
.ss_flags = 0,
};
sigemptyset(&sa.sa_mask);
test_init(argc, argv);
task_waiter_init(&t);
if (sigaction(SIGUSR1, &sa, NULL)) {
pr_perror("Can't set SIGUSR1 handler");
exit(-1);
}
if (pthread_create(&thread, NULL, &thread_func, NULL)) {
pr_perror("Can't create thread");
exit(-1);
}
if (sigaltstack(&sas_state[SAS_MAIN_OLD], NULL)) {
pr_perror("sigaltstack");
exit(-1);
}
task_waiter_complete(&t, 1);
task_waiter_wait4(&t, 2);
test_daemon();
test_waitsig();
test_msg("Thread may leave SAS\n");
task_waiter_complete(&t, 3);
syscall(__NR_tkill, gettid(), SIGUSR1);
if (pthread_join(thread, NULL)) {
fail("Error joining thread");
exit(-1);
}
task_waiter_fini(&t);
sas_state[SAS_THRD_OLD].ss_flags = SS_ONSTACK;
sas_state[SAS_MAIN_OLD].ss_flags = SS_ONSTACK;
show_ss("main old", &sas_state[SAS_MAIN_OLD]);
show_ss("main new", &sas_state[SAS_MAIN_NEW]);
show_ss("thrd old", &sas_state[SAS_THRD_OLD]);
show_ss("thrd new", &sas_state[SAS_THRD_NEW]);
if (sascmp(&sas_state[SAS_MAIN_OLD], &sas_state[SAS_MAIN_NEW]) ||
sascmp(&sas_state[SAS_THRD_OLD], &sas_state[SAS_THRD_NEW])) {
fail("sas not restored");
} else
pass();
return 0;
}
|