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