VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/ObjectsTracker.cpp@ 107866

Last change on this file since 107866 was 107866, checked in by vboxsync, 3 weeks ago

bugref:10806. Added documentation as the comment. It contains some description and the examples.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.4 KB
Line 
1/* $Id: ObjectsTracker.cpp 107866 2025-01-21 05:41:50Z vboxsync $ */
2/** @file
3 * VirtualBox Object tracker implementation
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/*
29 * Sometimes user wants to check or retrieve data or information about objects that may not exist at the time
30 * the user requests such objects. For example, some action was completed some time ago and all data related to
31 * this action was deleted, but the user missed this moment and later still wants to know how the action was
32 * completed. If it were possible to store such objects for some time, it would help the user.
33 *
34 * Example with Progress object
35 * 1. When Progress object is created it’s added into TrackedObjectCollector (call setTracked() in Progress::FinalConstruct()).
36 *
37 * 2. User keeps the Progress Id. VirtualBox API returns Progress Id to user everywhere where its’ needed.
38 * When user wants to know the status of action he makes a request to VirtualBox calling the function
39 * VirtualBox::getTrackedObject(). This function looks through TrackedObjectCollector and retrieves the information
40 * about a requested object and if one exists there returns a pointer to IUnknown interface.
41 * This pointer should be converted to the appropriate interface type (IProgress in this case). Next the data are
42 * extracted using the interface functions.
43 *
44 * 2.1. Approach 1.
45 * Getting information about a tracked object using VirtualBox API (VirtualBox frontend or any external client)
46 * - Call VirtualBox::getTrackedObjectIds() with a requested interface name and get back the list of tracked objects.
47 * - Go through the list, call VirtualBox::getTrackedObject() for each Id from the list.
48 * - Convert IUnknown interface to the requested interface.
49 * - Retrieve information about an object.
50 *
51 * See the full example 1 below.
52 *
53 * 2.2. Approach 2
54 * Getting information about a tracked object on server side (VBoxSVC) is:
55 * - Call TrackedObjectsCollector::getObjIdsByClassIID() with the interface name IID (our case is IID_IProgress)
56 * and get back the list of tracked objects.
57 * - Go through the list, call TrackedObjectsCollectorState::getObj() for each Id from the list.
58 * - Convert IUnknown interface to the requested interface.
59 * - Retrieve information about an object.
60 *
61 * See the full example 2 below.
62 *
63 * 3. Class TrackedObjectData keeps some additional data about the tracked object as creation time, last access time,
64 * life time and etc.
65 *
66 * 4. The last access time is updated for the requested object if it's needed (in the class TrackedObjectData).
67 *
68 * 5. For managing the items stored in the TrackedObjectCollector, a new thread TrackedObjectsThread is launched
69 * in VirtualBox::init() function.
70 *
71 * 6. Periodically (1 sec at present), the thread TrackedObjectsThread goes through the list of tracked objects,
72 * measures the difference between the current time and the creation time, if this value is greater than the life
73 * time the object is marked as "lifetime expired" and next the idletime is started for this object. When the idle
74 * time is expired the object is removed from the TrackedObjectsCollector.
75 *
76 * 7. There is a special case for an object with lifetime = 0. This means that the object has an infinite lifetime.
77 * How to handle this case? The idea is that the reference count of an unused object is 1, since the object is only
78 * represented inside the TrackedObjectCollector. When the count is 1, we mark the lifetime as expired and update
79 * the object with new data. After this action, the logic becomes standard (see point 6).
80 *
81 * Addon.
82 * Example 1. Getting information about a Progress tracked object on server side (VBoxSVC)
83 *
84 * std::vector<com::Utf8Str> lObjIdMap;
85 * gTrackedObjectsCollector.getObjIdsByClassIID(IID_IProgress, lObjIdMap);
86 * for (const com::Utf8Str &item : lObjIdMap)
87 * {
88 * if (gTrackedObjectsCollector.checkObj(item.c_str()))
89 * {
90 * TrackedObjectData temp;
91 * gTrackedObjectsCollector.getObj(item.c_str(), temp);
92 * Log2(("Tracked Progress Object with objectId %s was found\n", temp.objectIdStr().c_str()));
93 *
94 * ComPtr<IProgress> pProgress;
95 * temp.getInterface()->QueryInterface(IID_IProgress, (void **)pProgress.asOutParam());
96 * if (pProgress.isNotNull())
97 * {
98 * com::Bstr reqId(aId.toString());
99 * Bstr foundId;
100 * pProgress->COMGETTER(Id)(foundId.asOutParam());
101 * if (reqId == foundId)
102 * {
103 * BOOL aCompleted;
104 * pProgress->COMGETTER(Completed)(&aCompleted);
105 *
106 * BOOL aCanceled;
107 * pProgress->COMGETTER(Canceled)(&aCanceled);
108 *
109 * aProgressObject = pProgress;
110 * return S_OK;
111 * }
112 * }
113 * }
114 * }
115 *
116 * Example 2. Getting information about a Progress tracked object using VirtualBox API
117 *
118 * Utf8Str strObjUuid; // passed from the client
119 * Utf8Str strIfaceName;// passed from the client
120 * ComPtr<IVirtualBox> pVirtualBox;// set before. Usually each client has own ComPtr<IVirtualBox>.
121 *
122 * com::SafeArray<BSTR> ObjIDsList;
123 * hrc = pVirtualBox->GetTrackedObjectIds(Bstr(strIfaceName).raw(), ComSafeArrayAsOutParam(ObjIDsList));
124 * if (SUCCEEDED(hrc))
125 * {
126 * map < Bstr, TrackedObjInfo_T > lObjInfoMap;
127 * for (size_t i = 0; i < ObjIDsList.size(); ++i)
128 * {
129 * Bstr bstrObjId = ObjIDsList[i];
130 * if (bstrObjId.equals(strObjUuid.c_str()))
131 * {
132 * TrackedObjInfo_T objInfo;
133 * hrc = pVirtualBox->GetTrackedObject(bstrObjId.raw(),
134 * objInfo.pIUnknown.asOutParam(),
135 * &objInfo.enmState,
136 * &objInfo.creationTime,
137 * &objInfo.deletionTime);
138 *
139 * // print tracked object information as state, creation time, deletion time
140 * // objInfo.enmState, objInfo.creationTime, objInfo.deletionTime
141 *
142 * if (objInfo.enmState != TrackedObjectState_Invalid)
143 * {
144 * // Conversion IUnknown -> IProgress
145 * ComPtr<IProgress> pObj;
146 * objInfo.pIUnknown->QueryInterface(IID_IProgress, (void **)pObj.asOutParam());
147 * if (pObj.isNotNull())
148 * //print Progress Object data as description, completion, cancellation etc.
149 * }
150 * break;
151 * }
152 * }
153 * }
154*/
155
156#define LOG_GROUP LOG_GROUP_MAIN
157
158#include "LoggingNew.h"
159#include "VirtualBoxBase.h"
160#include "ObjectsTracker.h"
161#include <iprt/log.h>
162#include <iprt/stream.h>
163#include <iprt/time.h>
164#include <iprt/asm.h>
165#include <stdexcept>
166
167typedef std::map<com::Utf8Str, TrackedObjectData>::iterator IterTrObjData_T;
168typedef std::map<com::Utf8Str, TrackedObjectData>::const_iterator ConstIterTrObjData_T;
169
170static Utf8Str trackedObjectStateToStr(TrackedObjectState_T aState)
171{
172 Utf8Str strState("None");
173 switch (aState)
174 {
175 case TrackedObjectState_Alive:
176 strState = "Alive";
177 break;
178 case TrackedObjectState_Deleted:
179 strState = "Deleted";
180 break;
181 case TrackedObjectState_Invalid:
182 strState = "Invalid";
183 break;
184 case TrackedObjectState_None:
185 default:
186 strState = "None";
187 break;
188 }
189
190 return strState;
191}
192
193/////////////////////////////////////////////////////////////////////////////
194// TrackedObjectData
195/////////////////////////////////////////////////////////////////////////////
196TrackedObjectData::TrackedObjectData():
197 m_componentName("noname"),
198 m_lifeTime(0),
199 m_idleTime(1),
200 m_state(TrackedObjectState_None),
201 m_pIface(NULL)
202 {
203}
204
205TrackedObjectData::TrackedObjectData(const com::Guid &aObjId,
206 const com::Guid &aClassIID,
207 uint64_t aLifeTime,
208 uint64_t aIdleTime,
209 IUnknown* aPtr):
210
211 m_objId(aObjId),
212 m_classIID(aClassIID),
213 m_componentName("noname"),
214 m_lifeTime(aLifeTime),
215 m_idleTime(aIdleTime),
216 m_fIdleTimeStart(false),
217 m_fLifeTimeExpired(false),
218 m_pIface(aPtr)
219{
220 RTTimeNow(unconst(&m_creationTime));
221 m_lastAccessTime = m_creationTime;
222 m_state = TrackedObjectState_Alive;
223}
224
225TrackedObjectData::TrackedObjectData(const TrackedObjectData & that)
226{
227 LogFlowFuncEnter();
228 if (this != &that)
229 {
230 m_objId = that.m_objId;
231 m_classIID = that.m_classIID;
232 m_componentName = that.m_componentName;
233 m_lifeTime = that.m_lifeTime;
234 m_idleTime = that.m_idleTime;
235 m_pIface = that.m_pIface;
236 m_creationTime = that.m_creationTime;
237 m_deletionTime = that.m_deletionTime;
238 m_lastAccessTime = that.m_lastAccessTime;
239 m_idleTimeStart = that.m_idleTimeStart;
240 m_fIdleTimeStart = that.m_fIdleTimeStart;
241 m_fLifeTimeExpired = that.m_fLifeTimeExpired;
242 m_state = that.m_state;
243 }
244}
245
246TrackedObjectData::~TrackedObjectData()
247{
248 Log2(("%s destructor\n", __FUNCTION__));
249 Log2(("DELETED Object %s (class IID %s)\n",
250 m_objId.toString().c_str(),
251 m_classIID.toString().c_str()
252 ));
253}
254
255TrackedObjectData &TrackedObjectData::operator=(const TrackedObjectData & that)
256{
257 LogFlowFuncEnter();
258 if (this != &that)
259 {
260 m_objId = that.m_objId;
261 m_classIID = that.m_classIID;
262 m_componentName = that.m_componentName;
263 m_lifeTime = that.m_lifeTime;
264 m_idleTime = that.m_idleTime;
265 m_pIface = that.m_pIface;
266 m_creationTime = that.m_creationTime;
267 m_deletionTime = that.m_deletionTime;
268 m_lastAccessTime = that.m_lastAccessTime;
269 m_idleTimeStart = that.m_idleTimeStart;
270 m_fIdleTimeStart = that.m_fIdleTimeStart;
271 m_fLifeTimeExpired = that.m_fLifeTimeExpired;
272 m_state = that.m_state;
273 }
274
275 return *this;
276}
277
278com::Utf8Str TrackedObjectData::updateLastAccessTime()
279{
280 RTTimeNow(&m_lastAccessTime);
281
282 char szTime[RTTIME_STR_LEN];
283 RTTimeSpecToString(&m_lastAccessTime, szTime, sizeof(szTime));
284 return com::Utf8Str(szTime);
285}
286
287/** @todo r=bird: why on earth does this return a string? */
288com::Utf8Str TrackedObjectData::initIdleTime()
289{
290 if (!m_fIdleTimeStart)
291 {
292 RTTimeNow(unconst(&m_deletionTime));
293 updateState(TrackedObjectState_Deleted);//Alive -> Deleted
294 RTTimeNow(unconst(&m_idleTimeStart));
295 m_fIdleTimeStart = true;
296 m_fLifeTimeExpired = true;
297 }
298
299 char szTime[RTTIME_STR_LEN];
300 RTTimeSpecToString(&m_idleTimeStart, szTime, sizeof(szTime));
301 return com::Utf8Str(szTime);
302}
303
304com::Utf8Str TrackedObjectData::creationTimeStr() const
305{
306 char szCreationTime[RTTIME_STR_LEN];
307 RTTimeSpecToString(&m_creationTime, szCreationTime, sizeof(szCreationTime));
308
309 return com::Utf8Str(szCreationTime);
310}
311
312TrackedObjectState_T TrackedObjectData::deletionTime(PRTTIMESPEC aTime) const
313{
314 if (m_state != TrackedObjectState_Alive)
315 *aTime = m_deletionTime;
316 return m_state;
317}
318
319/* No locking here, be aware */
320unsigned long TrackedObjectData::i_checkRefCount(const Guid& aIID)
321{
322 ULONG cRefs = 0;
323 if (aIID == m_classIID)
324 {
325 m_pIface->AddRef();
326 cRefs = m_pIface->Release();
327
328 Log2(("**** Object %s (class IID %s) (refcount %lu) ****\n",
329 m_objId.toString().c_str(),
330 m_classIID.toString().c_str(),
331 cRefs
332 ));
333 }
334 return cRefs;
335}
336
337TrackedObjectState_T TrackedObjectData::updateState(TrackedObjectState_T aNewState)
338{
339 return m_state < aNewState ? m_state = aNewState : m_state;
340}
341
342/////////////////////////////////////////////////////////////////////////////
343// TrackedObjectsCollector
344/////////////////////////////////////////////////////////////////////////////
345class TrackedObjectsCollector;
346extern TrackedObjectsCollector gTrackedObjectsCollector;
347
348TrackedObjectsCollector::TrackedObjectsCollector(): m_fInitialized(false)
349{
350}
351
352TrackedObjectsCollector::~TrackedObjectsCollector()
353{
354 Log2(("%s destructor \n", __FUNCTION__));
355
356 int vrc = i_checkInitialization();
357
358 /*
359 * Someone forgot to call uninit()
360 */
361 if (RT_SUCCESS(vrc))
362 {
363 if (m_trackedObjectsData.size() != 0)
364 {
365 if (m_trackedObjectsData.size() > 1)
366 LogRel(("%u objects are still presented in the collector\n", m_trackedObjectsData.size()));
367 else
368 LogRel(("%u object is still presented in the collector\n", m_trackedObjectsData.size()));
369
370 m_Released += m_trackedObjectsData.size();
371 m_trackedObjectsData.clear();
372 }
373
374 LogRel(("The Objects Collector history data: added objects %u, released objects %u\n", m_Added, m_Released));
375
376 /* Try to delete m_CritSectData */
377 RTCritSectDelete(&m_CritSectData);
378 }
379}
380
381bool TrackedObjectsCollector::init(){
382 m_fInitialized = false;
383
384 /* Create the critical section protecting the m_trackedObjectsData */
385 int vrc = RTCritSectInit(&m_CritSectData);
386
387 if (RT_SUCCESS(vrc))
388 {
389 /*
390 * TrackedObjectsCollector initialization occurs only when new instance of VirtualBox is created.
391 * At this moment nobody uses the TrackedObjectsCollector and we can call the functions without any locking.
392 */
393 vrc = i_clear();//just in case
394 if (RT_SUCCESS(vrc))
395 {
396 m_fInitialized = true;
397 LogRel(("The collector has been initialized.\n"));
398 }
399 }
400
401 return m_fInitialized;
402}
403
404bool TrackedObjectsCollector::uninit()
405{
406 clear(Uninitialization);
407
408
409 /* Deletion the critical section protecting the m_trackedObjectsData */
410 int vrc = RTCritSectDelete(&m_CritSectData);
411
412 if (RT_SUCCESS(vrc))
413 m_fInitialized = false;
414
415 return m_fInitialized;
416}
417
418int TrackedObjectsCollector::i_checkInitialization() const
419{
420 int vrc = VINF_SUCCESS;
421 if (!m_fInitialized)
422 {
423 Log2(("The collector is in the uninitialized state...\n"));
424 vrc = VERR_INVALID_STATE;
425 }
426
427 return vrc;
428}
429
430HRESULT TrackedObjectsCollector::setObj (const com::Utf8Str &aObjId,
431 const com::Utf8Str &aClassIID,
432 uint64_t lifeTime,
433 uint64_t idleTime,
434 IUnknown* ptrIface)
435{
436 LogFlowFuncEnter();
437
438 HRESULT hrc = S_OK;
439 int vrc = i_checkInitialization();
440 if (RT_FAILURE(vrc))
441 return VBOX_E_INVALID_OBJECT_STATE;
442
443 /* Enter critical section here */
444 RTCritSectEnter(&m_CritSectData);
445
446 com::Guid idObj(aObjId);
447 com::Guid classIID(aClassIID);
448 std::pair < std::set<com::Utf8Str>::iterator, bool > opRes = m_trackedObjectIds.insert(aObjId);
449
450 /*
451 * The case for updating the tracked object data.
452 * The Id is presented in the m_trackedObjectIds. The original object is removed from m_trackedObjectsData.
453 */
454 if (!opRes.second)
455 {
456 Log2(("UPDATING TrackedObjectData: object Id %s, class IID %s, life time %i, idle time %i\n",
457 aObjId.c_str(), aClassIID.c_str(), lifeTime, idleTime));
458
459 m_trackedObjectsData.erase(aObjId.c_str());
460 /* decrease the counter */
461 --m_Added;
462 }
463 else if (LogIs2Enabled())
464 {
465 char szCreationTime[RTTIME_STR_LEN];
466 RTTIMESPEC time;
467 RTTimeSpecToString(RTTimeNow(&time), szCreationTime, sizeof(szCreationTime));
468 Log2(("ADDED TrackedObjectData: creation time %s, object Id %s, class IID %s\n",
469 szCreationTime, aObjId.c_str(), aClassIID.c_str()));
470 }
471
472 /* Data is stored in the m_trackedObjectsData under the passed Id. */
473 m_trackedObjectsData.insert(std::make_pair(aObjId.c_str(),
474 TrackedObjectData(idObj,
475 classIID,
476 lifeTime,
477 idleTime,
478 ptrIface)));
479
480 /* increase the counter */
481 ++m_Added;
482
483 /* Leave critical section here */
484 RTCritSectLeave(&m_CritSectData);
485
486 return hrc;
487}
488
489
490HRESULT TrackedObjectsCollector::updateObj (const TrackedObjectData& aObjData)
491{
492 LogFlowFuncEnter();
493
494 HRESULT hrc = S_OK;
495 int vrc = i_checkInitialization();
496 if (RT_FAILURE(vrc))
497 return VBOX_E_INVALID_OBJECT_STATE;
498
499 /* Enter critical section here */
500 RTCritSectEnter(&m_CritSectData);
501
502 std::pair < std::set<com::Utf8Str>::iterator, bool > opRes = m_trackedObjectIds.insert(aObjData.objectIdStr());
503
504 /*
505 * The case for updating the tracked object data.
506 * The Id is presented in the m_trackedObjectIds. The original object is removed from m_trackedObjectsData.
507 */
508 if (!opRes.second)
509 {
510 Utf8Str strState = trackedObjectStateToStr(aObjData.state());
511 Log2(("UPDATING TrackedObjectData:\n state %s\n object Id %s\n class IID %s\n life time %i\n idle time %i"
512 "\n life time expired - %s\n idle time started - %s\n",
513 strState.c_str(),
514 aObjData.objectIdStr().c_str(),
515 aObjData.classIIDStr().c_str(),
516 aObjData.lifeTime(),
517 aObjData.idleTime(),
518 (aObjData.isLifeTimeExpired() == true ? "True" : "False"),
519 (aObjData.isIdleTimeStarted() == true ? "True" : "False")));
520
521 m_trackedObjectsData.erase(aObjData.objectIdStr().c_str());
522 /* decrease the counter */
523 --m_Added;
524
525 /* Data is stored in the m_trackedObjectsData under the passed Id. */
526 m_trackedObjectsData.insert(std::make_pair(aObjData.objectIdStr(), aObjData));
527
528 /* increase the counter */
529 ++m_Added;
530 }
531 else
532 {
533 Log2(("UPDATING failed because the object Id %s hasn't existed.\n", aObjData.objectIdStr().c_str()));
534 m_trackedObjectIds.erase(aObjData.objectIdStr());
535 }
536
537 /* Leave critical section here */
538 RTCritSectLeave(&m_CritSectData);
539
540 return hrc;
541}
542
543HRESULT TrackedObjectsCollector::getObj(const com::Utf8Str &aObjId,
544 TrackedObjectData &aObjData,
545 bool fUpdate)
546{
547 LogFlowFuncEnter();
548
549 int vrc = i_checkInitialization();
550 if (RT_FAILURE(vrc))
551 return VBOX_E_INVALID_OBJECT_STATE;
552
553 /* Enter critical section here */
554 RTCritSectEnter(&m_CritSectData);
555
556 HRESULT hrc = E_FAIL;
557
558 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
559 if (pIter != m_trackedObjectsData.end())
560 {
561 if (fUpdate == true)
562 {
563 /* Update some fields in the found object if needed. in instance, the last access time */
564 com::Utf8Str lat = pIter->second.updateLastAccessTime(); /* Update the access time */
565 Log2(("The updated last access time is %s\n", lat.c_str()));
566 }
567 hrc = S_OK;
568 }
569 else
570 hrc = VBOX_E_OBJECT_NOT_FOUND;
571
572 if (SUCCEEDED(hrc))
573 aObjData = i_getObj(aObjId);
574
575 /* Leave critical section here */
576 RTCritSectLeave(&m_CritSectData);
577
578 return hrc;
579}
580
581const TrackedObjectData &TrackedObjectsCollector::i_getObj(const com::Utf8Str &aObjId) const
582{
583 /* No check for existence of aObjId */
584#if 0 /* the solaris VM's stl_map.h code doesn't have any at() function. */
585 return m_trackedObjectsData.at(aObjId);
586#else
587 ConstIterTrObjData_T const Iter = m_trackedObjectsData.find(aObjId);
588 if (Iter == m_trackedObjectsData.end())
589 throw std::out_of_range(aObjId.c_str());
590 return (*Iter).second;
591#endif
592}
593
594HRESULT TrackedObjectsCollector::initObjIdleTime(const com::Utf8Str &aObjId)
595{
596 LogFlowFuncEnter();
597
598 HRESULT hrc = S_OK;
599 int vrc = i_checkInitialization();
600 if (RT_FAILURE(vrc))
601 return VBOX_E_INVALID_OBJECT_STATE;
602
603 vrc = VERR_NOT_FOUND;
604 /* Enter critical section here */
605 RTCritSectEnter(&m_CritSectData);
606
607 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
608 if (pIter != m_trackedObjectsData.end())
609 {
610 /* Init idle time only once, next time returns the initialization time */
611 com::Utf8Str strTime = pIter->second.initIdleTime();
612 Log2(("The idle time start is %s\n", strTime.c_str()));
613 vrc = VINF_SUCCESS;
614 }
615
616 if (RT_FAILURE(vrc))
617 hrc = VBOX_E_OBJECT_NOT_FOUND;
618
619 /* Leave critical section here */
620 RTCritSectLeave(&m_CritSectData);
621
622 return hrc;
623}
624
625HRESULT TrackedObjectsCollector::removeObj(const com::Utf8Str &aObjId)
626{
627 Log2(("%s: object Id %s\n", __FUNCTION__, aObjId.c_str()));
628
629 HRESULT hrc = S_OK;
630 int vrc = i_checkInitialization();
631 if (RT_FAILURE(vrc))
632 return VBOX_E_INVALID_OBJECT_STATE;
633
634 vrc = VERR_NOT_FOUND;
635
636 /* Enter critical section here */
637 RTCritSectEnter(&m_CritSectData);
638
639 IterTrObjData_T Iter = m_trackedObjectsData.find(aObjId);
640 if (Iter != m_trackedObjectsData.end())
641 {
642 Log2(("RELEASED TrackedObjectData: creation time %s, object Id %s, class IID %s\n",
643 Iter->second.creationTimeStr().c_str(), Iter->second.objectIdStr().c_str(), Iter->second.classIIDStr().c_str()));
644
645 m_trackedObjectsData.erase(Iter);
646 m_trackedObjectIds.erase(aObjId);
647 m_trackedInvalidObjectIds.erase(aObjId);
648
649 /* increase the counter */
650 ++m_Released;
651
652 vrc = VINF_SUCCESS;
653 }
654
655 if (RT_FAILURE(vrc))
656 hrc = VBOX_E_OBJECT_NOT_FOUND;
657
658 /* Leave critical section here */
659 RTCritSectLeave(&m_CritSectData);
660
661 return hrc;
662}
663
664HRESULT TrackedObjectsCollector::getAllObjIds (std::vector<com::Utf8Str>& aObjIdMap)
665{
666 HRESULT hrc = S_OK;
667 int vrc = i_checkInitialization();
668 if (RT_FAILURE(vrc))
669 return VBOX_E_INVALID_OBJECT_STATE;
670
671 /* Enter critical section here */
672 RTCritSectEnter(&m_CritSectData);
673 vrc = i_getAllObjIds(aObjIdMap);
674 if (RT_FAILURE(vrc))
675 hrc = VBOX_E_OBJECT_NOT_FOUND;
676 /* Leave critical section here */
677 RTCritSectLeave(&m_CritSectData);
678
679 return hrc;
680}
681
682int TrackedObjectsCollector::i_getAllObjIds(std::vector<com::Utf8Str> &aObjIdMap) const
683{
684 //for (const com::Utf8Str &item : m_trackedObjectIds) - the gcc in the solaris VM doesn't grok this.
685 for (std::set<com::Utf8Str>::const_iterator Iter = m_trackedObjectIds.begin();
686 Iter != m_trackedObjectIds.end();
687 ++Iter)
688 aObjIdMap.push_back(*Iter);
689
690 return aObjIdMap.size() > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
691}
692
693HRESULT TrackedObjectsCollector::getObjIdsByClassIID (const Guid& iid,
694 std::vector<com::Utf8Str>& aObjIdMap)
695{
696 Log2(("%s: Getting all objects Ids with Class IID %s\n", __FUNCTION__, iid.toString().c_str()));
697
698 HRESULT hrc = S_OK;
699 int vrc = i_checkInitialization();
700 if (RT_FAILURE(vrc))
701 return VBOX_E_INVALID_OBJECT_STATE;
702
703 /* Enter critical section here */
704 RTCritSectEnter(&m_CritSectData);
705
706 vrc = i_getObjIdsByClassIID (iid, aObjIdMap);
707 if (RT_FAILURE(vrc))
708 hrc = VBOX_E_OBJECT_NOT_FOUND;
709 /* Leave critical section here */
710 RTCritSectLeave(&m_CritSectData);
711
712 return hrc;
713}
714
715int TrackedObjectsCollector::i_getObjIdsByClassIID(const Guid &aIId, std::vector<com::Utf8Str> &aObjIdMap) const
716{
717 //for (const std::pair<const com::Utf8Str, TrackedObjectData> &item : m_trackedObjectsData) - the gcc in the solaris VM doesn't grok this.
718 for (ConstIterTrObjData_T Iter = m_trackedObjectsData.begin();
719 Iter != m_trackedObjectsData.end();
720 ++Iter)
721 {
722 if (Iter->second.classIID() == aIId)
723 aObjIdMap.push_back(Iter->first);
724 }
725
726 return aObjIdMap.size() > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
727}
728
729bool TrackedObjectsCollector::checkObj(const com::Utf8Str &aObjId)
730{
731 Log2(("%s: Checking object with Id %s\n", __FUNCTION__, aObjId.c_str()));
732
733 int vrc = i_checkInitialization();
734 if (RT_FAILURE(vrc))
735 return false;
736
737 RTCritSectEnter(&m_CritSectData);
738 bool res = i_checkObj(aObjId);
739 RTCritSectLeave(&m_CritSectData);
740 return res;
741}
742
743bool TrackedObjectsCollector::i_checkObj(const com::Utf8Str& aObjId) const
744{
745 return m_trackedObjectIds.count(aObjId.c_str()) > 0 ? true : false;
746}
747
748HRESULT TrackedObjectsCollector::clear(TrackedObjectsCollectorState aState)
749{
750 LogFlowFuncEnter();
751
752 HRESULT hrc = S_OK;
753 int vrc = i_checkInitialization();
754 if (RT_FAILURE(vrc))
755 return VBOX_E_INVALID_OBJECT_STATE;
756
757 if (aState != Uninitialization)
758 {
759 /* Enter critical section here */
760 vrc = RTCritSectEnter(&m_CritSectData);
761 if (RT_FAILURE(vrc))
762 {
763 Log2(("%s: Coudn't enter into the critical section (%Rrc)\n", __FUNCTION__, vrc));
764 return E_ABORT;
765 }
766 }
767
768 if (m_trackedObjectsData.size() != 0)
769 {
770 if (m_trackedObjectsData.size() > 1)
771 Log2(("%u objects are still presented in the Objects Collector, clearing...\n", m_trackedObjectsData.size()));
772 else
773 Log2(("%u object is still presented in the Objects Collector, clearing...\n", m_trackedObjectsData.size()));
774
775 vrc = i_clear();
776 /* Ignore setting hrc */
777 if (RT_FAILURE(vrc))
778 LogRel(("Something wrong with clearing the Objects Collector\n"));
779 }
780
781 Log2(("The Objects Collector history data: added objects %u, released objects %u\n", m_Added, m_Released));
782
783 if (aState != Uninitialization)
784 {
785 /* Leave critical section here */
786 RTCritSectLeave(&m_CritSectData);
787 }
788
789 return hrc;
790}
791
792int TrackedObjectsCollector::i_clear()
793{
794 int vrc = VINF_SUCCESS;
795 try
796 {
797 m_Released += m_trackedObjectsData.size();
798 m_trackedObjectsData.clear();
799 m_trackedObjectIds.clear();
800 m_trackedInvalidObjectIds.clear();
801 }
802 catch (...)
803 {
804 vrc = VERR_GENERAL_FAILURE;
805 }
806 return vrc;
807}
808
809HRESULT TrackedObjectsCollector::tryToRemoveObj(const com::Utf8Str& aObjId)
810{
811 LogFlowFuncEnter();
812
813 HRESULT hrc = S_OK;
814 int vrc = i_checkInitialization();
815 if (RT_FAILURE(vrc))
816 return VBOX_E_INVALID_OBJECT_STATE;
817
818 /* Enter critical section here */
819 RTCritSectEnter(&m_CritSectData);
820
821 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId.c_str());
822 if (pIter != m_trackedObjectsData.end())
823 {
824 pIter->second.getInterface()->AddRef();
825 ULONG cRefs = pIter->second.getInterface()->Release();
826
827 if (cRefs > 1)
828 {
829 Log2(("Object %s with class IID %s can't be released if refcount is more than 1 (now %lu)\n",
830 pIter->second.objectIdStr().c_str(),
831 pIter->second.classIIDStr().c_str(),
832 cRefs
833 ));
834 hrc = E_FAIL;
835 }
836 else
837 {
838 Log2(("Object %s with class IID %s is released (refcount %lu)\n",
839 pIter->second.objectIdStr().c_str(),
840 pIter->second.classIIDStr().c_str(),
841 cRefs
842 ));
843 m_trackedObjectsData.erase(pIter);
844 m_trackedObjectIds.erase(aObjId);
845 m_trackedInvalidObjectIds.erase(aObjId);
846
847 /* increase the counter */
848 ++m_Released;
849 }
850 }
851 else
852 hrc = VBOX_E_OBJECT_NOT_FOUND;
853
854 /* Leave critical section here */
855 RTCritSectLeave(&m_CritSectData);
856
857 return hrc;
858}
859
860/**
861 * Invalidate the tracked object.
862 * Works ONLY in conjunction with setTracked()!
863 */
864HRESULT TrackedObjectsCollector::invalidateObj(const com::Utf8Str &aObjId)
865{
866 LogFlowFuncEnter();
867
868 int vrc = i_checkInitialization();
869 if (RT_FAILURE(vrc))
870 return VBOX_E_INVALID_OBJECT_STATE;
871
872 /* Enter critical section here */
873 RTCritSectEnter(&m_CritSectData);
874
875 HRESULT hrc = VBOX_E_OBJECT_NOT_FOUND;
876 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
877 if (pIter != m_trackedObjectsData.end())
878 {
879 pIter->second.updateState(TrackedObjectState_Invalid);//Deleted -> Invalid
880 m_trackedInvalidObjectIds.insert(aObjId);
881 hrc = S_OK;
882 }
883
884 /* Leave critical section here */
885 RTCritSectLeave(&m_CritSectData);
886
887 return hrc;
888}
889
890/////////////////////////////////////////////////////////////////////////////
891// ObjectTracker
892/////////////////////////////////////////////////////////////////////////////
893ObjectTracker::~ObjectTracker()
894{
895 LogFlowFuncEnter();
896 LogRel(("Start waiting the ObjectTracker thread termination\n"));
897 RTThreadWait(m_Thread, 30000, NULL);
898 LogRel(("Finished waiting the ObjectTracker thread termination\n"));
899 m_Thread = NIL_RTTHREAD;
900}
901
902bool ObjectTracker::init()
903{
904 LogFlowFuncEnter();
905 return true;
906}
907
908bool ObjectTracker::finish()
909{
910 LogFlowFuncEnter();
911 ASMAtomicWriteBool(&fFinish, true);
912 return true;
913}
914
915bool ObjectTracker::isFinished()
916{
917 LogFlowFuncEnter();
918 return ASMAtomicReadBool(&fFinish);
919}
920
921/*static*/
922DECLCALLBACK(int) ObjectTracker::objectTrackerTask(RTTHREAD ThreadSelf, void *pvUser)
923{
924 HRESULT hrc = S_OK;
925
926 NOREF(ThreadSelf);
927 ObjectTracker* const master = (ObjectTracker*)pvUser;
928
929 LogRel(("Starting the ObjectTracker thread %s\n", master->getTaskName().c_str()));
930
931 while (master != NULL && master->isFinished() != true)
932 {
933 std::vector<com::Utf8Str> lObjIdMap;
934 hrc = gTrackedObjectsCollector.getAllObjIds(lObjIdMap);
935
936 //for (const com::Utf8Str& item : lObjIdMap) - the gcc in the solaris VM doesn't grok this.
937 for (std::vector<com::Utf8Str>::const_iterator Iter = lObjIdMap.begin(); Iter != lObjIdMap.end(); ++Iter)
938 {
939 TrackedObjectData temp;
940 if(gTrackedObjectsCollector.checkObj(*Iter))
941 {
942 hrc = gTrackedObjectsCollector.getObj(*Iter, temp);
943 if (SUCCEEDED(hrc))
944 {
945 Log2(("Tracked Object with ID %s was found:\n", temp.m_objId.toString().c_str()));
946
947 RTTIMESPEC now;
948 int64_t currTime = RTTimeSpecGetMilli(RTTimeNow(&now));
949 int64_t creationTime = RTTimeSpecGetMilli(&temp.m_creationTime);
950 int64_t lifeTime = (int64_t)temp.m_lifeTime*1000; //convert to milliseconds
951
952 int64_t remainingLifeTime = lifeTime == 0 ? 0 : ((creationTime + lifeTime) - currTime)/1000;
953
954 bool fLifeTimeExpired = temp.m_fLifeTimeExpired;
955 if (!fLifeTimeExpired)
956 fLifeTimeExpired = (remainingLifeTime == 0 && lifeTime != 0) ? true : false;
957
958 /* lock? */
959 temp.m_pIface->AddRef();
960 unsigned long cRefs = temp.m_pIface->Release();
961
962 /* cRefs > 2 because we created the temporarily object temp */
963 Log2(("Object %s (class IID %s): refcount %lu, remaining life time is %ld sec\n",
964 temp.m_objId.toString().c_str(),
965 temp.m_classIID.toString().c_str(),
966 cRefs - 1,
967 remainingLifeTime
968 ));
969
970 if (fLifeTimeExpired)
971 {
972 {
973 if (temp.m_fIdleTimeStart == false)
974 {
975 gTrackedObjectsCollector.initObjIdleTime(*Iter);
976 Log2(("Idle time for the object with Id %s has been started\n", Iter->c_str()));
977 Log2((" class IID %s, refcount %lu\n", temp.m_classIID.toString().c_str(), cRefs - 1));
978 }
979 else
980 {
981 int64_t idleTime = (int64_t)temp.m_idleTime*1000; //convert to milliseconds
982 int64_t idleTimeStart = RTTimeSpecGetMilli(&temp.m_idleTimeStart);
983 bool fIdleTimeExpired = (currTime - idleTimeStart) > idleTime ? true : false;
984 if (fIdleTimeExpired)
985 {
986 Log2(("Object with Id %s removed from Object Collector "
987 "(recount is %u, idle time exceeded %u sec)\n", Iter->c_str(), cRefs - 1, temp.m_idleTime));
988 gTrackedObjectsCollector.removeObj(*Iter);
989 }
990 }
991 }
992 }
993 else
994 {
995 if (cRefs <= 2)
996 {
997 /*
998 * Special case for objects with the original lifeTime equal to 0 (0 means endless).
999 * For these objects the idle time starts when user deletes it.
1000 */
1001 if (lifeTime == 0)
1002 {
1003 temp.m_fLifeTimeExpired = true;
1004
1005 /* Updating the object data */
1006 gTrackedObjectsCollector.updateObj(temp);
1007 }
1008 }
1009 }
1010 }
1011 }
1012 else
1013 Log2(("Tracked Object with ID %s was not found\n", Iter->c_str()));
1014 }
1015
1016 //sleep 1 sec
1017 RTThreadSleep(RT_MS_1SEC);//1 sec
1018 }
1019
1020 LogRel(("Finishing the object tracker thread %s\n", master->getTaskName().c_str()));
1021
1022 return 0;
1023}
1024
1025int ObjectTracker::createThread()
1026{
1027 int vrc = RTThreadCreate(&m_Thread, objectTrackerTask, this, 0,
1028 RTTHREADTYPE_INFREQUENT_POLLER,
1029 RTTHREADFLAGS_WAITABLE,
1030 "ObjTracker");
1031
1032 return vrc;
1033}
1034
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette