1 #include <errno.h> 2 #include <netinet/in.h> 3 #include <signal.h> 4 #include <stdarg.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/socket.h> 9 10 #include <OS.h> 11 12 13 enum run_mode { 14 RUN_IGNORE_SIGNAL, 15 RUN_HANDLE_SIGNAL, 16 RUN_HANDLE_SIGNAL_RESTART 17 }; 18 19 20 class Test { 21 public: 22 Test(const char* name) 23 : fName(name) 24 { 25 } 26 27 virtual ~Test() 28 { 29 } 30 31 bool Run(run_mode mode) 32 { 33 fRunMode = mode; 34 fSignalHandlerCalled = false; 35 36 status_t error = Prepare(); 37 if (error != B_OK) 38 return Error("Failed to prepare test: %s", strerror(error)); 39 40 thread_id thread = spawn_thread(_ThreadEntry, fName, B_NORMAL_PRIORITY, 41 this); 42 if (thread < 0) 43 return Error("Failed to spawn thread: %s\n", strerror(thread)); 44 45 resume_thread(thread); 46 47 // ... 48 // * interrupt without restart 49 // * interrupt with restart 50 51 snooze(100000); 52 kill(thread, SIGINT); 53 54 PrepareFinish(); 55 56 status_t result; 57 wait_for_thread(thread, &result); 58 59 if (result != (Interrupted() ? B_INTERRUPTED : B_OK)) { 60 return Error("Unexpected syscall return value: %s\n", 61 strerror(result)); 62 } 63 64 if ((RunMode() == RUN_IGNORE_SIGNAL) == fSignalHandlerCalled) { 65 if (RunMode() == RUN_IGNORE_SIGNAL) 66 return Error("Handler was called but shouldn't have been!"); 67 else 68 return Error("Handler was not called!"); 69 } 70 71 return Finish(Interrupted()); 72 } 73 74 void Run() 75 { 76 printf("%s\n", fName); 77 78 struct { 79 const char* name; 80 run_mode mode; 81 } tests[] = { 82 { "ignore signal", RUN_IGNORE_SIGNAL }, 83 { "handle signal no restart", RUN_HANDLE_SIGNAL }, 84 { "handle signal restart", RUN_HANDLE_SIGNAL_RESTART }, 85 {} 86 }; 87 88 for (int i = 0; tests[i].name != NULL; i++) { 89 printf(" %-30s: ", tests[i].name); 90 fflush(stdout); 91 ClearError(); 92 if (Run(tests[i].mode)) 93 printf("ok\n"); 94 else 95 printf("failed (%s)\n", fError); 96 97 Cleanup(); 98 } 99 } 100 101 run_mode RunMode() const { return fRunMode; } 102 bool Interrupted() const { return RunMode() == RUN_HANDLE_SIGNAL; } 103 bigtime_t TimeWaited() const { return fTimeWaited; } 104 105 protected: 106 virtual status_t Prepare() 107 { 108 return B_OK; 109 } 110 111 virtual status_t DoSyscall() = 0; 112 113 virtual void HandleSignal() 114 { 115 } 116 117 virtual void PrepareFinish() 118 { 119 } 120 121 virtual bool Finish(bool interrupted) 122 { 123 return true; 124 } 125 126 virtual void Cleanup() 127 { 128 } 129 130 bool Error(const char* format,...) 131 { 132 va_list args; 133 va_start(args, format); 134 vsnprintf(fError, sizeof(fError), format, args); 135 va_end(args); 136 137 return false; 138 } 139 140 bool Check(bool condition, const char* format,...) 141 { 142 if (condition) 143 return true; 144 145 va_list args; 146 va_start(args, format); 147 vsnprintf(fError, sizeof(fError), format, args); 148 va_end(args); 149 150 return false; 151 } 152 153 void ClearError() 154 { 155 fError[0] = '\0'; 156 } 157 158 private: 159 static status_t _ThreadEntry(void* data) 160 { 161 return ((Test*)data)->_TestThread(); 162 } 163 164 static void _SignalHandler(int signal, char* userData) 165 { 166 Test* self = (Test*)userData; 167 168 self->fSignalHandlerCalled = true; 169 self->HandleSignal(); 170 } 171 172 status_t _TestThread() 173 { 174 // install handler 175 struct sigaction action; 176 if (RunMode() == RUN_IGNORE_SIGNAL) 177 action.sa_handler = SIG_IGN; 178 else 179 action.sa_handler = (void (*)(int))_SignalHandler; 180 181 action.sa_flags = RunMode() == RUN_HANDLE_SIGNAL_RESTART 182 ? SA_RESTART : 0; 183 184 sigemptyset(&action.sa_mask); 185 action.sa_userdata = this; 186 187 sigaction(SIGINT, &action, NULL); 188 189 bigtime_t startTime = system_time(); 190 status_t status = DoSyscall(); 191 fTimeWaited = system_time() - startTime; 192 193 return status; 194 } 195 196 private: 197 const char* fName; 198 run_mode fRunMode; 199 bool fSignalHandlerCalled; 200 bigtime_t fTimeWaited; 201 char fError[1024]; 202 }; 203 204 205 class SnoozeTest : public Test { 206 public: 207 SnoozeTest() 208 : Test("snooze") 209 { 210 } 211 212 virtual status_t DoSyscall() 213 { 214 return snooze(1000000); 215 } 216 217 virtual bool Finish(bool interrupted) 218 { 219 if (interrupted) 220 return Check(TimeWaited() < 200000, "waited too long"); 221 222 return Check(TimeWaited() > 900000 && TimeWaited() < 1100000, 223 "waited %lld us instead of 1000000 us", TimeWaited()); 224 } 225 }; 226 227 228 class ReadTest : public Test { 229 public: 230 ReadTest() 231 : Test("read") 232 { 233 } 234 235 virtual status_t Prepare() 236 { 237 fBytesRead = -1; 238 fFDs = (int[2]){-1, -1}; 239 240 if (pipe(fFDs) != 0) 241 return errno; 242 243 return B_OK; 244 } 245 246 virtual status_t DoSyscall() 247 { 248 char buffer[256]; 249 fBytesRead = read(fFDs[0], buffer, sizeof(buffer)); 250 251 return fBytesRead < 0 ? errno : B_OK; 252 } 253 254 virtual void PrepareFinish() 255 { 256 write(fFDs[1], "Ingo", 4); 257 } 258 259 virtual bool Finish(bool interrupted) 260 { 261 if (interrupted) 262 return Check(fBytesRead < 0, "unexpected read"); 263 264 return Check(fBytesRead == 4, "should have read 4 bytes, read only %ld " 265 "bytes", fBytesRead); 266 } 267 268 virtual void Cleanup() 269 { 270 close(fFDs[0]); 271 close(fFDs[1]); 272 } 273 274 private: 275 bigtime_t fTimeWaited; 276 ssize_t fBytesRead; 277 int fFDs[2]; 278 }; 279 280 281 class WriteTest : public Test { 282 public: 283 WriteTest() 284 : Test("write") 285 { 286 } 287 288 virtual status_t Prepare() 289 { 290 fBytesWritten = -1; 291 fFDs = (int[2]){-1, -1}; 292 293 if (pipe(fFDs) != 0) 294 return errno; 295 296 // fill pipe 297 fcntl(fFDs[1], F_SETFL, O_NONBLOCK); 298 while (write(fFDs[1], "a", 1) == 1); 299 300 return B_OK; 301 } 302 303 virtual status_t DoSyscall() 304 { 305 // blocking wait 306 fcntl(fFDs[1], F_SETFL, 0); 307 fBytesWritten = write(fFDs[1], "Ingo", 4); 308 309 return fBytesWritten < 0 ? errno : B_OK; 310 } 311 312 virtual void PrepareFinish() 313 { 314 char buffer[256]; 315 read(fFDs[0], buffer, sizeof(buffer)); 316 } 317 318 virtual bool Finish(bool interrupted) 319 { 320 if (interrupted) 321 return Check(fBytesWritten < 0, "unexpected write"); 322 323 return Check(fBytesWritten == 4, "should have written 4 bytes, wrote only %ld " 324 "bytes", fBytesWritten); 325 } 326 327 virtual void Cleanup() 328 { 329 close(fFDs[0]); 330 close(fFDs[1]); 331 } 332 333 private: 334 ssize_t fBytesWritten; 335 int fFDs[2]; 336 }; 337 338 339 class AcquireSwitchSemTest : public Test { 340 public: 341 AcquireSwitchSemTest(bool useSwitch) 342 : Test(useSwitch ? "switch_sem" : "acquire_sem"), 343 fSwitch(useSwitch) 344 { 345 } 346 347 virtual status_t Prepare() 348 { 349 fSemaphore = create_sem(0, "test sem"); 350 351 return (fSemaphore >= 0 ? B_OK : fSemaphore); 352 } 353 354 virtual status_t DoSyscall() 355 { 356 if (fSwitch) 357 return switch_sem(-1, fSemaphore); 358 359 return acquire_sem(fSemaphore); 360 } 361 362 virtual void PrepareFinish() 363 { 364 release_sem(fSemaphore); 365 } 366 367 /* 368 virtual bool Finish(bool interrupted) 369 { 370 // int32 semCount = -1; 371 // get_sem_count(fSemaphore, &semCount); 372 373 if (interrupted) 374 return true; 375 376 return Check(fBytesWritten == 4, "should have written 4 bytes, wrote only %ld " 377 "bytes", fBytesWritten); 378 } 379 */ 380 381 virtual void Cleanup() 382 { 383 delete_sem(fSemaphore); 384 } 385 386 protected: 387 sem_id fSemaphore; 388 bool fSwitch; 389 }; 390 391 392 class AcquireSwitchSemEtcTest : public Test { 393 public: 394 AcquireSwitchSemEtcTest(bool useSwitch) 395 : Test(useSwitch ? "switch_sem_etc" : "acquire_sem_etc"), 396 fSwitch(useSwitch) 397 { 398 } 399 400 virtual status_t Prepare() 401 { 402 fSemaphore = create_sem(0, "test sem"); 403 404 return fSemaphore >= 0 ? B_OK : fSemaphore; 405 } 406 407 virtual status_t DoSyscall() 408 { 409 status_t status; 410 if (fSwitch) { 411 status = switch_sem_etc(-1, fSemaphore, 1, B_RELATIVE_TIMEOUT, 412 1000000); 413 } else { 414 status = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT, 415 1000000); 416 } 417 418 if (!Interrupted() && status == B_TIMED_OUT) 419 return B_OK; 420 421 return status; 422 } 423 424 virtual bool Finish(bool interrupted) 425 { 426 if (interrupted) 427 return Check(TimeWaited() < 200000, "waited too long"); 428 429 return Check(TimeWaited() > 900000 && TimeWaited() < 1100000, 430 "waited %lld us instead of 1000000 us", TimeWaited()); 431 } 432 433 virtual void Cleanup() 434 { 435 delete_sem(fSemaphore); 436 } 437 438 protected: 439 sem_id fSemaphore; 440 bool fSwitch; 441 }; 442 443 444 class AcceptTest : public Test { 445 public: 446 AcceptTest() 447 : Test("accept") 448 { 449 } 450 451 virtual status_t Prepare() 452 { 453 fAcceptedSocket = -1; 454 455 fServerSocket = socket(AF_INET, SOCK_STREAM, 0); 456 if (fServerSocket < 0) { 457 fprintf(stderr, "Could not open server socket: %s\n", 458 strerror(errno)); 459 return errno; 460 } 461 462 int reuse = 1; 463 if (setsockopt(fServerSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, 464 sizeof(int)) == -1) { 465 fprintf(stderr, "Could not make server socket reusable: %s\n", 466 strerror(errno)); 467 return errno; 468 } 469 470 memset(&fServerAddress, 0, sizeof(sockaddr_in)); 471 fServerAddress.sin_family = AF_INET; 472 fServerAddress.sin_addr.s_addr = INADDR_LOOPBACK; 473 474 if (bind(fServerSocket, (struct sockaddr *)&fServerAddress, 475 sizeof(struct sockaddr)) == -1) { 476 fprintf(stderr, "Could not bind server socket: %s\n", 477 strerror(errno)); 478 return errno; 479 } 480 481 socklen_t length = sizeof(sockaddr_in); 482 getsockname(fServerSocket, (sockaddr*)&fServerAddress, 483 &length); 484 485 if (listen(fServerSocket, 10) == -1) { 486 fprintf(stderr, "Could not listen on server socket: %s\n", 487 strerror(errno)); 488 return errno; 489 } 490 491 return B_OK; 492 } 493 494 virtual status_t DoSyscall() 495 { 496 sockaddr_in clientAddress; 497 socklen_t length = sizeof(struct sockaddr_in); 498 499 fAcceptedSocket = accept(fServerSocket, 500 (struct sockaddr *)&clientAddress, &length); 501 if (fAcceptedSocket == -1) 502 return errno; 503 504 return B_OK; 505 } 506 507 virtual void PrepareFinish() 508 { 509 if (Interrupted()) 510 return; 511 512 int clientSocket = socket(AF_INET, SOCK_STREAM, 0); 513 if (clientSocket == -1) { 514 fprintf(stderr, "Could not open client socket: %s\n", 515 strerror(errno)); 516 return; 517 } 518 519 if (connect(clientSocket, (struct sockaddr *)&fServerAddress, 520 sizeof(struct sockaddr)) == -1) { 521 fprintf(stderr, "Could not connect to server socket: %s\n", 522 strerror(errno)); 523 } 524 525 close(clientSocket); 526 } 527 528 virtual bool Finish(bool interrupted) 529 { 530 if (interrupted) 531 return Check(fAcceptedSocket < 0, "got socket"); 532 533 return Check(fAcceptedSocket >= 0, "got no socket"); 534 } 535 536 virtual void Cleanup() 537 { 538 close(fAcceptedSocket); 539 close(fServerSocket); 540 } 541 542 protected: 543 int fServerSocket; 544 sockaddr_in fServerAddress; 545 int fAcceptedSocket; 546 }; 547 548 549 class ReceiveTest : public Test { 550 public: 551 ReceiveTest() 552 : Test("recv") 553 { 554 } 555 556 virtual status_t Prepare() 557 { 558 fBytesRead = -1; 559 fAcceptedSocket = -1; 560 fClientSocket = -1; 561 562 fServerSocket = socket(AF_INET, SOCK_STREAM, 0); 563 if (fServerSocket < 0) { 564 fprintf(stderr, "Could not open server socket: %s\n", 565 strerror(errno)); 566 return errno; 567 } 568 569 int reuse = 1; 570 if (setsockopt(fServerSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, 571 sizeof(int)) == -1) { 572 fprintf(stderr, "Could not make server socket reusable: %s\n", 573 strerror(errno)); 574 return errno; 575 } 576 577 memset(&fServerAddress, 0, sizeof(sockaddr_in)); 578 fServerAddress.sin_family = AF_INET; 579 fServerAddress.sin_addr.s_addr = INADDR_LOOPBACK; 580 581 if (bind(fServerSocket, (struct sockaddr *)&fServerAddress, 582 sizeof(struct sockaddr)) == -1) { 583 fprintf(stderr, "Could not bind server socket: %s\n", 584 strerror(errno)); 585 return errno; 586 } 587 588 socklen_t length = sizeof(sockaddr_in); 589 getsockname(fServerSocket, (sockaddr*)&fServerAddress, 590 &length); 591 592 if (listen(fServerSocket, 10) == -1) { 593 fprintf(stderr, "Could not listen on server socket: %s\n", 594 strerror(errno)); 595 return errno; 596 } 597 598 fClientSocket = socket(AF_INET, SOCK_STREAM, 0); 599 if (fClientSocket == -1) { 600 fprintf(stderr, "Could not open client socket: %s\n", 601 strerror(errno)); 602 return errno; 603 } 604 605 fcntl(fClientSocket, F_SETFL, O_NONBLOCK); 606 607 if (connect(fClientSocket, (struct sockaddr *)&fServerAddress, 608 sizeof(struct sockaddr)) == -1) { 609 if (errno != EINPROGRESS) { 610 fprintf(stderr, "Could not connect to server socket: %s\n", 611 strerror(errno)); 612 return errno; 613 } 614 } 615 616 sockaddr_in clientAddress; 617 length = sizeof(struct sockaddr_in); 618 619 fAcceptedSocket = accept(fServerSocket, 620 (struct sockaddr *)&clientAddress, &length); 621 if (fAcceptedSocket == -1) 622 return errno; 623 624 fcntl(fClientSocket, F_SETFL, 0); 625 626 snooze(100000); 627 628 return B_OK; 629 } 630 631 virtual status_t DoSyscall() 632 { 633 char buffer[256]; 634 fBytesRead = recv(fAcceptedSocket, buffer, sizeof(buffer), 0); 635 636 return fBytesRead < 0 ? errno : B_OK; 637 } 638 639 virtual void PrepareFinish() 640 { 641 write(fClientSocket, "Axel", 4); 642 } 643 644 virtual bool Finish(bool interrupted) 645 { 646 if (interrupted) 647 return Check(fBytesRead < 0, "unexpected read"); 648 649 return Check(fBytesRead == 4, "should have read 4 bytes, read only %ld " 650 "bytes", fBytesRead); 651 } 652 653 virtual void Cleanup() 654 { 655 close(fAcceptedSocket); 656 close(fServerSocket); 657 close(fClientSocket); 658 } 659 660 protected: 661 int fServerSocket; 662 sockaddr_in fServerAddress; 663 int fAcceptedSocket; 664 int fClientSocket; 665 ssize_t fBytesRead; 666 }; 667 668 669 int 670 main() 671 { 672 Test* tests[] = { 673 new SnoozeTest, 674 new ReadTest, 675 new WriteTest, 676 new AcquireSwitchSemTest(false), 677 new AcquireSwitchSemTest(true), 678 new AcquireSwitchSemEtcTest(false), 679 new AcquireSwitchSemEtcTest(true), 680 new AcceptTest, 681 new ReceiveTest, 682 NULL 683 }; 684 685 for (int i = 0; tests[i] != NULL; i++) 686 tests[i]->Run(); 687 688 return 0; 689 } 690