Changeset 75861 in vbox
- Timestamp:
- Dec 2, 2018 12:26:36 AM (6 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/GuestCtrlImplPrivate.h
r74734 r75861 1078 1078 int GetGuestError(void) const { return mGuestRc; } 1079 1079 int SignalExternal(IEvent *pEvent); 1080 const GuestEventTypes 1080 const GuestEventTypes &Types(void) { return mEventTypes; } 1081 1081 size_t TypeCount(void) { return mEventTypes.size(); } 1082 1082 … … 1140 1140 * for HGCM (VMMDev) communication. */ 1141 1141 Console *mConsole; 1142 /** The next upcoming context IDfor this object. */1142 /** The next context ID counter component for this object. */ 1143 1143 uint32_t mNextContextID; 1144 1144 /** Local listener for handling the waiting events -
trunk/src/VBox/Main/include/GuestSessionImpl.h
r75798 r75861 29 29 #include "GuestSessionImplTasks.h" 30 30 31 #include <iprt/asm.h> /** @todo r=bird: Needed for ASMBitSet() in GuestSession::Data constructor. Removed when 32 * that is moved into the class implementation file as it should be. */ 31 33 #include <deque> 32 34 … … 36 38 * Guest session implementation. 37 39 */ 38 class ATL_NO_VTABLE GuestSession :39 public GuestSessionWrap,40 public GuestBase40 class ATL_NO_VTABLE GuestSession 41 : public GuestSessionWrap 42 , public GuestBase 41 43 { 42 44 public: … … 245 247 struct SessionObject 246 248 { 247 /** Creation timestamp (in ms). */ 248 uint64_t tsCreatedMs; 249 /** Creation timestamp (in ms). 250 * @note not used by anyone at the moment. */ 251 uint64_t msBirth; 249 252 /** The object type. */ 250 253 SESSIONOBJECTTYPE enmType; … … 305 308 Guest *i_getParent(void) { return mParent; } 306 309 uint32_t i_getProtocolVersion(void) { return mData.mProtocolVersion; } 307 int i_objectRegister(SESSIONOBJECTTYPE enmType, uint32_t *puObjectID); 308 int i_objectRegisterEx(SESSIONOBJECTTYPE enmType, uint32_t fFlags, uint32_t *puObjectID); 310 int i_objectRegister(SESSIONOBJECTTYPE enmType, uint32_t *pidObject); 309 311 int i_objectUnregister(uint32_t uObjectID); 310 312 int i_pathRename(const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags, int *pGuestRc); … … 341 343 const ComObjPtr<EventSource> mEventSource; 342 344 345 /** @todo r=bird: One of the core points of the DATA sub-structures in Main is 346 * hinding implementation details and stuff that requires including iprt/asm.h. 347 * The way it's used here totally defeats that purpose. You need to make it 348 * a pointer to a anynmous Data struct and define that structure in 349 * GuestSessionImpl.cpp and allocate it in the Init() function. 350 */ 343 351 struct Data 344 352 { … … 367 375 /** Map of registered session objects (files, directories, ...). */ 368 376 SessionObjects mObjects; 369 /** Queue of object IDs which are not used anymore (free list).370 * Acts as a "free list" for the mObjects map. */371 SessionObjectsFree mObjectsFree;372 377 /** Guest control protocol version to be used. 373 378 * Guest Additions < VBox 4.3 have version 1, … … 379 384 * returned from the guest side. */ 380 385 int mRC; 386 /** Object ID allocation bitmap; clear bits are free, set bits are busy. */ 387 uint64_t bmObjectIds[VBOX_GUESTCTRL_MAX_OBJECTS / sizeof(uint64_t) / 8]; 381 388 382 389 Data(void) 383 390 : mpBaseEnvironment(NULL) 384 { } 391 { 392 RT_ZERO(bmObjectIds); 393 ASMBitSet(&bmObjectIds, VBOX_GUESTCTRL_MAX_OBJECTS - 1); /* Reserved for the session itself? */ 394 ASMBitSet(&bmObjectIds, 0); /* Let's reserve this too. */ 395 } 385 396 Data(const Data &rThat) 386 397 : mCredentials(rThat.mCredentials) … … 393 404 , mProcesses(rThat.mProcesses) 394 405 , mObjects(rThat.mObjects) 395 , mObjectsFree(rThat.mObjectsFree)396 406 , mProtocolVersion(rThat.mProtocolVersion) 397 407 , mTimeout(rThat.mTimeout) 398 408 , mRC(rThat.mRC) 399 { } 409 { 410 memcpy(&bmObjectIds, &rThat.bmObjectIds, sizeof(bmObjectIds)); 411 } 400 412 ~Data(void) 401 413 { -
trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp
r75854 r75861 160 160 alock.release(); 161 161 162 #ifdef DEBUG 162 163 bool fDispatch = true; 163 #ifdef DEBUG164 164 /* 165 165 * Pre-check: If we got a status message with an error and VERR_TOO_MUCH_DATA … … 188 188 } 189 189 } 190 if (fDispatch) 190 191 #endif 191 if (fDispatch)192 192 { 193 193 switch (pCtxCb->uFunction) -
trunk/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
r75801 r75861 37 37 #endif /* DEBUG */ 38 38 #include <iprt/fs.h> 39 #include <iprt/rand.h> 39 40 #include <iprt/time.h> 40 41 … … 648 649 649 650 GuestBase::GuestBase(void) 650 : mConsole(NULL) ,651 mNextContextID(0)651 : mConsole(NULL) 652 , mNextContextID(RTRandU32() % VBOX_GUESTCTRL_MAX_CONTEXTS) 652 653 { 653 654 } … … 791 792 792 793 uint32_t uCount = ASMAtomicIncU32(&mNextContextID); 793 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)794 if (uCount >= VBOX_GUESTCTRL_MAX_CONTEXTS) 794 795 uCount = 0; 795 796 796 uint32_t uNewContextID = 797 VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount); 797 uint32_t uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID, uObjectID, uCount); 798 798 799 799 *puContextID = uNewContextID; … … 812 812 * around once at a time. 813 813 * 814 * @returns IPRT status code. VERR_ALREADY_EXISTS if an event with the given session 815 * and object ID already has been registered. 814 * @returns IPRT status code. 815 * @retval VERR_ALREADY_EXISTS if an event with the given session and object ID 816 * already has been registered. r=bird: Incorrect, see explanation in 817 * registerWaitEventEx(). 816 818 * 817 819 * @param uSessionID Session ID to register wait event for. … … 827 829 828 830 /** 829 * Registers (creates) a new wait event based on a given session, object ID 830 * and a list of event types to wait for. 831 * 832 * From those IDs an unique context ID (CID) will be built, which only can be 833 * around once at a time. 834 * 835 * @returns IPRT status code. VERR_ALREADY_EXISTS if an event with the given session 836 * and object ID already has been registered. 831 * Creates and registers a new wait event object that waits on a set of events 832 * related to a given object within the session. 833 * 834 * From the session ID and object ID a one-time unique context ID (CID) is built 835 * for this wait object. Normally the CID is then passed to the guest along 836 * with a request, and the guest passed the CID back with the reply. The 837 * handler for the reply then emits a signal on the event type associated with 838 * the reply, which includes signalling the object returned by this method and 839 * the waking up the thread waiting on it. 840 * 841 * @returns VBox status code. 842 * @retval VERR_ALREADY_EXISTS if an event with the given session and object ID 843 * already has been registered. r=bird: No, this isn't when this is 844 * returned, it is returned when generateContextID() generates a 845 * duplicate. The duplicate being in the count part (bits 15:0) of the 846 * session ID. So, VERR_DUPLICATE would be more appropraite. 837 847 * 838 848 * @param uSessionID Session ID to register wait event for. … … 845 855 GuestWaitEvent **ppEvent) 846 856 { 857 AssertReturn(!lstEvents.empty(), VERR_INVALID_PARAMETER); 847 858 AssertPtrReturn(ppEvent, VERR_INVALID_POINTER); 848 859 849 uint32_t uContextID;850 int rc = generateContextID(uSessionID, uObjectID, & uContextID);851 if (RT_FAILURE(rc))852 return rc; 853 860 uint32_t idContext; 861 int rc = generateContextID(uSessionID, uObjectID, &idContext); 862 AssertRCReturn(rc, rc); 863 864 #if 1 /** @todo r=bird: Incorrect exception and memory handling, no strategy for dealing with duplicate IDs: */ 854 865 rc = RTCritSectEnter(&mWaitEventCritSect); 855 866 if (RT_SUCCESS(rc)) … … 857 868 try 858 869 { 859 GuestWaitEvent *pEvent = new GuestWaitEvent( uContextID, lstEvents);870 GuestWaitEvent *pEvent = new GuestWaitEvent(idContext, lstEvents); 860 871 AssertPtr(pEvent); 861 872 862 LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, uContextID));873 LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, idContext)); 863 874 864 875 /* Insert event into matching event group. This is for faster per-group … … 869 880 /* Check if the event group already has an event with the same 870 881 * context ID in it (collision). */ 871 GuestWaitEvents eventGroup = mWaitEventGroups[(*itEvents)]; 872 if (eventGroup.find( uContextID) == eventGroup.end())882 GuestWaitEvents eventGroup = mWaitEventGroups[(*itEvents)]; /** @todo r=bird: Why copy it? */ 883 if (eventGroup.find(idContext) == eventGroup.end()) 873 884 { 874 885 /* No, insert. */ 875 mWaitEventGroups[(*itEvents)].insert(std::pair<uint32_t, GuestWaitEvent *>( uContextID, pEvent));886 mWaitEventGroups[(*itEvents)].insert(std::pair<uint32_t, GuestWaitEvent *>(idContext, pEvent)); 876 887 } 877 888 else … … 885 896 { 886 897 /* Register event in regular event list. */ 887 if (mWaitEvents.find( uContextID) == mWaitEvents.end())898 if (mWaitEvents.find(idContext) == mWaitEvents.end()) 888 899 { 889 mWaitEvents[ uContextID] = pEvent;900 mWaitEvents[idContext] = pEvent; 890 901 } 891 902 else … … 905 916 rc = rc2; 906 917 } 907 908 918 return rc; 919 920 #else /** @todo r=bird: Version with proper exception handling, no leaks and limited duplicate CID handling: */ 921 922 GuestWaitEvent *pEvent = new GuestWaitEvent(idContext, lstEvents); 923 AssertReturn(pEvent, VERR_NO_MEMORY); 924 LogFlowThisFunc(("New event=%p, CID=%RU32\n", pEvent, idContext)); 925 926 rc = RTCritSectEnter(&mWaitEventCritSect); 927 if (RT_SUCCESS(rc)) 928 { 929 /* 930 * Check that we don't have any context ID collisions (should be very unlikely). 931 * 932 * The ASSUMPTION here is that mWaitEvents has all the same events as 933 * mWaitEventGroups, so it suffices to check one of the two. 934 */ 935 if (mWaitEvents.find(idContext) != mWaitEvents.end()) 936 { 937 uint32_t cTries = 0; 938 do 939 { 940 rc = generateContextID(uSessionID, uObjectID, &idContext); 941 AssertRCBreak(rc); 942 Log(("Duplicate! Trying a different context ID: %#x\n", idContext)); 943 if (mWaitEvents.find(idContext) != mWaitEvents.end()) 944 rc = VERR_ALREADY_EXISTS; 945 } while (RT_FAILURE_NP(rc) && cTries++ < 10); 946 } 947 if (RT_SUCCESS(rc)) 948 { 949 /* 950 * Insert event into matching event group. This is for faster per-group lookup of all events later. 951 */ 952 uint32_t cInserts = 0; 953 for (GuestEventTypes::const_iterator ItType = lstEvents.begin(); ItType != lstEvents.end(); ++ItType) 954 { 955 GuestWaitEvents &eventGroup = mWaitEventGroups[*ItType]; 956 if (eventGroup.find(idContext) == eventGroup.end()) 957 { 958 try 959 { 960 eventGroup.insert(std::pair<uint32_t, GuestWaitEvent *>(idContext, pEvent)); 961 cInserts++; 962 } 963 catch (std::bad_alloc &) 964 { 965 while (ItType != lstEvents.begin()) 966 { 967 --ItType; 968 mWaitEventGroups[*ItType].erase(idContext); 969 } 970 rc = VERR_NO_MEMORY; 971 break; 972 } 973 } 974 else 975 Assert(cInserts > 0); /* else: lstEvents has duplicate entries. */ 976 } 977 if (RT_SUCCESS(rc)) 978 { 979 Assert(cInserts > 0); 980 NOREF(cInserts); 981 982 /* 983 * Register event in the regular event list. 984 */ 985 try 986 { 987 mWaitEvents[idContext] = pEvent; 988 } 989 catch (std::bad_alloc &) 990 { 991 for (GuestEventTypes::const_iterator ItType = lstEvents.begin(); ItType != lstEvents.end(); ++ItType) 992 mWaitEventGroups[*ItType].erase(idContext); 993 rc = VERR_NO_MEMORY; 994 } 995 } 996 } 997 998 RTCritSectLeave(&mWaitEventCritSect); 999 } 1000 if (RT_SUCCESS(rc)) 1001 return rc; 1002 1003 delete pEvent; 1004 return rc; 1005 #endif 909 1006 } 910 1007 … … 920 1017 if (itGroup != mWaitEventGroups.end()) 921 1018 { 1019 #if 1 /** @todo r=bird: consider the other variant. */ 922 1020 GuestWaitEvents::iterator itEvents = itGroup->second.begin(); 923 1021 while (itEvents != itGroup->second.end()) … … 930 1028 VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(itEvents->first))); 931 1029 #endif 932 ComPtr<IEvent> pThisEvent = aEvent; 1030 ComPtr<IEvent> pThisEvent = aEvent; /** @todo r=bird: This means addref/release for each iteration. Isn't that silly? */ 933 1031 Assert(!pThisEvent.isNull()); 934 1032 int rc2 = itEvents->second->SignalExternal(aEvent); 935 1033 if (RT_SUCCESS(rc)) 936 rc = rc2; 1034 rc = rc2; /** @todo r=bird: This doesn't make much sense since it will only fail if not 1035 * properly initialized or major memory corruption. And if it's broken, why 1036 * don't you just remove it instead of leaving it in the group??? It would 1037 * make life so much easier here as you could just change the while condition 1038 * to while ((itEvents = itGroup->second.begin() != itGroup->second.end()) 1039 * and skip all this two step removal below. I'll put this in a #if 0 and show what I mean... */ 937 1040 938 1041 if (RT_SUCCESS(rc2)) 939 1042 { 1043 /** @todo r=bird: I don't follow the logic here. Why don't you just remove 1044 * it from all groups, including this one? You just have move the */ 1045 940 1046 /* Remove the event from all other event groups (except the 941 1047 * original one!) because it was signalled. */ … … 975 1081 #endif 976 1082 } 1083 #else 1084 /* Signal all events in the group, leaving the group empty afterwards. */ 1085 GuestWaitEvents::iterator ItWaitEvt; 1086 while ((ItWaitEvt = itGroup->second.begin()) != itGroup->second.end()) 1087 { 1088 LogFlowThisFunc(("Signalling event=%p, type=%ld (CID %#x: Session=%RU32, Object=%RU32, Count=%RU32) ...\n", 1089 ItWaitEvt->second, aType, ItWaitEvt->first, VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(ItWaitEvt->first), 1090 VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(ItWaitEvt->first), VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(ItWaitEvt->first))); 1091 1092 int rc2 = ItWaitEvt->second->SignalExternal(aEvent); 1093 AssertRC(rc2); 1094 1095 /* Take down the wait event object details before we erase it from this list and invalid ItGrpEvt. */ 1096 const GuestEventTypes &EvtTypes = ItWaitEvt->second->Types(); 1097 uint32_t idContext = ItWaitEvt->first; 1098 itGroup->second.erase(ItWaitEvt); 1099 1100 for (GuestEventTypes::const_iterator ItType = EvtTypes.begin(); ItType != EvtTypes.end(); ++ItType) 1101 { 1102 GuestEventGroup::iterator EvtTypeGrp = mWaitEventGroups.find(*ItType); 1103 if (EvtTypeGrp != mWaitEventGroups.end()) 1104 { 1105 ItWaitEvt = EvtTypeGrp->second.find(idContext); 1106 if (ItWaitEvt != EvtTypeGrp->second.end()) 1107 { 1108 LogFlowThisFunc(("Removing event %p (CID %#x) from type %d group\n", ItWaitEvt->second, idContext, *ItType)); 1109 EvtTypeGrp->second.erase(ItWaitEvt); 1110 LogFlowThisFunc(("%zu events left for type %d\n", EvtTypeGrp->second.size(), *ItType)); 1111 Assert(EvtTypeGrp->second.find(idContext) == EvtTypeGrp->second.end()); /* no duplicates */ 1112 } 1113 } 1114 } 1115 } 1116 #endif 977 1117 } 978 1118 … … 1035 1175 * 1036 1176 * @returns IPRT status code. 1037 * @param p Event Event to unregister (delete).1038 */ 1039 int GuestBase::unregisterWaitEvent(GuestWaitEvent *p Event)1040 { 1041 if (!p Event) /* Nothing to unregister. */1177 * @param pWaitEvt Wait event to unregister (delete). 1178 */ 1179 int GuestBase::unregisterWaitEvent(GuestWaitEvent *pWaitEvt) 1180 { 1181 if (!pWaitEvt) /* Nothing to unregister. */ 1042 1182 return VINF_SUCCESS; 1043 1183 … … 1045 1185 if (RT_SUCCESS(rc)) 1046 1186 { 1047 LogFlowThisFunc(("pEvent=%p\n", pEvent)); 1048 1187 LogFlowThisFunc(("pWaitEvt=%p\n", pWaitEvt)); 1188 1189 /** @todo r=bird: One way of optimizing this would be to use the pointer 1190 * instead of the context ID as index into the groups, i.e. revert the value 1191 * pair for the GuestWaitEvents type. 1192 * 1193 * An even more efficent way, would be to not use sexy std::xxx containers for 1194 * the types, but iprt/list.h, as that would just be a RTListNodeRemove call for 1195 * each type w/o needing to iterate much at all. I.e. add a struct { 1196 * RTLISTNODE, GuestWaitEvent *pSelf} array to GuestWaitEvent, and change 1197 * GuestEventGroup to std::map<VBoxEventType_T, RTListAnchorClass> 1198 * (RTListAnchorClass == RTLISTANCHOR wrapper with a constructor)). 1199 * 1200 * P.S. the try/catch is now longer needed after I changed pWaitEvt->Types() to 1201 * return a const reference rather than a copy of the type list (and it think it 1202 * is safe to assume iterators are not hitting the heap). Copy vs reference is 1203 * an easy mistake to make in C++. 1204 * 1205 * P.P.S. The mWaitEventGroups optimization is probably just a lot of extra work 1206 * with little payoff. 1207 */ 1049 1208 try 1050 1209 { 1051 1210 /* Remove the event from all event type groups. */ 1052 const GuestEventTypes lstTypes = pEvent->Types();1211 const GuestEventTypes &lstTypes = pWaitEvt->Types(); 1053 1212 for (GuestEventTypes::const_iterator itType = lstTypes.begin(); 1054 1213 itType != lstTypes.end(); ++itType) … … 1058 1217 while (itCurEvent != mWaitEventGroups[(*itType)].end()) 1059 1218 { 1060 if (itCurEvent->second == p Event)1219 if (itCurEvent->second == pWaitEvt) 1061 1220 { 1062 1221 mWaitEventGroups[(*itType)].erase(itCurEvent); 1063 1222 break; 1064 1223 } 1065 else 1066 ++itCurEvent; 1224 ++itCurEvent; 1067 1225 } 1068 1226 } 1069 1227 1070 1228 /* Remove the event from the general event list as well. */ 1071 GuestWaitEvents::iterator itEvent = mWaitEvents.find(p Event->ContextID());1229 GuestWaitEvents::iterator itEvent = mWaitEvents.find(pWaitEvt->ContextID()); 1072 1230 1073 1231 Assert(itEvent != mWaitEvents.end()); 1074 Assert(itEvent->second == p Event);1232 Assert(itEvent->second == pWaitEvt); 1075 1233 1076 1234 mWaitEvents.erase(itEvent); 1077 1235 1078 delete p Event;1079 p Event = NULL;1236 delete pWaitEvt; 1237 pWaitEvt = NULL; 1080 1238 } 1081 1239 catch (const std::exception &ex) … … 1094 1252 1095 1253 /** 1096 * Waits for a formerly registered guest event.1254 * Waits for an already registered guest wait event. 1097 1255 * 1098 1256 * @return IPRT status code. 1099 * @param p EventPointer to event to wait for.1100 * @param uTimeoutMSTimeout (in ms) for waiting.1257 * @param pWaitEvt Pointer to event to wait for. 1258 * @param msTimeout Timeout (in ms) for waiting. 1101 1259 * @param pType Event type of following IEvent. 1102 1260 * Optional. … … 1104 1262 * for this event. Optional. 1105 1263 */ 1106 int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t uTimeoutMS, 1107 VBoxEventType_T *pType, IEvent **ppEvent) 1264 int GuestBase::waitForEvent(GuestWaitEvent *pEvent, uint32_t msTimeout, VBoxEventType_T *pType, IEvent **ppEvent) 1108 1265 { 1109 1266 AssertPtrReturn(pEvent, VERR_INVALID_POINTER); … … 1111 1268 /* ppEvent is optional. */ 1112 1269 1113 int vrc = pEvent->Wait( uTimeoutMS);1270 int vrc = pEvent->Wait(msTimeout); 1114 1271 if (RT_SUCCESS(vrc)) 1115 1272 { 1116 1273 const ComPtr<IEvent> pThisEvent = pEvent->Event(); 1117 if ( !pThisEvent.isNull()) /* Having a VBoxEventType_ event is optional.*/1274 if (pThisEvent.isNotNull()) /* Having a VBoxEventType_ event is optional. */ /** @todo r=bird: misplaced comment? */ 1118 1275 { 1119 1276 if (pType) … … 1269 1426 } 1270 1427 1271 int GuestWaitEventBase::Wait(RTMSINTERVAL uTimeoutMS)1428 int GuestWaitEventBase::Wait(RTMSINTERVAL msTimeout) 1272 1429 { 1273 1430 int rc = VINF_SUCCESS; … … 1280 1437 AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); 1281 1438 1282 RTMSINTERVAL msInterval = uTimeoutMS; 1283 if (!uTimeoutMS) 1284 msInterval = RT_INDEFINITE_WAIT; 1285 rc = RTSemEventWait(mEventSem, msInterval); 1439 rc = RTSemEventWait(mEventSem, msTimeout ? msTimeout : RT_INDEFINITE_WAIT); 1286 1440 if (ASMAtomicReadBool(&mfAborted)) 1287 1441 rc = VERR_CANCELLED; … … 1301 1455 { 1302 1456 int rc2 = Init(uCID); 1303 AssertRC(rc2); /** @todo Throw exception here. */ 1457 AssertRC(rc2); /** @todo Throw exception here. */ /** @todo r=bird: add+use Init() instead. Will cause weird VERR_CANCELLED errors in GuestBase::signalWaitEvent. */ 1304 1458 1305 1459 mEventTypes = lstEvents; … … 1309 1463 { 1310 1464 int rc2 = Init(uCID); 1311 AssertRC(rc2); /** @todo Throw exception here. */ 1465 AssertRC(rc2); /** @todo Throw exception here. */ /** @todo r=bird: add+use Init() instead. Will cause weird VERR_CANCELLED errors in GuestBase::signalWaitEvent. */ 1312 1466 } 1313 1467 … … 1345 1499 int GuestWaitEvent::SignalExternal(IEvent *pEvent) 1346 1500 { 1501 /** @todo r=bird: VERR_CANCELLED is misleading. mEventSem can only be NIL if 1502 * not successfully initialized! */ 1347 1503 AssertReturn(mEventSem != NIL_RTSEMEVENT, VERR_CANCELLED); 1348 1504 -
trunk/src/VBox/Main/src-client/GuestFileImpl.cpp
r75737 r75861 295 295 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 296 296 297 /** @todo r=bird: Why do you have both a offset and a tell() function? 298 * After a ReadAt or WriteAt with a non-current offset, the tell() result will 299 * differ from this value, because mOffCurrent is only ever incremented with 300 * data read or written. */ 297 301 *aOffset = mData.mOffCurrent; 298 302 -
trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp
r75801 r75861 46 46 #include <iprt/file.h> /* For CopyTo/From. */ 47 47 #include <iprt/path.h> 48 #include <iprt/rand.h> 48 49 49 50 #include <VBox/com/array.h> … … 341 342 342 343 mData.mObjects.clear(); 343 mData.mObjectsFree.clear();344 344 345 345 mData.mEnvironmentChanges.reset(); … … 1017 1017 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1018 1018 1019 const uint32_t uObjectID= pDirectory->getObjectID();1020 1021 LogFlowFunc(("Removing directory (objectID=%RU32) ...\n", uObjectID));1022 1023 int rc = i_objectUnregister( uObjectID);1019 const uint32_t idObject = pDirectory->getObjectID(); 1020 1021 LogFlowFunc(("Removing directory (objectID=%RU32) ...\n", idObject)); 1022 1023 int rc = i_objectUnregister(idObject); 1024 1024 if (RT_FAILURE(rc)) 1025 1025 return rc; 1026 1026 1027 SessionDirectories::iterator itDirs = mData.mDirectories.find( uObjectID);1027 SessionDirectories::iterator itDirs = mData.mDirectories.find(idObject); 1028 1028 AssertReturn(itDirs != mData.mDirectories.end(), VERR_NOT_FOUND); 1029 1029 … … 1032 1032 1033 1033 LogFlowFunc(("Removing directory ID=%RU32 (session %RU32, now total %zu directories)\n", 1034 uObjectID, mData.mSession.mID, mData.mDirectories.size()));1034 idObject, mData.mSession.mID, mData.mDirectories.size())); 1035 1035 1036 1036 rc = pDirConsumed->i_onRemove(); … … 1162 1162 1163 1163 /* Register a new object ID. */ 1164 uint32_t uObjectID;1165 int rc = i_objectRegister(SESSIONOBJECTTYPE_DIRECTORY, & uObjectID);1164 uint32_t idObject; 1165 int rc = i_objectRegister(SESSIONOBJECTTYPE_DIRECTORY, &idObject); 1166 1166 if (RT_FAILURE(rc)) 1167 1167 return rc; … … 1175 1175 AssertPtr(pConsole); 1176 1176 1177 int vrc = pDirectory->init(pConsole, this /* Parent */, uObjectID, openInfo);1177 int vrc = pDirectory->init(pConsole, this /* Parent */, idObject, openInfo); 1178 1178 if (RT_FAILURE(vrc)) 1179 1179 return vrc; … … 1189 1189 { 1190 1190 /* Add the created directory to our map. */ 1191 mData.mDirectories[ uObjectID] = pDirectory;1191 mData.mDirectories[idObject] = pDirectory; 1192 1192 1193 1193 LogFlowFunc(("Added new guest directory \"%s\" (Session: %RU32) (now total %zu directories)\n", … … 1416 1416 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 1417 1417 1418 const uint32_t uObjectID= pFile->getObjectID();1419 1420 LogFlowFunc(("Removing file (objectID=%RU32) ...\n", uObjectID));1421 1422 int rc = i_objectUnregister( uObjectID);1418 const uint32_t idObject = pFile->getObjectID(); 1419 1420 LogFlowFunc(("Removing file (objectID=%RU32) ...\n", idObject)); 1421 1422 int rc = i_objectUnregister(idObject); 1423 1423 if (RT_FAILURE(rc)) 1424 1424 return rc; 1425 1425 1426 SessionFiles::iterator itFiles = mData.mFiles.find( uObjectID);1426 SessionFiles::iterator itFiles = mData.mFiles.find(idObject); 1427 1427 AssertReturn(itFiles != mData.mFiles.end(), VERR_NOT_FOUND); 1428 1428 … … 1520 1520 1521 1521 /* Register a new object ID. */ 1522 uint32_t uObjectID;1523 int rc = i_objectRegister(SESSIONOBJECTTYPE_FILE, & uObjectID);1522 uint32_t idObject; 1523 int rc = i_objectRegister(SESSIONOBJECTTYPE_FILE, &idObject); 1524 1524 if (RT_FAILURE(rc)) 1525 1525 return rc; … … 1533 1533 AssertPtr(pConsole); 1534 1534 1535 rc = pFile->init(pConsole, this /* GuestSession */, uObjectID, openInfo);1535 rc = pFile->init(pConsole, this /* GuestSession */, idObject, openInfo); 1536 1536 if (RT_FAILURE(rc)) 1537 1537 return rc; … … 1547 1547 { 1548 1548 /* Add the created file to our vector. */ 1549 mData.mFiles[ uObjectID] = pFile;1549 mData.mFiles[idObject] = pFile; 1550 1550 1551 1551 LogFlowFunc(("Added new guest file \"%s\" (Session: %RU32) (now total %zu files)\n", … … 2035 2035 2036 2036 /** 2037 * Registers an object to a session.2037 * Registers an object with the session, i.e. allocates an object ID. 2038 2038 * 2039 * @return VBox status code. 2040 * @param enmType Session object type to register. 2041 * @param puObjectID Returns registered object ID on success. Optional. 2039 * @return VBox status code. 2040 * @retval VERR_GSTCTL_MAX_OBJECTS_REACHED if the maximum of concurrent objects 2041 * is reached. 2042 * @param enmType Session object type to register. 2043 * @param pidObject Where to return the object ID on success. 2042 2044 */ 2043 int GuestSession::i_objectRegister(SESSIONOBJECTTYPE enmType, uint32_t *puObjectID) 2044 { 2045 return i_objectRegisterEx(enmType, 0 /* fFlags */, puObjectID); 2045 int GuestSession::i_objectRegister(SESSIONOBJECTTYPE enmType, uint32_t *pidObject) 2046 { 2047 /* 2048 * Pick a random bit as starting point. If it's in use, search forward 2049 * for a free one, wrapping around. We've reserved both the zero'th and 2050 * max-1 IDs (see Data constructor). 2051 */ 2052 uint32_t idObject = RTRandU32Ex(1, VBOX_GUESTCTRL_MAX_OBJECTS - 2); 2053 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2054 if (!ASMBitTestAndSet(&mData.bmObjectIds[0], idObject)) 2055 { /* likely */ } 2056 else if (mData.mObjects.size() < VBOX_GUESTCTRL_MAX_OBJECTS - 2 /* First and last are not used */) 2057 { 2058 /* Forward search. */ 2059 int iHit = ASMBitNextClear(&mData.bmObjectIds[0], VBOX_GUESTCTRL_MAX_OBJECTS, idObject); 2060 if (iHit < 0) 2061 iHit = ASMBitFirstClear(&mData.bmObjectIds[0], VBOX_GUESTCTRL_MAX_OBJECTS); 2062 AssertLogRelMsgReturn(iHit >= 0, ("object count: %#zu\n", mData.mObjects.size()), VERR_GSTCTL_MAX_OBJECTS_REACHED); 2063 idObject = iHit; 2064 AssertLogRelMsgReturn(!ASMBitTestAndSet(&mData.bmObjectIds[0], idObject), ("idObject=%#x\n", idObject), VERR_INTERNAL_ERROR_2); 2065 } 2066 else 2067 { 2068 LogFunc(("enmType=%RU32 -> VERR_GSTCTL_MAX_OBJECTS_REACHED!! (%zu objects)\n", enmType, mData.mObjects.size())); 2069 return VERR_GSTCTL_MAX_OBJECTS_REACHED; 2070 } 2071 2072 Log2Func(("enmType=%RU32 -> idObject=%RU32 (%zu objects)\n", enmType, idObject, mData.mObjects.size())); 2073 2074 try 2075 { 2076 mData.mObjects[idObject].enmType = enmType; 2077 mData.mObjects[idObject].msBirth = RTTimeMilliTS(); 2078 } 2079 catch (std::bad_alloc &) 2080 { 2081 ASMBitClear(&mData.bmObjectIds[0], idObject); 2082 return VERR_NO_MEMORY; 2083 } 2084 2085 alock.release(); 2086 2087 *pidObject = idObject; 2088 return VINF_SUCCESS; 2046 2089 } 2047 2090 2048 2091 /** 2049 * Registers an object to a session, extended version.2092 * Unregisters an object from a session. 2050 2093 * 2051 * @return VBox status code. VERR_GSTCTL_MAX_OBJECTS_REACHED if the maximum of concurrent objects is reached. 2052 * @param enmType Session object type to register. 2053 * @param fFlags Registration flags. Not used yet and must be 0. 2054 * @param puObjectID Returns registered object ID on success. Optional. 2094 * @retval VINF_SUCCESS on success. 2095 * @retval VERR_NOT_FOUND if the object ID was not found. 2096 * @param idObject Object ID to unregister. 2055 2097 */ 2056 int GuestSession::i_objectRegisterEx(SESSIONOBJECTTYPE enmType, uint32_t fFlags, uint32_t *puObjectID) 2057 { 2058 RT_NOREF(fFlags); 2059 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); 2060 2098 int GuestSession::i_objectUnregister(uint32_t idObject) 2099 { 2061 2100 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2062 2101 2063 2102 int rc = VINF_SUCCESS; 2064 2065 uint32_t uObjectID = 0; /* Shut up MSVC. */ 2066 2067 if (mData.mObjects.size() < VBOX_GUESTCTRL_MAX_OBJECTS - 1 /* Minus 1 for the session itself */) 2068 { 2069 SessionObjects::reverse_iterator itRend = mData.mObjects.rbegin(); 2070 if (itRend != mData.mObjects.rend()) 2071 uObjectID = itRend->first + 1; /* Last key plus 1. */ 2072 else 2073 uObjectID = 0; 2074 } 2075 else 2076 { 2077 /* Utilize our "free list" to get the next free object ID in the map. */ 2078 if (mData.mObjectsFree.size()) 2079 { 2080 /* Always re-use the oldest object ID to avoid trouble. */ 2081 uObjectID = mData.mObjectsFree.front(); 2082 mData.mObjectsFree.pop_front(); 2083 } 2084 else 2085 rc = VERR_GSTCTL_MAX_OBJECTS_REACHED; 2086 } 2087 2088 Log2Func(("enmType=%RU32, fFlags=%RU32 -> uObjectID=%RU32 (%zu objects, %zu on free list), rc=%Rrc\n", 2089 enmType, fFlags, uObjectID, mData.mObjects.size(), mData.mObjectsFree.size(), rc)); 2090 2091 if (RT_SUCCESS(rc)) 2092 { 2093 mData.mObjects[uObjectID].enmType = enmType; 2094 mData.mObjects[uObjectID].tsCreatedMs = RTTimeMilliTS(); 2095 2096 if (puObjectID) 2097 *puObjectID = uObjectID; 2098 } 2103 AssertMsgStmt(ASMBitTestAndClear(&mData.bmObjectIds, idObject), ("idObject=%#x\n", idObject), rc = VERR_NOT_FOUND); 2104 2105 SessionObjects::const_iterator ItObj = mData.mObjects.find(idObject); 2106 AssertMsgReturn(ItObj != mData.mObjects.end(), ("idObject=%#x\n", idObject), VERR_NOT_FOUND); 2107 mData.mObjects.erase(ItObj); 2099 2108 2100 2109 return rc; 2101 }2102 2103 /**2104 * Unregisters a formerly registered object from a session.2105 *2106 * @return VBox status code. VERR_NOT_FOUND if object to unregister was not found.2107 * @param uObjectID Object ID to unregister.2108 */2109 int GuestSession::i_objectUnregister(uint32_t uObjectID)2110 {2111 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);2112 2113 SessionObjects::const_iterator itObj = mData.mObjects.find(uObjectID);2114 if (itObj != mData.mObjects.end())2115 {2116 Log2Func(("uObjectID=%RU32 (now %zu objects in free list)\n", uObjectID, mData.mObjectsFree.size()));2117 2118 /* Note: Do not remove object from object list (mData.mObjects) here, as we continue operating2119 * on the free list (mData.mObjectsFree) if we reached the object list's maximum. */2120 2121 mData.mObjectsFree.push_back(uObjectID);2122 Assert(mData.mObjectsFree.size() <= VBOX_GUESTCTRL_MAX_OBJECTS);2123 return VINF_SUCCESS;2124 }2125 2126 AssertFailed();2127 return VERR_NOT_FOUND;2128 2110 } 2129 2111 … … 2283 2265 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 2284 2266 2285 const uint32_t uObjectID= pProcess->getObjectID();2286 2287 LogFlowFunc(("Removing process (objectID=%RU32) ...\n", uObjectID));2288 2289 int rc = i_objectUnregister( uObjectID);2267 const uint32_t idObject = pProcess->getObjectID(); 2268 2269 LogFlowFunc(("Removing process (objectID=%RU32) ...\n", idObject)); 2270 2271 int rc = i_objectUnregister(idObject); 2290 2272 if (RT_FAILURE(rc)) 2291 2273 return rc; 2292 2274 2293 SessionProcesses::iterator itProcs = mData.mProcesses.find( uObjectID);2275 SessionProcesses::iterator itProcs = mData.mProcesses.find(idObject); 2294 2276 AssertReturn(itProcs != mData.mProcesses.end(), VERR_NOT_FOUND); 2295 2277 … … 2302 2284 2303 2285 LogFlowFunc(("Removing process ID=%RU32 (session %RU32, guest PID %RU32, now total %zu processes)\n", 2304 uObjectID, mData.mSession.mID, uPID, mData.mProcesses.size()));2286 idObject, mData.mSession.mID, uPID, mData.mProcesses.size())); 2305 2287 2306 2288 rc = pProcess->i_onRemove(); … … 2380 2362 2381 2363 /* Register a new object ID. */ 2382 uint32_t uObjectID;2383 int rc = i_objectRegister(SESSIONOBJECTTYPE_PROCESS, & uObjectID);2364 uint32_t idObject; 2365 int rc = i_objectRegister(SESSIONOBJECTTYPE_PROCESS, &idObject); 2384 2366 if (RT_FAILURE(rc)) 2385 2367 return rc; … … 2390 2372 return VERR_COM_UNEXPECTED; 2391 2373 2392 rc = pProcess->init(mParent->i_getConsole() /* Console */, this /* Session */, uObjectID,2374 rc = pProcess->init(mParent->i_getConsole() /* Console */, this /* Session */, idObject, 2393 2375 procInfo, mData.mpBaseEnvironment); 2394 2376 if (RT_FAILURE(rc)) … … 2398 2380 try 2399 2381 { 2400 mData.mProcesses[ uObjectID] = pProcess;2382 mData.mProcesses[idObject] = pProcess; 2401 2383 2402 2384 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %zu processes)\n", 2403 mData.mSession.mID, uObjectID, mData.mProcesses.size()));2385 mData.mSession.mID, idObject, mData.mProcesses.size())); 2404 2386 2405 2387 alock.release(); /* Release lock before firing off event. */
Note:
See TracChangeset
for help on using the changeset viewer.