Changeset 5004 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Sep 24, 2007 1:57:39 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Serial/DrvHostSerial.cpp
r4993 r5004 40 40 41 41 #ifdef RT_OS_LINUX 42 # include <errno.h> 42 43 # include <termios.h> 43 44 # include <sys/types.h> … … 72 73 /** Our char interface. */ 73 74 PDMICHAR IChar; 74 /** Flag to notify the receive thread it should terminate. */ 75 volatile bool fShutdown; 76 /** Receive thread ID. */ 77 RTTHREAD ReceiveThread; 78 /** Send thread ID. */ 79 RTTHREAD SendThread; 75 /** Receive thread. */ 76 PPDMTHREAD pReceiveThread; 77 /** Send thread. */ 78 PPDMTHREAD pSendThread; 80 79 /** Send event semephore */ 81 80 RTSEMEVENT SendSem; 82 81 83 #ifdef RT_OS_LINUX84 /** The receive thread wakeup pipe. */85 RTFILE WakeupPipeR;86 RTFILE WakeupPipeW;87 #endif88 89 82 /** the device path */ 90 83 char *pszDevicePath; 84 85 #ifdef RT_OS_LINUX 91 86 /** the device handle */ 92 87 RTFILE DeviceFile; 88 /** The read end of the control pipe */ 89 RTFILE WakeupPipeR; 90 /** The write end of the control pipe */ 91 RTFILE WakeupPipeW; 92 #elif RT_OS_WINDOWS 93 /** the device handle */ 94 HANDLE hDeviceFile; 95 /** The event semaphore for waking up the receive thread */ 96 HANDLE hHaltEventSem; 97 /** The event semaphore for overlapped receiving */ 98 HANDLE hEventReceive; 99 /** The event semaphore for overlapped sending */ 100 HANDLE hEventSend; 101 #endif 93 102 94 103 /** Internal send FIFO queue */ … … 106 115 #define PDMICHAR_2_DRVHOSTSERIAL(pInterface) ( (PDRVHOSTSERIAL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTSERIAL, IChar)) ) 107 116 108 #ifdef RT_OS_LINUX 109 /** String written to the wakeup pipe. */ 110 #define WAKE_UP_STRING "WakeUp!" 111 /** Length of the string written. */ 112 #define WAKE_UP_STRING_LEN ( sizeof (WAKE_UP_STRING) - 1 ) 113 #endif 117 114 118 /* -=-=-=-=- IBase -=-=-=-=- */ 115 119 … … 375 379 comSetup->EvtChar = 0; 376 380 377 SetCommState( (HANDLE)pData->DeviceFile, comSetup);381 SetCommState(pData->hDeviceFile, comSetup); 378 382 RTMemFree(comSetup); 379 383 #endif /* RT_OS_WINDOWS */ … … 391 395 * @param pvUser User argument. 392 396 */ 393 static DECLCALLBACK(int) drvHostSerialSendLoop(RTTHREAD ThreadSelf, void *pvUser) 394 { 395 PDRVHOSTSERIAL pData = (PDRVHOSTSERIAL)pvUser; 396 397 while (!pData->fShutdown) 397 static DECLCALLBACK(int) drvHostSerialSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 398 { 399 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 400 401 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 402 return VINF_SUCCESS; 403 404 #ifdef RT_OS_WINDOWS 405 HANDLE haWait[2]; 406 haWait[0] = pData->hEventSend; 407 haWait[1] = pData->hHaltEventSem; 408 #endif 409 410 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 398 411 { 399 412 int rc = RTSemEventWait(pData->SendSem, RT_INDEFINITE_WAIT); … … 404 417 * Write the character to the host device. 405 418 */ 406 while ( !pData->fShutdown407 && 419 while ( pThread->enmState == PDMTHREADSTATE_RUNNING 420 && pData->iSendQueueTail != pData->iSendQueueHead) 408 421 { 409 422 unsigned cbProcessed = 1; 410 423 424 #if defined(RT_OS_LINUX) 425 411 426 rc = RTFileWrite(pData->DeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed, NULL); 427 428 #elif defined(RT_OS_WINDOWS) 429 430 DWORD cbBytesWritten; 431 OVERLAPPED overlapped; 432 memset(&overlapped, 0, sizeof(overlapped)); 433 overlapped.hEvent = pData->hEventSend; 434 435 if (!WriteFile(pData->hDeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed, &cbBytesWritten, &overlapped)) 436 { 437 DWORD dwRet = GetLastError(); 438 if (dwRet == ERROR_IO_PENDING) 439 { 440 /* 441 * write blocked, wait ... 442 */ 443 dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE); 444 if (dwRet != WAIT_OBJECT_0) 445 break; 446 } 447 else 448 rc = RTErrConvertFromWin32(dwRet); 449 } 450 451 #endif 452 412 453 if (VBOX_SUCCESS(rc)) 413 454 { … … 418 459 else if (VBOX_FAILURE(rc)) 419 460 { 420 Log Flow(("Write failed with %Vrc; skipping\n", rc));421 break;461 LogRel(("HostSerial#%d: Serial Write failed with %Vrc; terminating send thread\n", pDrvIns->iInstance, rc)); 462 return VINF_SUCCESS; 422 463 } 423 464 } … … 427 468 } 428 469 470 /** 471 * Unblock the send thread so it can respond to a state change. 472 * 473 * @returns a VBox status code. 474 * @param pDrvIns The driver instance. 475 * @param pThread The send thread. 476 */ 477 static DECLCALLBACK(int) drvHostSerialWakeupSendThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 478 { 479 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 480 int rc; 481 482 rc = RTSemEventSignal(pData->SendSem); 483 if (RT_FAILURE(rc)) 484 return rc; 485 486 #ifdef RT_OS_WINDOWS 487 if (!SetEvent(pData->hHaltEventSem)) 488 return RTErrConvertFromWin32(GetLastError()); 489 #endif 490 491 return VINF_SUCCESS; 492 } 429 493 430 494 /* -=-=-=-=- receive thread -=-=-=-=- */ … … 440 504 * @param pvUser User argument. 441 505 */ 442 static DECLCALLBACK(int) drvHostSerialReceive Loop(RTTHREAD ThreadSelf, void *pvUser)443 { 444 PDRVHOSTSERIAL pData = (PDRVHOSTSERIAL)pvUser;506 static DECLCALLBACK(int) drvHostSerialReceiveThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 507 { 508 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 445 509 uint8_t abBuffer[256]; 446 510 uint8_t *pbBuffer = NULL; … … 448 512 int rc = VINF_SUCCESS; 449 513 450 while (!pData->fShutdown) 514 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 515 return VINF_SUCCESS; 516 517 #ifdef RT_OS_WINDOWS 518 HANDLE haWait[2]; 519 haWait[0] = pData->hEventReceive; 520 haWait[1] = pData->hHaltEventSem; 521 #endif 522 523 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 451 524 { 452 525 if (!cbRemaining) 453 526 { 454 527 /* Get a block of data from the host serial device. */ 455 size_t cbRead; 456 457 #ifdef RT_OS_LINUX 458 s truct pollfd pfd[2];459 460 pfd[0].fd= pData->DeviceFile;461 pfd[0].events= POLLIN;462 pfd[1].fd = pData->WakeupPipeR;463 pfd[1].events = POLLIN | POLLERR | POLLHUP;464 465 rc = poll(&pfd[0], 2, -1);466 528 529 #if defined(RT_OS_LINUX) 530 531 size_t cbRead; 532 struct pollfd aFDs[2]; 533 aFDs[0].fd = pData->DeviceFile; 534 aFDs[0].events = POLLIN; 535 aFDs[0].revents = 0; 536 aFDs[1].fd = pData->WakeupPipeR; 537 aFDs[1].events = POLLIN | POLLERR | POLLHUP; 538 aFDs[1].revents = 0; 539 rc = poll(aFDs, ELEMENTS(aFDs), -1); 467 540 if (rc < 0) 541 { 542 /* poll failed for whatever reason */ 468 543 break; 469 470 if (rc > 0) 471 { 472 if (pfd[1].revents & POLLIN) 544 } 545 /* this might have changed in the meantime */ 546 if (pThread->enmState != PDMTHREADSTATE_RUNNING) 547 break; 548 if (rc > 0 && aFDs[1].revents) 549 { 550 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL)) 551 break; 552 /* notification to terminate -- drain the pipe */ 553 char ch; 554 size_t cbRead; 555 RTFileRead(pData->WakeupPipeR, &ch, 1, &cbRead); 556 continue; 557 } 558 rc = RTFileRead(pData->DeviceFile, abBuffer, sizeof(abBuffer), &cbRead); 559 if (VBOX_FAILURE(rc)) 560 { 561 LogRel(("HostSerial#%d: Read failed with %Vrc, terminating the worker thread.\n", pDrvIns->iInstance, rc)); 562 break; 563 } 564 cbRemaining = cbRead; 565 566 #elif defined(RT_OS_WINDOWS) 567 568 DWORD dwEventMask = 0; 569 DWORD dwNumberOfBytesTransferred; 570 OVERLAPPED overlapped; 571 572 memset(&overlapped, 0, sizeof(overlapped)); 573 overlapped.hEvent = pData->hEventReceive; 574 575 if (!WaitCommEvent(pData->hDeviceFile, &dwEventMask, &overlapped)) 576 { 577 DWORD dwRet = GetLastError(); 578 if (dwRet == ERROR_IO_PENDING) 473 579 { 474 /* Empty the pipe. */ 475 char szBuf[WAKE_UP_STRING_LEN]; 476 rc = RTFileRead (pData->WakeupPipeR, szBuf, sizeof (szBuf), NULL); 477 AssertRC (rc); 580 dwRet = WaitForMultipleObjects(2, haWait, FALSE, INFINITE); 581 if (dwRet != WAIT_OBJECT_0) 582 { 583 /* notification to terminate */ 584 break; 585 } 586 } 587 else 588 { 589 LogRel(("HostSerial#%d: Wait failed with error %Vrc; terminating the worker thread.\n", pDrvIns->iInstance, RTErrConvertFromWin32(dwRet))); 478 590 break; 479 591 } 480 592 } 481 #elif defined(RT_OS_WINDOWS) 482 BOOL retval; 483 DWORD dwEventMask = EV_RXCHAR; 484 485 retval = WaitCommEvent((HANDLE)pData->DeviceFile, &dwEventMask, NULL); 486 487 if (!retval) 488 { 489 LogRel(("Host Serial Driver: WaitCommEvent failed, terminating the worker thread.\n")); 593 /* this might have changed in the meantime */ 594 if (pThread->enmState != PDMTHREADSTATE_RUNNING) 490 595 break; 491 } 492 #endif 493 494 rc = RTFileRead(pData->DeviceFile, abBuffer, sizeof(abBuffer), &cbRead); 495 if (VBOX_FAILURE(rc)) 496 { 497 LogRel(("Host Serial Driver: Read failed with %Vrc, terminating the worker thread.\n", rc)); 596 if (!ReadFile(pData->hDeviceFile, abBuffer, sizeof(abBuffer), &dwNumberOfBytesTransferred, &overlapped)) 597 { 598 LogRel(("HostSerial#%d: Read failed with error %Vrc; terminating the worker thread.\n", pDrvIns->iInstance, RTErrConvertFromWin32(GetLastError()))); 498 599 break; 499 600 } 500 Log(("Host Serial Driver: Read %d bytes.\n", cbRead)); 501 cbRemaining = cbRead; 601 cbRemaining = dwNumberOfBytesTransferred; 602 603 #endif 604 605 Log(("Read %d bytes.\n", cbRemaining)); 502 606 pbBuffer = abBuffer; 503 607 } … … 522 626 else 523 627 { 524 LogRel(("Host Serial Driver: NotifyRead failed with %Vrc, terminating the worker thread.\n", rc));628 LogRel(("HostSerial#%d: NotifyRead failed with %Vrc, terminating the worker thread.\n", pDrvIns->iInstance, rc)); 525 629 break; 526 630 } … … 529 633 530 634 return VINF_SUCCESS; 635 } 636 637 /** 638 * Unblock the send thread so it can respond to a state change. 639 * 640 * @returns a VBox status code. 641 * @param pDrvIns The driver instance. 642 * @param pThread The send thread. 643 */ 644 static DECLCALLBACK(int) drvHostSerialWakeupReceiveThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 645 { 646 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 647 #ifdef RT_OS_LINUX 648 return RTFileWrite(pData->WakeupPipeW, "", 1, NULL); 649 #elif RT_OS_WINDOWS 650 if (!SetEvent(pData->hHaltEventSem)) 651 return RTErrConvertFromWin32(GetLastError()); 652 return VINF_SUCCESS; 653 #else 654 # error adapt me! 655 #endif 531 656 } 532 657 … … 549 674 { 550 675 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 551 #ifdef RT_OS_LINUX552 int filedes[2];553 #endif554 555 676 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance)); 556 677 … … 558 679 * Init basic data members and interfaces. 559 680 */ 560 pData->ReceiveThread = NIL_RTTHREAD;561 pData->SendThread = NIL_RTTHREAD;562 pData->fShutdown = false;563 681 /* IBase. */ 564 682 pDrvIns->IBase.pfnQueryInterface = drvHostSerialQueryInterface; … … 581 699 * Open the device 582 700 */ 701 #ifdef RT_OS_WINDOWS 702 703 pData->hHaltEventSem = CreateEvent(NULL, FALSE, FALSE, NULL); 704 AssertReturn(pData->hHaltEventSem != NULL, VERR_NO_MEMORY); 705 706 pData->hEventReceive = CreateEvent(NULL, FALSE, FALSE, NULL); 707 AssertReturn(pData->hEventReceive != NULL, VERR_NO_MEMORY); 708 709 pData->hEventSend = CreateEvent(NULL, FALSE, FALSE, NULL); 710 AssertReturn(pData->hEventSend != NULL, VERR_NO_MEMORY); 711 712 HANDLE hFile = CreateFile(pData->pszDevicePath, 713 GENERIC_READ | GENERIC_WRITE, 714 0, // must be opened with exclusive access 715 NULL, // no SECURITY_ATTRIBUTES structure 716 OPEN_EXISTING, // must use OPEN_EXISTING 717 FILE_FLAG_OVERLAPPED, // overlapped I/O 718 NULL); // no template file 719 if (hFile == INVALID_HANDLE_VALUE) 720 rc = RTErrConvertFromWin32(GetLastError()); 721 else 722 { 723 pData->hDeviceFile = hFile; 724 /* for overlapped read */ 725 if (!SetCommMask(hFile, EV_RXCHAR)) 726 { 727 LogRel(("HostSerial#%d: SetCommMask failed with error %d.\n", pDrvIns->iInstance, GetLastError())); 728 return VERR_FILE_IO_ERROR; 729 } 730 rc = VINF_SUCCESS; 731 } 732 733 #else 734 735 pData->DeviceFile = NIL_RTFILE; 583 736 rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE); 584 737 585 if (VBOX_FAILURE(rc)) { 586 pData->DeviceFile = NIL_RTFILE; 738 #endif 739 740 if (VBOX_FAILURE(rc)) 741 { 587 742 AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pData->pszDevicePath, rc)); 588 switch (rc) { 743 switch (rc) 744 { 589 745 case VERR_ACCESS_DENIED: 590 746 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, … … 608 764 /* Set to non blocking I/O */ 609 765 #ifdef RT_OS_LINUX 766 610 767 fcntl(pData->DeviceFile, F_SETFL, O_NONBLOCK); 611 /* Create the wakeup pipe. */ 612 if (!pipe(filedes)) 613 { 614 pData->WakeupPipeR = filedes[0]; 615 pData->WakeupPipeW = filedes[1]; 616 } 768 int aFDs[2]; 769 if (pipe(aFDs) != 0) 770 { 771 int rc = RTErrConvertFromErrno(errno); 772 AssertRC(rc); 773 return rc; 774 } 775 pData->WakeupPipeR = aFDs[0]; 776 pData->WakeupPipeW = aFDs[1]; 777 617 778 #elif defined(RT_OS_WINDOWS) 779 618 780 /* Set the COMMTIMEOUTS to get non blocking I/O */ 619 781 COMMTIMEOUTS comTimeout; … … 625 787 comTimeout.WriteTotalTimeoutConstant = 0; 626 788 627 SetCommTimeouts((HANDLE)pData->DeviceFile, &comTimeout); 789 SetCommTimeouts(pData->hDeviceFile, &comTimeout); 790 628 791 #endif 629 792 … … 635 798 return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance); 636 799 637 rc = RTThreadCreate(&pData->ReceiveThread, drvHostSerialReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Receive");800 rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pData->pReceiveThread, pData, drvHostSerialReceiveThread, drvHostSerialWakeupReceiveThread, 0, RTTHREADTYPE_IO, "Char Receive"); 638 801 if (VBOX_FAILURE(rc)) 639 802 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance); … … 642 805 AssertRC(rc); 643 806 644 rc = RTThreadCreate(&pData->SendThread, drvHostSerialSendLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Serial Send");807 rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pData->pSendThread, pData, drvHostSerialSendThread, drvHostSerialWakeupSendThread, 0, RTTHREADTYPE_IO, "Serial Send"); 645 808 if (VBOX_FAILURE(rc)) 646 809 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance); … … 664 827 static DECLCALLBACK(void) drvHostSerialDestruct(PPDMDRVINS pDrvIns) 665 828 { 666 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 667 int rc; 829 PDRVHOSTSERIAL pData = PDMINS2DATA(pDrvIns, PDRVHOSTSERIAL); 668 830 669 831 LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance)); 670 671 ASMAtomicXchgBool(&pData->fShutdown, true);672 673 #ifdef RT_OS_LINUX674 /* Notify the receive thread that we want to shutdown. */675 rc = RTFileWrite (pData->WakeupPipeW, WAKE_UP_STRING, WAKE_UP_STRING_LEN, NULL);676 if (VBOX_SUCCESS (rc))677 RTFileFlush (pData->WakeupPipeW);678 #endif679 if (pData->ReceiveThread != NIL_RTTHREAD)680 {681 rc = RTThreadWait(pData->ReceiveThread, 15000, NULL);682 if (RT_FAILURE(rc))683 LogRel(("HostSerial%d: receive thread did not terminate (rc=%Rrc)\n", pDrvIns->iInstance, rc));684 pData->ReceiveThread = NIL_RTTHREAD;685 }686 832 687 833 /* Empty the send queue */ 688 834 pData->iSendQueueTail = pData->iSendQueueHead = 0; 689 835 690 RTSemEventSignal(pData->SendSem);691 836 RTSemEventDestroy(pData->SendSem); 692 837 pData->SendSem = NIL_RTSEMEVENT; 693 838 694 if (pData->SendThread != NIL_RTTHREAD) 695 { 696 int rc = RTThreadWait(pData->SendThread, 15000, NULL); 697 if (RT_FAILURE(rc)) 698 LogRel(("HostSerial%d: send thread did not terminate (rc=%Rrc)\n", pDrvIns->iInstance, rc)); 699 pData->SendThread = NIL_RTTHREAD; 700 } 701 702 #ifdef RT_OS_LINUX 703 RTFileClose(pData->WakeupPipeR); 704 RTFileClose(pData->WakeupPipeW); 705 #endif 706 707 RTFileClose(pData->DeviceFile); 839 #if defined(RT_OS_LINUX) 840 841 if (pData->WakeupPipeW != NIL_RTFILE) 842 { 843 int rc = RTFileClose(pData->WakeupPipeW); 844 AssertRC(rc); 845 pData->WakeupPipeW = NIL_RTFILE; 846 } 847 if (pData->WakeupPipeR != NIL_RTFILE) 848 { 849 int rc = RTFileClose(pData->WakeupPipeR); 850 AssertRC(rc); 851 pData->WakeupPipeR = NIL_RTFILE; 852 } 853 if (pData->DeviceFile != NIL_RTFILE) 854 { 855 int rc = RTFileClose(pData->DeviceFile); 856 AssertRC(rc); 857 pData->DeviceFile = NIL_RTFILE; 858 } 859 860 #elif defined(RT_OS_WINDOWS) 861 862 CloseHandle(pData->hEventReceive); 863 CloseHandle(pData->hEventSend); 864 CancelIo(pData->hDeviceFile); 865 CloseHandle(pData->hDeviceFile); 866 867 #endif 708 868 } 709 869
Note:
See TracChangeset
for help on using the changeset viewer.