1/* 2 * This tests the Mac OS X Superpage API introduced in 10.7 3 * 4 * Note that most of these calls go through the mach_vm_allocate() interface, 5 * but the actually supported and documented interface is the mmap() one 6 * (see mmap(2)). 7 */ 8#include <stdio.h> 9#include <stdlib.h> 10#include <signal.h> 11#include <setjmp.h> 12#include <mach/mach.h> 13#include <mach/mach_vm.h> 14#include <time.h> 15#include <unistd.h> 16#include <fcntl.h> 17#include <sys/mman.h> 18 19#define SUPERPAGE_SIZE (2*1024*1024) 20#define SUPERPAGE_MASK (-SUPERPAGE_SIZE) 21 22#ifdef __LP64__ 23#define FIXED_ADDRESS1 (0x100000000ULL+500*1024*1024) /* at 4 GB + 500 MB virtual */ 24#define FIXED_ADDRESS2 (0x100000000ULL+502*1024*1024 + 4*1024) /* at 4 GB + 502 MB + 4 KB virtual */ 25#else 26#define FIXED_ADDRESS1 (500*1024*1024) /* at 500 MB virtual */ 27#define FIXED_ADDRESS2 (502*1024*1024 + 4*1024) /* at 502 MB + 4 KB virtual */ 28#endif 29 30char error[100]; 31 32jmp_buf resume; 33void test_signal_handler(int signo) 34{ 35 longjmp(resume, signo); 36} 37 38char *signame[32] = { 39 [SIGBUS] "SIGBUS", 40 [SIGSEGV] "SIGSEGV" 41}; 42 43typedef struct { 44 char *description; 45 boolean_t (*fn)(); 46} test_t; 47 48boolean_t 49check_kr(int kr, char *fn) { 50 if (kr) { 51 sprintf(error, "%s() returned %d", fn, kr); 52 return FALSE; 53 } 54 return TRUE; 55} 56 57boolean_t 58check_addr0(mach_vm_address_t addr, char *fn) { 59 if (!addr) { 60 sprintf(error, "%s() returned address 0", fn); 61 return FALSE; 62 } 63 return TRUE; 64} 65 66boolean_t 67check_addr(mach_vm_address_t addr1, mach_vm_address_t addr2, char *fn) { 68 if (addr1 != addr2) { 69 sprintf(error, "%s() returned address %llx instead of %llx", fn, addr1, addr2); 70 return FALSE; 71 } 72 return TRUE; 73} 74 75boolean_t 76check_align(mach_vm_address_t addr) { 77 if (addr & !SUPERPAGE_MASK) { 78 sprintf(error, "address not aligned properly: 0x%llx", addr); 79 return FALSE; 80 } 81 return TRUE; 82} 83 84boolean_t 85check_r(mach_vm_address_t addr, mach_vm_size_t size, int *res) { 86 volatile char *data = (char*)(uintptr_t)addr; 87 int i, sig, test; 88 89 if ((sig = setjmp(resume)) != 0) { 90 sprintf(error, "%s when reading", signame[sig]); 91 return FALSE; 92 } 93 test = 0; 94 for (i=0; i<size; i++) 95 test += (data)[i]; 96 97 if (res) 98 *res = test; 99 100 return TRUE; 101} 102 103/* check that no subpage of the superpage is readable */ 104boolean_t 105check_nr(mach_vm_address_t addr, mach_vm_size_t size, int *res) { 106 int i; 107 boolean_t ret; 108 for (i=0; i<size/PAGE_SIZE; i++) { 109 if ((ret = check_r(addr+i*PAGE_SIZE, PAGE_SIZE, res))) { 110 sprintf(error, "page still readable"); 111 return FALSE; 112 } 113 } 114 return TRUE; 115} 116 117boolean_t 118check_w(mach_vm_address_t addr, mach_vm_size_t size) { 119 char *data = (char*)(uintptr_t)addr; 120 int i, sig; 121 122 if ((sig = setjmp(resume)) != 0) { 123 sprintf(error, "%s when writing", signame[sig]); 124 return FALSE; 125 } 126 127 for (i=0; i<size; i++) 128 (data)[i] = i & 0xFF; 129 130 return TRUE; 131} 132 133boolean_t 134check_nw(mach_vm_address_t addr, mach_vm_size_t size) { 135 int i; 136 boolean_t ret; 137 138 for (i=0; i<size/PAGE_SIZE; i++) { 139 if ((ret = check_w(addr+i*PAGE_SIZE, PAGE_SIZE))) { 140 sprintf(error, "page still writable"); 141 return FALSE; 142 } 143 } 144 return TRUE; 145} 146 147boolean_t 148check_rw(mach_vm_address_t addr, mach_vm_size_t size) { 149 int ret; 150 int res; 151 if (!(ret = check_w(addr, size))) return ret; 152 if (!(ret = check_r(addr, size, &res))) return ret; 153 if ((size==SUPERPAGE_SIZE) && (res!=0xfff00000)) { 154 sprintf(error, "checksum error"); 155 return FALSE; 156 } 157 158 return TRUE; 159} 160 161mach_vm_address_t global_addr = 0; 162mach_vm_size_t global_size = 0; 163 164/* 165 * If we allocate a 2 MB superpage read-write without specifying an address, 166 * - the call should succeed 167 * - not return 0 168 * - return a 2 MB aligned address 169 * - the memory should be readable and writable 170 */ 171boolean_t 172test_allocate() { 173 int kr, ret; 174 175 global_addr = 0; 176 global_size = SUPERPAGE_SIZE; 177 178 kr = mach_vm_allocate(mach_task_self(), &global_addr, global_size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 179 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 180 if (!(ret = check_addr0(global_addr, "mach_vm_allocate"))) return ret; 181 if (!(ret = check_align(global_addr))) return ret; 182 if (!(ret = check_rw(global_addr, global_size))) return ret; 183 184 return TRUE; 185} 186 187/* 188 * If we deallocate a superpage, 189 * - the call should succeed 190 * - make the memory inaccessible 191 */ 192boolean_t 193test_deallocate() { 194 mach_vm_size_t size = SUPERPAGE_SIZE; 195 int kr, ret; 196 197 if (!global_addr) { 198 sprintf(error, "skipped deallocation"); 199 return FALSE; 200 } 201 kr = mach_vm_deallocate(mach_task_self(), global_addr, global_size); 202 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 203 if (!(ret = check_nr(global_addr, size, NULL))) return ret; 204 return TRUE; 205} 206 207/* 208 * If we allocate a superpage of any size read-write without specifying an address 209 * - the call should succeed 210 * - not return 0 211 * - the memory should be readable and writable 212 * If we deallocate it, 213 * - the call should succeed 214 * - make the memory inaccessible 215 */ 216boolean_t 217test_allocate_size_any() { 218 int kr; 219 int ret; 220 mach_vm_address_t addr = 0; 221 mach_vm_size_t size = 2*PAGE_SIZE; /* will be rounded up to some superpage size */ 222 223 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_ANY); 224 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 225 if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret; 226 if (!(ret = check_rw(addr, size))) return ret; 227 kr = mach_vm_deallocate(mach_task_self(), addr, size); 228 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 229 if (!(ret = check_nr(addr, size, NULL))) return ret; 230 return TRUE; 231} 232 233/* 234 * If we allocate a 2 MB superpage read-write at a 2 MB aligned address, 235 * - the call should succeed 236 * - return the address we wished for 237 * - the memory should be readable and writable 238 * If we deallocate it, 239 * - the call should succeed 240 * - make the memory inaccessible 241 */ 242boolean_t 243test_allocatefixed() { 244 int kr; 245 int ret; 246 mach_vm_address_t addr = FIXED_ADDRESS1; 247 mach_vm_size_t size = SUPERPAGE_SIZE; 248 249 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB); 250 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 251 if (!(ret = check_addr(addr, FIXED_ADDRESS1, "mach_vm_allocate"))) return ret; 252 if (!(ret = check_rw(addr, size))) return ret; 253 kr = mach_vm_deallocate(mach_task_self(), addr, size); 254 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 255 if (!(ret = check_nr(addr, size, NULL))) return ret; 256 return TRUE; 257} 258 259/* 260 * If we allocate a 2 MB superpage read-write at an unaligned address, 261 * - the call should fail 262 */ 263boolean_t 264test_allocateunalignedfixed() { 265 int kr; 266 int ret; 267 mach_vm_address_t addr = FIXED_ADDRESS2; 268 mach_vm_size_t size = SUPERPAGE_SIZE; 269 270 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB); 271 /* is supposed to fail */ 272 if ((ret = check_kr(kr, "mach_vm_allocate"))) { 273 sprintf(error, "mach_vm_allocate() should have failed"); 274 return FALSE; 275 } 276 return TRUE; 277} 278 279/* 280 * If we allocate an amount of memory not divisible by 2 MB as a 2 MB superpage 281 * - the call should fail 282 */ 283boolean_t 284test_allocateoddsize() { 285 int kr; 286 int ret; 287 mach_vm_address_t addr = FIXED_ADDRESS1; 288 mach_vm_size_t size = PAGE_SIZE; /* != 2 MB */ 289 290 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_SUPERPAGE_SIZE_2MB); 291 /* is supposed to fail */ 292 if ((ret = check_kr(kr, "mach_vm_allocate"))) { 293 sprintf(error, "mach_vm_allocate() should have failed"); 294 return FALSE; 295 } 296 return TRUE; 297} 298 299/* 300 * If we deallocate a sub-page of a superpage, 301 * - the call should succeed 302 * - make the complete memory inaccessible 303 */ 304boolean_t 305test_deallocatesubpage() { 306 int kr; 307 int ret; 308 mach_vm_address_t addr = 0; 309 mach_vm_size_t size = SUPERPAGE_SIZE; 310 311 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 312 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 313 kr = mach_vm_deallocate(mach_task_self(), addr + PAGE_SIZE, size); 314 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 315 if (!(ret = check_nr(addr, size, NULL))) return ret; 316 return TRUE; 317} 318 319/* 320 * If we try to allocate memory occupied by superpages as normal pages 321 * - the call should fail 322 */ 323boolean_t 324test_reallocate() { 325 mach_vm_address_t addr = 0, addr2; 326 mach_vm_size_t size = SUPERPAGE_SIZE; 327 int kr, ret; 328 int i; 329 330 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 331 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 332 333 /* attempt to allocate every sub-page of superpage */ 334 for (i=0; i<SUPERPAGE_SIZE/PAGE_SIZE; i++) { 335 addr2 = addr + i*PAGE_SIZE; 336 size = PAGE_SIZE; 337 kr = mach_vm_allocate(mach_task_self(), &addr2, size, 0); 338 if ((ret = check_kr(kr, "mach_vm_allocate"))) { 339 sprintf(error, "could allocate already allocated space, page %d", i); 340 mach_vm_deallocate(mach_task_self(), addr, size); 341 return FALSE; 342 } 343 } 344 kr = mach_vm_deallocate(mach_task_self(), addr, size); 345 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 346 return TRUE; 347} 348 349/* 350 * If we try to wire superpages 351 * - the call should succeed 352 * - the memory should remain readable and writable 353 */ 354boolean_t 355test_wire() { 356 int kr; 357 int ret; 358 mach_vm_address_t addr = 0; 359 mach_vm_size_t size = SUPERPAGE_SIZE; 360 361 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 362 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 363 364 kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_WRITE | VM_PROT_READ); 365 366 if (!geteuid()) /* may fail as user */ 367 if (!(ret = check_kr(kr, "mach_vm_wire"))) return ret; 368 369 if (!(ret = check_rw(addr, size))) return ret; 370 371 kr = mach_vm_deallocate(mach_task_self(), addr, size); 372 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 373 374 return TRUE; 375} 376 377/* 378 * If we try to wire superpages 379 * - the call should fail 380 * - the memory should remain readable and writable 381 * Currently, superpages are always wired. 382 */ 383boolean_t 384test_unwire() { 385 int kr; 386 int ret; 387 mach_vm_address_t addr = 0; 388 mach_vm_size_t size = SUPERPAGE_SIZE; 389 390 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 391 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 392 393 kr = mach_vm_wire(mach_host_self(), mach_task_self(), addr, size, VM_PROT_NONE); 394 if ((ret = check_kr(kr, "mach_vm_wire"))) { 395 sprintf(error, "could unwire"); 396 return FALSE; 397 } 398 399 if (!(ret = check_rw(addr, size))) return ret; 400 401 kr = mach_vm_deallocate(mach_task_self(), addr, size); 402 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 403 404 return TRUE; 405} 406 407/* 408 * If we try to write-protect superpages 409 * - the call should succeed 410 * - the memory should remain readable 411 * - the memory should not be writable 412 */ 413boolean_t 414test_readonly() { 415 int kr; 416 int ret; 417 mach_vm_address_t addr = 0; 418 mach_vm_size_t size = SUPERPAGE_SIZE; 419 420 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 421 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 422 423 mach_vm_protect(mach_task_self(), addr, size, 0, VM_PROT_READ); 424 if (!(ret = check_kr(kr, "mach_vm_protect"))) return ret; 425 426 if (!(ret = check_r(addr, size, NULL))) return ret; 427 if (!(ret = check_nw(addr, size))) return ret; 428 429 kr = mach_vm_deallocate(mach_task_self(), addr, size); 430 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 431 432 return TRUE; 433} 434 435/* 436 * If we try to write-protect a sub-page of a superpage 437 * - the call should succeed 438 * - the complete memory should remain readable 439 * - the complete memory should not be writable 440 */ 441boolean_t 442test_readonlysubpage() { 443 int kr; 444 int ret; 445 mach_vm_address_t addr = 0; 446 mach_vm_size_t size = SUPERPAGE_SIZE; 447 448 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 449 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 450 451 mach_vm_protect(mach_task_self(), addr+PAGE_SIZE, PAGE_SIZE, 0, VM_PROT_READ); 452 if (!(ret = check_kr(kr, "mach_vm_protect"))) return ret; 453 454 if (!(ret = check_r(addr, size, NULL))) return ret; 455 if (!(ret = check_nw(addr, size))) return ret; 456 457 kr = mach_vm_deallocate(mach_task_self(), addr, size); 458 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 459 460 return TRUE; 461} 462 463/* 464 * If we fork with active superpages 465 * - the parent should still be able to access the superpages 466 * - the child should not be able to access the superpages 467 */ 468boolean_t 469test_fork() { 470 mach_vm_address_t addr = 0; 471 mach_vm_size_t size = SUPERPAGE_SIZE; 472 int kr, ret; 473 pid_t pid; 474 475 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 476 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 477 478 fflush(stdout); 479 if ((pid=fork())) { /* parent */ 480 if (!(ret = check_rw(addr, size))) return ret; 481 waitpid(pid, &ret, 0); 482 if (!ret) { 483 sprintf(error, "child could access superpage"); 484 return ret; 485 } 486 } else { /* child */ 487 if (!(ret = check_nr(addr, size, NULL))) exit(ret); 488 exit(TRUE); 489 } 490 491 kr = mach_vm_deallocate(mach_task_self(), addr, size); 492 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 493 return TRUE; 494} 495 496/* 497 * Doing file I/O with superpages 498 * - should succeed 499 * - should behave the same as with base pages (i.e. no bad data) 500 */ 501#define FILENAME "/mach_kernel" 502boolean_t 503test_fileio() { 504 mach_vm_address_t addr1 = 0; 505 mach_vm_address_t addr2 = 0; 506 mach_vm_size_t size = SUPERPAGE_SIZE; 507 int kr, ret; 508 int fd; 509 unsigned int bytes; 510 511 /* allocate one superpage */ 512 kr = mach_vm_allocate(mach_task_self(), &addr1, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 513 if (!(ret = check_kr(kr, "mach_vm_allocate (1)"))) return ret; 514 515 /* allocate base pages (superpage-sized) */ 516 kr = mach_vm_allocate(mach_task_self(), &addr2, size, VM_FLAGS_ANYWHERE); 517 if (!(ret = check_kr(kr, "mach_vm_allocate (2)"))) return ret; 518 519 if ((fd = open(FILENAME, O_RDONLY))<0) { 520 sprintf(error, "couldn't open %s", FILENAME); 521 return FALSE; 522 } 523 fcntl(fd, F_NOCACHE, 1); 524 /* read kernel into superpage */ 525 if ((bytes = read(fd, (void*)(uintptr_t)addr1, SUPERPAGE_SIZE)) < SUPERPAGE_SIZE) { 526 sprintf(error, "short read (1)"); 527 return FALSE; 528 } 529 lseek(fd, 0, SEEK_SET); 530 /* read kernel into base pages */ 531 if ((bytes = read(fd, (void*)(uintptr_t)addr2, SUPERPAGE_SIZE)) < SUPERPAGE_SIZE) { 532 sprintf(error, "short read (2)"); 533 return FALSE; 534 } 535 close(fd); 536 537 /* compare */ 538 if (memcmp((void*)(uintptr_t)addr1, (void*)(uintptr_t)addr2, bytes)) { 539 sprintf(error, "read data corrupt"); 540 return FALSE; 541 } 542 543 kr = mach_vm_deallocate(mach_task_self(), addr1, size); 544 if (!(ret = check_kr(kr, "mach_vm_deallocate (1)"))) return ret; 545 kr = mach_vm_deallocate(mach_task_self(), addr2, size); 546 if (!(ret = check_kr(kr, "mach_vm_deallocate (2)"))) return ret; 547 return TRUE; 548} 549 550/* 551 * The mmap() interface should work just as well! 552 */ 553boolean_t 554test_mmap() { 555 int kr, ret; 556 uintptr_t addr = 0; 557 int size = SUPERPAGE_SIZE; 558 559 addr = (uintptr_t)mmap((void*)addr, size, PROT_READ, MAP_ANON | MAP_PRIVATE, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0); 560 if (addr == (uintptr_t)MAP_FAILED) { 561 sprintf(error, "mmap()"); 562 return FALSE; 563 } 564 if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret; 565 if (!(ret = check_align(addr))) return ret; 566 if (!(ret = check_r(addr, SUPERPAGE_SIZE, NULL))) return ret; 567 if (!(ret = check_nw(addr, SUPERPAGE_SIZE))) return ret; 568 kr = munmap((void*)addr, size); 569 if (!(ret = check_kr(kr, "munmap"))) return ret; 570 if (!(ret = check_nr(addr, size, NULL))) return ret; 571 572 return TRUE; 573} 574 575/* 576 * Tests one allocation/deallocaton cycle; used in a loop this tests for leaks 577 */ 578boolean_t 579test_alloc_dealloc() { 580 mach_vm_address_t addr = 0; 581 mach_vm_size_t size = SUPERPAGE_SIZE; 582 int kr, ret; 583 584 kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | VM_FLAGS_SUPERPAGE_SIZE_2MB); 585 if (!(ret = check_kr(kr, "mach_vm_allocate"))) return ret; 586 if (!(ret = check_addr0(addr, "mach_vm_allocate"))) return ret; 587 if (!(ret = check_align(addr))) return ret; 588 if (!(ret = check_rw(addr, size))) return ret; 589 kr = mach_vm_deallocate(mach_task_self(), addr, size); 590 if (!(ret = check_kr(kr, "mach_vm_deallocate"))) return ret; 591 return TRUE; 592} 593 594test_t test[] = { 595 { "allocate one page anywhere", test_allocate }, 596 { "deallocate a page", test_deallocate }, 597 { "allocate a SIZE_ANY page anywhere", test_allocate_size_any }, 598 { "allocate one page at a fixed address", test_allocatefixed }, 599 { "allocate one page at an unaligned fixed address", test_allocateunalignedfixed }, 600 { "deallocate sub-page", test_deallocatesubpage }, 601 { "allocate already allocated subpage", test_reallocate }, 602 { "wire a page", test_wire }, 603 { "unwire a page", test_unwire }, 604 { "make page readonly", test_readonly }, 605 { "make sub-page readonly", test_readonlysubpage }, 606 { "file I/O", test_fileio }, 607 { "mmap()", test_mmap }, 608 { "fork", test_fork }, 609}; 610#define TESTS ((int)(sizeof(test)/sizeof(*test))) 611 612boolean_t 613testit(int i) { 614 boolean_t ret; 615 616 error[0] = 0; 617 printf ("Test #%d \"%s\"...", i+1, test[i].description); 618 ret = test[i].fn(); 619 if (ret) 620 printf ("OK\n"); 621 else { 622 printf ("FAILED!"); 623 if (error[0]) 624 printf (" (%s)\n", error); 625 else 626 printf ("\n"); 627 } 628} 629 630int main(int argc, char **argv) { 631 int i; 632 uint64_t time1, time2; 633 634 int mode = 0; 635 if (argc>1) { 636 if (!strcmp(argv[1], "-h")) { 637 printf("Usage: %s <mode>\n", argv[0]); 638 printf("\tmode = 0: test all cases\n"); 639 printf("\tmode = -1: allocate/deallocate until failure\n"); 640 printf("\tmode > 0: run test <tmode>\n"); 641 exit(0); 642 } 643 mode=atoi(argv[1]); 644 } 645 646 /* install SIGBUS handler */ 647 struct sigaction my_sigaction; 648 my_sigaction.sa_handler = test_signal_handler; 649 my_sigaction.sa_flags = SA_RESTART; 650 my_sigaction.sa_mask = 0; 651 sigaction( SIGBUS, &my_sigaction, NULL ); 652 sigaction( SIGSEGV, &my_sigaction, NULL ); 653 654 if (mode>0) /* one specific test */ 655 testit(mode-1); 656 657 if (mode==0) { /* test all cases */ 658 printf("Running %d tests:\n", TESTS); 659 for (i=0; i<TESTS; i++) { 660 testit(i); 661 } 662 } 663 if (mode==-1) { /* alloc/dealloc */ 664 boolean_t ret; 665 do { 666 ret = test_alloc_dealloc(TRUE); 667 printf("."); 668 fflush(stdout); 669 } while (ret); 670 if (error[0]) 671 printf (" (%s)\n", error); 672 } 673 return 0; 674} 675