PKUOS - Pintos
Pintos source browser for PKU Operating System course
multi-oom.c
Go to the documentation of this file.
1/** Recursively executes itself until the child fails to execute.
2 We expect that at least 30 copies can run.
3
4 We count how many children your kernel was able to execute
5 before it fails to start a new process. We require that,
6 if a process doesn't actually get to start, exec() must
7 return -1, not a valid PID.
8
9 We repeat this process 10 times, checking that your kernel
10 allows for the same level of depth every time.
11
12 In addition, some processes will spawn children that terminate
13 abnormally after allocating some resources.
14
15 Written by Godmar Back <godmar@gmail.com>
16 */
17
18#include <debug.h>
19#include <stdio.h>
20#include <string.h>
21#include <stdlib.h>
22#include <stdbool.h>
23#include <syscall.h>
24#include <random.h>
25#include "tests/lib.h"
26
27static const int EXPECTED_DEPTH_TO_PASS = 30;
28static const int EXPECTED_REPETITIONS = 10;
29
30const char *test_name = "multi-oom";
31
33
34/** Spawn a recursive copy of ourselves, passing along instructions
35 for the child. */
36static pid_t
38{
39 char child_cmd[128];
40 snprintf (child_cmd, sizeof child_cmd,
41 "%s %d %s", test_name, c, mode == CRASH ? "-k" : "");
42 return exec (child_cmd);
43}
44
45/** Open a number of files (and fail to close them).
46 The kernel must free any kernel resources associated
47 with these file descriptors. */
48static void
50{
51 int fd, fdmax = 126;
52
53 /* Open as many files as we can, up to fdmax.
54 Depending on how file descriptors are allocated inside
55 the kernel, open() may fail if the kernel is low on memory.
56 A low-memory condition in open() should not lead to the
57 termination of the process. */
58 for (fd = 0; fd < fdmax; fd++)
59 if (open (test_name) == -1)
60 break;
61}
62
63/** Consume some resources, then terminate this process
64 in some abnormal way. */
65static int NO_INLINE
67{
69 random_init (seed);
70 volatile int *PHYS_BASE = (volatile int *)0xC0000000;
71
72 switch (random_ulong () % 5)
73 {
74 case 0:
75 *(volatile int *) NULL = 42;
76
77 case 1:
78 return *(volatile int *) NULL;
79
80 case 2:
81 return *PHYS_BASE;
82
83 case 3:
84 *PHYS_BASE = 42;
85
86 case 4:
87 open ((char *)PHYS_BASE);
88 exit (-1);
89
90 default:
91 NOT_REACHED ();
92 }
93 return 0;
94}
95
96/** The first copy is invoked without command line arguments.
97 Subsequent copies are invoked with a parameter 'depth'
98 that describes how many parent processes preceded them.
99 Each process spawns one or multiple recursive copies of
100 itself, passing 'depth+1' as depth.
101
102 Some children are started with the '-k' flag, which will
103 result in abnormal termination.
104 */
105int
106main (int argc, char *argv[])
107{
108 int n;
109
110 n = argc > 1 ? atoi (argv[1]) : 0;
111 bool is_at_root = (n == 0);
112 if (is_at_root)
113 msg ("begin");
114
115 /* If -k is passed, crash this process. */
116 if (argc > 2 && !strcmp(argv[2], "-k"))
117 {
119 NOT_REACHED ();
120 }
121
122 int howmany = is_at_root ? EXPECTED_REPETITIONS : 1;
123 int i, expected_depth = -1;
124
125 for (i = 0; i < howmany; i++)
126 {
127 pid_t child_pid;
128
129 /* Spawn a child that will be abnormally terminated.
130 To speed the test up, do this only for processes
131 spawned at a certain depth. */
132 if (n > EXPECTED_DEPTH_TO_PASS/2)
133 {
134 child_pid = spawn_child (n + 1, CRASH);
135 if (child_pid != -1)
136 {
137 if (wait (child_pid) != -1)
138 fail ("crashed child should return -1.");
139 }
140 /* If spawning this child failed, so should
141 the next spawn_child below. */
142 }
143
144 /* Now spawn the child that will recurse. */
145 child_pid = spawn_child (n + 1, RECURSE);
146
147 /* If maximum depth is reached, return result. */
148 if (child_pid == -1)
149 return n;
150
151 /* Else wait for child to report how deeply it was able to recurse. */
152 int reached_depth = wait (child_pid);
153 if (reached_depth == -1)
154 fail ("wait returned -1.");
155
156 /* Record the depth reached during the first run; on subsequent
157 runs, fail if those runs do not match the depth achieved on the
158 first run. */
159 if (i == 0)
160 expected_depth = reached_depth;
161 else if (expected_depth != reached_depth)
162 fail ("after run %d/%d, expected depth %d, actual depth %d.",
163 i, howmany, expected_depth, reached_depth);
164 ASSERT (expected_depth == reached_depth);
165 }
166
168
169 if (n == 0)
170 {
171 if (expected_depth < EXPECTED_DEPTH_TO_PASS)
172 fail ("should have forked at least %d times.", EXPECTED_DEPTH_TO_PASS);
173 msg ("success. program forked %d times.", howmany);
174 msg ("end");
175 }
176
177 return expected_depth;
178}
179// vim: sw=2
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
#define NOT_REACHED()
lib/debug.h
Definition: debug.h:35
#define NO_INLINE
Definition: debug.h:9
static void wait(struct intq *q, struct thread **waiter)
int snprintf(char *buffer, size_t buf_size, const char *format,...)
Like printf(), except that output is stored into BUFFER, which must have space for BUF_SIZE character...
Definition: stdio.c:62
int atoi(const char *s)
Converts a string representation of a signed decimal integer in S into an ‘int’, which is returned.
Definition: stdlib.c:10
void exit(int status)
Definition: syscall.c:72
int open(const char *file)
Definition: syscall.c:103
pid_t exec(const char *file)
Definition: syscall.c:79
int pid_t
Process identifier.
Definition: syscall.h:8
void fail(const char *format,...)
Definition: lib.c:40
void msg(const char *format,...)
Definition: lib.c:28
static void consume_some_resources(void)
Open a number of files (and fail to close them).
Definition: multi-oom.c:49
int main(int argc, char *argv[])
The first copy is invoked without command line arguments.
Definition: multi-oom.c:106
child_termination_mode
Definition: multi-oom.c:32
@ CRASH
Definition: multi-oom.c:32
@ RECURSE
Definition: multi-oom.c:32
static const int EXPECTED_DEPTH_TO_PASS
Recursively executes itself until the child fails to execute.
Definition: multi-oom.c:27
const char * test_name
Child process for syn-read test.
Definition: multi-oom.c:30
static pid_t spawn_child(int c, enum child_termination_mode mode)
Spawn a recursive copy of ourselves, passing along instructions for the child.
Definition: multi-oom.c:37
static const int EXPECTED_REPETITIONS
Definition: multi-oom.c:28
static int NO_INLINE consume_some_resources_and_die(int seed)
Consume some resources, then terminate this process in some abnormal way.
Definition: multi-oom.c:66
unsigned long random_ulong(void)
Returns a pseudo-random unsigned long.
Definition: random.c:78
void random_init(unsigned seed)
Initializes or reinitializes the PRNG with the given SEED.
Definition: random.c:34
static enum @0 mode
Transmission mode.
#define NULL
Definition: stddef.h:4
int strcmp(const char *a_, const char *b_)
Finds the first differing characters in strings A and B.
Definition: string.c:73
#define PHYS_BASE
Base address of the 1:1 physical-to-virtual mapping.
Definition: vaddr.h:53