summaryrefslogtreecommitdiffstats
path: root/tests/userprog/no-vm
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2012-03-27 11:51:08 +0200
committermanuel <manuel@mausz.at>2012-03-27 11:51:08 +0200
commit4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b (patch)
tree868c52e06f207b5ec8a3cc141f4b8b2bdfcc165c /tests/userprog/no-vm
parenteae0bd57f0a26314a94785061888d193d186944a (diff)
downloadprogos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.tar.gz
progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.tar.bz2
progos-4f670845ff9ab6c48bcb5f7bf4d4ef6dc3c3064b.zip
reorganize file structure to match the upstream requirements
Diffstat (limited to 'tests/userprog/no-vm')
-rw-r--r--tests/userprog/no-vm/Make.tests8
-rw-r--r--tests/userprog/no-vm/Rubric3
-rw-r--r--tests/userprog/no-vm/multi-oom.c179
-rw-r--r--tests/userprog/no-vm/multi-oom.ck10
4 files changed, 200 insertions, 0 deletions
diff --git a/tests/userprog/no-vm/Make.tests b/tests/userprog/no-vm/Make.tests
new file mode 100644
index 0000000..a545e18
--- /dev/null
+++ b/tests/userprog/no-vm/Make.tests
@@ -0,0 +1,8 @@
1# -*- makefile -*-
2
3tests/userprog/no-vm_TESTS = tests/userprog/no-vm/multi-oom
4tests/userprog/no-vm_PROGS = $(tests/userprog/no-vm_TESTS)
5tests/userprog/no-vm/multi-oom_SRC = tests/userprog/no-vm/multi-oom.c \
6tests/lib.c
7
8tests/userprog/no-vm/multi-oom.output: TIMEOUT = 360
diff --git a/tests/userprog/no-vm/Rubric b/tests/userprog/no-vm/Rubric
new file mode 100644
index 0000000..c3816c6
--- /dev/null
+++ b/tests/userprog/no-vm/Rubric
@@ -0,0 +1,3 @@
1Functionality of features that VM might break:
2
31 multi-oom
diff --git a/tests/userprog/no-vm/multi-oom.c b/tests/userprog/no-vm/multi-oom.c
new file mode 100644
index 0000000..6a4472d
--- /dev/null
+++ b/tests/userprog/no-vm/multi-oom.c
@@ -0,0 +1,179 @@
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
32enum child_termination_mode { RECURSE, CRASH };
33
34/* Spawn a recursive copy of ourselves, passing along instructions
35 for the child. */
36static pid_t
37spawn_child (int c, enum child_termination_mode mode)
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
49consume_some_resources (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
66consume_some_resources_and_die (int seed)
67{
68 consume_some_resources ();
69 random_init (seed);
70 int *PHYS_BASE = (int *)0xC0000000;
71
72 switch (random_ulong () % 5)
73 {
74 case 0:
75 *(int *) NULL = 42;
76
77 case 1:
78 return *(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 {
118 consume_some_resources_and_die (n);
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
167 consume_some_resources ();
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
diff --git a/tests/userprog/no-vm/multi-oom.ck b/tests/userprog/no-vm/multi-oom.ck
new file mode 100644
index 0000000..59a0bcd
--- /dev/null
+++ b/tests/userprog/no-vm/multi-oom.ck
@@ -0,0 +1,10 @@
1# -*- perl -*-
2use strict;
3use warnings;
4use tests::tests;
5check_expected (IGNORE_USER_FAULTS => 1, IGNORE_EXIT_CODES => 1, [<<'EOF']);
6(multi-oom) begin
7(multi-oom) success. program forked 10 times.
8(multi-oom) end
9EOF
10pass;