00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <debug.h>
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <stdlib.h>
00022 #include <stdbool.h>
00023 #include <syscall.h>
00024 #include <random.h>
00025 #include "tests/lib.h"
00026
00027 static const int EXPECTED_DEPTH_TO_PASS = 30;
00028 static const int EXPECTED_REPETITIONS = 10;
00029
00030 const char *test_name = "multi-oom";
00031
00032 enum child_termination_mode { RECURSE, CRASH };
00033
00034
00035
00036 static pid_t
00037 spawn_child (int c, enum child_termination_mode mode)
00038 {
00039 char child_cmd[128];
00040 snprintf (child_cmd, sizeof child_cmd,
00041 "%s %d %s", test_name, c, mode == CRASH ? "-k" : "");
00042 return exec (child_cmd);
00043 }
00044
00045
00046
00047
00048 static void
00049 consume_some_resources (void)
00050 {
00051 int fd, fdmax = 126;
00052
00053
00054
00055
00056
00057
00058 for (fd = 0; fd < fdmax; fd++)
00059 if (open (test_name) == -1)
00060 break;
00061 }
00062
00063
00064
00065 static int NO_INLINE
00066 consume_some_resources_and_die (int seed)
00067 {
00068 consume_some_resources ();
00069 random_init (seed);
00070 int *PHYS_BASE = (int *)0xC0000000;
00071
00072 switch (random_ulong () % 5)
00073 {
00074 case 0:
00075 *(int *) NULL = 42;
00076
00077 case 1:
00078 return *(int *) NULL;
00079
00080 case 2:
00081 return *PHYS_BASE;
00082
00083 case 3:
00084 *PHYS_BASE = 42;
00085
00086 case 4:
00087 open ((char *)PHYS_BASE);
00088 exit (-1);
00089
00090 default:
00091 NOT_REACHED ();
00092 }
00093 return 0;
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 int
00106 main (int argc, char *argv[])
00107 {
00108 int n;
00109
00110 n = argc > 1 ? atoi (argv[1]) : 0;
00111 bool is_at_root = (n == 0);
00112 if (is_at_root)
00113 msg ("begin");
00114
00115
00116 if (argc > 2 && !strcmp(argv[2], "-k"))
00117 {
00118 consume_some_resources_and_die (n);
00119 NOT_REACHED ();
00120 }
00121
00122 int howmany = is_at_root ? EXPECTED_REPETITIONS : 1;
00123 int i, expected_depth = -1;
00124
00125 for (i = 0; i < howmany; i++)
00126 {
00127 pid_t child_pid;
00128
00129
00130
00131
00132 if (n > EXPECTED_DEPTH_TO_PASS/2)
00133 {
00134 child_pid = spawn_child (n + 1, CRASH);
00135 if (child_pid != -1)
00136 {
00137 if (wait (child_pid) != -1)
00138 fail ("crashed child should return -1.");
00139 }
00140
00141
00142 }
00143
00144
00145 child_pid = spawn_child (n + 1, RECURSE);
00146
00147
00148 if (child_pid == -1)
00149 return n;
00150
00151
00152 int reached_depth = wait (child_pid);
00153 if (reached_depth == -1)
00154 fail ("wait returned -1.");
00155
00156
00157
00158
00159 if (i == 0)
00160 expected_depth = reached_depth;
00161 else if (expected_depth != reached_depth)
00162 fail ("after run %d/%d, expected depth %d, actual depth %d.",
00163 i, howmany, expected_depth, reached_depth);
00164 ASSERT (expected_depth == reached_depth);
00165 }
00166
00167 consume_some_resources ();
00168
00169 if (n == 0)
00170 {
00171 if (expected_depth < EXPECTED_DEPTH_TO_PASS)
00172 fail ("should have forked at least %d times.", EXPECTED_DEPTH_TO_PASS);
00173 msg ("success. program forked %d times.", howmany);
00174 msg ("end");
00175 }
00176
00177 return expected_depth;
00178 }
00179