Changeset 75800 in vbox for trunk/src/VBox/HostServices/GuestControl/service.cpp
- Timestamp:
- Nov 29, 2018 12:42:18 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/GuestControl/service.cpp
r75799 r75800 447 447 typedef struct ClientState 448 448 { 449 PVBOXHGCMSVCHELPERS mSvcHelpers; 450 /** The client's ID. */ 451 uint32_t mID; 452 /** Host command list to process. */ 453 HostCmdList mHostCmdList; 454 /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending. 455 * 456 * This means the client waits for a new host command to reply and won't return 457 * from the waiting call until a new host command is available. */ 458 guestControl::eGuestFn mIsPending; 459 /** The client's pending connection. */ 460 ClientConnection mPendingCon; 461 /** Set if we've got a pending wait cancel. */ 462 bool m_fPendingCancel; 463 /** Set if master. */ 464 bool m_fIsMaster; 465 /** The session ID for this client, UINT32_MAX if not set or master. */ 466 uint32_t m_idSession; 467 468 449 469 ClientState(void) 450 470 : mSvcHelpers(NULL) 451 471 , mID(0) 452 472 , mIsPending((guestControl::eGuestFn)0) 473 , m_fPendingCancel(false) 453 474 , m_fIsMaster(false) 454 475 , m_idSession(UINT32_MAX) … … 462 483 , mID(idClient) 463 484 , mIsPending((guestControl::eGuestFn)0) 485 , m_fPendingCancel(false) 464 486 , m_fIsMaster(false) 465 487 , m_idSession(UINT32_MAX) … … 470 492 471 493 /** 494 * Used by for Service::hostProcessCommand(). 495 */ 496 int EnqueueCommand(HostCommand *pHostCmd) 497 { 498 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 499 500 try 501 { 502 mHostCmdList.push_back(pHostCmd); 503 } 504 catch (std::bad_alloc &) 505 { 506 return VERR_NO_MEMORY; 507 } 508 509 pHostCmd->Retain(); 510 return VINF_SUCCESS; 511 } 512 513 /** 514 * Used by for Service::hostProcessCommand(). 515 * 516 * @note This wakes up both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers. 517 */ 518 int Wakeup(void) 519 { 520 int rc = VINF_NO_CHANGE; 521 522 if (mIsPending != 0) 523 { 524 LogFlowFunc(("[Client %RU32] Waking up ...\n", mID)); 525 526 rc = VINF_SUCCESS; 527 528 HostCmdListIter curCmd = mHostCmdList.begin(); 529 if (curCmd != mHostCmdList.end()) 530 { 531 HostCommand *pHostCmd = (*curCmd); 532 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 533 534 LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%RU32, cParms=%RU32, m_cRefs=%RU32)\n", 535 mID, pHostCmd->mMsgType, pHostCmd->m_idContext, pHostCmd->mParmCount, pHostCmd->m_cRefs)); 536 537 if (mIsPending == GUEST_MSG_PEEK_WAIT) 538 { 539 HGCMSvcSetU32(&mPendingCon.mParms[0], pHostCmd->mMsgType); 540 HGCMSvcSetU32(&mPendingCon.mParms[1], pHostCmd->mParmCount); 541 for (uint32_t i = pHostCmd->mParmCount; i >= 2; i--) 542 switch (pHostCmd->mpParms[i - 2].type) 543 { 544 case VBOX_HGCM_SVC_PARM_32BIT: mPendingCon.mParms[i].u.uint32 = ~(uint32_t)sizeof(uint32_t); break; 545 case VBOX_HGCM_SVC_PARM_64BIT: mPendingCon.mParms[i].u.uint32 = ~(uint32_t)sizeof(uint64_t); break; 546 case VBOX_HGCM_SVC_PARM_PTR: mPendingCon.mParms[i].u.uint32 = pHostCmd->mpParms[i - 2].u.pointer.size; break; 547 } 548 549 rc = mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, VINF_SUCCESS); 550 mIsPending = (guestControl::eGuestFn)0; 551 } 552 else if (mIsPending == GUEST_MSG_WAIT) 553 rc = OldRun(&mPendingCon, pHostCmd); 554 else 555 AssertMsgFailed(("mIsPending=%d\n", mIsPending)); 556 } 557 else 558 AssertMsgFailed(("Waking up client ID=%RU32 with no host command in queue is a bad idea\n", mID)); 559 560 return rc; 561 } 562 563 return VINF_NO_CHANGE; 564 } 565 566 /** 567 * Used by Service::call() to handle GUEST_MSG_CANCEL. 568 * 569 * @note This cancels both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers. 570 */ 571 int CancelWaiting() 572 { 573 LogFlowFunc(("[Client %RU32] Cancelling waiting thread, isPending=%d, pendingNumParms=%RU32, m_idSession=%x\n", 574 mID, mIsPending, mPendingCon.mNumParms, m_idSession)); 575 576 /* 577 * The PEEK call is simple: At least two parameters, all set to zero before sleeping. 578 */ 579 int rcComplete; 580 if (mIsPending == GUEST_MSG_PEEK_WAIT) 581 { 582 HGCMSvcSetU32(&mPendingCon.mParms[0], HOST_CANCEL_PENDING_WAITS); 583 rcComplete = VINF_TRY_AGAIN; 584 } 585 /* 586 * The GUEST_MSG_WAIT call is complicated, though we're generally here 587 * to wake up someone who is peeking and have two parameters. If there 588 * aren't two parameters, fail the call. 589 */ 590 else if (mIsPending != 0) 591 { 592 Assert(mIsPending == GUEST_MSG_WAIT); 593 if (mPendingCon.mNumParms > 0) 594 HGCMSvcSetU32(&mPendingCon.mParms[0], HOST_CANCEL_PENDING_WAITS); 595 if (mPendingCon.mNumParms > 1) 596 HGCMSvcSetU32(&mPendingCon.mParms[1], 0); 597 rcComplete = mPendingCon.mNumParms == 2 ? VINF_SUCCESS : VERR_TRY_AGAIN; 598 } 599 /* 600 * If nobody is waiting, flag the next wait call as cancelled. 601 */ 602 else 603 { 604 m_fPendingCancel = true; 605 return VINF_SUCCESS; 606 } 607 608 mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, rcComplete); 609 mIsPending = (guestControl::eGuestFn)0; 610 m_fPendingCancel = false; 611 return VINF_SUCCESS; 612 } 613 614 615 /** @name The GUEST_MSG_WAIT state and helpers. 616 * 617 * @note Don't try understand this, it is certificable! 618 * 619 * @{ 620 */ 621 622 /** Last (most recent) rc after handling the host command. */ 623 int mHostCmdRc; 624 /** How many GUEST_MSG_WAIT calls the client has issued to retrieve one command. 625 * 626 * This is used as a heuristic to remove a message that the client appears not 627 * to be able to successfully retrieve. */ 628 uint32_t mHostCmdTries; 629 /** Number of times we've peeked at a pending message. 630 * 631 * This is necessary for being compatible with older Guest Additions. In case 632 * there are commands which only have two (2) parameters and therefore would fit 633 * into the GUEST_MSG_WAIT reply immediately, we now can make sure that the 634 * client first gets back the GUEST_MSG_WAIT results first. 635 */ 636 uint32_t mPeekCount; 637 638 /** 472 639 * Ditches the first host command and crazy GUEST_MSG_WAIT state. 473 */ 474 void DitchFirstHostCmd() 640 * 641 * @note Only used by GUEST_MSG_WAIT scenarios. 642 */ 643 void OldDitchFirstHostCmd() 475 644 { 476 645 Assert(!mHostCmdList.empty()); … … 484 653 mHostCmdTries = 0; 485 654 mPeekCount = 0; 486 }487 488 int EnqueueCommand(HostCommand *pHostCmd)489 {490 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER);491 492 try493 {494 mHostCmdList.push_back(pHostCmd);495 }496 catch (std::bad_alloc &)497 {498 return VERR_NO_MEMORY;499 }500 501 pHostCmd->Retain();502 return VINF_SUCCESS;503 }504 505 /**506 * Set to indicate that a client call (GUEST_MSG_WAIT) is pending.507 *508 * @note Only used by GUEST_MSG_WAIT scenarios.509 */510 int OldSetPending(const ClientConnection *pConnection)511 {512 AssertPtrReturn(pConnection, VERR_INVALID_POINTER);513 514 if (mIsPending != 0)515 {516 LogFlowFunc(("[Client %RU32] Already is in pending mode\n", mID));517 518 /*519 * Signal that we don't and can't return yet.520 */521 return VINF_HGCM_ASYNC_EXECUTE;522 }523 524 if (mHostCmdList.empty())525 {526 AssertMsg(mIsPending == 0, ("Client ID=%RU32 already is pending but tried to receive a new host command\n", mID));527 528 mPendingCon.mHandle = pConnection->mHandle;529 mPendingCon.mNumParms = pConnection->mNumParms;530 mPendingCon.mParms = pConnection->mParms;531 532 mIsPending = GUEST_MSG_WAIT;533 534 LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID));535 536 /*537 * Signal that we don't and can't return yet.538 */539 return VINF_HGCM_ASYNC_EXECUTE;540 }541 542 /*543 * Signal that there already is a connection pending.544 * Shouldn't happen in daily usage.545 */546 AssertMsgFailed(("Client already has a connection pending\n"));547 return VERR_SIGNAL_PENDING;548 655 } 549 656 … … 605 712 { 606 713 Assert(*mHostCmdList.begin() == pHostCmd); 607 DitchFirstHostCmd();714 OldDitchFirstHostCmd(); 608 715 } 609 716 … … 613 720 614 721 /** 722 * Set to indicate that a client call (GUEST_MSG_WAIT) is pending. 723 * 615 724 * @note Only used by GUEST_MSG_WAIT scenarios. 616 725 */ 726 int OldSetPending(const ClientConnection *pConnection) 727 { 728 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 729 730 if (mIsPending != 0) 731 { 732 LogFlowFunc(("[Client %RU32] Already is in pending mode\n", mID)); 733 734 /* 735 * Signal that we don't and can't return yet. 736 */ 737 return VINF_HGCM_ASYNC_EXECUTE; 738 } 739 740 if (mHostCmdList.empty()) 741 { 742 AssertMsg(mIsPending == 0, ("Client ID=%RU32 already is pending but tried to receive a new host command\n", mID)); 743 744 mPendingCon.mHandle = pConnection->mHandle; 745 mPendingCon.mNumParms = pConnection->mNumParms; 746 mPendingCon.mParms = pConnection->mParms; 747 748 mIsPending = GUEST_MSG_WAIT; 749 750 LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID)); 751 752 /* 753 * Signal that we don't and can't return yet. 754 */ 755 return VINF_HGCM_ASYNC_EXECUTE; 756 } 757 758 /* 759 * Signal that there already is a connection pending. 760 * Shouldn't happen in daily usage. 761 */ 762 AssertMsgFailed(("Client already has a connection pending\n")); 763 return VERR_SIGNAL_PENDING; 764 } 765 766 /** 767 * @note Only used by GUEST_MSG_WAIT scenarios. 768 */ 617 769 int OldRunCurrent(const ClientConnection *pConnection) 618 770 { 619 771 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 620 772 621 int rc; 773 /* 774 * If the host command list is empty, the request must wait for one to be posted. 775 */ 622 776 if (mHostCmdList.empty()) 623 777 { 624 rc = OldSetPending(pConnection); 625 } 626 else 627 { 628 AssertMsgReturn(mIsPending == 0, 629 ("Client ID=%RU32 still is in pending mode; can't use another connection\n", mID), VERR_INVALID_PARAMETER); 630 631 HostCmdListIter curCmd = mHostCmdList.begin(); 632 Assert(curCmd != mHostCmdList.end()); 633 HostCommand *pHostCmd = *curCmd; 634 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 635 636 rc = OldRun(pConnection, pHostCmd); 637 } 638 639 return rc; 640 } 641 642 /** 643 * Used by for Service::hostProcessCommand(). 644 * 645 * @note This wakes up both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers. 646 */ 647 int Wakeup(void) 648 { 649 int rc = VINF_NO_CHANGE; 650 651 if (mIsPending != 0) 652 { 653 LogFlowFunc(("[Client %RU32] Waking up ...\n", mID)); 654 655 rc = VINF_SUCCESS; 656 657 HostCmdListIter curCmd = mHostCmdList.begin(); 658 if (curCmd != mHostCmdList.end()) 778 if (!m_fPendingCancel) 659 779 { 660 HostCommand *pHostCmd = (*curCmd); 661 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 662 663 LogFlowThisFunc(("[Client %RU32] Current host command is %RU32 (CID=%RU32, cParms=%RU32, m_cRefs=%RU32)\n", 664 mID, pHostCmd->mMsgType, pHostCmd->m_idContext, pHostCmd->mParmCount, pHostCmd->m_cRefs)); 665 666 if (mIsPending == GUEST_MSG_PEEK_WAIT) 667 { 668 HGCMSvcSetU32(&mPendingCon.mParms[0], pHostCmd->mMsgType); 669 HGCMSvcSetU32(&mPendingCon.mParms[1], pHostCmd->mParmCount); 670 for (uint32_t i = pHostCmd->mParmCount; i >= 2; i--) 671 switch (pHostCmd->mpParms[i - 2].type) 672 { 673 case VBOX_HGCM_SVC_PARM_32BIT: mPendingCon.mParms[i].u.uint32 = ~(uint32_t)sizeof(uint32_t); break; 674 case VBOX_HGCM_SVC_PARM_64BIT: mPendingCon.mParms[i].u.uint32 = ~(uint32_t)sizeof(uint64_t); break; 675 case VBOX_HGCM_SVC_PARM_PTR: mPendingCon.mParms[i].u.uint32 = pHostCmd->mpParms[i - 2].u.pointer.size; break; 676 } 677 678 rc = mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, VINF_SUCCESS); 679 mIsPending = (guestControl::eGuestFn)0; 680 } 681 else if (mIsPending == GUEST_MSG_WAIT) 682 rc = OldRun(&mPendingCon, pHostCmd); 683 else 684 AssertMsgFailed(("mIsPending=%d\n", mIsPending)); 780 /* Go to sleep. */ 781 ASSERT_GUEST_RETURN(mIsPending == 0, VERR_WRONG_ORDER); 782 mPendingCon = *pConnection; 783 mIsPending = GUEST_MSG_WAIT; 784 LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID)); 785 return VINF_HGCM_ASYNC_EXECUTE; 685 786 } 686 else 687 AssertMsgFailed(("Waking up client ID=%RU32 with no host command in queue is a bad idea\n", mID)); 688 689 return rc; 690 } 691 692 return VINF_NO_CHANGE; 693 } 694 695 /** 696 * Used by Service::call() to handle GUEST_MSG_CANCEL. 697 * 698 * @note This cancels both GUEST_MSG_WAIT and GUEST_MSG_PEEK_WAIT sleepers. 699 */ 700 int CancelWaiting() 701 { 702 LogFlowFunc(("[Client %RU32] Cancelling waiting thread, isPending=%d, pendingNumParms=%RU32, m_idSession=%x\n", 703 mID, mIsPending, mPendingCon.mNumParms, m_idSession)); 704 /** @todo r=bird: This must be made sticky if no pending call, i.e. next wait 705 * call must return immediately. otherwise there will be a race and 706 * occational long VBoxService shutdown times. */ 707 708 int rc; 709 if ( mIsPending != 0 710 && mPendingCon.mNumParms >= 2) 711 { 712 HGCMSvcSetU32(&mPendingCon.mParms[0], HOST_CANCEL_PENDING_WAITS); /* Message ID. */ 713 HGCMSvcSetU32(&mPendingCon.mParms[1], 0); /* Required parameters for message. */ 714 715 AssertPtr(mSvcHelpers); 716 mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, mIsPending == GUEST_MSG_WAIT ? VINF_SUCCESS : VINF_TRY_AGAIN); 717 718 mIsPending = (guestControl::eGuestFn)0; 719 720 rc = VINF_SUCCESS; 721 } 722 else if (mPendingCon.mNumParms < 2) 723 rc = VERR_BUFFER_OVERFLOW; 724 else /** @todo Enqueue command instead of dropping? */ 725 rc = VERR_WRONG_ORDER; 726 727 return rc; 787 788 /* Wait was cancelled. */ 789 m_fPendingCancel = false; 790 if (pConnection->mNumParms > 0) 791 HGCMSvcSetU32(&pConnection->mParms[0], HOST_CANCEL_PENDING_WAITS); 792 if (pConnection->mNumParms > 1) 793 HGCMSvcSetU32(&pConnection->mParms[1], 0); 794 return pConnection->mNumParms == 2 ? VINF_SUCCESS : VERR_TRY_AGAIN; 795 } 796 797 /* 798 * Return first host command. 799 */ 800 AssertMsgReturn(mIsPending == 0, 801 ("Client ID=%RU32 still is in pending mode; can't use another connection\n", mID), VERR_INVALID_PARAMETER); 802 803 HostCmdListIter curCmd = mHostCmdList.begin(); 804 Assert(curCmd != mHostCmdList.end()); 805 HostCommand *pHostCmd = *curCmd; 806 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 807 808 return OldRun(pConnection, pHostCmd); 728 809 } 729 810 … … 795 876 } 796 877 797 PVBOXHGCMSVCHELPERS mSvcHelpers;798 /** The client's ID. */799 uint32_t mID;800 /** Host command list to process. */801 HostCmdList mHostCmdList;802 /** Pending client call (GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT), zero if none pending.803 *804 * This means the client waits for a new host command to reply and won't return805 * from the waiting call until a new host command is available. */806 guestControl::eGuestFn mIsPending;807 /** The client's pending connection. */808 ClientConnection mPendingCon;809 /** Set if master. */810 bool m_fIsMaster;811 /** The session ID for this client, UINT32_MAX if not set or master. */812 uint32_t m_idSession;813 814 /** @name The GUEST_MSG_WAIT state.815 * @note Don't try understand this, it is certificable!816 * @{ */817 /** Last (most recent) rc after handling the host command. */818 int mHostCmdRc;819 /** How many GUEST_MSG_WAIT calls the client has issued to retrieve one command.820 *821 * This is used as a heuristic to remove a message that the client appears not822 * to be able to successfully retrieve. */823 uint32_t mHostCmdTries;824 /** Number of times we've peeked at a pending message.825 *826 * This is necessary for being compatible with older Guest Additions. In case827 * there are commands which only have two (2) parameters and therefore would fit828 * into the GUEST_MSG_WAIT reply immediately, we now can make sure that the829 * client first gets back the GUEST_MSG_WAIT results first.830 */831 uint32_t mPeekCount;832 878 /** @} */ 833 834 879 } ClientState; 835 880 typedef std::map< uint32_t, ClientState > ClientStateMap; … … 895 940 } 896 941 897 /** 898 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnUnload} 899 * Simply deletes the GstCtrlService object 900 */ 901 static DECLCALLBACK(int) svcUnload(void *pvService) 902 { 903 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 904 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 905 int rc = pSelf->uninit(); 906 AssertRC(rc); 907 if (RT_SUCCESS(rc)) 908 delete pSelf; 909 return rc; 910 } 911 912 /** 913 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect} 914 * Stub implementation of pfnConnect and pfnDisconnect. 915 */ 916 static DECLCALLBACK(int) svcConnect(void *pvService, 917 uint32_t u32ClientID, 918 void *pvClient, 919 uint32_t fRequestor, bool fRestoring) 920 { 921 RT_NOREF(fRestoring); 922 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 923 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 924 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 925 return pSelf->clientConnect(u32ClientID, pvClient, fRequestor); 926 } 927 928 /** 929 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect} 930 * Stub implementation of pfnConnect and pfnDisconnect. 931 */ 932 static DECLCALLBACK(int) svcDisconnect(void *pvService, 933 uint32_t u32ClientID, 934 void *pvClient) 935 { 936 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 937 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 938 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 939 return pSelf->clientDisconnect(u32ClientID, pvClient); 940 } 941 942 /** 943 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnCall} 944 * Wraps to the call member function 945 */ 946 static DECLCALLBACK(void) svcCall(void * pvService, 947 VBOXHGCMCALLHANDLE callHandle, 948 uint32_t u32ClientID, 949 void *pvClient, 950 uint32_t u32Function, 951 uint32_t cParms, 952 VBOXHGCMSVCPARM paParms[], 953 uint64_t tsArrival) 954 { 955 AssertLogRelReturnVoid(VALID_PTR(pvService)); 956 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 957 AssertPtrReturnVoid(pSelf); 958 RT_NOREF_PV(tsArrival); 959 pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms); 960 } 961 962 /** 963 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnHostCall} 964 * Wraps to the hostCall member function 965 */ 966 static DECLCALLBACK(int) svcHostCall(void *pvService, 967 uint32_t u32Function, 968 uint32_t cParms, 969 VBOXHGCMSVCPARM paParms[]) 970 { 971 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 972 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 973 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 974 return pSelf->hostCall(u32Function, cParms, paParms); 975 } 976 977 /** 978 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnRegisterExtension} 979 * Installs a host callback for notifications of property changes. 980 */ 981 static DECLCALLBACK(int) svcRegisterExtension(void *pvService, 982 PFNHGCMSVCEXT pfnExtension, 983 void *pvExtension) 984 { 985 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 986 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 987 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 988 pSelf->mpfnHostCallback = pfnExtension; 989 pSelf->mpvHostData = pvExtension; 990 return VINF_SUCCESS; 991 } 942 static DECLCALLBACK(int) svcUnload(void *pvService); 943 static DECLCALLBACK(int) svcConnect(void *pvService, uint32_t u32ClientID, void *pvClient, 944 uint32_t fRequestor, bool fRestoring); 945 static DECLCALLBACK(int) svcDisconnect(void *pvService, uint32_t u32ClientID, void *pvClient); 946 static DECLCALLBACK(void) svcCall(void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, 947 uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival); 948 static DECLCALLBACK(int) svcHostCall(void *pvService, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 949 static DECLCALLBACK(int) svcRegisterExtension(void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension); 992 950 993 951 private: 994 995 int prepareExecute(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);996 int clientConnect(uint32_t u32ClientID, void *pvClient, uint32_t fRequestor);997 int clientDisconnect(uint32_t u32ClientID, void *pvClient);998 999 952 int clientMakeMeMaster(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms); 1000 953 int clientMsgPeek(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fWait); … … 1013 966 int hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1014 967 int hostProcessCommand(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 1015 void call(VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void *pvClient, uint32_t idFunction,1016 uint32_t cParms, VBOXHGCMSVCPARM paParms[]);1017 int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);1018 int uninit(void);1019 968 1020 969 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(GstCtrlService); … … 1023 972 1024 973 /** 1025 * Handles a client which just connected. 1026 * 1027 * @return IPRT status code. 1028 * @param idClient 1029 * @param pvClient 1030 * @param fRequestor VMMDevRequestHeader::fRequestor value, if available. 1031 */ 1032 int GstCtrlService::clientConnect(uint32_t idClient, void *pvClient, uint32_t fRequestor) 1033 { 1034 RT_NOREF(pvClient); 974 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnUnload, 975 * Simply deletes the GstCtrlService object} 976 */ 977 /*static*/ DECLCALLBACK(int) 978 GstCtrlService::svcUnload(void *pvService) 979 { 980 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 981 SELF *pThis = reinterpret_cast<SELF *>(pvService); 982 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 983 984 delete pThis; 985 986 return VINF_SUCCESS; 987 } 988 989 990 991 /** 992 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect, 993 * Initializes the state for a new client.} 994 */ 995 /*static*/ DECLCALLBACK(int) 996 GstCtrlService::svcConnect(void *pvService, uint32_t idClient, void *pvClient, uint32_t fRequestor, bool fRestoring) 997 { 1035 998 LogFlowFunc(("[Client %RU32] Connected\n", idClient)); 1036 AssertMsg(mClientStateMap.find(idClient) == mClientStateMap.end(), 999 1000 RT_NOREF(fRestoring, pvClient); 1001 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 1002 SELF *pThis = reinterpret_cast<SELF *>(pvService); 1003 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1004 1005 AssertMsg(pThis->mClientStateMap.find(idClient) == pThis->mClientStateMap.end(), 1037 1006 ("Client with ID=%RU32 already connected when it should not\n", idClient)); 1038 1007 … … 1042 1011 try 1043 1012 { 1044 mClientStateMap[idClient] = ClientState(mpHelpers, idClient);1013 pThis->mClientStateMap[idClient] = ClientState(pThis->mpHelpers, idClient); 1045 1014 } 1046 1015 catch (std::bad_alloc) … … 1048 1017 return VERR_NO_MEMORY; 1049 1018 } 1050 ClientState &rClientState = mClientStateMap[idClient];1019 ClientState &rClientState = pThis->mClientStateMap[idClient]; 1051 1020 1052 1021 /* … … 1056 1025 */ 1057 1026 /** @todo make picking the master more dynamic/flexible. */ 1058 if ( m_fLegacyMode1059 && m_idMasterClient == UINT32_MAX)1027 if ( pThis->m_fLegacyMode 1028 && pThis->m_idMasterClient == UINT32_MAX) 1060 1029 { 1061 1030 if ( fRequestor == VMMDEV_REQUESTOR_LEGACY … … 1063 1032 { 1064 1033 LogFunc(("Picking %u as master for now.\n", idClient)); 1065 m_idMasterClient = idClient;1034 pThis->m_idMasterClient = idClient; 1066 1035 rClientState.m_fIsMaster = true; 1067 1036 } … … 1073 1042 1074 1043 /** 1075 * Handles a client which disconnected. 1044 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnConnect, 1045 * Handles a client which disconnected.} 1076 1046 * 1077 1047 * This functiond does some internal cleanup as well as sends notifications to 1078 1048 * the host so that the host can do the same (if required). 1079 * 1080 * @return IPRT status code. 1081 * @param idClient The client's ID of which disconnected. 1082 * @param pvClient User data, not used at the moment. 1083 */ 1084 int GstCtrlService::clientDisconnect(uint32_t idClient, void *pvClient) 1049 */ 1050 /*static*/ DECLCALLBACK(int) 1051 GstCtrlService::svcDisconnect(void *pvService, uint32_t idClient, void *pvClient) 1085 1052 { 1086 1053 RT_NOREF(pvClient); 1087 LogFlowFunc(("[Client %RU32] Disconnected (%zu clients total)\n", idClient, mClientStateMap.size())); 1088 1089 ClientStateMapIter ItClientState = mClientStateMap.find(idClient); 1090 AssertMsgReturn(ItClientState != mClientStateMap.end(), 1054 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 1055 SELF *pThis = reinterpret_cast<SELF *>(pvService); 1056 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 1057 LogFlowFunc(("[Client %RU32] Disconnected (%zu clients total)\n", idClient, pThis->mClientStateMap.size())); 1058 1059 ClientStateMapIter ItClientState = pThis->mClientStateMap.find(idClient); 1060 AssertMsgReturn(ItClientState != pThis->mClientStateMap.end(), 1091 1061 ("Client ID=%RU32 not found in client list when it should be there\n", idClient), 1092 1062 VINF_SUCCESS); … … 1109 1079 VBOXHGCMSVCPARM Parm; 1110 1080 HGCMSvcSetU32(&Parm, idContext); 1111 int rc2 = hostCallback(GUEST_DISCONNECTED, 1, &Parm);1081 int rc2 = pThis->hostCallback(GUEST_DISCONNECTED, 1, &Parm); 1112 1082 LogFlowFunc(("Cancelled host command %u (%s) with idContext=%#x -> %Rrc\n", 1113 1083 idFunction, GstCtrlHostFnName((eHostFn)idFunction), idContext, rc2)); … … 1120 1090 * Delete the client state. 1121 1091 */ 1122 mClientStateMap.erase(ItClientState);1092 pThis->mClientStateMap.erase(ItClientState); 1123 1093 1124 1094 /* 1125 1095 * If it's the master disconnecting, we need to reset related globals. 1126 1096 */ 1127 if (idClient == m_idMasterClient)1128 { 1129 m_idMasterClient = UINT32_MAX;1097 if (idClient == pThis->m_idMasterClient) 1098 { 1099 pThis->m_idMasterClient = UINT32_MAX; 1130 1100 GstCtrlPreparedSession *pCur, *pNext; 1131 RTListForEachSafe(& m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry)1101 RTListForEachSafe(&pThis->m_PreparedSessions, pCur, pNext, GstCtrlPreparedSession, ListEntry) 1132 1102 { 1133 1103 RTMemFree(pCur); 1134 1104 } 1135 m_cPreparedSessions = 0;1136 } 1137 1138 if ( mClientStateMap.empty())1139 m_fLegacyMode = true;1105 pThis->m_cPreparedSessions = 0; 1106 } 1107 1108 if (pThis->mClientStateMap.empty()) 1109 pThis->m_fLegacyMode = true; 1140 1110 1141 1111 /* 1142 1112 * Host command sanity check. 1143 1113 */ 1144 Assert(RTListIsEmpty(& mHostCmdList) || !mClientStateMap.empty());1114 Assert(RTListIsEmpty(&pThis->mHostCmdList) || !pThis->mClientStateMap.empty()); 1145 1115 1146 1116 return VINF_SUCCESS; … … 1205 1175 * @param hCall The client's call handle. 1206 1176 * @param cParms Number of parameters. 1207 * @param paParms Array of parameters.1208 * @param fWait Set if we should wait for a message, clear if to return1209 * immediately.1210 1177 */ 1211 1178 int GstCtrlService::clientMakeMeMaster(uint32_t idClient, VBOXHGCMCALLHANDLE hCall, uint32_t cParms) … … 1881 1848 */ 1882 1849 if (!rClientState.mHostCmdList.empty()) 1883 rClientState. DitchFirstHostCmd();1850 rClientState.OldDitchFirstHostCmd(); 1884 1851 1885 1852 LogFlowFunc(("[Client %RU32] Skipped current message - leagcy function\n", idClient)); … … 1893 1860 * 1894 1861 * @return IPRT status code. 1895 * @param eFunction Function (event) that occured. 1896 * @param cParms Number of parameters. 1897 * @param paParms Array of parameters. 1898 */ 1899 int GstCtrlService::hostCallback(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1900 { 1901 LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n", 1902 eFunction, cParms, paParms)); 1862 * @param idFunction Function (event) that occured. 1863 * @param cParms Number of parameters. 1864 * @param paParms Array of parameters. 1865 */ 1866 int GstCtrlService::hostCallback(uint32_t idFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1867 { 1868 LogFlowFunc(("idFunction=%u (%s), cParms=%ld, paParms=%p\n", idFunction, GstCtrlGuestFnName((eGuestFn)idFunction), cParms, paParms)); 1903 1869 1904 1870 int rc; … … 1915 1881 try 1916 1882 { 1917 rc = mpfnHostCallback(mpvHostData, eFunction, (void *)(&data), sizeof(data));1883 rc = mpfnHostCallback(mpvHostData, idFunction, (void *)(&data), sizeof(data)); 1918 1884 } 1919 1885 catch (std::bad_alloc &) … … 2023 1989 2024 1990 /** 2025 * Worker for svcCall() that helps implement VBOXHGCMSVCFNTABLE::pfnCall. 1991 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnHostCall, 1992 * Wraps to the hostProcessCommand() member function.} 1993 */ 1994 /*static*/ DECLCALLBACK(int) 1995 GstCtrlService::svcHostCall(void *pvService, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1996 { 1997 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 1998 SELF *pThis = reinterpret_cast<SELF *>(pvService); 1999 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 2000 2001 LogFlowFunc(("fn=%RU32, cParms=%RU32, paParms=0x%p\n", u32Function, cParms, paParms)); 2002 AssertReturn(u32Function != HOST_CANCEL_PENDING_WAITS, VERR_INVALID_FUNCTION); 2003 return pThis->hostProcessCommand(u32Function, cParms, paParms); 2004 } 2005 2006 2007 /** 2008 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnCall} 2026 2009 * 2027 2010 * @note All functions which do not involve an unreasonable delay will be 2028 2011 * handled synchronously. If needed, we will add a request handler 2029 2012 * thread in future for those which do. 2030 *2031 2013 * @thread HGCM 2032 2014 */ 2033 void GstCtrlService::call(VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void * /* pvClient */, uint32_t idFunction, 2034 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 2015 /*static*/ DECLCALLBACK(void) 2016 GstCtrlService::svcCall(void *pvService, VBOXHGCMCALLHANDLE hCall, uint32_t idClient, void *pvClient, 2017 uint32_t idFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival) 2035 2018 { 2036 2019 LogFlowFunc(("[Client %RU32] idFunction=%RU32 (%s), cParms=%RU32, paParms=0x%p\n", 2037 2020 idClient, idFunction, GstCtrlHostFnName((eHostFn)idFunction), cParms, paParms)); 2021 RT_NOREF(tsArrival, pvClient); 2022 2023 AssertLogRelReturnVoid(VALID_PTR(pvService)); 2024 SELF *pThis= reinterpret_cast<SELF *>(pvService); 2025 AssertPtrReturnVoid(pThis); 2026 2038 2027 int rc; 2039 2028 switch (idFunction) … … 2041 2030 case GUEST_MAKE_ME_MASTER: 2042 2031 LogFlowFunc(("[Client %RU32] GUEST_MAKE_ME_MASTER\n", idClient)); 2043 rc = clientMakeMeMaster(idClient, hCall, cParms);2032 rc = pThis->clientMakeMeMaster(idClient, hCall, cParms); 2044 2033 break; 2045 2034 case GUEST_MSG_PEEK_NOWAIT: 2046 2035 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_NOWAIT\n", idClient)); 2047 rc = clientMsgPeek(idClient, hCall, cParms, paParms, false /*fWait*/);2036 rc = pThis->clientMsgPeek(idClient, hCall, cParms, paParms, false /*fWait*/); 2048 2037 break; 2049 2038 case GUEST_MSG_PEEK_WAIT: 2050 2039 LogFlowFunc(("[Client %RU32] GUEST_MSG_PEEK_WAIT\n", idClient)); 2051 rc = clientMsgPeek(idClient, hCall, cParms, paParms, true /*fWait*/);2040 rc = pThis->clientMsgPeek(idClient, hCall, cParms, paParms, true /*fWait*/); 2052 2041 break; 2053 2042 case GUEST_MSG_GET: 2054 2043 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", idClient)); 2055 rc = clientMsgGet(idClient, hCall, cParms, paParms);2044 rc = pThis->clientMsgGet(idClient, hCall, cParms, paParms); 2056 2045 break; 2057 2046 case GUEST_MSG_CANCEL: 2058 2047 LogFlowFunc(("[Client %RU32] GUEST_MSG_CANCEL\n", idClient)); 2059 rc = clientMsgCancel(idClient, cParms);2048 rc = pThis->clientMsgCancel(idClient, cParms); 2060 2049 break; 2061 2050 case GUEST_MSG_SKIP: 2062 2051 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", idClient)); 2063 rc = clientMsgSkip(idClient, hCall, cParms);2052 rc = pThis->clientMsgSkip(idClient, hCall, cParms); 2064 2053 break; 2065 2054 case GUEST_SESSION_PREPARE: 2066 2055 LogFlowFunc(("[Client %RU32] GUEST_SESSION_PREPARE\n", idClient)); 2067 rc = clientSessionPrepare(idClient, hCall, cParms, paParms);2056 rc = pThis->clientSessionPrepare(idClient, hCall, cParms, paParms); 2068 2057 break; 2069 2058 case GUEST_SESSION_CANCEL_PREPARED: 2070 2059 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CANCEL_PREPARED\n", idClient)); 2071 rc = clientSessionCancelPrepared(idClient, cParms, paParms);2060 rc = pThis->clientSessionCancelPrepared(idClient, cParms, paParms); 2072 2061 break; 2073 2062 case GUEST_SESSION_ACCEPT: 2074 2063 LogFlowFunc(("[Client %RU32] GUEST_SESSION_ACCEPT\n", idClient)); 2075 rc = clientSessionAccept(idClient, hCall, cParms, paParms);2064 rc = pThis->clientSessionAccept(idClient, hCall, cParms, paParms); 2076 2065 break; 2077 2066 case GUEST_SESSION_CLOSE: 2078 2067 LogFlowFunc(("[Client %RU32] GUEST_SESSION_CLOSE\n", idClient)); 2079 rc = clientSessionCloseOther(idClient, cParms, paParms);2068 rc = pThis->clientSessionCloseOther(idClient, cParms, paParms); 2080 2069 break; 2081 2070 … … 2086 2075 */ 2087 2076 default: 2088 rc = hostCallback(idFunction, cParms, paParms);2077 rc = pThis->hostCallback(idFunction, cParms, paParms); 2089 2078 break; 2090 2079 … … 2095 2084 case GUEST_MSG_WAIT: 2096 2085 LogFlowFunc(("[Client %RU32] GUEST_MSG_WAIT\n", idClient)); 2097 clientMsgOldGet(idClient, hCall, cParms, paParms);2086 pThis->clientMsgOldGet(idClient, hCall, cParms, paParms); 2098 2087 rc = VINF_HGCM_ASYNC_EXECUTE; 2099 2088 break; … … 2101 2090 case GUEST_MSG_SKIP_OLD: 2102 2091 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP_OLD\n", idClient)); 2103 rc = clientMsgOldSkip(idClient, cParms);2092 rc = pThis->clientMsgOldSkip(idClient, cParms); 2104 2093 break; 2105 2094 2106 2095 case GUEST_MSG_FILTER_SET: 2107 2096 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER_SET\n", idClient)); 2108 rc = clientMsgOldFilterSet(idClient, cParms, paParms);2097 rc = pThis->clientMsgOldFilterSet(idClient, cParms, paParms); 2109 2098 break; 2110 2099 … … 2119 2108 /* Tell the client that the call is complete (unblocks waiting). */ 2120 2109 LogFlowFunc(("[Client %RU32] Calling pfnCallComplete w/ rc=%Rrc\n", idClient, rc)); 2121 AssertPtr( mpHelpers);2122 mpHelpers->pfnCallComplete(hCall, rc);2110 AssertPtr(pThis->mpHelpers); 2111 pThis->mpHelpers->pfnCallComplete(hCall, rc); 2123 2112 } 2124 2113 } … … 2126 2115 2127 2116 /** 2128 * Service call handler for the host. 2129 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnHostCall} 2130 * @thread hgcm 2131 */ 2132 int GstCtrlService::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 2133 { 2134 LogFlowFunc(("fn=%RU32, cParms=%RU32, paParms=0x%p\n", eFunction, cParms, paParms)); 2135 2136 switch (eFunction) 2137 { 2138 default: 2139 return hostProcessCommand(eFunction, cParms, paParms); 2140 2141 /** @todo r=bird: Why is this here, I cannot find anyone using this in Main. 2142 * I thought the HOST_CANCEL_PENDING_WAITS was only for return to the _guest_ 2143 * when the root VBoxService wanted to shut down. */ 2144 case HOST_CANCEL_PENDING_WAITS: 2145 { 2146 LogFlowFunc(("HOST_CANCEL_PENDING_WAITS\n")); 2147 AssertFailed(); /* want to know who uses this function! */ 2148 ClientStateMapIter itClientState = mClientStateMap.begin(); 2149 while (itClientState != mClientStateMap.end()) 2150 { 2151 int rc2 = itClientState->second.CancelWaiting(); 2152 if (RT_FAILURE(rc2)) 2153 LogFlowFunc(("Cancelling waiting for client ID=%RU32 failed with rc=%Rrc", 2154 itClientState->first, rc2)); 2155 ++itClientState; 2156 } 2157 return VINF_SUCCESS; 2158 } 2159 } 2160 } 2161 2162 2163 int GstCtrlService::uninit(void) 2164 { 2117 * @interface_method_impl{VBOXHGCMSVCFNTABLE,pfnRegisterExtension, 2118 * Installs a host callback for notifications of property changes.} 2119 */ 2120 /*static*/ DECLCALLBACK(int) GstCtrlService::svcRegisterExtension(void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension) 2121 { 2122 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 2123 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 2124 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 2125 pSelf->mpfnHostCallback = pfnExtension; 2126 pSelf->mpvHostData = pvExtension; 2165 2127 return VINF_SUCCESS; 2166 2128 } 2167 2168 2129 2169 2130
Note:
See TracChangeset
for help on using the changeset viewer.