]>
Commit | Line | Data |
---|---|---|
2d21ac55 A |
1 | /* |
2 | * memory_tests.c.c | |
3 | * xnu_quick_test | |
4 | * | |
5 | * Created by Jerry Cottingham on 4/12/05. | |
6 | * Copyright 2005 Apple Computer Inc. All rights reserved. | |
7 | * | |
8 | */ | |
9 | ||
10 | #include "tests.h" | |
b0d623f7 | 11 | #include <mach/mach.h> |
2d21ac55 A |
12 | |
13 | extern char g_target_path[ PATH_MAX ]; | |
14 | ||
6d2010ae A |
15 | /* |
16 | * static to localize to this compilation unit; volatile to avoid register | |
17 | * optimization which would prevent modification by a signal handler. | |
18 | */ | |
19 | static volatile int my_err; | |
20 | ||
6d2010ae A |
21 | void |
22 | bus_handler(int sig, siginfo_t *si, void *mcontext) | |
23 | { | |
24 | /* Reset global error value when we see a SIGBUS */ | |
39236c6e A |
25 | if (sig == SIGBUS) { |
26 | _exit(0); | |
6d2010ae | 27 | } |
6d2010ae A |
28 | } |
29 | ||
2d21ac55 A |
30 | /* ************************************************************************************************************** |
31 | * Test madvise, mincore, minherit, mlock, mlock, mmap, mprotect, msync, munmap system calls. | |
32 | * todo - see if Francois has better versions of these tests... | |
33 | * ************************************************************************************************************** | |
34 | */ | |
35 | int memory_tests( void * the_argp ) | |
36 | { | |
2d21ac55 A |
37 | int my_page_size, my_status; |
38 | int my_fd = -1; | |
39 | char * my_pathp = NULL; | |
40 | char * my_bufp = NULL; | |
41 | char * my_addr = NULL; | |
42 | char * my_test_page_p = NULL; | |
43 | ssize_t my_result; | |
44 | pid_t my_pid, my_wait_pid; | |
b0d623f7 | 45 | kern_return_t my_kr; |
6d2010ae | 46 | struct sigaction my_sa; |
2d21ac55 | 47 | |
b0d623f7 A |
48 | my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_pathp, PATH_MAX, VM_FLAGS_ANYWHERE); |
49 | if(my_kr != KERN_SUCCESS){ | |
50 | printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
51 | goto test_failed_exit; | |
52 | } | |
53 | ||
2d21ac55 A |
54 | *my_pathp = 0x00; |
55 | strcat( my_pathp, &g_target_path[0] ); | |
56 | strcat( my_pathp, "/" ); | |
57 | ||
58 | /* create a test file */ | |
59 | my_err = create_random_name( my_pathp, 1 ); | |
60 | if ( my_err != 0 ) { | |
61 | goto test_failed_exit; | |
62 | } | |
63 | ||
64 | my_page_size = getpagesize( ); | |
b0d623f7 A |
65 | my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_test_page_p, my_page_size, VM_FLAGS_ANYWHERE); |
66 | if(my_kr != KERN_SUCCESS){ | |
67 | printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
68 | goto test_failed_exit; | |
69 | } | |
70 | ||
2d21ac55 A |
71 | *my_test_page_p = 0x00; |
72 | strcat( my_test_page_p, "parent data" ); | |
73 | ||
74 | /* test minherit - share a page with child, add to the string in child then | |
75 | * check for modification after child terminates. | |
76 | */ | |
77 | my_err = minherit( my_test_page_p, my_page_size, VM_INHERIT_SHARE ); | |
78 | if ( my_err == -1 ) { | |
79 | printf( "minherit failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
80 | goto test_failed_exit; | |
81 | } | |
82 | ||
83 | /* | |
84 | * spin off a child process that we will use for testing. | |
85 | */ | |
86 | my_pid = fork( ); | |
87 | if ( my_pid == -1 ) { | |
88 | printf( "fork failed with errno %d - %s \n", errno, strerror( errno ) ); | |
89 | goto test_failed_exit; | |
90 | } | |
91 | if ( my_pid == 0 ) { | |
92 | /* | |
93 | * child process... | |
94 | */ | |
95 | strcat( my_test_page_p, " child data" ); | |
96 | ||
97 | /* create a test file in page size chunks */ | |
b0d623f7 A |
98 | my_kr = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*)&my_bufp, (my_page_size * 10), VM_FLAGS_ANYWHERE); |
99 | if(my_kr != KERN_SUCCESS){ | |
100 | printf( "vm_allocate failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
101 | my_err = -1; | |
102 | goto exit_child; | |
103 | } | |
104 | ||
105 | /* test madvise on anonymous memory */ | |
106 | my_err = madvise(my_bufp, (my_page_size * 10), MADV_WILLNEED); | |
107 | if ( my_err == -1 ) { | |
108 | printf("madvise WILLNEED on anon memory failed with error %d - \"%s\" \n", errno, strerror( errno ) ); | |
2d21ac55 A |
109 | my_err = -1; |
110 | goto exit_child; | |
111 | } | |
112 | ||
113 | memset( my_bufp, 'j', (my_page_size * 10) ); | |
114 | my_fd = open( my_pathp, O_RDWR, 0 ); | |
115 | if ( my_fd == -1 ) { | |
116 | printf( "open call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
117 | my_err = -1; | |
118 | goto exit_child; | |
119 | } | |
120 | ||
b0d623f7 A |
121 | /* test madvise on anonymous memory */ |
122 | my_err = madvise(my_bufp, (my_page_size * 10), MADV_DONTNEED); | |
123 | if ( my_err == -1 ) { | |
124 | printf("madvise DONTNEED on anon memory failed with error %d - \"%s\" \n", errno, strerror( errno ) ); | |
125 | my_err = -1; | |
126 | goto exit_child; | |
127 | } | |
128 | ||
2d21ac55 A |
129 | my_result = write( my_fd, my_bufp, (my_page_size * 10) ); |
130 | if ( my_result == -1 ) { | |
131 | printf( "write call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
132 | my_err = -1; | |
133 | goto exit_child; | |
134 | } | |
135 | ||
136 | /* map the file into memory */ | |
137 | my_addr = (char *) mmap( NULL, (my_page_size * 2), (PROT_READ | PROT_WRITE), (MAP_FILE | MAP_SHARED), my_fd, 0 ); | |
138 | if ( my_addr == (char *) -1 ) { | |
139 | printf( "mmap call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
140 | my_err = -1; | |
141 | goto exit_child; | |
142 | } | |
143 | ||
144 | /* make sure we got the right data mapped */ | |
145 | if ( *my_addr != 'j' || *(my_addr + my_page_size) != 'j' ) { | |
146 | printf( "did not map in correct data \n" ); | |
147 | my_err = -1; | |
148 | goto exit_child; | |
149 | } | |
150 | ||
151 | /* test madvise */ | |
152 | my_err = madvise( my_addr, (my_page_size * 2), MADV_WILLNEED ); | |
153 | if ( my_err == -1 ) { | |
b0d623f7 A |
154 | printf( "madvise WILLNEED call failed with error %d - \"%s\" \n", errno, strerror( errno) ); |
155 | my_err = -1; | |
156 | goto exit_child; | |
157 | } | |
158 | ||
159 | my_err = madvise( my_addr, (my_page_size * 2), MADV_DONTNEED ); | |
160 | if ( my_err == -1 ) { | |
161 | printf( "madvise DONTNEED call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
2d21ac55 A |
162 | my_err = -1; |
163 | goto exit_child; | |
164 | } | |
165 | ||
166 | /* test mincore, mlock, mlock */ | |
167 | my_err = mlock( my_addr, my_page_size ); | |
168 | if ( my_err == -1 ) { | |
169 | printf( "mlock call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
170 | my_err = -1; | |
171 | goto exit_child; | |
172 | } | |
173 | ||
b0d623f7 A |
174 | /* mybufp is about to be reused, so test madvise on anonymous memory */ |
175 | my_err = madvise(my_bufp, (my_page_size * 10), MADV_FREE); | |
176 | if ( my_err == -1 ) { | |
177 | printf("madvise FREE on anon memory failed with error %d - \"%s\" \n", errno, strerror( errno ) ); | |
178 | my_err = -1; | |
179 | goto exit_child; | |
180 | } | |
181 | ||
2d21ac55 A |
182 | my_err = mincore( my_addr, 1, my_bufp ); |
183 | if ( my_err == -1 ) { | |
184 | printf( "mincore call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
185 | my_err = -1; | |
186 | goto exit_child; | |
187 | } | |
188 | /* page my_addr is in should be resident after mlock */ | |
189 | if ( (*my_bufp & MINCORE_INCORE) == 0 ) { | |
190 | printf( "mincore call failed to find resident page \n" ); | |
191 | my_err = -1; | |
192 | goto exit_child; | |
193 | } | |
194 | ||
195 | my_err = munlock( my_addr, my_page_size ); | |
196 | if ( my_err == -1 ) { | |
197 | printf( "munlock call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
198 | my_err = -1; | |
199 | goto exit_child; | |
200 | } | |
201 | ||
202 | /* modify first page then use msync to push data out */ | |
203 | memset( my_addr, 'x', my_page_size ); | |
204 | my_err = msync( my_addr, my_page_size, (MS_SYNC | MS_INVALIDATE) ); | |
205 | if ( my_err == -1 ) { | |
206 | printf( "msync call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
207 | my_err = -1; | |
208 | goto exit_child; | |
209 | } | |
210 | ||
b0d623f7 A |
211 | /* test madvise */ |
212 | my_err = madvise( my_addr, (my_page_size * 2), MADV_DONTNEED ); | |
213 | if ( my_err == -1 ) { | |
214 | printf( "madvise DONTNEED call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
215 | my_err = -1; | |
216 | goto exit_child; | |
217 | } | |
218 | ||
219 | /* test madvise */ | |
220 | my_err = madvise( my_addr, (my_page_size * 2), MADV_FREE ); | |
221 | if ( my_err == -1 ) { | |
222 | printf( "madvise FREE call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
223 | my_err = -1; | |
224 | goto exit_child; | |
225 | } | |
226 | ||
2d21ac55 A |
227 | /* verify that the file was updated */ |
228 | lseek( my_fd, 0, SEEK_SET ); | |
229 | bzero( (void *)my_bufp, my_page_size ); | |
230 | my_result = read( my_fd, my_bufp, my_page_size ); | |
231 | if ( my_result == -1 ) { | |
232 | printf( "read call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
233 | my_err = -1; | |
234 | goto exit_child; | |
235 | } | |
236 | if ( *my_bufp != 'x' ) { | |
237 | printf( "msync did not flush correct data \n" ); | |
238 | my_err = -1; | |
239 | goto exit_child; | |
240 | } | |
241 | ||
242 | /* unmap our test page */ | |
243 | my_err = munmap( my_addr, (my_page_size * 2) ); | |
244 | if ( my_err == -1 ) { | |
245 | printf( "munmap call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
246 | my_err = -1; | |
247 | goto exit_child; | |
248 | } | |
249 | my_addr = NULL; | |
250 | ||
251 | /* map the file into memory again for mprotect test */ | |
252 | my_addr = (char *) mmap( NULL, (my_page_size * 2), (PROT_READ | PROT_WRITE), (MAP_FILE | MAP_SHARED), my_fd, 0 ); | |
253 | if ( my_addr == (char *) -1 ) { | |
254 | printf( "mmap call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
255 | my_err = -1; | |
256 | goto exit_child; | |
257 | } | |
258 | *my_addr = 'a'; | |
259 | ||
260 | ||
261 | ||
262 | /* test mprotect - change protection to only PROT_READ */ | |
263 | my_err = mprotect( my_addr, my_page_size, PROT_READ ); | |
264 | if ( my_err == -1 ) { | |
265 | printf( "mprotect call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
266 | my_err = -1; | |
267 | goto exit_child; | |
268 | } | |
269 | ||
6d2010ae A |
270 | my_sa.sa_sigaction = bus_handler; |
271 | my_sa.sa_flags = SA_SIGINFO | SA_RESETHAND; | |
272 | if ((my_err = sigaction(SIGBUS, &my_sa, NULL)) != 0) { | |
273 | printf("sigaction call failed with error %d - \"%s\" \n", errno, strerror( errno) ); | |
274 | my_err = -1; | |
275 | goto exit_child; | |
276 | } | |
277 | ||
278 | my_err = -1; /* default to error out if we do NOT trigger a SIGBUS */ | |
279 | ||
2d21ac55 | 280 | *my_addr = 'z'; /* should cause SIGBUS signal (we look for this at child termination within the parent) */ |
2d21ac55 | 281 | |
6d2010ae A |
282 | /* NOTREACHED */ |
283 | ||
284 | printf("Expected SIGBUS signal, got nothing!\n"); | |
285 | my_err = -1; | |
2d21ac55 A |
286 | exit_child: |
287 | exit( my_err ); | |
288 | } | |
289 | ||
2d21ac55 | 290 | /* parent process - |
6d2010ae | 291 | * we should get no error if the child has completed all tests successfully |
2d21ac55 A |
292 | */ |
293 | my_wait_pid = wait4( my_pid, &my_status, 0, NULL ); | |
294 | if ( my_wait_pid == -1 ) { | |
295 | printf( "wait4 failed with errno %d - %s \n", errno, strerror( errno ) ); | |
296 | goto test_failed_exit; | |
297 | } | |
298 | ||
299 | /* wait4 should return our child's pid when it exits */ | |
300 | if ( my_wait_pid != my_pid ) { | |
301 | printf( "wait4 did not return child pid - returned %d should be %d \n", my_wait_pid, my_pid ); | |
302 | goto test_failed_exit; | |
303 | } | |
304 | ||
39236c6e | 305 | /* If we did not exit cleanly, report it |
6d2010ae | 306 | */ |
39236c6e A |
307 | if ( !WIFEXITED( my_status ) || (WEXITSTATUS( my_status ) != 0)) { |
308 | printf( "wait4 returned child died of status - 0x%08X \n", my_status ); | |
6d2010ae A |
309 | goto test_failed_exit; |
310 | } | |
311 | ||
2d21ac55 A |
312 | /* make sure shared page got modified in child */ |
313 | if ( strcmp( my_test_page_p, "parent data child data" ) != 0 ) { | |
314 | printf( "minherit did not work correctly - shared page looks wrong \n" ); | |
315 | goto test_failed_exit; | |
316 | } | |
317 | my_err = 0; | |
318 | goto test_passed_exit; | |
319 | ||
320 | test_failed_exit: | |
321 | my_err = -1; | |
322 | ||
323 | test_passed_exit: | |
324 | if ( my_pathp != NULL ) { | |
325 | remove( my_pathp ); | |
b0d623f7 | 326 | vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX); |
2d21ac55 A |
327 | } |
328 | if ( my_test_page_p != NULL ) { | |
b0d623f7 | 329 | vm_deallocate(mach_task_self(), (vm_address_t)my_test_page_p, my_page_size); |
2d21ac55 A |
330 | } |
331 | return( my_err ); | |
332 | } | |
333 |