VirtualBox

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

Last change on this file since 107257 was 107257, checked in by vboxsync, 7 weeks ago

bugref:10806. Updated TrackedObjectsCollector::i_getAllObjIds(). jiraref:VBP-1459.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.6 KB
Line 
1/* $Id: ObjectsTracker.cpp 107257 2024-12-09 13:17:33Z 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#define LOG_GROUP LOG_GROUP_MAIN
29
30#include "LoggingNew.h"
31#include "VirtualBoxBase.h"
32#include "ObjectsTracker.h"
33#include <iprt/log.h>
34#include <iprt/stream.h>
35#include <iprt/time.h>
36#include <iprt/asm.h>
37#include <stdexcept>
38
39typedef std::map<com::Utf8Str, TrackedObjectData>::iterator IterTrObjData_T;
40typedef std::map<com::Utf8Str, TrackedObjectData>::const_iterator ConstIterTrObjData_T;
41
42static Utf8Str trackedObjectStateToStr(TrackedObjectState_T aState)
43{
44 Utf8Str strState("None");
45 switch (aState)
46 {
47 case TrackedObjectState_Alive:
48 strState = "Alive";
49 break;
50 case TrackedObjectState_Deleted:
51 strState = "Deleted";
52 break;
53 case TrackedObjectState_Invalid:
54 strState = "Invalid";
55 break;
56 case TrackedObjectState_None:
57 default:
58 strState = "None";
59 break;
60 }
61
62 return strState;
63}
64
65/////////////////////////////////////////////////////////////////////////////
66// TrackedObjectData
67/////////////////////////////////////////////////////////////////////////////
68TrackedObjectData::TrackedObjectData():
69 m_componentName("noname"),
70 m_lifeTime(0),
71 m_idleTime(1),
72 m_state(TrackedObjectState_None),
73 m_pIface(NULL)
74 {
75}
76
77TrackedObjectData::TrackedObjectData(const com::Guid &aObjId,
78 const com::Guid &aClassIID,
79 uint64_t aLifeTime,
80 uint64_t aIdleTime,
81 IUnknown* aPtr):
82
83 m_objId(aObjId),
84 m_classIID(aClassIID),
85 m_componentName("noname"),
86 m_lifeTime(aLifeTime),
87 m_idleTime(aIdleTime),
88 m_fIdleTimeStart(false),
89 m_fLifeTimeExpired(false),
90 m_pIface(aPtr)
91{
92 RTTimeNow(unconst(&m_creationTime));
93 m_lastAccessTime = m_creationTime;
94 m_state = TrackedObjectState_Alive;
95}
96
97TrackedObjectData::TrackedObjectData(const TrackedObjectData & that)
98{
99 LogFlowFuncEnter();
100 if (this != &that)
101 {
102 m_objId = that.m_objId;
103 m_classIID = that.m_classIID;
104 m_componentName = that.m_componentName;
105 m_lifeTime = that.m_lifeTime;
106 m_idleTime = that.m_idleTime;
107 m_pIface = that.m_pIface;
108 m_creationTime = that.m_creationTime;
109 m_deletionTime = that.m_deletionTime;
110 m_lastAccessTime = that.m_lastAccessTime;
111 m_idleTimeStart = that.m_idleTimeStart;
112 m_fIdleTimeStart = that.m_fIdleTimeStart;
113 m_fLifeTimeExpired = that.m_fLifeTimeExpired;
114 m_state = that.m_state;
115 }
116}
117
118TrackedObjectData::~TrackedObjectData()
119{
120 Log2(("%s destructor\n", __FUNCTION__));
121 Log2(("DELETED Object %s (class IID %s)\n",
122 m_objId.toString().c_str(),
123 m_classIID.toString().c_str()
124 ));
125}
126
127TrackedObjectData &TrackedObjectData::operator=(const TrackedObjectData & that)
128{
129 LogFlowFuncEnter();
130 if (this != &that)
131 {
132 m_objId = that.m_objId;
133 m_classIID = that.m_classIID;
134 m_componentName = that.m_componentName;
135 m_lifeTime = that.m_lifeTime;
136 m_idleTime = that.m_idleTime;
137 m_pIface = that.m_pIface;
138 m_creationTime = that.m_creationTime;
139 m_deletionTime = that.m_deletionTime;
140 m_lastAccessTime = that.m_lastAccessTime;
141 m_idleTimeStart = that.m_idleTimeStart;
142 m_fIdleTimeStart = that.m_fIdleTimeStart;
143 m_fLifeTimeExpired = that.m_fLifeTimeExpired;
144 m_state = that.m_state;
145 }
146
147 return *this;
148}
149
150com::Utf8Str TrackedObjectData::updateLastAccessTime()
151{
152 RTTimeNow(&m_lastAccessTime);
153
154 char szTime[RTTIME_STR_LEN];
155 RTTimeSpecToString(&m_lastAccessTime, szTime, sizeof(szTime));
156 return com::Utf8Str(szTime);
157}
158
159/** @todo r=bird: why on earth does this return a string? */
160com::Utf8Str TrackedObjectData::initIdleTime()
161{
162 if (!m_fIdleTimeStart)
163 {
164 RTTimeNow(unconst(&m_deletionTime));
165 updateState(TrackedObjectState_Deleted);//Alive -> Deleted
166 RTTimeNow(unconst(&m_idleTimeStart));
167 m_fIdleTimeStart = true;
168 m_fLifeTimeExpired = true;
169 }
170
171 char szTime[RTTIME_STR_LEN];
172 RTTimeSpecToString(&m_idleTimeStart, szTime, sizeof(szTime));
173 return com::Utf8Str(szTime);
174}
175
176com::Utf8Str TrackedObjectData::creationTimeStr() const
177{
178 char szCreationTime[RTTIME_STR_LEN];
179 RTTimeSpecToString(&m_creationTime, szCreationTime, sizeof(szCreationTime));
180
181 return com::Utf8Str(szCreationTime);
182}
183
184TrackedObjectState_T TrackedObjectData::deletionTime(PRTTIMESPEC aTime) const
185{
186 if (m_state != TrackedObjectState_Alive)
187 *aTime = m_deletionTime;
188 return m_state;
189}
190
191/* No locking here, be aware */
192unsigned long TrackedObjectData::i_checkRefCount(const Guid& aIID)
193{
194 ULONG cRefs = 0;
195 if (aIID == m_classIID)
196 {
197 m_pIface->AddRef();
198 cRefs = m_pIface->Release();
199
200 Log2(("**** Object %s (class IID %s) (refcount %lu) ****\n",
201 m_objId.toString().c_str(),
202 m_classIID.toString().c_str(),
203 cRefs
204 ));
205 }
206 return cRefs;
207}
208
209TrackedObjectState_T TrackedObjectData::updateState(TrackedObjectState_T aNewState)
210{
211 return m_state < aNewState ? m_state = aNewState : m_state;
212}
213
214/////////////////////////////////////////////////////////////////////////////
215// TrackedObjectsCollector
216/////////////////////////////////////////////////////////////////////////////
217class TrackedObjectsCollector;
218extern TrackedObjectsCollector gTrackedObjectsCollector;
219
220TrackedObjectsCollector::TrackedObjectsCollector(): m_fInitialized(false)
221{
222}
223
224TrackedObjectsCollector::~TrackedObjectsCollector()
225{
226 Log2(("%s destructor \n", __FUNCTION__));
227
228 int vrc = i_checkInitialization();
229
230 /*
231 * Someone forgot to call uninit()
232 */
233 if (RT_SUCCESS(vrc))
234 {
235 if (m_trackedObjectsData.size() != 0)
236 {
237 if (m_trackedObjectsData.size() > 1)
238 LogRel(("%u objects are still presented in the collector\n", m_trackedObjectsData.size()));
239 else
240 LogRel(("%u object is still presented in the collector\n", m_trackedObjectsData.size()));
241
242 m_Released += m_trackedObjectsData.size();
243 m_trackedObjectsData.clear();
244 }
245
246 LogRel(("The Objects Collector history data: added objects %u, released objects %u\n", m_Added, m_Released));
247
248 /* Try to delete m_CritSectData */
249 RTCritSectDelete(&m_CritSectData);
250 }
251}
252
253bool TrackedObjectsCollector::init(){
254 m_fInitialized = false;
255
256 /* Create the critical section protecting the m_trackedObjectsData */
257 int vrc = RTCritSectInit(&m_CritSectData);
258
259 if (RT_SUCCESS(vrc))
260 {
261 /*
262 * TrackedObjectsCollector initialization occurs only when new instance of VirtualBox is created.
263 * At this moment nobody uses the TrackedObjectsCollector and we can call the functions without any locking.
264 */
265 vrc = i_clear();//just in case
266 if (RT_SUCCESS(vrc))
267 {
268 m_fInitialized = true;
269 LogRel(("The collector has been initialized.\n"));
270 }
271 }
272
273 return m_fInitialized;
274}
275
276bool TrackedObjectsCollector::uninit()
277{
278 clear(Uninitialization);
279
280
281 /* Deletion the critical section protecting the m_trackedObjectsData */
282 int vrc = RTCritSectDelete(&m_CritSectData);
283
284 if (RT_SUCCESS(vrc))
285 m_fInitialized = false;
286
287 return m_fInitialized;
288}
289
290int TrackedObjectsCollector::i_checkInitialization() const
291{
292 int vrc = VINF_SUCCESS;
293 if (!m_fInitialized)
294 {
295 Log2(("The collector is in the uninitialized state...\n"));
296 vrc = VERR_INVALID_STATE;
297 }
298
299 return vrc;
300}
301
302HRESULT TrackedObjectsCollector::setObj (const com::Utf8Str &aObjId,
303 const com::Utf8Str &aClassIID,
304 uint64_t lifeTime,
305 uint64_t idleTime,
306 IUnknown* ptrIface)
307{
308 LogFlowFuncEnter();
309
310 HRESULT hrc = S_OK;
311 int vrc = i_checkInitialization();
312 if (RT_FAILURE(vrc))
313 return VBOX_E_INVALID_OBJECT_STATE;
314
315 /* Enter critical section here */
316 RTCritSectEnter(&m_CritSectData);
317
318 com::Guid idObj(aObjId);
319 com::Guid classIID(aClassIID);
320 std::pair < std::set<com::Utf8Str>::iterator, bool > opRes = m_trackedObjectIds.insert(aObjId);
321
322 /*
323 * The case for updating the tracked object data.
324 * The Id is presented in the m_trackedObjectIds. The original object is removed from m_trackedObjectsData.
325 */
326 if (!opRes.second)
327 {
328 Log2(("UPDATING TrackedObjectData: object Id %s, class IID %s, life time %i, idle time %i\n",
329 aObjId.c_str(), aClassIID.c_str(), lifeTime, idleTime));
330
331 m_trackedObjectsData.erase(aObjId.c_str());
332 /* decrease the counter */
333 --m_Added;
334 }
335 else if (LogIs2Enabled())
336 {
337 char szCreationTime[RTTIME_STR_LEN];
338 RTTIMESPEC time;
339 RTTimeSpecToString(RTTimeNow(&time), szCreationTime, sizeof(szCreationTime));
340 Log2(("ADDED TrackedObjectData: creation time %s, object Id %s, class IID %s\n",
341 szCreationTime, aObjId.c_str(), aClassIID.c_str()));
342 }
343
344 /* Data is stored in the m_trackedObjectsData under the passed Id. */
345 m_trackedObjectsData.insert(std::make_pair(aObjId.c_str(),
346 TrackedObjectData(idObj,
347 classIID,
348 lifeTime,
349 idleTime,
350 ptrIface)));
351
352 /* increase the counter */
353 ++m_Added;
354
355 /* Leave critical section here */
356 RTCritSectLeave(&m_CritSectData);
357
358 return hrc;
359}
360
361
362HRESULT TrackedObjectsCollector::updateObj (const TrackedObjectData& aObjData)
363{
364 LogFlowFuncEnter();
365
366 HRESULT hrc = S_OK;
367 int vrc = i_checkInitialization();
368 if (RT_FAILURE(vrc))
369 return VBOX_E_INVALID_OBJECT_STATE;
370
371 /* Enter critical section here */
372 RTCritSectEnter(&m_CritSectData);
373
374 std::pair < std::set<com::Utf8Str>::iterator, bool > opRes = m_trackedObjectIds.insert(aObjData.objectIdStr());
375
376 /*
377 * The case for updating the tracked object data.
378 * The Id is presented in the m_trackedObjectIds. The original object is removed from m_trackedObjectsData.
379 */
380 if (!opRes.second)
381 {
382 Log2(("UPDATING TrackedObjectData:\n state %s\n object Id %s\n class IID %s\n life time %i\n idle time %i"
383 "\n life time expired - %s\n idle time started - %s\n",
384 trackedObjectStateToStr(aObjData.state()).c_str(),
385 aObjData.objectIdStr().c_str(),
386 aObjData.classIIDStr().c_str(),
387 aObjData.lifeTime(),
388 aObjData.idleTime(),
389 (aObjData.isLifeTimeExpired() == true ? "True" : "False"),
390 (aObjData.isIdleTimeStarted() == true ? "True" : "False")));
391
392 m_trackedObjectsData.erase(aObjData.objectIdStr().c_str());
393 /* decrease the counter */
394 --m_Added;
395
396 /* Data is stored in the m_trackedObjectsData under the passed Id. */
397 m_trackedObjectsData.insert(std::make_pair(aObjData.objectIdStr(), aObjData));
398
399 /* increase the counter */
400 ++m_Added;
401 }
402 else
403 {
404 Log2(("UPDATING failed because the object Id %s hasn't existed.\n", aObjData.objectIdStr().c_str()));
405 m_trackedObjectIds.erase(aObjData.objectIdStr());
406 }
407
408 /* Leave critical section here */
409 RTCritSectLeave(&m_CritSectData);
410
411 return hrc;
412}
413
414HRESULT TrackedObjectsCollector::getObj(const com::Utf8Str &aObjId,
415 TrackedObjectData &aObjData,
416 bool fUpdate)
417{
418 LogFlowFuncEnter();
419
420 int vrc = i_checkInitialization();
421 if (RT_FAILURE(vrc))
422 return VBOX_E_INVALID_OBJECT_STATE;
423
424 /* Enter critical section here */
425 RTCritSectEnter(&m_CritSectData);
426
427 HRESULT hrc = E_FAIL;
428
429 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
430 if (pIter != m_trackedObjectsData.end())
431 {
432 if (fUpdate == true)
433 {
434 /* Update some fields in the found object if needed. in instance, the last access time */
435 com::Utf8Str lat = pIter->second.updateLastAccessTime(); /* Update the access time */
436 Log2(("The updated last access time is %s\n", lat.c_str()));
437 }
438 hrc = S_OK;
439 }
440 else
441 hrc = VBOX_E_OBJECT_NOT_FOUND;
442
443 if (SUCCEEDED(hrc))
444 aObjData = i_getObj(aObjId);
445
446 /* Leave critical section here */
447 RTCritSectLeave(&m_CritSectData);
448
449 return hrc;
450}
451
452const TrackedObjectData &TrackedObjectsCollector::i_getObj(const com::Utf8Str &aObjId) const
453{
454 /* No check for existence of aObjId */
455#if 0 /* the solaris VM's stl_map.h code doesn't have any at() function. */
456 return m_trackedObjectsData.at(aObjId);
457#else
458 ConstIterTrObjData_T const Iter = m_trackedObjectsData.find(aObjId);
459 if (Iter == m_trackedObjectsData.end())
460 throw std::out_of_range(aObjId.c_str());
461 return (*Iter).second;
462#endif
463}
464
465HRESULT TrackedObjectsCollector::initObjIdleTime(const com::Utf8Str &aObjId)
466{
467 LogFlowFuncEnter();
468
469 HRESULT hrc = S_OK;
470 int vrc = i_checkInitialization();
471 if (RT_FAILURE(vrc))
472 return VBOX_E_INVALID_OBJECT_STATE;
473
474 vrc = VERR_NOT_FOUND;
475 /* Enter critical section here */
476 RTCritSectEnter(&m_CritSectData);
477
478 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
479 if (pIter != m_trackedObjectsData.end())
480 {
481 /* Init idle time only once, next time returns the initialization time */
482 com::Utf8Str strTime = pIter->second.initIdleTime();
483 Log2(("The idle time start is %s\n", strTime.c_str()));
484 vrc = VINF_SUCCESS;
485 }
486
487 if (RT_FAILURE(vrc))
488 hrc = VBOX_E_OBJECT_NOT_FOUND;
489
490 /* Leave critical section here */
491 RTCritSectLeave(&m_CritSectData);
492
493 return hrc;
494}
495
496HRESULT TrackedObjectsCollector::removeObj(const com::Utf8Str &aObjId)
497{
498 Log2(("%s: object Id %s\n", __FUNCTION__, aObjId.c_str()));
499
500 HRESULT hrc = S_OK;
501 int vrc = i_checkInitialization();
502 if (RT_FAILURE(vrc))
503 return VBOX_E_INVALID_OBJECT_STATE;
504
505 vrc = VERR_NOT_FOUND;
506
507 /* Enter critical section here */
508 RTCritSectEnter(&m_CritSectData);
509
510 IterTrObjData_T Iter = m_trackedObjectsData.find(aObjId);
511 if (Iter != m_trackedObjectsData.end())
512 {
513 Log2(("RELEASED TrackedObjectData: creation time %s, object Id %s, class IID %s\n",
514 Iter->second.creationTimeStr().c_str(), Iter->second.objectIdStr().c_str(), Iter->second.classIIDStr().c_str()));
515
516 m_trackedObjectsData.erase(Iter);
517 m_trackedObjectIds.erase(aObjId);
518 m_trackedInvalidObjectIds.erase(aObjId);
519
520 /* increase the counter */
521 ++m_Released;
522
523 vrc = VINF_SUCCESS;
524 }
525
526 if (RT_FAILURE(vrc))
527 hrc = VBOX_E_OBJECT_NOT_FOUND;
528
529 /* Leave critical section here */
530 RTCritSectLeave(&m_CritSectData);
531
532 return hrc;
533}
534
535HRESULT TrackedObjectsCollector::getAllObjIds (std::vector<com::Utf8Str>& aObjIdMap)
536{
537 HRESULT hrc = S_OK;
538 int vrc = i_checkInitialization();
539 if (RT_FAILURE(vrc))
540 return VBOX_E_INVALID_OBJECT_STATE;
541
542 /* Enter critical section here */
543 RTCritSectEnter(&m_CritSectData);
544 vrc = i_getAllObjIds(aObjIdMap);
545 if (RT_FAILURE(vrc))
546 hrc = VBOX_E_OBJECT_NOT_FOUND;
547 /* Leave critical section here */
548 RTCritSectLeave(&m_CritSectData);
549
550 return hrc;
551}
552
553int TrackedObjectsCollector::i_getAllObjIds(std::vector<com::Utf8Str> &aObjIdMap) const
554{
555 //for (const com::Utf8Str &item : m_trackedObjectIds) - the gcc in the solaris VM doesn't grok this.
556 for (std::set<com::Utf8Str>::const_iterator Iter = m_trackedObjectIds.begin();
557 Iter != m_trackedObjectIds.end();
558 ++Iter)
559 aObjIdMap.push_back(*Iter);
560
561 return aObjIdMap.size() > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
562}
563
564HRESULT TrackedObjectsCollector::getObjIdsByClassIID (const Guid& iid,
565 std::vector<com::Utf8Str>& aObjIdMap)
566{
567 Log2(("%s: Getting all objects Ids with Class IID %s\n", __FUNCTION__, iid.toString().c_str()));
568
569 HRESULT hrc = S_OK;
570 int vrc = i_checkInitialization();
571 if (RT_FAILURE(vrc))
572 return VBOX_E_INVALID_OBJECT_STATE;
573
574 /* Enter critical section here */
575 RTCritSectEnter(&m_CritSectData);
576
577 vrc = i_getObjIdsByClassIID (iid, aObjIdMap);
578 if (RT_FAILURE(vrc))
579 hrc = VBOX_E_OBJECT_NOT_FOUND;
580 /* Leave critical section here */
581 RTCritSectLeave(&m_CritSectData);
582
583 return hrc;
584}
585
586int TrackedObjectsCollector::i_getObjIdsByClassIID(const Guid &aIId, std::vector<com::Utf8Str> &aObjIdMap) const
587{
588 //for (const std::pair<const com::Utf8Str, TrackedObjectData> &item : m_trackedObjectsData) - the gcc in the solaris VM doesn't grok this.
589 for (ConstIterTrObjData_T Iter = m_trackedObjectsData.begin();
590 Iter != m_trackedObjectsData.end();
591 ++Iter)
592 {
593 /* IID found and the object is valid */
594 if (Iter->second.classIID() == aIId && !m_trackedInvalidObjectIds.count(Iter->first))
595 aObjIdMap.push_back(Iter->first);
596 }
597
598 return aObjIdMap.size() > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
599}
600
601bool TrackedObjectsCollector::checkObj(const com::Utf8Str &aObjId)
602{
603 Log2(("%s: Checking object with Id %s\n", __FUNCTION__, aObjId.c_str()));
604
605 int vrc = i_checkInitialization();
606 if (RT_FAILURE(vrc))
607 return false;
608
609 RTCritSectEnter(&m_CritSectData);
610 bool res = i_checkObj(aObjId);
611 RTCritSectLeave(&m_CritSectData);
612 return res;
613}
614
615bool TrackedObjectsCollector::i_checkObj(const com::Utf8Str& aObjId) const
616{
617 return m_trackedObjectIds.count(aObjId.c_str()) > 0 ? true : false;
618}
619
620HRESULT TrackedObjectsCollector::clear(TrackedObjectsCollectorState aState)
621{
622 LogFlowFuncEnter();
623
624 HRESULT hrc = S_OK;
625 int vrc = i_checkInitialization();
626 if (RT_FAILURE(vrc))
627 return VBOX_E_INVALID_OBJECT_STATE;
628
629 if (aState != Uninitialization)
630 {
631 /* Enter critical section here */
632 vrc = RTCritSectEnter(&m_CritSectData);
633 if (RT_FAILURE(vrc))
634 {
635 Log2(("%s: Coudn't enter into the critical section (%Rrc)\n", __FUNCTION__, vrc));
636 return E_ABORT;
637 }
638 }
639
640 if (m_trackedObjectsData.size() != 0)
641 {
642 if (m_trackedObjectsData.size() > 1)
643 Log2(("%u objects are still presented in the Objects Collector, clearing...\n", m_trackedObjectsData.size()));
644 else
645 Log2(("%u object is still presented in the Objects Collector, clearing...\n", m_trackedObjectsData.size()));
646
647 vrc = i_clear();
648 /* Ignore setting hrc */
649 if (RT_FAILURE(vrc))
650 LogRel(("Something wrong with clearing the Objects Collector\n"));
651 }
652
653 Log2(("The Objects Collector history data: added objects %u, released objects %u\n", m_Added, m_Released));
654
655 if (aState != Uninitialization)
656 {
657 /* Leave critical section here */
658 RTCritSectLeave(&m_CritSectData);
659 }
660
661 return hrc;
662}
663
664int TrackedObjectsCollector::i_clear()
665{
666 int vrc = VINF_SUCCESS;
667 try
668 {
669 m_Released += m_trackedObjectsData.size();
670 m_trackedObjectsData.clear();
671 m_trackedObjectIds.clear();
672 m_trackedInvalidObjectIds.clear();
673 }
674 catch (...)
675 {
676 vrc = VERR_GENERAL_FAILURE;
677 }
678 return vrc;
679}
680
681HRESULT TrackedObjectsCollector::tryToRemoveObj(const com::Utf8Str& aObjId)
682{
683 LogFlowFuncEnter();
684
685 HRESULT hrc = S_OK;
686 int vrc = i_checkInitialization();
687 if (RT_FAILURE(vrc))
688 return VBOX_E_INVALID_OBJECT_STATE;
689
690 /* Enter critical section here */
691 RTCritSectEnter(&m_CritSectData);
692
693 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId.c_str());
694 if (pIter != m_trackedObjectsData.end())
695 {
696 pIter->second.getInterface()->AddRef();
697 ULONG cRefs = pIter->second.getInterface()->Release();
698
699 if (cRefs > 1)
700 {
701 Log2(("Object %s with class IID %s can't be released if refcount is more than 1 (now %lu)\n",
702 pIter->second.objectIdStr().c_str(),
703 pIter->second.classIIDStr().c_str(),
704 cRefs
705 ));
706 hrc = E_FAIL;
707 }
708 else
709 {
710 Log2(("Object %s with class IID %s is released (refcount %lu)\n",
711 pIter->second.objectIdStr().c_str(),
712 pIter->second.classIIDStr().c_str(),
713 cRefs
714 ));
715 m_trackedObjectsData.erase(pIter);
716 m_trackedObjectIds.erase(aObjId);
717 m_trackedInvalidObjectIds.erase(aObjId);
718
719 /* increase the counter */
720 ++m_Released;
721 }
722 }
723 else
724 hrc = VBOX_E_OBJECT_NOT_FOUND;
725
726 /* Leave critical section here */
727 RTCritSectLeave(&m_CritSectData);
728
729 return hrc;
730}
731
732/**
733 * Invalidate the tracked object.
734 * Works ONLY in conjunction with setTracked()!
735 */
736HRESULT TrackedObjectsCollector::invalidateObj(const com::Utf8Str &aObjId)
737{
738 LogFlowFuncEnter();
739
740 int vrc = i_checkInitialization();
741 if (RT_FAILURE(vrc))
742 return VBOX_E_INVALID_OBJECT_STATE;
743
744 /* Enter critical section here */
745 RTCritSectEnter(&m_CritSectData);
746
747 HRESULT hrc = VBOX_E_OBJECT_NOT_FOUND;
748 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
749 if (pIter != m_trackedObjectsData.end())
750 {
751 pIter->second.updateState(TrackedObjectState_Invalid);//Deleted -> Invalid
752 m_trackedInvalidObjectIds.insert(aObjId);
753 hrc = S_OK;
754 }
755
756 /* Leave critical section here */
757 RTCritSectLeave(&m_CritSectData);
758
759 return hrc;
760}
761
762/////////////////////////////////////////////////////////////////////////////
763// ObjectTracker
764/////////////////////////////////////////////////////////////////////////////
765ObjectTracker::~ObjectTracker()
766{
767 LogFlowFuncEnter();
768 LogRel(("Start waiting the ObjectTracker thread termination\n"));
769 RTThreadWait(m_Thread, 30000, NULL);
770 LogRel(("Finished waiting the ObjectTracker thread termination\n"));
771 m_Thread = NIL_RTTHREAD;
772}
773
774bool ObjectTracker::init()
775{
776 LogFlowFuncEnter();
777 return true;
778}
779
780bool ObjectTracker::finish()
781{
782 LogFlowFuncEnter();
783 ASMAtomicWriteBool(&fFinish, true);
784 return true;
785}
786
787bool ObjectTracker::isFinished()
788{
789 LogFlowFuncEnter();
790 return ASMAtomicReadBool(&fFinish);
791}
792
793/*static*/
794DECLCALLBACK(int) ObjectTracker::objectTrackerTask(RTTHREAD ThreadSelf, void *pvUser)
795{
796 HRESULT hrc = S_OK;
797
798 NOREF(ThreadSelf);
799 ObjectTracker* const master = (ObjectTracker*)pvUser;
800
801 LogRel(("Starting the ObjectTracker thread %s\n", master->getTaskName().c_str()));
802
803 while (master != NULL && master->isFinished() != true)
804 {
805 std::vector<com::Utf8Str> lObjIdMap;
806 hrc = gTrackedObjectsCollector.getAllObjIds(lObjIdMap);
807
808 //for (const com::Utf8Str& item : lObjIdMap) - the gcc in the solaris VM doesn't grok this.
809 for (std::vector<com::Utf8Str>::const_iterator Iter = lObjIdMap.begin(); Iter != lObjIdMap.end(); ++Iter)
810 {
811 TrackedObjectData temp;
812 if(gTrackedObjectsCollector.checkObj(*Iter))
813 {
814 hrc = gTrackedObjectsCollector.getObj(*Iter, temp);
815 if (SUCCEEDED(hrc))
816 {
817 Log2(("Tracked Object with ID %s was found:\n", temp.m_objId.toString().c_str()));
818
819 RTTIMESPEC now;
820 int64_t currTime = RTTimeSpecGetMilli(RTTimeNow(&now));
821 int64_t creationTime = RTTimeSpecGetMilli(&temp.m_creationTime);
822 int64_t lifeTime = (int64_t)temp.m_lifeTime*1000; //convert to milliseconds
823
824 int64_t remainingLifeTime = ((creationTime + lifeTime) - currTime)/1000;
825
826 /* lock? */
827 temp.m_pIface->AddRef();
828 unsigned long cRefs = temp.m_pIface->Release();
829
830 /* cRefs > 2 because we created the temporarily object temp */
831 Log2(("Object %s (class IID %s): refcount %lu, remaining life time is %ld sec\n",
832 temp.m_objId.toString().c_str(),
833 temp.m_classIID.toString().c_str(),
834 cRefs - 1,
835 remainingLifeTime
836 ));
837
838 bool fLifeTimeEnd = (currTime - creationTime) > lifeTime ? true : false;
839
840 if (!fLifeTimeEnd)
841 {
842 if (cRefs <= 2 || remainingLifeTime <= 0)
843 {
844 if (temp.m_fIdleTimeStart == false)
845 {
846 gTrackedObjectsCollector.initObjIdleTime(*Iter);
847 Log2(("Idle time for the object with Id %s has been started\n", Iter->c_str()));
848 }
849 else
850 {
851 int64_t idleTime = (int64_t)temp.m_idleTime*1000; //convert to milliseconds
852 int64_t idleTimeStart = RTTimeSpecGetMilli(&temp.m_idleTimeStart);
853 bool fObsolete = (currTime - idleTimeStart) > idleTime ? true : false;
854 if (fObsolete)
855 {
856 Log2(("Object with Id %s removed from Object Collector "
857 "(recount is %u, idle time exceeded %u sec)\n", Iter->c_str(), cRefs - 1, temp.m_idleTime));
858 gTrackedObjectsCollector.removeObj(*Iter);
859 }
860 }
861 }
862 }
863 else
864 {
865 if (cRefs <= 2)
866 {
867 /*
868 * Special case for objects with the original lifeTime equal to 0 (0 means endless).
869 * For these objects the idle time starts when user deletes it.
870 */
871 if (lifeTime == 0)
872 {
873 /* set lifeTime to 60 sec (1 min) */
874 lifeTime = 60;
875 /* Updating the object data */
876 gTrackedObjectsCollector.setObj(temp.objectIdStr(),
877 temp.classIIDStr(),
878 (uint64_t)lifeTime,
879 temp.m_idleTime,
880 temp.m_pIface);
881 }
882 else
883 {
884 Log2(("Object with Id %s removed from Object Collector "
885 "(lifetime exceeded %u sec)\n", Iter->c_str(), temp.m_lifeTime));
886 gTrackedObjectsCollector.removeObj(*Iter);
887 }
888 }
889 }
890 }
891 }
892 else
893 Log2(("Tracked Object with ID %s was not found\n", Iter->c_str()));
894 }
895
896 //sleep 1 sec
897 RTThreadSleep(RT_MS_1SEC);//1 sec
898 }
899
900 LogRel(("Finishing the object tracker thread %s\n", master->getTaskName().c_str()));
901
902 return 0;
903}
904
905int ObjectTracker::createThread()
906{
907 int vrc = RTThreadCreate(&m_Thread, objectTrackerTask, this, 0,
908 RTTHREADTYPE_INFREQUENT_POLLER,
909 RTTHREADFLAGS_WAITABLE,
910 "ObjTracker");
911
912 return vrc;
913}
914
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