add a show_backtrace function for debugging.
[trinity.git] / child.c
blob33162007199870a97fc4eed8964d25bb4d42f930
1 /*
2 * Each process that gets forked runs this code.
3 */
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <signal.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <sched.h>
12 #include <sys/time.h>
13 #include <sys/resource.h>
14 #include <sys/prctl.h>
16 #include "child.h"
17 #include "list.h"
18 #include "log.h"
19 #include "maps.h"
20 #include "params.h" // for 'debug'
21 #include "pids.h"
22 #include "random.h"
23 #include "shm.h"
24 #include "signals.h"
25 #include "syscall.h"
26 #include "tables.h"
27 #include "trinity.h" // ARRAY_SIZE
28 #include "utils.h" // zmalloc
30 static struct rlimit oldrlimit;
32 static void disable_coredumps(void)
34 struct rlimit limit;
36 if (debug == TRUE) {
37 (void)signal(SIGSEGV, SIG_DFL);
38 return;
41 getrlimit(RLIMIT_CORE, &oldrlimit);
43 limit.rlim_cur = 0;
44 limit.rlim_max = oldrlimit.rlim_max;
45 if (setrlimit(RLIMIT_CORE, &limit) != 0)
46 perror( "setrlimit(RLIMIT_CORE)" );
49 static void reenable_coredumps(void)
51 if (debug == TRUE)
52 return;
54 prctl(PR_SET_DUMPABLE, TRUE);
56 if (setrlimit(RLIMIT_CORE, &oldrlimit) != 0) {
57 outputerr("[%d] Error restoring rlimits to cur:%d max:%d (%s)\n",
58 getpid(),
59 (unsigned int) oldrlimit.rlim_cur,
60 (unsigned int) oldrlimit.rlim_max,
61 strerror(errno));
64 static void set_make_it_fail(void)
66 int fd;
67 const char *buf = "1";
69 /* If we failed last time, don't bother trying in future. */
70 if (shm->do_make_it_fail == TRUE)
71 return;
73 fd = open("/proc/self/make-it-fail", O_WRONLY);
74 if (fd == -1)
75 return;
77 if (write(fd, buf, 1) == -1) {
78 if (errno != EPERM)
79 outputerr("writing to /proc/self/make-it-fail failed! (%s)\n", strerror(errno));
80 else
81 shm->do_make_it_fail = TRUE;
83 close(fd);
87 * We call this occasionally to set some FPU state, in the hopes that we
88 * might tickle some weird FPU/scheduler related bugs
90 static void use_fpu(void)
92 double x = 0;
93 asm volatile("":"+m" (x));
94 x += 1;
95 asm volatile("":"+m" (x));
98 int this_child = 0;
100 void init_child(int childno)
102 cpu_set_t set;
103 pid_t pid = getpid();
105 this_child = childno;
107 set_seed(childno);
109 shm->kill_count[childno] = 0;
111 disable_coredumps();
113 if (sched_getaffinity(pid, sizeof(set), &set) == 0) {
114 CPU_ZERO(&set);
115 CPU_SET(childno, &set);
116 sched_setaffinity(pid, sizeof(set), &set);
119 shm->child_syscall_count[childno] = 0;
121 set_make_it_fail();
123 if (rand() % 100 < 50)
124 use_fpu();
126 shm->num_mappings[childno] = 0;
127 shm->mappings[childno] = zmalloc(sizeof(struct map));
128 INIT_LIST_HEAD(&shm->mappings[childno]->list);
131 void check_parent_pid(void)
133 pid_t pid;
134 unsigned int i;
135 static unsigned int parent_check_time = 10;
137 parent_check_time--;
138 if (parent_check_time != 0)
139 return;
141 parent_check_time = 10;
143 if (getppid() == shm->mainpid)
144 return;
146 pid = getpid();
148 //FIXME: Add locking so only one child does this output.
149 output(0, BUGTXT "CHILD (pid:%d) GOT REPARENTED! "
150 "parent pid:%d. Watchdog pid:%d\n",
151 pid, shm->mainpid, watchdog_pid);
152 output(0, BUGTXT "Last syscalls:\n");
154 for (i = 0; i < MAX_NR_CHILDREN; i++) {
155 // Skip over 'boring' entries.
156 if ((shm->pids[i] == -1) &&
157 (shm->previous_syscallno[i] == 0) &&
158 (shm->child_syscall_count[i] == 0))
159 continue;
161 output(0, "[%d] pid:%d call:%s callno:%d\n",
162 i, shm->pids[i],
163 print_syscall_name(shm->previous_syscallno[i], shm->do32bit[i]), // FIXME: need previous do32bit
164 shm->child_syscall_count[i]);
166 shm->exit_reason = EXIT_REPARENT_PROBLEM;
167 exit(EXIT_FAILURE);
168 //TODO: Emergency logging.
171 struct child_funcs {
172 int type;
173 const char *name;
174 int (*func)(int childno);
177 static const struct child_funcs child_functions[] = {
178 { .type = CHILD_RANDOM_SYSCALLS, .name = "rand_syscalls", .func = child_random_syscalls },
179 #ifdef DEBUG_MULTI
180 { .type = CHILD_OPEN_ALL_FILES, .name = "read_all_files", .func = child_read_all_files },
181 #endif
184 int child_process(int childno)
186 int ret;
187 unsigned int i;
189 i = rand() % ARRAY_SIZE(child_functions);
191 #ifdef DEBUG_MULTI
192 output(0, "Chose %s.\n", child_functions[i].name);
193 #endif
195 shm->child_type[childno] = child_functions[i].type;
196 ret = child_functions[i].func(childno);
198 reenable_coredumps();
200 return ret;