xref: /xnu-11417.140.69/tests/vm/memorystatus_kill_counts.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <mach/mach.h>
4 #include <unistd.h>
5 #include <mach-o/dyld.h>
6 #include <sys/sysctl.h>
7 #include <sys/kern_memorystatus.h>
8 
9 #include <darwintest.h>
10 #include <darwintest_utils.h>
11 
12 T_GLOBAL_META(
13 	T_META_RUN_CONCURRENTLY(false),
14 	T_META_RADAR_COMPONENT_NAME("xnu"),
15 	T_META_RADAR_COMPONENT_VERSION("VM"));
16 
17 #define MAX_TRIES 3
18 
19 static int
get_kill_counts(uint32_t * buffer,size_t buffer_size,int band,int flags)20 get_kill_counts(uint32_t *buffer, size_t buffer_size, int band, int flags)
21 {
22 	return memorystatus_control(MEMORYSTATUS_CMD_GET_KILL_COUNTS, band, flags, buffer, buffer_size);
23 }
24 
25 T_HELPER_DECL(thrown_overboard, "child to be jetsammed") {
26 	for (;;) {
27 		sleep(1);
28 	}
29 }
30 
31 static void
spawn_and_jetsam(int32_t band)32 spawn_and_jetsam(int32_t band)
33 {
34 	static char path[PATH_MAX] = {0};
35 	static uint32_t path_size = sizeof(path);
36 	int error;
37 	pid_t child;
38 	memorystatus_priority_properties_t prop;
39 
40 	if (!path[0]) {
41 		T_ASSERT_POSIX_ZERO(_NSGetExecutablePath(path, &path_size), "_NSGetExecutablePath");
42 	}
43 
44 	char *args[] = { path, "-n", "thrown_overboard", NULL};
45 	error = dt_launch_tool(&child, args, false, NULL, NULL);
46 	T_QUIET; T_ASSERT_POSIX_ZERO(error, "spawn child");
47 	prop.priority = band;
48 	prop.user_data = 0;
49 	error = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, child, 0, &prop, sizeof(prop));
50 	T_QUIET; T_ASSERT_POSIX_ZERO(error, "set child properties");
51 	error = memorystatus_control(MEMORYSTATUS_CMD_TEST_JETSAM, child, 0, NULL, 0);
52 	T_QUIET; T_ASSERT_POSIX_ZERO(error, "jetsam child");
53 }
54 
55 #define N_TEST_BANDS 5
56 int32_t test_bands[N_TEST_BANDS] = {0, 30, 35, 40, 45};
57 int32_t proc_counts[N_TEST_BANDS] = {2, 3, 1, 2, 4};
58 
59 #define BUFFER_SIZE (sizeof(uint32_t) * (JETSAM_REASON_MEMORYSTATUS_MAX + 1))
60 
61 T_DECL(memorystatus_kill_counts, "jetsam kill counts",
62     T_META_ASROOT(true))
63 {
64 	int i, j;
65 	uint32_t *buffers[N_TEST_BANDS];
66 
67 	/* Spawn a handful of children and kill them */
68 	for (i = 0; i < N_TEST_BANDS; i++) {
69 		buffers[i] = malloc(BUFFER_SIZE);
70 		T_QUIET; T_ASSERT_POSIX_NOTNULL(buffers[i], "malloc()");
71 		for (j = 0; j < proc_counts[i]; j++) {
72 			spawn_and_jetsam(test_bands[i]);
73 		}
74 	}
75 
76 	void (^get_all_kill_counts)(uint32_t**, int) = ^(uint32_t **buffers, int flags){
77 		int i, error;
78 		for (i = 0; i < N_TEST_BANDS; i++) {
79 			error = get_kill_counts(buffers[i], BUFFER_SIZE, test_bands[i], flags);
80 			T_ASSERT_POSIX_ZERO(error, "get kill counts (band %d)", test_bands[i]);
81 		}
82 	};
83 
84 	/* Query for size */
85 	void (^check_buffer)(uint32_t**, bool) = ^(uint32_t **buffers, bool expect_missing) {
86 		int i;
87 		bool missing_proc;
88 
89 		missing_proc = false;
90 		for (i = 0; i < N_TEST_BANDS; i++) {
91 			uint32_t count = buffers[i][kMemorystatusKilled];
92 			missing_proc = missing_proc || (count < proc_counts[i]);
93 			if (!expect_missing) {
94 				T_QUIET; T_EXPECT_LE(proc_counts[i], count, "Children in band %d found in kill list.", test_bands[i]);
95 			}
96 		}
97 
98 		if (!expect_missing) {
99 			T_EXPECT_FALSE(missing_proc, "Found all children in kill list");
100 		} else {
101 			T_EXPECT_TRUE(missing_proc, "Previously cleared entries not in list");
102 		}
103 	};
104 
105 	/* Get the list once, and don't clear it. */
106 	T_LOG("--- Getting kill counts (without clear) ---");
107 	get_all_kill_counts(buffers, 0);
108 	check_buffer(buffers, false);
109 
110 	/* Check again (w/ clear) - The list should still have the same entries. */
111 	T_LOG("--- Getting kill counts (with clear) ---");
112 	get_all_kill_counts(buffers, MEMORYSTATUS_GET_KILL_COUNTS_CLEAR);
113 	check_buffer(buffers, false);
114 
115 	/*
116 	 * Check one last time - The list should have been cleared.
117 	 * Things could have been jetsammed since we cleared the list, but we only
118 	 * care about the presence of our test children who have a generic
119 	 * jetsam reason - that shouldn't happen elsewhere.
120 	 */
121 	T_LOG("--- Getting kill counts (after clear) ---");
122 	get_all_kill_counts(buffers, 0);
123 	check_buffer(buffers, true);
124 }
125