xref: /xnu-12377.61.12/tests/vm/memorystatus_convert_limit_bytes.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 #include <sys/kern_memorystatus.h>
2 #include <sys/sysctl.h>
3 #include <sys/types.h>
4 #include <unistd.h>
5 
6 #include <darwintest.h>
7 
8 #define MAX_TASK_MEM "kern.max_task_pmem"
9 
10 T_GLOBAL_META(
11 	T_META_NAMESPACE("xnu.vm"),
12 	T_META_RADAR_COMPONENT_NAME("xnu"),
13 	T_META_RADAR_COMPONENT_VERSION("VM"),
14 	T_META_BOOTARGS_SET("memstat_no_task_limit_increase=1"),
15 	T_META_ENABLED(!TARGET_OS_OSX));
16 
17 T_DECL(memorystatus_convert_limit_bytes, "memorystatus_convert_limit_bytes default limit", T_META_TAG_VM_PREFERRED)
18 {
19 	int ret;
20 	int32_t max_task_pmem = 0;
21 	size_t size_max_task_pmem = sizeof(max_task_pmem);
22 
23 	ret = sysctlbyname(MAX_TASK_MEM, &max_task_pmem, &size_max_task_pmem, NULL, 0);
24 	T_ASSERT_POSIX_SUCCESS(ret, "call sysctlbyname to get max task physical memory.");
25 
26 	if (max_task_pmem == 0) {
27 		T_SKIP("Device does not have a default task memory limit.");
28 	}
29 
30 	ret = memorystatus_control(MEMORYSTATUS_CMD_CONVERT_MEMLIMIT_MB, getpid(), (int32_t) -1, NULL, 0);
31 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
32 	T_QUIET; T_ASSERT_EQ(ret, max_task_pmem, "default limit is converted correctly");
33 }
34 
35 T_DECL(memorystatus_set_task_limit_always_fatal,
36     "Verify that a converted task limit is always fatal")
37 {
38 	int ret;
39 	int32_t max_task_pmem = 0;
40 	size_t size_max_task_pmem = sizeof(max_task_pmem);
41 	pid_t pid = getpid();
42 
43 	ret = sysctlbyname(MAX_TASK_MEM, &max_task_pmem, &size_max_task_pmem, NULL, 0);
44 	T_ASSERT_POSIX_SUCCESS(ret, "call sysctlbyname to get max task physical memory.");
45 
46 	if (max_task_pmem == 0) {
47 		T_SKIP("Device does not have a default task memory limit.");
48 	}
49 
50 	/* Request non-fatal memlimits */
51 	memorystatus_memlimit_properties2_t mmprops = {
52 		.v1 = {
53 			.memlimit_active = max_task_pmem,
54 			.memlimit_inactive = max_task_pmem,
55 			.memlimit_active_attr = 0,
56 			.memlimit_inactive_attr = 0,
57 		},
58 	};
59 	ret = memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops.v1, sizeof(mmprops.v1));
60 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
61 
62 	ret = memorystatus_control(MEMORYSTATUS_CMD_GET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops, sizeof(mmprops));
63 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
64 
65 	T_EXPECT_BITS_SET(mmprops.v1.memlimit_active_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
66 	    "Active limit (task limit) should be fatal");
67 	T_EXPECT_BITS_SET(mmprops.v1.memlimit_inactive_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
68 	    "Inactive limit (task limit) should be fatal");
69 
70 	/* Request non-fatal memlimits */
71 	mmprops.v1.memlimit_active = -1;
72 	mmprops.v1.memlimit_inactive = -1;
73 	mmprops.v1.memlimit_active_attr = 0;
74 	mmprops.v1.memlimit_inactive_attr = 0;
75 
76 	ret = memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops.v1, sizeof(mmprops.v1));
77 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
78 
79 	ret = memorystatus_control(MEMORYSTATUS_CMD_GET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops, sizeof(mmprops));
80 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
81 
82 	T_EXPECT_BITS_SET(mmprops.v1.memlimit_active_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
83 	    "Active limit (-1) should be fatal");
84 	T_EXPECT_BITS_SET(mmprops.v1.memlimit_inactive_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
85 	    "Inactive (-1) limit should be fatal");
86 
87 	/* Request non-fatal memlimits */
88 	mmprops.v1.memlimit_active = 0;
89 	mmprops.v1.memlimit_inactive = 0;
90 	mmprops.v1.memlimit_active_attr = 0;
91 	mmprops.v1.memlimit_inactive_attr = 0;
92 
93 	ret = memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops.v1, sizeof(mmprops.v1));
94 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
95 
96 	ret = memorystatus_control(MEMORYSTATUS_CMD_GET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops, sizeof(mmprops));
97 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
98 
99 	T_EXPECT_BITS_SET(mmprops.v1.memlimit_active_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
100 	    "Active limit (0) should be fatal");
101 	T_EXPECT_BITS_SET(mmprops.v1.memlimit_inactive_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
102 	    "Inactive (0) limit should be fatal");
103 }
104 
105 T_DECL(memorystatus_memlimit_gt_task_limit,
106     "Verify that memory limits can exceed the task limit")
107 {
108 	int ret;
109 	int32_t max_task_pmem = 0;
110 	size_t size_max_task_pmem = sizeof(max_task_pmem);
111 	pid_t pid = getpid();
112 
113 	ret = sysctlbyname(MAX_TASK_MEM, &max_task_pmem, &size_max_task_pmem, NULL, 0);
114 	T_ASSERT_POSIX_SUCCESS(ret, "call sysctlbyname to get max task physical memory.");
115 
116 	if (max_task_pmem == 0) {
117 		T_SKIP("Device does not have a default task memory limit.");
118 	}
119 
120 	/* Request non-fatal memlimits */
121 	int32_t expected_memlimit = max_task_pmem + 100;
122 	memorystatus_memlimit_properties2_t mmprops = {
123 		.v1 = {
124 			.memlimit_active = expected_memlimit,
125 			.memlimit_inactive = expected_memlimit,
126 			.memlimit_active_attr = 0,
127 			.memlimit_inactive_attr = 0,
128 		},
129 	};
130 	ret = memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops.v1, sizeof(mmprops.v1));
131 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
132 
133 	ret = memorystatus_control(MEMORYSTATUS_CMD_GET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops, sizeof(mmprops));
134 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
135 
136 	T_EXPECT_EQ(mmprops.v1.memlimit_active, expected_memlimit, "Active limit can exceed task limit");
137 	T_EXPECT_EQ(mmprops.v1.memlimit_inactive, expected_memlimit, "Inactive limit can exceed task limit");
138 	T_EXPECT_BITS_NOTSET(mmprops.v1.memlimit_active_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
139 	    "Active limit should be non-fatal");
140 	T_EXPECT_BITS_NOTSET(mmprops.v1.memlimit_inactive_attr, MEMORYSTATUS_MEMLIMIT_ATTR_FATAL,
141 	    "Inactive limit should be non-fatal");
142 }
143