Changeset 45415 in vbox for trunk/src/VBox/HostServices
- Timestamp:
- Apr 8, 2013 9:40:42 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 84843
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/GuestControl/service.cpp
r45010 r45415 59 59 * Header Files * 60 60 *******************************************************************************/ 61 #define LOG_GROUP LOG_GROUP_HGCM 61 #ifdef LOG_GROUP 62 #undef LOG_GROUP 63 #endif 64 #define LOG_GROUP LOG_GROUP_GUEST_CONTROL 62 65 #include <VBox/HostServices/GuestControlSvc.h> 63 66 … … 84 87 85 88 /** Flag for indicating that the client only is interested in 86 * messages for specific contexts. */89 * messages of specific context IDs. */ 87 90 #define CLIENTSTATE_FLAG_CONTEXTFILTER RT_BIT(0) 88 91 … … 113 116 uint32_t AddRef(void) 114 117 { 118 #ifdef DEBUG_andy 119 LogFlowFunc(("Adding reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n", 120 this, mContextID, mRefCount + 1)); 121 #endif 115 122 return ++mRefCount; 116 123 } … … 118 125 uint32_t Release(void) 119 126 { 120 LogFlowFunc(("Releasing CID=%RU32, refCount=%RU32\n", 121 mContextID, mRefCount)); 122 127 #ifdef DEBUG_andy 128 LogFlowFunc(("Releasing reference pHostCmd=%p, CID=%RU32, new refCount=%RU32\n", 129 this, mContextID, mRefCount - 1)); 130 #endif 123 131 /* Release reference for current command. */ 124 132 Assert(mRefCount); … … 139 147 int Allocate(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 140 148 { 141 LogFlowFunc(("Allocating uMsg=%RU32, cParms=%RU32, paParms=%p\n",142 uMsg, cParms, paParms));149 LogFlowFunc(("Allocating pHostCmd=%p, uMsg=%RU32, cParms=%RU32, paParms=%p\n", 150 this, uMsg, cParms, paParms)); 143 151 144 152 if (!cParms) /* At least one parameter (context ID) must be present. */ … … 219 227 */ 220 228 rc = mpParms[0].getUInt32(&mContextID); 229 230 /* Set timestamp so that clients can distinguish between already 231 * processed commands and new ones. */ 232 mTimestamp = RTTimeNanoTS(); 221 233 } 222 234 … … 232 244 void Free(void) 233 245 { 234 AssertMsg(mRefCount == 0, (" CommandCID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n",235 mContextID, mRefCount));236 237 LogFlowFunc(("Freeing host command CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",238 mContextID, mMsgType, mParmCount, mpParms));246 AssertMsg(mRefCount == 0, ("pHostCmd=%p, CID=%RU32 still being used by a client (%RU32 refs), cannot free yet\n", 247 this, mContextID, mRefCount)); 248 249 LogFlowFunc(("Freeing host command pHostCmd=%p, CID=%RU32, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 250 this, mContextID, mMsgType, mParmCount, mpParms)); 239 251 240 252 for (uint32_t i = 0; i < mParmCount; i++) … … 260 272 mParmCount = 0; 261 273 262 /* Removes the command from its list */263 RTListNodeRemove(&Node);274 /* Removes the command from its list */ 275 RTListNodeRemove(&Node); 264 276 } 265 277 … … 274 286 int CopyTo(VBOXHGCMSVCPARM paDstParms[], uint32_t cDstParms) const 275 287 { 288 LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mContextID=%RU32\n", 289 this, mMsgType, mParmCount, mContextID)); 290 276 291 int rc = VINF_SUCCESS; 277 292 if (cDstParms != mParmCount) … … 294 309 else 295 310 { 296 #ifdef DEBUG_andy297 LogFlowFunc(("\tmpParms[%RU32] type = %RU32\n",298 i, mpParms[i].type));299 #endif300 311 switch (mpParms[i].type) 301 312 { … … 362 373 int rc; 363 374 364 LogFlowFunc((" mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n",365 mMsgType, mParmCount, mpParms));375 LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 376 this, mMsgType, mParmCount, mpParms)); 366 377 367 378 /* Does the current host command need more parameter space which … … 392 403 } 393 404 394 LogFlowFunc(("Returned with rc=%Rrc\n", rc));395 405 return rc; 396 406 } … … 400 410 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 401 411 402 LogFlowFunc(("mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 403 mMsgType, mParmCount, mpParms)); 404 LogFlowFunc(("Telling client the next upcoming message type=%RU32, count=%RU32\n", 405 mMsgType, mParmCount)); 412 LogFlowFunc(("pHostCmd=%p, mMsgType=%RU32, mParmCount=%RU32, mpParms=%p\n", 413 this, mMsgType, mParmCount, mpParms)); 406 414 407 415 if (pConnection->mNumParms >= 2) … … 431 439 /** Dynamic structure for holding the HGCM parms */ 432 440 uint32_t mMsgType; 441 /** Number of HGCM parameters. */ 433 442 uint32_t mParmCount; 443 /** Array of HGCM parameters. */ 434 444 PVBOXHGCMSVCPARM mpParms; 445 /** Incoming timestamp (us). */ 446 uint64_t mTimestamp; 435 447 } HostCommand; 448 typedef std::list< HostCommand *> HostCmdList; 449 typedef std::list< HostCommand *>::iterator HostCmdListIter; 450 typedef std::list< HostCommand *>::const_iterator HostCmdListIterConst; 436 451 437 452 /** … … 459 474 { 460 475 ClientState(void) 461 : mSvcHelpers(NULL), 476 : mID(0), 477 mSvcHelpers(NULL), 462 478 mFlags(0), mContextFilter(0), 463 mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 464 mIsPending(false) {} 465 466 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers) 467 : mSvcHelpers(pSvcHelpers), 479 mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 480 mHostCmdTS(0), 481 mIsPending(false) { } 482 483 ClientState(PVBOXHGCMSVCHELPERS pSvcHelpers, uint32_t uClientID) 484 : mID(uClientID), 485 mSvcHelpers(pSvcHelpers), 468 486 mFlags(0), mContextFilter(0), 469 mpHostCmd(NULL), mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 470 mIsPending(false) {} 487 mHostCmdRc(VINF_SUCCESS), mHostCmdTries(0), 488 mHostCmdTS(0), 489 mIsPending(false) { } 490 491 void DequeueAll(void) 492 { 493 HostCmdListIter curItem = mHostCmdList.begin(); 494 while (curItem != mHostCmdList.end()) 495 Dequeue(curItem++); 496 } 497 498 void DequeueCurrent(void) 499 { 500 HostCmdListIter curCmd = mHostCmdList.begin(); 501 if (curCmd != mHostCmdList.end()) 502 Dequeue(curCmd); 503 } 504 505 void Dequeue(HostCommand *pHostCmd) 506 { 507 AssertPtrReturnVoid(pHostCmd); 508 509 HostCmdListIter curItem = mHostCmdList.begin(); 510 while (curItem != mHostCmdList.end()) 511 { 512 if ((*curItem) == pHostCmd) 513 { 514 Dequeue(curItem); 515 break; 516 } 517 518 curItem++; 519 } 520 } 521 522 void Dequeue(HostCmdListIter &curItem) 523 { 524 HostCommand *pHostCmd = (*curItem); 525 AssertPtr(pHostCmd); 526 527 if (pHostCmd->Release() == 0) 528 { 529 LogFlowFunc(("[Client %RU32] Destroying pHostCmd=%p\n", 530 mID, (*curItem))); 531 532 delete pHostCmd; 533 pHostCmd = NULL; 534 } 535 536 mHostCmdList.erase(curItem); 537 538 /* Reset everything else. */ 539 mHostCmdRc = VINF_SUCCESS; 540 mHostCmdTries = 0; 541 } 542 543 int EnqueueCommand(HostCommand *pHostCmd) 544 { 545 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 546 547 int rc = VINF_SUCCESS; 548 549 try 550 { 551 mHostCmdList.push_back(pHostCmd); 552 pHostCmd->AddRef(); 553 } 554 catch (std::bad_alloc) 555 { 556 rc = VERR_NO_MEMORY; 557 } 558 559 return rc; 560 } 471 561 472 562 bool WantsHostCommand(const HostCommand *pHostCmd) const … … 475 565 476 566 #ifdef DEBUG_andy 477 LogFlowFunc(("mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x\n", 478 mFlags, pHostCmd->mContextID, mContextFilter, pHostCmd->mContextID & mContextFilter)); 567 LogFlowFunc(("mHostCmdTS=%RU64, pHostCmdTS=%RU64\n", 568 mHostCmdTS, pHostCmd->mTimestamp)); 569 #endif 570 571 /* Only process newer commands. */ 572 if (pHostCmd->mTimestamp <= mHostCmdTS) 573 return false; 574 575 #ifdef DEBUG_andy 576 LogFlowFunc(("[Client %RU32] mFlags=%x, mContextID=%RU32, mContextFilter=%x, filterRes=%x, sessionID=%RU32\n", 577 mID, mFlags, pHostCmd->mContextID, mContextFilter, 578 pHostCmd->mContextID & mContextFilter, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pHostCmd->mContextID))); 479 579 #endif 480 580 /* 481 581 * If a sesseion filter is set, only obey those sessions we're interested in. 482 582 */ 583 bool fWant = false; 483 584 if (mFlags & CLIENTSTATE_FLAG_CONTEXTFILTER) 484 585 { 485 586 if ((pHostCmd->mContextID & mContextFilter) == mContextFilter) 486 returntrue;587 fWant = true; 487 588 } 488 589 else /* Client is interested in all commands. */ 489 returntrue;490 491 return f alse;590 fWant = true; 591 592 return fWant; 492 593 } 493 594 … … 496 597 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 497 598 498 LogFlowFunc(("mIsPending=%RTbool, mpHostCmd=%p, CID=%RU32, type=%RU32\n",499 mIsPending, mpHostCmd,500 mpHostCmd ? mpHostCmd->mContextID : 0,501 mpHostCmd ? mpHostCmd->mMsgType : 0));502 503 599 if (mIsPending) 504 600 { 505 LogFlowFunc((" Client already is in pending mode\n"));601 LogFlowFunc(("[Client %RU32] Already is in pending mode\n", mID)); 506 602 507 603 /* … … 511 607 } 512 608 513 if (m pHostCmd == NULL)609 if (mHostCmdList.empty()) 514 610 { 515 611 AssertMsg(mIsPending == false, 516 ("Client %p already is pending but tried to receive a new host command\n", this));517 518 mPending .mHandle = pConnection->mHandle;519 mPending .mNumParms = pConnection->mNumParms;520 mPending .mParms = pConnection->mParms;612 ("Client ID=%RU32 already is pending but tried to receive a new host command\n", mID)); 613 614 mPendingCon.mHandle = pConnection->mHandle; 615 mPendingCon.mNumParms = pConnection->mNumParms; 616 mPendingCon.mParms = pConnection->mParms; 521 617 522 618 mIsPending = true; 523 619 524 LogFlowFunc((" Client now is in pending mode\n"));620 LogFlowFunc(("[Client %RU32] Is now in pending mode\n", mID)); 525 621 526 622 /* … … 538 634 } 539 635 540 int SetNextCommand(HostCommand *pHostCmd) 541 { 636 int Run(const ClientConnection *pConnection, 637 HostCommand *pHostCmd) 638 { 639 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 542 640 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 543 641 544 mpHostCmd = pHostCmd;545 AssertPtr(mpHostCmd);546 mpHostCmd->AddRef();547 548 /* Create a command context to keep track of client-specific549 * information about a certain command. */550 Assert(mContextMap.find(mpHostCmd->mContextID) == mContextMap.end());551 mContextMap[mpHostCmd->mContextID] = ClientContext(mpHostCmd);552 /** @todo Exception handling! */553 554 LogFlowFunc(("Assigning next host comamnd CID=%RU32, cmdType=%RU32, cmdParms=%RU32, new refCount=%RU32\n",555 mpHostCmd->mContextID, mpHostCmd->mMsgType, mpHostCmd->mParmCount, mpHostCmd->mRefCount));556 557 return VINF_SUCCESS;558 }559 560 int Run(const ClientConnection *pConnection,561 const RTLISTANCHOR *pHostCmdList)562 {563 642 int rc = VINF_SUCCESS; 564 643 565 LogFlowFunc(("Client pConnection=%p, pHostCmdList=%p\n", 566 pConnection, pHostCmdList)); 567 LogFlowFunc(("Client hostCmd=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n", 568 mpHostCmd, mHostCmdRc, mHostCmdTries)); 569 570 /* No current command? Try getting a new one to process now. */ 571 if (mpHostCmd == NULL) 572 { 573 /* Get the next host command the clienet is interested in. */ 574 bool fFoundCmd = false; 575 HostCommand *pCurCmd; 576 RTListForEach(pHostCmdList, pCurCmd, HostCommand, Node) 644 LogFlowFunc(("[Client %RU32] pConnection=%p, mHostCmdRc=%Rrc, mHostCmdTries=%RU32\n", 645 mID, pConnection, mHostCmdRc, mHostCmdTries)); 646 647 mHostCmdRc = SendReply(pConnection, pHostCmd); 648 LogFlowFunc(("[Client %RU32] Processing pHostCmd=%p ended with rc=%Rrc\n", 649 mID, pHostCmd, mHostCmdRc)); 650 651 bool fRemove = false; 652 if (RT_FAILURE(mHostCmdRc)) 653 { 654 mHostCmdTries++; 655 656 /* 657 * If the client understood the message but supplied too little buffer space 658 * don't send this message again and drop it after 3 unsuccessful attempts. 659 * The host then should take care of next actions (maybe retry it with a smaller buffer). 660 */ 661 if (mHostCmdRc == VERR_TOO_MUCH_DATA) 577 662 { 578 fFoundCmd = WantsHostCommand(pCurCmd); 579 if (fFoundCmd) 580 { 581 int rc2 = SetNextCommand(pCurCmd); 582 if (RT_SUCCESS(rc2)) 583 break; 584 } 585 } 586 587 LogFlowFunc(("Client %s new command\n", 588 fFoundCmd ? "found" : "did not find a")); 589 590 /* If no new command was found, set client into pending state. */ 591 if (!fFoundCmd) 592 rc = SetPending(pConnection); 593 } 594 595 if (mpHostCmd) 596 { 597 AssertPtr(mpHostCmd); 598 mHostCmdRc = SendReply(pConnection, mpHostCmd); 599 LogFlowFunc(("Processing command CID=%RU32 ended with rc=%Rrc\n", 600 mpHostCmd->mContextID, mHostCmdRc)); 601 602 bool fRemove = false; 603 if (RT_FAILURE(mHostCmdRc)) 604 { 605 mHostCmdTries++; 606 607 /* 608 * If the client understood the message but supplied too little buffer space 609 * don't send this message again and drop it after 3 unsuccessful attempts. 610 * The host then should take care of next actions (maybe retry it with a smaller buffer). 611 */ 612 if ( mHostCmdRc == VERR_TOO_MUCH_DATA 613 && mHostCmdTries >= 3) 614 { 615 fRemove = true; 616 } 617 /* Client did not understand the message or something else weird happened. Try again one 618 * more time and drop it if it didn't get handled then. */ 619 else if (mHostCmdTries > 1) 663 if (mHostCmdTries >= 3) 620 664 fRemove = true; 621 665 } 666 /* Client did not understand the message or something else weird happened. Try again one 667 * more time and drop it if it didn't get handled then. */ 668 else if (mHostCmdTries > 1) 669 fRemove = true; 670 } 671 else 672 fRemove = true; /* Everything went fine, remove it. */ 673 674 LogFlowFunc(("[Client %RU32] Tried pHostCmd=%p for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n", 675 mID, pHostCmd, mHostCmdTries, mHostCmdRc, fRemove)); 676 677 if (RT_SUCCESS(rc)) 678 rc = mHostCmdRc; 679 680 if (fRemove) 681 Dequeue(pHostCmd); 682 683 LogFlowFunc(("[Client %RU32] Returned with rc=%Rrc\n", mID, rc)); 684 return rc; 685 } 686 687 int RunCurrent(const ClientConnection *pConnection) 688 { 689 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 690 691 int rc; 692 if (mHostCmdList.empty()) 693 { 694 rc = SetPending(pConnection); 695 } 696 else 697 { 698 AssertMsgReturn(!mIsPending, 699 ("Client ID=%RU32 still is in pending mode; can't use another connection\n", mID), VERR_INVALID_PARAMETER); 700 701 HostCmdListIter curCmd = mHostCmdList.begin(); 702 Assert(curCmd != mHostCmdList.end()); 703 HostCommand *pHostCmd = (*curCmd); 704 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 705 706 rc = Run(pConnection, pHostCmd); 707 } 708 709 return rc; 710 } 711 712 int Wakeup(void) 713 { 714 int rc = VINF_NO_CHANGE; 715 716 if (mIsPending) 717 { 718 LogFlowFunc(("[Client %RU32] Waking up ...\n", mID)); 719 720 rc = VINF_SUCCESS; 721 722 HostCmdListIter curCmd = mHostCmdList.begin(); 723 if (curCmd != mHostCmdList.end()) 724 { 725 HostCommand *pHostCmd = (*curCmd); 726 AssertPtrReturn(pHostCmd, VERR_INVALID_POINTER); 727 728 LogFlowFunc(("[Client %RU32] Current host command is pHostCmd=%p, CID=%RU32, cmdType=%RU32, cmdParms=%RU32, refCount=%RU32\n", 729 mID, pHostCmd, pHostCmd->mContextID, pHostCmd->mMsgType, pHostCmd->mParmCount, pHostCmd->mRefCount)); 730 731 rc = Run(&mPendingCon, pHostCmd); 732 } 622 733 else 623 fRemove = true; /* Everything went fine, remove it. */ 624 625 LogFlowFunc(("Client tried CID=%RU32 for %RU32 times, (last result=%Rrc, fRemove=%RTbool)\n", 626 mpHostCmd->mContextID, mHostCmdTries, mHostCmdRc, fRemove)); 627 628 if (fRemove) 629 { 630 /* Try fetching next command. */ 631 HostCommand *pCmdNext = RTListGetNext(pHostCmdList, mpHostCmd, HostCommand, Node); 632 633 LogFlowFunc(("Client removes itself from command CID=%RU32 (next command: %p, CID=%RU32)\n", 634 mpHostCmd->mContextID, pCmdNext, pCmdNext ? pCmdNext->mContextID : 0)); 635 636 /* Remove command from context map. */ 637 /** @todo Exception handling! */ 638 mContextMap.erase(mpHostCmd->mContextID); 639 640 /* Release reference for current command. */ 641 if (mpHostCmd->Release() == 0) 642 { 643 LogFlowFunc(("Destroying command CID=%RU32\n", 644 mpHostCmd->mContextID)); 645 646 RTMemFree(mpHostCmd); 647 } 648 649 /* Assign next command (if any) to this client. */ 650 if (pCmdNext) 651 { 652 rc = SetNextCommand(pCmdNext); 653 } 654 else 655 mpHostCmd = NULL; 656 657 /* Reset everything else. */ 658 mHostCmdRc = VINF_SUCCESS; 659 mHostCmdTries = 0; 660 } 661 662 if (RT_SUCCESS(rc)) 663 rc = mHostCmdRc; 664 } 665 666 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 667 return rc; 668 } 669 670 int RunNow(const ClientConnection *pConnection, 671 const PRTLISTANCHOR pHostCmdList) 672 { 673 AssertPtrReturn(pConnection, VERR_INVALID_POINTER); 674 AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER); 675 676 AssertMsgReturn(!mIsPending, ("Can't use another connection when client still is in pending mode\n"), 677 VERR_INVALID_PARAMETER); 678 679 int rc = Run(pConnection, pHostCmdList); 680 681 LogFlowFunc(("Returned with rc=%Rrc\n")); 682 return rc; 683 } 684 685 int Wakeup(const PRTLISTANCHOR pHostCmdList) 686 { 687 AssertPtrReturn(pHostCmdList, VERR_INVALID_POINTER); 688 AssertMsgReturn(mIsPending, ("Cannot wake up a client which is not in pending mode\n"), 689 VERR_INVALID_PARAMETER); 690 691 int rc = Run(&mPending, pHostCmdList); 692 693 /* Reset pending state. */ 694 mIsPending = false; 695 696 LogFlowFunc(("Returned with rc=%Rrc\n")); 697 return rc; 734 AssertMsgFailed(("Waking up client ID=%RU32 with no host command in queue is a bad idea\n", mID)); 735 736 return rc; 737 } 738 739 return VINF_NO_CHANGE; 698 740 } 699 741 700 742 int CancelWaiting(int rcPending) 701 743 { 702 LogFlowFunc((" Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n",703 rcPending, mIsPending, mPending.mNumParms, mFlags));744 LogFlowFunc(("[Client %RU32] Cancelling waiting with %Rrc, isPending=%RTbool, pendingNumParms=%RU32, flags=%x\n", 745 mID, rcPending, mIsPending, mPendingCon.mNumParms, mFlags)); 704 746 705 747 if ( mIsPending 706 && mPending .mNumParms >= 2)707 { 708 mPending .mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */709 mPending .mParms[1].setUInt32(0); /* Required parameters for message. */748 && mPendingCon.mNumParms >= 2) 749 { 750 mPendingCon.mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */ 751 mPendingCon.mParms[1].setUInt32(0); /* Required parameters for message. */ 710 752 711 753 AssertPtr(mSvcHelpers); 712 mSvcHelpers->pfnCallComplete(mPending .mHandle, rcPending);754 mSvcHelpers->pfnCallComplete(mPendingCon.mHandle, rcPending); 713 755 714 756 mIsPending = false; … … 740 782 } 741 783 784 /* Reset pending status. */ 785 mIsPending = false; 786 742 787 /* In any case the client did something, so complete 743 788 * the pending call with the result we just got. */ … … 745 790 mSvcHelpers->pfnCallComplete(pConnection->mHandle, rc); 746 791 747 LogFlowFunc((" pConnection=%p, pHostCmd=%p, rc=%Rrc\n",748 pConnection, pHostCmd, rc));792 LogFlowFunc(("[Client %RU32] pConnection=%p, pHostCmd=%p, replyRc=%Rrc\n", 793 mID, pConnection, pHostCmd, rc)); 749 794 return rc; 750 795 } 751 796 752 797 PVBOXHGCMSVCHELPERS mSvcHelpers; 798 /** The client's ID. */ 799 uint32_t mID; 753 800 /** Client flags. @sa CLIENTSTATE_FLAG_ flags. */ 754 801 uint32_t mFlags; 755 802 /** The context ID filter, based on the flags set. */ 756 803 uint32_t mContextFilter; 757 /** Pointer to current host commandto process. */758 HostC ommand *mpHostCmd;804 /** Host command list to process. */ 805 HostCmdList mHostCmdList; 759 806 /** Last (most recent) rc after handling the 760 807 * host command. */ … … 763 810 * command to the according client. */ 764 811 uint32_t mHostCmdTries; 765 /** Map containing all context IDs a client is assigned to. */766 ClientContextMap mContextMap;812 /** Timestamp (us) of last host command processed. */ 813 uint64_t mHostCmdTS; 767 814 /** Flag indicating whether the client currently is pending. */ 768 815 bool mIsPending; 769 816 /** The client's pending connection. */ 770 ClientConnection mPending ;817 ClientConnection mPendingCon; 771 818 } ClientState; 772 819 typedef std::map< uint32_t, ClientState > ClientStateMap; … … 831 878 { 832 879 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 833 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));834 880 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 881 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 835 882 return pSelf->clientConnect(u32ClientID, pvClient); 836 883 } … … 845 892 { 846 893 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 847 LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));848 894 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 895 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 849 896 return pSelf->clientDisconnect(u32ClientID, pvClient); 850 897 } … … 863 910 { 864 911 AssertLogRelReturnVoid(VALID_PTR(pvService)); 865 LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n",866 pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));867 912 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 913 AssertPtrReturnVoid(pSelf); 868 914 pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms); 869 915 } … … 879 925 { 880 926 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 881 LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));882 927 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 928 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 883 929 return pSelf->hostCall(u32Function, cParms, paParms); 884 930 } … … 894 940 AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER); 895 941 SELF *pSelf = reinterpret_cast<SELF *>(pvService); 942 AssertPtrReturn(pSelf, VERR_INVALID_POINTER); 896 943 pSelf->mpfnHostCallback = pfnExtension; 897 944 pSelf->mpvHostData = pvExtension; … … 906 953 int clientGetCommand(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 907 954 int clientSetMsgFilter(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 955 int clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 908 956 int cancelHostCmd(uint32_t u32ContextID); 909 957 int cancelPendingWaits(uint32_t u32ClientID, int rcPending); … … 924 972 int Service::clientConnect(uint32_t u32ClientID, void *pvClient) 925 973 { 926 LogFlowFunc((" New client with ID=%RU32 connected\n", u32ClientID));974 LogFlowFunc(("[Client %RU32] Connected\n", u32ClientID)); 927 975 #ifdef VBOX_STRICT 928 976 ClientStateMapIterConst it = mClientStateMap.find(u32ClientID); … … 934 982 } 935 983 #endif 936 ClientState c s(mpHelpers);937 mClientStateMap[u32ClientID] = c s;984 ClientState clientState(mpHelpers, u32ClientID); 985 mClientStateMap[u32ClientID] = clientState; 938 986 /** @todo Exception handling! */ 939 987 return VINF_SUCCESS; … … 951 999 int Service::clientDisconnect(uint32_t u32ClientID, void *pvClient) 952 1000 { 953 LogFlowFunc((" Client with ID=%RU32 (%zu clients total) disconnected\n",1001 LogFlowFunc(("[Client %RU32] Disonnected (%zu clients total)\n", 954 1002 u32ClientID, mClientStateMap.size())); 955 1003 956 /* If this was the last connected (guest) client we need to 957 * unblock all eventually queued up (waiting) host calls. */ 1004 AssertMsg(mClientStateMap.size(), 1005 ("No clients in list anymore when there should (client ID=%RU32)\n", u32ClientID)); 1006 1007 int rc = VINF_SUCCESS; 1008 1009 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1010 AssertMsg(itClientState != mClientStateMap.end(), 1011 ("Clients ID=%RU32 not found in client list when it should be there\n", u32ClientID)); 1012 1013 if (itClientState != mClientStateMap.end()) 1014 { 1015 itClientState->second.DequeueAll(); 1016 1017 mClientStateMap.erase(itClientState); 1018 } 1019 958 1020 bool fAllClientsDisconnected = mClientStateMap.size() == 0; 959 1021 if (fAllClientsDisconnected) 960 LogFlowFunc(("No connected clients left, notifying all queued up host callbacks\n")); 961 962 /* 963 * Throw out all stale clients. 964 */ 965 int rc = VINF_SUCCESS; 966 967 ClientStateMapIter itClientState = mClientStateMap.begin(); 968 while ( itClientState != mClientStateMap.end() 969 && RT_SUCCESS(rc)) 970 { 971 /* 972 * Unblock/call back all queued items of the specified client 973 * or for all items in case there is no waiting client around 974 * anymore. 975 */ 976 if ( itClientState->first == u32ClientID 977 || fAllClientsDisconnected) 978 { 979 LogFlowFunc(("Cancelling %RU32 context(s) of client ID=%RU32\n", 980 itClientState->second.mContextMap.size(), u32ClientID)); 981 982 ClientContextMapIter itContext = itClientState->second.mContextMap.begin(); 983 while (itContext != itClientState->second.mContextMap.end()) 984 { 985 uint32_t uContextID = itContext->first; 986 987 /* 988 * Notify the host that clients with u32ClientID are no longer 989 * around and need to be cleaned up (canceling waits etc). 990 */ 991 LogFlowFunc(("Notifying CID=%RU32 of disconnect ...\n", uContextID)); 992 int rc2 = cancelHostCmd(uContextID); 993 if (RT_FAILURE(rc2)) 994 { 995 LogFlowFunc(("Cancelling host command with CID=%RU32 failed with rc=%Rrc\n", 996 uContextID, rc2)); 997 /* Keep going. */ 998 } 999 1000 AssertPtr(itContext->second.mpHostCmd); 1001 itContext->second.mpHostCmd->Release(); 1002 1003 itContext++; 1004 } 1005 1006 itClientState->second.mContextMap.clear(); 1007 1008 /** @todo Exception handling! */ 1009 mClientStateMap.erase(itClientState++); 1010 } 1011 else 1012 itClientState++; 1013 } 1014 1015 if (fAllClientsDisconnected) 1016 { 1022 { 1023 LogFlowFunc(("All clients disconnected, cancelling all host commands ...\n")); 1024 1017 1025 /* 1018 1026 * If all clients disconnected we also need to make sure that all buffered … … 1034 1042 } 1035 1043 1036 pCurCmd->Free();1037 1038 RTListNodeRemove(&pCurCmd->Node);1039 RTMemFree(pCurCmd);1044 while (pCurCmd->Release()); 1045 1046 delete pCurCmd; 1047 pCurCmd = NULL; 1040 1048 1041 1049 if (fLast) … … 1082 1090 thisCon.mParms = paParms; 1083 1091 1084 /* 1085 * If host command list is empty (nothing to do right now) just 1086 * defer the call until we got something to do (makes the client 1087 * wait). 1088 */ 1089 int rc; 1090 if (RTListIsEmpty(&mHostCmdList)) 1091 { 1092 rc = clientState.SetPending(&thisCon); 1093 } 1094 else 1095 { 1096 rc = clientState.RunNow(&thisCon, &mHostCmdList); 1097 } 1098 1099 LogFlowFunc(("Returned with rc=%Rrc\n", rc)); 1100 return rc; 1092 return clientState.RunCurrent(&thisCon); 1101 1093 } 1102 1094 … … 1123 1115 if (RT_SUCCESS(rc)) 1124 1116 { 1125 /* paParms[1] unused yet. */1126 1127 1117 ClientState &clientState = itClientState->second; 1128 1118 … … 1138 1128 } 1139 1129 1140 LogFlowFunc(("Returned with rc=%Rrc\n", rc));1141 1130 return rc; 1131 } 1132 1133 int Service::clientSkipMsg(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, 1134 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 1135 { 1136 /* 1137 * Lookup client in our list so that we can assign the context ID of 1138 * a command to that client. 1139 */ 1140 ClientStateMapIter itClientState = mClientStateMap.find(u32ClientID); 1141 AssertMsg(itClientState != mClientStateMap.end(), ("Client ID=%RU32 not found when it should be present\n", 1142 u32ClientID)); 1143 if (itClientState == mClientStateMap.end()) 1144 return VERR_NOT_FOUND; /* Should never happen. */ 1145 1146 if (cParms != 0) 1147 return VERR_INVALID_PARAMETER; 1148 1149 LogFlowFunc(("Client ID=%RU32 skipping message ...\n", u32ClientID)); 1150 1151 itClientState->second.DequeueCurrent(); 1152 1153 return VINF_SUCCESS; 1142 1154 } 1143 1155 … … 1228 1240 1229 1241 int rc; 1230 HostCommand *pHostCmd = (HostCommand*)RTMemAllocZ(sizeof(HostCommand)); 1231 if (pHostCmd) 1232 { 1242 1243 HostCommand *pHostCmd = NULL; 1244 try 1245 { 1246 pHostCmd = new HostCommand(); 1233 1247 rc = pHostCmd->Allocate(eFunction, cParms, paParms); 1234 1248 if (RT_SUCCESS(rc)) 1235 RTListAppend(&mHostCmdList, &pHostCmd->Node); 1236 } 1237 else 1249 /* rc = */ RTListAppend(&mHostCmdList, &pHostCmd->Node); 1250 } 1251 catch (std::bad_alloc) 1252 { 1238 1253 rc = VERR_NO_MEMORY; 1254 } 1239 1255 1240 1256 if (RT_SUCCESS(rc)) 1241 1257 { 1242 LogFlowFunc(("Handling host command CID=%RU32, numClients=%zu\n",1243 pHostCmd->mContextID, mClientStateMap.size()));1258 LogFlowFunc(("Handling host command CID=%RU32, eFunction=%RU32, cParms=%RU32, paParms=%p, numClients=%zu\n", 1259 pHostCmd->mContextID, eFunction, cParms, paParms, mClientStateMap.size())); 1244 1260 1245 1261 /* … … 1250 1266 uint32_t uClientsWokenUp = 0; 1251 1267 #endif 1252 1253 1268 ClientStateMapIter itClientState = mClientStateMap.begin(); 1254 1269 AssertMsg(itClientState != mClientStateMap.end(), ("Client state map is empty when it should not\n")); 1255 1270 while (itClientState != mClientStateMap.end()) 1256 1271 { 1257 if (itClientState->second.mIsPending) /* Only wake up pending clients. */ 1272 ClientState &clientState = itClientState->second; 1273 1274 /* If a client indicates that it it wants the new host command, 1275 * add a reference to not delete it.*/ 1276 if (clientState.WantsHostCommand(pHostCmd)) 1258 1277 { 1259 LogFlowFunc(("Waking up client ID=%RU32 (isPending=%RTbool) ...\n", 1260 itClientState->first, itClientState->second.mIsPending)); 1261 1262 ClientState &clientState = itClientState->second; 1263 int rc2 = clientState.Wakeup(&mHostCmdList); 1264 LogFlowFunc(("Client ID=%RU32 wakeup ended with rc=%Rrc\n", 1265 itClientState->first, rc2)); 1266 #ifdef DEBUG 1278 clientState.EnqueueCommand(pHostCmd); 1279 1280 int rc2 = clientState.Wakeup(); 1281 if (RT_FAILURE(rc2)) 1282 LogFlowFunc(("Waking up client ID=%RU32 failed with rc=%Rrc\n", 1283 itClientState->first, rc2)); 1284 #ifdef DEBUG_andy 1267 1285 uClientsWokenUp++; 1268 1286 #endif 1269 1287 } 1270 else1271 LogFlowFunc(("Client ID=%RU32 is not in pending state\n",1272 itClientState->first));1273 1288 1274 1289 itClientState++; 1275 1290 } 1276 1291 1277 #ifdef DEBUG 1278 LogFlowFunc(("%RU32 clients have been succcessfully woken up\n", 1279 uClientsWokenUp)); 1292 #ifdef DEBUG_andy 1293 LogFlowFunc(("%RU32 clients have been woken up\n", uClientsWokenUp)); 1280 1294 #endif 1281 1295 } 1282 1296 1283 LogFlowFunc(("Returned with rc=%Rrc\n", rc));1284 1297 return rc; 1285 1298 } … … 1299 1312 { 1300 1313 int rc = VINF_SUCCESS; 1301 LogFlowFunc((" u32ClientID=%RU32, fn=%RU32, cParms=%RU32, paParms=0x%p\n",1314 LogFlowFunc(("[Client %RU32] eFunction=%RU32, cParms=%RU32, paParms=0x%p\n", 1302 1315 u32ClientID, eFunction, cParms, paParms)); 1303 1316 try … … 1308 1321 if (eFunction == GUEST_MSG_WAIT) 1309 1322 { 1310 LogFlowFunc((" GUEST_MSG_GET\n"));1323 LogFlowFunc(("[Client %RU32] GUEST_MSG_GET\n", u32ClientID)); 1311 1324 rc = clientGetCommand(u32ClientID, callHandle, cParms, paParms); 1312 1325 } … … 1321 1334 */ 1322 1335 case GUEST_CANCEL_PENDING_WAITS: 1323 LogFlowFunc((" GUEST_CANCEL_PENDING_WAITS\n"));1336 LogFlowFunc(("[Client %RU32] GUEST_CANCEL_PENDING_WAITS\n", u32ClientID)); 1324 1337 rc = cancelPendingWaits(u32ClientID, VINF_SUCCESS /* Pending result */); 1325 1338 break; … … 1330 1343 */ 1331 1344 case GUEST_MSG_FILTER: 1332 LogFlowFunc((" GUEST_MSG_FILTER\n"));1345 LogFlowFunc(("[Client %RU32] GUEST_MSG_FILTER\n", u32ClientID)); 1333 1346 rc = clientSetMsgFilter(u32ClientID, callHandle, cParms, paParms); 1347 break; 1348 1349 /* 1350 * The guest only wants skip the currently assigned messages. 1351 * Since VBox 4.3+. 1352 */ 1353 case GUEST_MSG_SKIP: 1354 LogFlowFunc(("[Client %RU32] GUEST_MSG_SKIP\n", u32ClientID)); 1355 rc = clientSkipMsg(u32ClientID, callHandle, cParms, paParms); 1334 1356 break; 1335 1357 … … 1416 1438 * @copydoc VBOXHGCMSVCLOAD 1417 1439 */ 1418 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *p table)1440 extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable) 1419 1441 { 1420 1442 int rc = VINF_SUCCESS; 1421 1443 1422 LogFlowFunc(("p table = %p\n", ptable));1423 1424 if (!VALID_PTR(p table))1444 LogFlowFunc(("pTable=%p\n", pTable)); 1445 1446 if (!VALID_PTR(pTable)) 1425 1447 { 1426 1448 rc = VERR_INVALID_PARAMETER; … … 1428 1450 else 1429 1451 { 1430 LogFlowFunc(("p table->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));1431 1432 if ( p table->cbSize != sizeof (VBOXHGCMSVCFNTABLE)1433 || p table->u32Version != VBOX_HGCM_SVC_VERSION)1452 LogFlowFunc(("pTable->cbSize=%d, pTable->u32Version=0x%08X\n", pTable->cbSize, pTable->u32Version)); 1453 1454 if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE) 1455 || pTable->u32Version != VBOX_HGCM_SVC_VERSION) 1434 1456 { 1435 1457 rc = VERR_VERSION_MISMATCH; … … 1440 1462 /* No exceptions may propagate outside. */ 1441 1463 try { 1442 apService = std::auto_ptr<Service>(new Service(p table->pHelpers));1464 apService = std::auto_ptr<Service>(new Service(pTable->pHelpers)); 1443 1465 } catch (int rcThrown) { 1444 1466 rc = rcThrown; … … 1453 1475 * because we're a class which can have members for that :-). 1454 1476 */ 1455 p table->cbClient = 0;1477 pTable->cbClient = 0; 1456 1478 1457 1479 /* Register functions. */ 1458 p table->pfnUnload = Service::svcUnload;1459 p table->pfnConnect = Service::svcConnect;1460 p table->pfnDisconnect = Service::svcDisconnect;1461 p table->pfnCall = Service::svcCall;1462 p table->pfnHostCall = Service::svcHostCall;1463 p table->pfnSaveState = NULL; /* The service is stateless, so the normal */1464 p table->pfnLoadState = NULL; /* construction done before restoring suffices */1465 p table->pfnRegisterExtension = Service::svcRegisterExtension;1480 pTable->pfnUnload = Service::svcUnload; 1481 pTable->pfnConnect = Service::svcConnect; 1482 pTable->pfnDisconnect = Service::svcDisconnect; 1483 pTable->pfnCall = Service::svcCall; 1484 pTable->pfnHostCall = Service::svcHostCall; 1485 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */ 1486 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */ 1487 pTable->pfnRegisterExtension = Service::svcRegisterExtension; 1466 1488 1467 1489 /* Service specific initialization. */ 1468 p table->pvService = apService.release();1490 pTable->pvService = apService.release(); 1469 1491 } 1470 1492 } 1471 1493 } 1472 1494 1473 LogFlowFunc((" returning %Rrc\n", rc));1495 LogFlowFunc(("Returning %Rrc\n", rc)); 1474 1496 return rc; 1475 1497 }
Note:
See TracChangeset
for help on using the changeset viewer.