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" 11#include <mach/mach.h> 12 13extern char g_target_path[ PATH_MAX ]; 14 15/* 16 * static to localize to this compilation unit; volatile to avoid register 17 * optimization which would prevent modification by a signal handler. 18 */ 19static volatile int my_err; 20 21void 22bus_handler(int sig, siginfo_t *si, void *mcontext) 23{ 24 /* Reset global error value when we see a SIGBUS */ 25 if (sig == SIGBUS) { 26 _exit(0); 27 } 28} 29 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 */ 35int memory_tests( void * the_argp ) 36{ 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; 45 kern_return_t my_kr; 46 struct sigaction my_sa; 47 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 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( ); 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 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 */ 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 ) ); 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 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 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 ) { 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) ); 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 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 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 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 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 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 280 *my_addr = 'z'; /* should cause SIGBUS signal (we look for this at child termination within the parent) */ 281 282 /* NOTREACHED */ 283 284 printf("Expected SIGBUS signal, got nothing!\n"); 285 my_err = -1; 286exit_child: 287 exit( my_err ); 288 } 289 290 /* parent process - 291 * we should get no error if the child has completed all tests successfully 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 305 /* If we did not exit cleanly, report it 306 */ 307 if ( !WIFEXITED( my_status ) || (WEXITSTATUS( my_status ) != 0)) { 308 printf( "wait4 returned child died of status - 0x%08X \n", my_status ); 309 goto test_failed_exit; 310 } 311 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 320test_failed_exit: 321 my_err = -1; 322 323test_passed_exit: 324 if ( my_pathp != NULL ) { 325 remove( my_pathp ); 326 vm_deallocate(mach_task_self(), (vm_address_t)my_pathp, PATH_MAX); 327 } 328 if ( my_test_page_p != NULL ) { 329 vm_deallocate(mach_task_self(), (vm_address_t)my_test_page_p, my_page_size); 330 } 331 return( my_err ); 332} 333 334