VirtualBox

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

Last change on this file since 107255 was 107255, checked in by vboxsync, 6 weeks ago

bugref:10806. Added function trackedObjectStateToStr(). jiraref:VBP-1459.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.0 KB
Line 
1/* $Id: ObjectsTracker.cpp 107255 2024-12-09 13:12:10Z 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() && fUpdate == true)
431 {
432 /* Update some fields in the found object if needed. in instance, the last access time */
433 com::Utf8Str lat = pIter->second.updateLastAccessTime(); /* Update the access time */
434 Log2(("The updated last access time is %s\n", lat.c_str()));
435 hrc = S_OK;
436 }
437
438 if (SUCCEEDED(hrc))
439 {
440 /** @todo r=bird: Why do three lookups? */
441 if ( i_getObj(aObjId).getInterface().isNotNull() )
442 {
443 if (i_getObj(aObjId).state() != TrackedObjectState_Invalid)
444 {
445 aObjData = i_getObj(aObjId);
446 hrc = S_OK;
447 }
448 else
449 hrc = VBOX_E_INVALID_OBJECT_STATE;
450 }
451 else
452 hrc = VBOX_E_OBJECT_NOT_FOUND;
453 }
454
455 /* Leave critical section here */
456 RTCritSectLeave(&m_CritSectData);
457
458 return hrc;
459}
460
461const TrackedObjectData &TrackedObjectsCollector::i_getObj(const com::Utf8Str &aObjId) const
462{
463 /* No check for existence of aObjId */
464#if 0 /* the solaris VM's stl_map.h code doesn't have any at() function. */
465 return m_trackedObjectsData.at(aObjId);
466#else
467 ConstIterTrObjData_T const Iter = m_trackedObjectsData.find(aObjId);
468 if (Iter == m_trackedObjectsData.end())
469 throw std::out_of_range(aObjId.c_str());
470 return (*Iter).second;
471#endif
472}
473
474HRESULT TrackedObjectsCollector::initObjIdleTime(const com::Utf8Str &aObjId)
475{
476 LogFlowFuncEnter();
477
478 HRESULT hrc = S_OK;
479 int vrc = i_checkInitialization();
480 if (RT_FAILURE(vrc))
481 return VBOX_E_INVALID_OBJECT_STATE;
482
483 vrc = VERR_NOT_FOUND;
484 /* Enter critical section here */
485 RTCritSectEnter(&m_CritSectData);
486
487 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
488 if (pIter != m_trackedObjectsData.end())
489 {
490 /* Init idle time only once, next time returns the initialization time */
491 com::Utf8Str strTime = pIter->second.initIdleTime();
492 Log2(("The idle time start is %s\n", strTime.c_str()));
493 vrc = VINF_SUCCESS;
494 }
495
496 if (RT_FAILURE(vrc))
497 hrc = VBOX_E_OBJECT_NOT_FOUND;
498
499 /* Leave critical section here */
500 RTCritSectLeave(&m_CritSectData);
501
502 return hrc;
503}
504
505HRESULT TrackedObjectsCollector::removeObj(const com::Utf8Str &aObjId)
506{
507 Log2(("%s: object Id %s\n", __FUNCTION__, aObjId.c_str()));
508
509 HRESULT hrc = S_OK;
510 int vrc = i_checkInitialization();
511 if (RT_FAILURE(vrc))
512 return VBOX_E_INVALID_OBJECT_STATE;
513
514 vrc = VERR_NOT_FOUND;
515
516 /* Enter critical section here */
517 RTCritSectEnter(&m_CritSectData);
518
519 IterTrObjData_T Iter = m_trackedObjectsData.find(aObjId);
520 if (Iter != m_trackedObjectsData.end())
521 {
522 Log2(("RELEASED TrackedObjectData: creation time %s, object Id %s, class IID %s\n",
523 Iter->second.creationTimeStr().c_str(), Iter->second.objectIdStr().c_str(), Iter->second.classIIDStr().c_str()));
524
525 m_trackedObjectsData.erase(Iter);
526 m_trackedObjectIds.erase(aObjId);
527 m_trackedInvalidObjectIds.erase(aObjId);
528
529 /* increase the counter */
530 ++m_Released;
531
532 vrc = VINF_SUCCESS;
533 }
534
535 if (RT_FAILURE(vrc))
536 hrc = VBOX_E_OBJECT_NOT_FOUND;
537
538 /* Leave critical section here */
539 RTCritSectLeave(&m_CritSectData);
540
541 return hrc;
542}
543
544HRESULT TrackedObjectsCollector::getAllObjIds (std::vector<com::Utf8Str>& aObjIdMap)
545{
546 HRESULT hrc = S_OK;
547 int vrc = i_checkInitialization();
548 if (RT_FAILURE(vrc))
549 return VBOX_E_INVALID_OBJECT_STATE;
550
551 /* Enter critical section here */
552 RTCritSectEnter(&m_CritSectData);
553 vrc = i_getAllObjIds(aObjIdMap);
554 if (RT_FAILURE(vrc))
555 hrc = VBOX_E_OBJECT_NOT_FOUND;
556 /* Leave critical section here */
557 RTCritSectLeave(&m_CritSectData);
558
559 return hrc;
560}
561
562int TrackedObjectsCollector::i_getAllObjIds(std::vector<com::Utf8Str> &aObjIdMap) const
563{
564 //for (const com::Utf8Str &item : m_trackedObjectIds) - the gcc in the solaris VM doesn't grok this.
565 for (std::set<com::Utf8Str>::const_iterator Iter = m_trackedObjectIds.begin();
566 Iter != m_trackedObjectIds.end();
567 ++Iter)
568 {
569 if (!m_trackedInvalidObjectIds.count(*Iter))
570 aObjIdMap.push_back(*Iter);
571 }
572
573 return aObjIdMap.size() > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
574}
575
576HRESULT TrackedObjectsCollector::getObjIdsByClassIID (const Guid& iid,
577 std::vector<com::Utf8Str>& aObjIdMap)
578{
579 Log2(("%s: Getting all objects Ids with Class IID %s\n", __FUNCTION__, iid.toString().c_str()));
580
581 HRESULT hrc = S_OK;
582 int vrc = i_checkInitialization();
583 if (RT_FAILURE(vrc))
584 return VBOX_E_INVALID_OBJECT_STATE;
585
586 /* Enter critical section here */
587 RTCritSectEnter(&m_CritSectData);
588
589 vrc = i_getObjIdsByClassIID (iid, aObjIdMap);
590 if (RT_FAILURE(vrc))
591 hrc = VBOX_E_OBJECT_NOT_FOUND;
592 /* Leave critical section here */
593 RTCritSectLeave(&m_CritSectData);
594
595 return hrc;
596}
597
598int TrackedObjectsCollector::i_getObjIdsByClassIID(const Guid &aIId, std::vector<com::Utf8Str> &aObjIdMap) const
599{
600 //for (const std::pair<const com::Utf8Str, TrackedObjectData> &item : m_trackedObjectsData) - the gcc in the solaris VM doesn't grok this.
601 for (ConstIterTrObjData_T Iter = m_trackedObjectsData.begin();
602 Iter != m_trackedObjectsData.end();
603 ++Iter)
604 {
605 /* IID found and the object is valid */
606 if (Iter->second.classIID() == aIId && !m_trackedInvalidObjectIds.count(Iter->first))
607 aObjIdMap.push_back(Iter->first);
608 }
609
610 return aObjIdMap.size() > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
611}
612
613bool TrackedObjectsCollector::checkObj(const com::Utf8Str &aObjId)
614{
615 Log2(("%s: Checking object with Id %s\n", __FUNCTION__, aObjId.c_str()));
616
617 int vrc = i_checkInitialization();
618 if (RT_FAILURE(vrc))
619 return false;
620
621 RTCritSectEnter(&m_CritSectData);
622 bool res = i_checkObj(aObjId);
623 RTCritSectLeave(&m_CritSectData);
624 return res;
625}
626
627bool TrackedObjectsCollector::i_checkObj(const com::Utf8Str& aObjId) const
628{
629 return m_trackedObjectIds.count(aObjId.c_str()) > 0 ? true : false;
630}
631
632HRESULT TrackedObjectsCollector::clear(TrackedObjectsCollectorState aState)
633{
634 LogFlowFuncEnter();
635
636 HRESULT hrc = S_OK;
637 int vrc = i_checkInitialization();
638 if (RT_FAILURE(vrc))
639 return VBOX_E_INVALID_OBJECT_STATE;
640
641 if (aState != Uninitialization)
642 {
643 /* Enter critical section here */
644 vrc = RTCritSectEnter(&m_CritSectData);
645 if (RT_FAILURE(vrc))
646 {
647 Log2(("%s: Coudn't enter into the critical section (%Rrc)\n", __FUNCTION__, vrc));
648 return E_ABORT;
649 }
650 }
651
652 if (m_trackedObjectsData.size() != 0)
653 {
654 if (m_trackedObjectsData.size() > 1)
655 Log2(("%u objects are still presented in the Objects Collector, clearing...\n", m_trackedObjectsData.size()));
656 else
657 Log2(("%u object is still presented in the Objects Collector, clearing...\n", m_trackedObjectsData.size()));
658
659 vrc = i_clear();
660 /* Ignore setting hrc */
661 if (RT_FAILURE(vrc))
662 LogRel(("Something wrong with clearing the Objects Collector\n"));
663 }
664
665 Log2(("The Objects Collector history data: added objects %u, released objects %u\n", m_Added, m_Released));
666
667 if (aState != Uninitialization)
668 {
669 /* Leave critical section here */
670 RTCritSectLeave(&m_CritSectData);
671 }
672
673 return hrc;
674}
675
676int TrackedObjectsCollector::i_clear()
677{
678 int vrc = VINF_SUCCESS;
679 try
680 {
681 m_Released += m_trackedObjectsData.size();
682 m_trackedObjectsData.clear();
683 m_trackedObjectIds.clear();
684 m_trackedInvalidObjectIds.clear();
685 }
686 catch (...)
687 {
688 vrc = VERR_GENERAL_FAILURE;
689 }
690 return vrc;
691}
692
693HRESULT TrackedObjectsCollector::tryToRemoveObj(const com::Utf8Str& aObjId)
694{
695 LogFlowFuncEnter();
696
697 HRESULT hrc = S_OK;
698 int vrc = i_checkInitialization();
699 if (RT_FAILURE(vrc))
700 return VBOX_E_INVALID_OBJECT_STATE;
701
702 /* Enter critical section here */
703 RTCritSectEnter(&m_CritSectData);
704
705 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId.c_str());
706 if (pIter != m_trackedObjectsData.end())
707 {
708 pIter->second.getInterface()->AddRef();
709 ULONG cRefs = pIter->second.getInterface()->Release();
710
711 if (cRefs > 1)
712 {
713 Log2(("Object %s with class IID %s can't be released if refcount is more than 1 (now %lu)\n",
714 pIter->second.objectIdStr().c_str(),
715 pIter->second.classIIDStr().c_str(),
716 cRefs
717 ));
718 hrc = E_FAIL;
719 }
720 else
721 {
722 Log2(("Object %s with class IID %s is released (refcount %lu)\n",
723 pIter->second.objectIdStr().c_str(),
724 pIter->second.classIIDStr().c_str(),
725 cRefs
726 ));
727 m_trackedObjectsData.erase(pIter);
728 m_trackedObjectIds.erase(aObjId);
729 m_trackedInvalidObjectIds.erase(aObjId);
730
731 /* increase the counter */
732 ++m_Released;
733 }
734 }
735 else
736 hrc = VBOX_E_OBJECT_NOT_FOUND;
737
738 /* Leave critical section here */
739 RTCritSectLeave(&m_CritSectData);
740
741 return hrc;
742}
743
744/**
745 * Invalidate the tracked object.
746 * Works ONLY in conjunction with setTracked()!
747 */
748HRESULT TrackedObjectsCollector::invalidateObj(const com::Utf8Str &aObjId)
749{
750 LogFlowFuncEnter();
751
752 int vrc = i_checkInitialization();
753 if (RT_FAILURE(vrc))
754 return VBOX_E_INVALID_OBJECT_STATE;
755
756 /* Enter critical section here */
757 RTCritSectEnter(&m_CritSectData);
758
759 HRESULT hrc = VBOX_E_OBJECT_NOT_FOUND;
760 IterTrObjData_T pIter = m_trackedObjectsData.find(aObjId);
761 if (pIter != m_trackedObjectsData.end())
762 {
763 pIter->second.updateState(TrackedObjectState_Invalid);//Deleted -> Invalid
764 m_trackedInvalidObjectIds.insert(aObjId);
765 hrc = S_OK;
766 }
767
768 /* Leave critical section here */
769 RTCritSectLeave(&m_CritSectData);
770
771 return hrc;
772}
773
774/////////////////////////////////////////////////////////////////////////////
775// ObjectTracker
776/////////////////////////////////////////////////////////////////////////////
777ObjectTracker::~ObjectTracker()
778{
779 LogFlowFuncEnter();
780 LogRel(("Start waiting the ObjectTracker thread termination\n"));
781 RTThreadWait(m_Thread, 30000, NULL);
782 LogRel(("Finished waiting the ObjectTracker thread termination\n"));
783 m_Thread = NIL_RTTHREAD;
784}
785
786bool ObjectTracker::init()
787{
788 LogFlowFuncEnter();
789 return true;
790}
791
792bool ObjectTracker::finish()
793{
794 LogFlowFuncEnter();
795 ASMAtomicWriteBool(&fFinish, true);
796 return true;
797}
798
799bool ObjectTracker::isFinished()
800{
801 LogFlowFuncEnter();
802 return ASMAtomicReadBool(&fFinish);
803}
804
805/*static*/
806DECLCALLBACK(int) ObjectTracker::objectTrackerTask(RTTHREAD ThreadSelf, void *pvUser)
807{
808 HRESULT hrc = S_OK;
809
810 NOREF(ThreadSelf);
811 ObjectTracker* const master = (ObjectTracker*)pvUser;
812
813 LogRel(("Starting the ObjectTracker thread %s\n", master->getTaskName().c_str()));
814
815 while (master != NULL && master->isFinished() != true)
816 {
817 std::vector<com::Utf8Str> lObjIdMap;
818 hrc = gTrackedObjectsCollector.getAllObjIds(lObjIdMap);
819
820 //for (const com::Utf8Str& item : lObjIdMap) - the gcc in the solaris VM doesn't grok this.
821 for (std::vector<com::Utf8Str>::const_iterator Iter = lObjIdMap.begin(); Iter != lObjIdMap.end(); ++Iter)
822 {
823 TrackedObjectData temp;
824 if(gTrackedObjectsCollector.checkObj(*Iter))
825 {
826 hrc = gTrackedObjectsCollector.getObj(*Iter, temp);
827 if (SUCCEEDED(hrc))
828 {
829 Log2(("Tracked Object with ID %s was found:\n", temp.m_objId.toString().c_str()));
830
831 RTTIMESPEC now;
832 int64_t currTime = RTTimeSpecGetMilli(RTTimeNow(&now));
833 int64_t creationTime = RTTimeSpecGetMilli(&temp.m_creationTime);
834 int64_t lifeTime = (int64_t)temp.m_lifeTime*1000; //convert to milliseconds
835
836 int64_t remainingLifeTime = ((creationTime + lifeTime) - currTime)/1000;
837
838 /* lock? */
839 temp.m_pIface->AddRef();
840 unsigned long cRefs = temp.m_pIface->Release();
841
842 /* cRefs > 2 because we created the temporarily object temp */
843 Log2(("Object %s (class IID %s): refcount %lu, remaining life time is %ld sec\n",
844 temp.m_objId.toString().c_str(),
845 temp.m_classIID.toString().c_str(),
846 cRefs - 1,
847 remainingLifeTime
848 ));
849
850 bool fLifeTimeEnd = (currTime - creationTime) > lifeTime ? true : false;
851
852 if (!fLifeTimeEnd)
853 {
854 if (cRefs <= 2 || remainingLifeTime <= 0)
855 {
856 if (temp.m_fIdleTimeStart == false)
857 {
858 gTrackedObjectsCollector.initObjIdleTime(*Iter);
859 Log2(("Idle time for the object with Id %s has been started\n", Iter->c_str()));
860 }
861 else
862 {
863 int64_t idleTime = (int64_t)temp.m_idleTime*1000; //convert to milliseconds
864 int64_t idleTimeStart = RTTimeSpecGetMilli(&temp.m_idleTimeStart);
865 bool fObsolete = (currTime - idleTimeStart) > idleTime ? true : false;
866 if (fObsolete)
867 {
868 Log2(("Object with Id %s removed from Object Collector "
869 "(recount is %u, idle time exceeded %u sec)\n", Iter->c_str(), cRefs - 1, temp.m_idleTime));
870 gTrackedObjectsCollector.removeObj(*Iter);
871 }
872 }
873 }
874 }
875 else
876 {
877 if (cRefs <= 2)
878 {
879 /*
880 * Special case for objects with the original lifeTime equal to 0 (0 means endless).
881 * For these objects the idle time starts when user deletes it.
882 */
883 if (lifeTime == 0)
884 {
885 /* set lifeTime to 60 sec (1 min) */
886 lifeTime = 60;
887 /* Updating the object data */
888 gTrackedObjectsCollector.setObj(temp.objectIdStr(),
889 temp.classIIDStr(),
890 (uint64_t)lifeTime,
891 temp.m_idleTime,
892 temp.m_pIface);
893 }
894 else
895 {
896 Log2(("Object with Id %s removed from Object Collector "
897 "(lifetime exceeded %u sec)\n", Iter->c_str(), temp.m_lifeTime));
898 gTrackedObjectsCollector.removeObj(*Iter);
899 }
900 }
901 }
902 }
903 }
904 else
905 Log2(("Tracked Object with ID %s was not found\n", Iter->c_str()));
906 }
907
908 //sleep 1 sec
909 RTThreadSleep(RT_MS_1SEC);//1 sec
910 }
911
912 LogRel(("Finishing the object tracker thread %s\n", master->getTaskName().c_str()));
913
914 return 0;
915}
916
917int ObjectTracker::createThread()
918{
919 int vrc = RTThreadCreate(&m_Thread, objectTrackerTask, this, 0,
920 RTTHREADTYPE_INFREQUENT_POLLER,
921 RTTHREADFLAGS_WAITABLE,
922 "ObjTracker");
923
924 return vrc;
925}
926
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