]>
Commit | Line | Data |
---|---|---|
f427ee49 A |
1 | #include "mach_vm_tests.h" |
2 | ||
3 | T_GLOBAL_META(T_META_NAMESPACE("xnu.vm")); | |
4 | ||
5 | extern char **environ; | |
6 | ||
7 | static void | |
8 | spawn_process(char *action, char *serviceName, char *extraArg, | |
9 | mach_port_t *server_Port, pid_t *serverPid, boolean_t use4k); | |
10 | ||
11 | static void mach_client(void); | |
12 | ||
13 | mach_port_t serverPort; | |
14 | static pid_t serverPid; | |
15 | ||
16 | boolean_t debug = TRUE; | |
17 | ||
18 | void | |
19 | spawn_process(char *action, char *serviceName, char *extraArg, | |
20 | mach_port_t *server_Port, pid_t *server_Pid, boolean_t use4k) | |
21 | { | |
22 | char buffer[PATH_MAX]; | |
23 | char *argv[10] = {0}; | |
24 | int arg_index = 0; | |
25 | pid_t pid = -1; | |
26 | int r = proc_pidpath(getpid(), buffer, sizeof(buffer)); | |
27 | T_ASSERT_NE(r, -1, "proc_pidpath"); | |
28 | r = (int)strlcat(buffer, "_server", sizeof(buffer)); | |
29 | T_ASSERT_LT(r, (int)sizeof(buffer), "strlcat"); | |
30 | ||
31 | if (use4k) { | |
32 | int supported = 0; | |
33 | size_t supported_size = sizeof(supported); | |
34 | ||
35 | r = sysctlbyname("debug.vm_mixed_pagesize_supported", &supported, &supported_size, NULL, 0); | |
36 | if (r == 0 && supported) { | |
37 | T_LOG("Using %s to spawn process with 4k", VM_SPAWN_TOOL); | |
38 | argv[arg_index++] = VM_SPAWN_TOOL; | |
39 | } else { | |
40 | /* | |
41 | * We didnt find debug.vm.mixed_page.supported OR its set to 0. | |
42 | * Skip the test. | |
43 | */ | |
44 | T_SKIP("Hardware doesn't support 4K pages, skipping test..."); | |
45 | exit(0); | |
46 | } | |
47 | } | |
48 | argv[arg_index++] = (char *)&buffer[0]; | |
49 | argv[arg_index++] = (char *)action; | |
50 | argv[arg_index++] = (char *)serviceName; | |
51 | argv[arg_index++] = (char *)extraArg; | |
52 | argv[arg_index++] = NULL; | |
53 | ||
54 | printf("posix_spawn with argv: "); | |
55 | for (r = 0; r <= arg_index; r++) { | |
56 | printf("%s ", argv[r]); | |
57 | } | |
58 | printf("\n"); | |
59 | ||
60 | T_LOG("Spawning %s process(%s) with service name %s at %s\n", action, buffer, serviceName, buffer); | |
61 | ||
62 | ||
63 | posix_spawn_file_actions_t actions; | |
64 | posix_spawn_file_actions_init(&actions); | |
65 | ||
66 | T_ASSERT_POSIX_ZERO(posix_spawn(&pid, buffer, &actions, NULL, argv, environ), "spawn %s", serviceName); | |
67 | posix_spawn_file_actions_destroy(&actions); | |
68 | ||
69 | kern_return_t ret; | |
70 | mach_port_t servicePort; | |
71 | int attempts = 0; | |
72 | const int kMaxAttempts = 10; | |
73 | do { | |
74 | sleep(1); | |
75 | ret = bootstrap_look_up(bootstrap_port, serviceName, &servicePort); | |
76 | attempts++; | |
77 | } while (ret == BOOTSTRAP_UNKNOWN_SERVICE && attempts < kMaxAttempts); | |
78 | ||
79 | if (ret != KERN_SUCCESS) { | |
80 | printf("ERROR: Failed bootstrap lookup for process with mach service name '%s': (%d) %s\n", serviceName, ret, mach_error_string(ret)); | |
81 | if (pid > 0) { | |
82 | kill(pid, SIGKILL); | |
83 | } | |
84 | T_FAIL("Failed bootstrap lookup for process with mach service"); | |
85 | } | |
86 | ||
87 | *server_Port = servicePort; | |
88 | *server_Pid = pid; | |
89 | T_LOG("Server pid=%d port 0x%x", pid, servicePort); | |
90 | } | |
91 | ||
92 | ||
93 | ||
94 | ||
95 | void | |
96 | mach_client() | |
97 | { | |
98 | mach_port_t replyPort; | |
99 | T_ASSERT_POSIX_ZERO(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort), "create recieve port"); | |
100 | T_ASSERT_POSIX_ZERO(mach_port_insert_right(mach_task_self(), replyPort, replyPort, MACH_MSG_TYPE_MAKE_SEND), "insert send port"); | |
101 | ||
102 | ipc_message_t message; | |
103 | bzero(&message, sizeof(message)); | |
104 | message.header.msgh_id = 1; | |
105 | ||
106 | message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_COPY_SEND); | |
107 | message.header.msgh_remote_port = serverPort; | |
108 | message.header.msgh_local_port = replyPort; | |
109 | message.header.msgh_size = sizeof(message); | |
110 | ||
111 | /* reply creation is not necessary in this case. | |
112 | * mach_msg_size_t replySize = sizeof(ipc_message_t) + sizeof(mach_msg_trailer_t) + 64; | |
113 | * ipc_message_t *reply = calloc(1, replySize); | |
114 | */ | |
115 | T_LOG("sending message to %d of size %u", message.header.msgh_remote_port, message.header.msgh_size); | |
116 | kern_return_t ret = mach_msg(&message.header, MACH_SEND_MSG, message.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); | |
117 | T_ASSERT_MACH_SUCCESS(ret, "mach_msg to serverProcess"); | |
118 | mach_vm_client(replyPort); | |
119 | T_LOG("Sending SIGKILL to server(%d)", serverPid); | |
120 | kill(serverPid, SIGKILL); | |
121 | } | |
122 | ||
123 | T_DECL(memory_share_tests, | |
124 | "test vm memory sharing between client and server process with different process PAGE_SIZE", | |
125 | T_META_ASROOT(true)) | |
126 | { | |
127 | boolean_t use4k = FALSE; | |
128 | char serviceName[64]; | |
129 | ||
130 | struct sigaction action = { | |
131 | .sa_handler = SIG_IGN, | |
132 | .sa_flags = SA_NOCLDWAIT | |
133 | }; | |
134 | sigaction(SIGCHLD, &action, NULL); | |
135 | ||
136 | if (getenv("USE4K")) { | |
137 | use4k = TRUE; | |
138 | } | |
139 | ||
140 | if (getenv("QUIET")) { | |
141 | debug = FALSE; | |
142 | } | |
143 | ||
144 | T_LOG("running with use4k=%d debug=%d", use4k, (int)debug); | |
145 | ||
146 | strcpy(serviceName, MACH_VM_TEST_SERVICE_NAME); | |
147 | ||
148 | spawn_process("machserver", serviceName, NULL, &serverPort, &serverPid, use4k); | |
149 | mach_client(); | |
150 | } | |
151 | ||
152 | T_DECL_REF(memory_share_tests_4k, memory_share_tests, "vm memory sharing with 4k processes", | |
153 | T_META_ENVVAR("USE4K=YES"), | |
154 | T_META_ASROOT(true) | |
155 | ); |