VirtualBox

source: vbox/trunk/src/VBox/Main/Performance.cpp@ 33000

Last change on this file since 33000 was 32056, checked in by vboxsync, 14 years ago

Applied a simple memory leak detector to libjpeg and VBoxC (Windows host only), the code completely disabled by default.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1/* $Id: Performance.cpp 32056 2010-08-27 16:04:23Z vboxsync $ */
2
3/** @file
4 *
5 * VBox Performance Classes implementation.
6 */
7
8/*
9 * Copyright (C) 2008 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/*
21 * @todo list:
22 *
23 * 1) Detection of erroneous metric names
24 */
25
26#ifndef VBOX_COLLECTOR_TEST_CASE
27#include "VirtualBoxImpl.h"
28#include "MachineImpl.h"
29#endif
30#include "Performance.h"
31
32#include <VBox/com/array.h>
33#include <VBox/com/ptr.h>
34#include <VBox/com/string.h>
35#include <VBox/err.h>
36#include <iprt/string.h>
37#ifndef VBOX_WITH_VRDP_MEMLEAK_DETECTOR
38#include <iprt/mem.h>
39#endif /* !VBOX_WITH_VRDP_MEMLEAK_DETECTOR */
40#include <iprt/cpuset.h>
41
42#include <algorithm>
43
44#include "Logging.h"
45
46using namespace pm;
47
48// Stubs for non-pure virtual methods
49
50int CollectorHAL::getHostCpuLoad(ULONG * /* user */, ULONG * /* kernel */, ULONG * /* idle */)
51{
52 return E_NOTIMPL;
53}
54
55int CollectorHAL::getProcessCpuLoad(RTPROCESS /* process */, ULONG * /* user */, ULONG * /* kernel */)
56{
57 return E_NOTIMPL;
58}
59
60int CollectorHAL::getRawHostCpuLoad(uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* idle */)
61{
62 return E_NOTIMPL;
63}
64
65int CollectorHAL::getRawProcessCpuLoad(RTPROCESS /* process */, uint64_t * /* user */, uint64_t * /* kernel */, uint64_t * /* total */)
66{
67 return E_NOTIMPL;
68}
69
70int CollectorHAL::getHostMemoryUsage(ULONG * /* total */, ULONG * /* used */, ULONG * /* available */)
71{
72 return E_NOTIMPL;
73}
74
75int CollectorHAL::getProcessMemoryUsage(RTPROCESS /* process */, ULONG * /* used */)
76{
77 return E_NOTIMPL;
78}
79
80int CollectorHAL::enable()
81{
82 return E_NOTIMPL;
83}
84
85int CollectorHAL::disable()
86{
87 return E_NOTIMPL;
88}
89
90/* Generic implementations */
91
92int CollectorHAL::getHostCpuMHz(ULONG *mhz)
93{
94 unsigned cCpus = 0;
95 uint64_t u64TotalMHz = 0;
96 RTCPUSET OnlineSet;
97 RTMpGetOnlineSet(&OnlineSet);
98 for (RTCPUID iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
99 {
100 LogAleksey(("{%p} " LOG_FN_FMT ": Checking if CPU %d is member of online set...\n",
101 this, __PRETTY_FUNCTION__, (int)iCpu));
102 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
103 {
104 LogAleksey(("{%p} " LOG_FN_FMT ": Getting frequency for CPU %d...\n",
105 this, __PRETTY_FUNCTION__, (int)iCpu));
106 uint32_t uMHz = RTMpGetCurFrequency(RTMpCpuIdFromSetIndex(iCpu));
107 if (uMHz != 0)
108 {
109 LogAleksey(("{%p} " LOG_FN_FMT ": CPU %d %u MHz\n",
110 this, __PRETTY_FUNCTION__, (int)iCpu, uMHz));
111 u64TotalMHz += uMHz;
112 cCpus++;
113 }
114 }
115 }
116
117 AssertReturn(cCpus, VERR_NOT_IMPLEMENTED);
118 *mhz = (ULONG)(u64TotalMHz / cCpus);
119
120 return VINF_SUCCESS;
121}
122
123#ifndef VBOX_COLLECTOR_TEST_CASE
124
125uint32_t CollectorGuestHAL::cVMsEnabled = 0;
126
127CollectorGuestHAL::CollectorGuestHAL(Machine *machine, CollectorHAL *hostHAL)
128 : CollectorHAL(), cEnabled(0), mMachine(machine), mConsole(NULL),
129 mGuest(NULL), mLastTick(0), mHostHAL(hostHAL), mCpuUser(0),
130 mCpuKernel(0), mCpuIdle(0), mMemTotal(0), mMemFree(0),
131 mMemBalloon(0), mMemShared(0), mMemCache(0), mPageTotal(0)
132{
133 Assert(mMachine);
134 /* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
135 mMachine->AddRef();
136}
137
138CollectorGuestHAL::~CollectorGuestHAL()
139{
140 /* cannot use ComObjPtr<Machine> in Performance.h, do it manually */
141 mMachine->Release();
142 Assert(!cEnabled);
143}
144
145int CollectorGuestHAL::enable()
146{
147 /* Must make sure that the machine object does not get uninitialized
148 * in the middle of enabling this collector. Causes timing-related
149 * behavior otherwise, which we don't want. In particular the
150 * GetRemoteConsole call below can hang if the VM didn't completely
151 * terminate (the VM processes stop processing events shortly before
152 * closing the session). This avoids the hang. */
153 AutoCaller autoCaller(mMachine);
154 if (FAILED(autoCaller.rc())) return autoCaller.rc();
155
156 HRESULT ret = S_OK;
157
158 if (ASMAtomicIncU32(&cEnabled) == 1)
159 {
160 ASMAtomicIncU32(&cVMsEnabled);
161 ComPtr<IInternalSessionControl> directControl;
162
163 ret = mMachine->getDirectControl(&directControl);
164 if (ret != S_OK)
165 return ret;
166
167 /* get the associated console; this is a remote call (!) */
168 ret = directControl->GetRemoteConsole(mConsole.asOutParam());
169 if (ret != S_OK)
170 return ret;
171
172 ret = mConsole->COMGETTER(Guest)(mGuest.asOutParam());
173 if (ret == S_OK)
174 mGuest->COMSETTER(StatisticsUpdateInterval)(1 /* 1 sec */);
175 }
176 return ret;
177}
178
179int CollectorGuestHAL::disable()
180{
181 if (ASMAtomicDecU32(&cEnabled) == 0)
182 {
183 if (ASMAtomicDecU32(&cVMsEnabled) == 0)
184 {
185 if (mHostHAL)
186 mHostHAL->setMemHypervisorStats(0 /* ulMemAllocTotal */, 0 /* ulMemFreeTotal */, 0 /* ulMemBalloonTotal */, 0 /* ulMemSharedTotal */);
187 }
188 Assert(mGuest && mConsole);
189 mGuest->COMSETTER(StatisticsUpdateInterval)(0 /* off */);
190 }
191 return S_OK;
192}
193
194int CollectorGuestHAL::preCollect(const CollectorHints& /* hints */, uint64_t iTick)
195{
196 if ( mGuest
197 && iTick != mLastTick)
198 {
199 ULONG ulMemAllocTotal, ulMemFreeTotal, ulMemBalloonTotal, ulMemSharedTotal;
200
201 mGuest->InternalGetStatistics(&mCpuUser, &mCpuKernel, &mCpuIdle,
202 &mMemTotal, &mMemFree, &mMemBalloon, &mMemShared, &mMemCache,
203 &mPageTotal, &ulMemAllocTotal, &ulMemFreeTotal, &ulMemBalloonTotal, &ulMemSharedTotal);
204
205 if (mHostHAL)
206 mHostHAL->setMemHypervisorStats(ulMemAllocTotal, ulMemFreeTotal, ulMemBalloonTotal, ulMemSharedTotal);
207
208 mLastTick = iTick;
209 }
210 return S_OK;
211}
212
213#endif /* !VBOX_COLLECTOR_TEST_CASE */
214
215bool BaseMetric::collectorBeat(uint64_t nowAt)
216{
217 if (isEnabled())
218 {
219 if (nowAt - mLastSampleTaken >= mPeriod * 1000)
220 {
221 mLastSampleTaken = nowAt;
222 Log4(("{%p} " LOG_FN_FMT ": Collecting %s for obj(%p)...\n",
223 this, __PRETTY_FUNCTION__, getName(), (void *)mObject));
224 return true;
225 }
226 }
227 return false;
228}
229
230/*bool BaseMetric::associatedWith(ComPtr<IUnknown> object)
231{
232 LogFlowThisFunc(("mObject(%p) == object(%p) is %s.\n", mObject, object, mObject == object ? "true" : "false"));
233 return mObject == object;
234}*/
235
236void HostCpuLoad::init(ULONG period, ULONG length)
237{
238 mPeriod = period;
239 mLength = length;
240 mUser->init(mLength);
241 mKernel->init(mLength);
242 mIdle->init(mLength);
243}
244
245void HostCpuLoad::collect()
246{
247 ULONG user, kernel, idle;
248 int rc = mHAL->getHostCpuLoad(&user, &kernel, &idle);
249 if (RT_SUCCESS(rc))
250 {
251 mUser->put(user);
252 mKernel->put(kernel);
253 mIdle->put(idle);
254 }
255}
256
257void HostCpuLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */)
258{
259 hints.collectHostCpuLoad();
260}
261
262void HostCpuLoadRaw::collect()
263{
264 uint64_t user, kernel, idle;
265 uint64_t userDiff, kernelDiff, idleDiff, totalDiff;
266
267 int rc = mHAL->getRawHostCpuLoad(&user, &kernel, &idle);
268 if (RT_SUCCESS(rc))
269 {
270 userDiff = user - mUserPrev;
271 kernelDiff = kernel - mKernelPrev;
272 idleDiff = idle - mIdlePrev;
273 totalDiff = userDiff + kernelDiff + idleDiff;
274
275 if (totalDiff == 0)
276 {
277 /* This is only possible if none of counters has changed! */
278 LogFlowThisFunc(("Impossible! User, kernel and idle raw "
279 "counters has not changed since last sample.\n" ));
280 mUser->put(0);
281 mKernel->put(0);
282 mIdle->put(0);
283 }
284 else
285 {
286 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * userDiff / totalDiff));
287 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * kernelDiff / totalDiff));
288 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * idleDiff / totalDiff));
289 }
290
291 mUserPrev = user;
292 mKernelPrev = kernel;
293 mIdlePrev = idle;
294 }
295}
296
297void HostCpuMhz::init(ULONG period, ULONG length)
298{
299 mPeriod = period;
300 mLength = length;
301 mMHz->init(mLength);
302}
303
304void HostCpuMhz::collect()
305{
306 ULONG mhz;
307 int rc = mHAL->getHostCpuMHz(&mhz);
308 if (RT_SUCCESS(rc))
309 mMHz->put(mhz);
310}
311
312void HostRamUsage::init(ULONG period, ULONG length)
313{
314 mPeriod = period;
315 mLength = length;
316 mTotal->init(mLength);
317 mUsed->init(mLength);
318 mAvailable->init(mLength);
319 mAllocVMM->init(mLength);
320 mFreeVMM->init(mLength);
321 mBalloonVMM->init(mLength);
322 mSharedVMM->init(mLength);
323}
324
325void HostRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
326{
327 hints.collectHostRamUsage();
328}
329
330void HostRamUsage::collect()
331{
332 ULONG total, used, available;
333 int rc = mHAL->getHostMemoryUsage(&total, &used, &available);
334 if (RT_SUCCESS(rc))
335 {
336 mTotal->put(total);
337 mUsed->put(used);
338 mAvailable->put(available);
339
340 }
341 ULONG allocVMM, freeVMM, balloonVMM, sharedVMM;
342
343 mHAL->getMemHypervisorStats(&allocVMM, &freeVMM, &balloonVMM, &sharedVMM);
344 mAllocVMM->put(allocVMM);
345 mFreeVMM->put(freeVMM);
346 mBalloonVMM->put(balloonVMM);
347 mSharedVMM->put(sharedVMM);
348}
349
350
351
352void MachineCpuLoad::init(ULONG period, ULONG length)
353{
354 mPeriod = period;
355 mLength = length;
356 mUser->init(mLength);
357 mKernel->init(mLength);
358}
359
360void MachineCpuLoad::collect()
361{
362 ULONG user, kernel;
363 int rc = mHAL->getProcessCpuLoad(mProcess, &user, &kernel);
364 if (RT_SUCCESS(rc))
365 {
366 mUser->put(user);
367 mKernel->put(kernel);
368 }
369}
370
371void MachineCpuLoadRaw::preCollect(CollectorHints& hints, uint64_t /* iTick */)
372{
373 hints.collectProcessCpuLoad(mProcess);
374}
375
376void MachineCpuLoadRaw::collect()
377{
378 uint64_t processUser, processKernel, hostTotal;
379
380 int rc = mHAL->getRawProcessCpuLoad(mProcess, &processUser, &processKernel, &hostTotal);
381 if (RT_SUCCESS(rc))
382 {
383 if (hostTotal == mHostTotalPrev)
384 {
385 /* Nearly impossible, but... */
386 mUser->put(0);
387 mKernel->put(0);
388 }
389 else
390 {
391 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processUser - mProcessUserPrev) / (hostTotal - mHostTotalPrev)));
392 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * (processKernel - mProcessKernelPrev ) / (hostTotal - mHostTotalPrev)));
393 }
394
395 mHostTotalPrev = hostTotal;
396 mProcessUserPrev = processUser;
397 mProcessKernelPrev = processKernel;
398 }
399}
400
401void MachineRamUsage::init(ULONG period, ULONG length)
402{
403 mPeriod = period;
404 mLength = length;
405 mUsed->init(mLength);
406}
407
408void MachineRamUsage::preCollect(CollectorHints& hints, uint64_t /* iTick */)
409{
410 hints.collectProcessRamUsage(mProcess);
411}
412
413void MachineRamUsage::collect()
414{
415 ULONG used;
416 int rc = mHAL->getProcessMemoryUsage(mProcess, &used);
417 if (RT_SUCCESS(rc))
418 mUsed->put(used);
419}
420
421
422void GuestCpuLoad::init(ULONG period, ULONG length)
423{
424 mPeriod = period;
425 mLength = length;
426
427 mUser->init(mLength);
428 mKernel->init(mLength);
429 mIdle->init(mLength);
430}
431
432void GuestCpuLoad::preCollect(CollectorHints& hints, uint64_t iTick)
433{
434 mHAL->preCollect(hints, iTick);
435}
436
437void GuestCpuLoad::collect()
438{
439 ULONG CpuUser = 0, CpuKernel = 0, CpuIdle = 0;
440
441 mGuestHAL->getGuestCpuLoad(&CpuUser, &CpuKernel, &CpuIdle);
442 mUser->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * CpuUser) / 100);
443 mKernel->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * CpuKernel) / 100);
444 mIdle->put((ULONG)(PM_CPU_LOAD_MULTIPLIER * CpuIdle) / 100);
445}
446
447void GuestRamUsage::init(ULONG period, ULONG length)
448{
449 mPeriod = period;
450 mLength = length;
451
452 mTotal->init(mLength);
453 mFree->init(mLength);
454 mBallooned->init(mLength);
455 mShared->init(mLength);
456 mCache->init(mLength);
457 mPagedTotal->init(mLength);
458}
459
460void GuestRamUsage::preCollect(CollectorHints& hints, uint64_t iTick)
461{
462 mHAL->preCollect(hints, iTick);
463}
464
465void GuestRamUsage::collect()
466{
467 ULONG ulMemTotal = 0, ulMemFree = 0, ulMemBalloon = 0, ulMemShared = 0, ulMemCache = 0, ulPageTotal = 0;
468
469 mGuestHAL->getGuestMemLoad(&ulMemTotal, &ulMemFree, &ulMemBalloon, &ulMemShared, &ulMemCache, &ulPageTotal);
470 mTotal->put(ulMemTotal);
471 mFree->put(ulMemFree);
472 mBallooned->put(ulMemBalloon);
473 mShared->put(ulMemShared);
474 mCache->put(ulMemCache);
475 mPagedTotal->put(ulPageTotal);
476}
477
478void CircularBuffer::init(ULONG ulLength)
479{
480 if (mData)
481 RTMemFree(mData);
482 mLength = ulLength;
483 if (mLength)
484 mData = (ULONG*)RTMemAllocZ(ulLength * sizeof(ULONG));
485 else
486 mData = NULL;
487 mWrapped = false;
488 mEnd = 0;
489 mSequenceNumber = 0;
490}
491
492ULONG CircularBuffer::length()
493{
494 return mWrapped ? mLength : mEnd;
495}
496
497void CircularBuffer::put(ULONG value)
498{
499 if (mData)
500 {
501 mData[mEnd++] = value;
502 if (mEnd >= mLength)
503 {
504 mEnd = 0;
505 mWrapped = true;
506 }
507 ++mSequenceNumber;
508 }
509}
510
511void CircularBuffer::copyTo(ULONG *data)
512{
513 if (mWrapped)
514 {
515 memcpy(data, mData + mEnd, (mLength - mEnd) * sizeof(ULONG));
516 // Copy the wrapped part
517 if (mEnd)
518 memcpy(data + (mLength - mEnd), mData, mEnd * sizeof(ULONG));
519 }
520 else
521 memcpy(data, mData, mEnd * sizeof(ULONG));
522}
523
524void SubMetric::query(ULONG *data)
525{
526 copyTo(data);
527}
528
529void Metric::query(ULONG **data, ULONG *count, ULONG *sequenceNumber)
530{
531 ULONG length;
532 ULONG *tmpData;
533
534 length = mSubMetric->length();
535 *sequenceNumber = mSubMetric->getSequenceNumber() - length;
536 if (length)
537 {
538 tmpData = (ULONG*)RTMemAlloc(sizeof(*tmpData)*length);
539 mSubMetric->query(tmpData);
540 if (mAggregate)
541 {
542 *count = 1;
543 *data = (ULONG*)RTMemAlloc(sizeof(**data));
544 **data = mAggregate->compute(tmpData, length);
545 RTMemFree(tmpData);
546 }
547 else
548 {
549 *count = length;
550 *data = tmpData;
551 }
552 }
553 else
554 {
555 *count = 0;
556 *data = 0;
557 }
558}
559
560ULONG AggregateAvg::compute(ULONG *data, ULONG length)
561{
562 uint64_t tmp = 0;
563 for (ULONG i = 0; i < length; ++i)
564 tmp += data[i];
565 return (ULONG)(tmp / length);
566}
567
568const char * AggregateAvg::getName()
569{
570 return "avg";
571}
572
573ULONG AggregateMin::compute(ULONG *data, ULONG length)
574{
575 ULONG tmp = *data;
576 for (ULONG i = 0; i < length; ++i)
577 if (data[i] < tmp)
578 tmp = data[i];
579 return tmp;
580}
581
582const char * AggregateMin::getName()
583{
584 return "min";
585}
586
587ULONG AggregateMax::compute(ULONG *data, ULONG length)
588{
589 ULONG tmp = *data;
590 for (ULONG i = 0; i < length; ++i)
591 if (data[i] > tmp)
592 tmp = data[i];
593 return tmp;
594}
595
596const char * AggregateMax::getName()
597{
598 return "max";
599}
600
601Filter::Filter(ComSafeArrayIn(IN_BSTR, metricNames),
602 ComSafeArrayIn(IUnknown *, objects))
603{
604 /*
605 * Let's work around null/empty safe array mess. I am not sure there is
606 * a way to pass null arrays via webservice, I haven't found one. So I
607 * guess the users will be forced to use empty arrays instead. Constructing
608 * an empty SafeArray is a bit awkward, so what we do in this method is
609 * actually convert null arrays to empty arrays and pass them down to
610 * init() method. If someone knows how to do it better, please be my guest,
611 * fix it.
612 */
613 if (ComSafeArrayInIsNull(metricNames))
614 {
615 com::SafeArray<BSTR> nameArray;
616 if (ComSafeArrayInIsNull(objects))
617 {
618 com::SafeIfaceArray<IUnknown> objectArray;
619 objectArray.reset(0);
620 init(ComSafeArrayAsInParam(nameArray),
621 ComSafeArrayAsInParam(objectArray));
622 }
623 else
624 {
625 com::SafeIfaceArray<IUnknown> objectArray(ComSafeArrayInArg(objects));
626 init(ComSafeArrayAsInParam(nameArray),
627 ComSafeArrayAsInParam(objectArray));
628 }
629 }
630 else
631 {
632 com::SafeArray<IN_BSTR> nameArray(ComSafeArrayInArg(metricNames));
633 if (ComSafeArrayInIsNull(objects))
634 {
635 com::SafeIfaceArray<IUnknown> objectArray;
636 objectArray.reset(0);
637 init(ComSafeArrayAsInParam(nameArray),
638 ComSafeArrayAsInParam(objectArray));
639 }
640 else
641 {
642 com::SafeIfaceArray<IUnknown> objectArray(ComSafeArrayInArg(objects));
643 init(ComSafeArrayAsInParam(nameArray),
644 ComSafeArrayAsInParam(objectArray));
645 }
646 }
647}
648
649void Filter::init(ComSafeArrayIn(IN_BSTR, metricNames),
650 ComSafeArrayIn(IUnknown *, objects))
651{
652 com::SafeArray<IN_BSTR> nameArray(ComSafeArrayInArg(metricNames));
653 com::SafeIfaceArray<IUnknown> objectArray(ComSafeArrayInArg(objects));
654
655 if (!objectArray.size())
656 {
657 if (nameArray.size())
658 {
659 for (size_t i = 0; i < nameArray.size(); ++i)
660 processMetricList(com::Utf8Str(nameArray[i]), ComPtr<IUnknown>());
661 }
662 else
663 processMetricList("*", ComPtr<IUnknown>());
664 }
665 else
666 {
667 for (size_t i = 0; i < objectArray.size(); ++i)
668 switch (nameArray.size())
669 {
670 case 0:
671 processMetricList("*", objectArray[i]);
672 break;
673 case 1:
674 processMetricList(com::Utf8Str(nameArray[0]), objectArray[i]);
675 break;
676 default:
677 processMetricList(com::Utf8Str(nameArray[i]), objectArray[i]);
678 break;
679 }
680 }
681}
682
683void Filter::processMetricList(const com::Utf8Str &name, const ComPtr<IUnknown> object)
684{
685 size_t startPos = 0;
686
687 for (size_t pos = name.find(",");
688 pos != com::Utf8Str::npos;
689 pos = name.find(",", startPos))
690 {
691 mElements.push_back(std::make_pair(object, iprt::MiniString(name.substr(startPos, pos - startPos).c_str())));
692 startPos = pos + 1;
693 }
694 mElements.push_back(std::make_pair(object, iprt::MiniString(name.substr(startPos).c_str())));
695}
696
697/**
698 * The following method was borrowed from stamR3Match (VMM/STAM.cpp) and
699 * modified to handle the special case of trailing colon in the pattern.
700 *
701 * @returns True if matches, false if not.
702 * @param pszPat Pattern.
703 * @param pszName Name to match against the pattern.
704 * @param fSeenColon Seen colon (':').
705 */
706bool Filter::patternMatch(const char *pszPat, const char *pszName,
707 bool fSeenColon)
708{
709 /* ASSUMES ASCII */
710 for (;;)
711 {
712 char chPat = *pszPat;
713 switch (chPat)
714 {
715 default:
716 if (*pszName != chPat)
717 return false;
718 break;
719
720 case '*':
721 {
722 while ((chPat = *++pszPat) == '*' || chPat == '?')
723 /* nothing */;
724
725 /* Handle a special case, the mask terminating with a colon. */
726 if (chPat == ':')
727 {
728 if (!fSeenColon && !pszPat[1])
729 return !strchr(pszName, ':');
730 fSeenColon = true;
731 }
732
733 for (;;)
734 {
735 char ch = *pszName++;
736 if ( ch == chPat
737 && ( !chPat
738 || patternMatch(pszPat + 1, pszName, fSeenColon)))
739 return true;
740 if (!ch)
741 return false;
742 }
743 /* won't ever get here */
744 break;
745 }
746
747 case '?':
748 if (!*pszName)
749 return false;
750 break;
751
752 /* Handle a special case, the mask terminating with a colon. */
753 case ':':
754 if (!fSeenColon && !pszPat[1])
755 return !*pszName;
756 if (*pszName != ':')
757 return false;
758 fSeenColon = true;
759 break;
760
761 case '\0':
762 return !*pszName;
763 }
764 pszName++;
765 pszPat++;
766 }
767 return true;
768}
769
770bool Filter::match(const ComPtr<IUnknown> object, const iprt::MiniString &name) const
771{
772 ElementList::const_iterator it;
773
774 LogAleksey(("Filter::match(%p, %s)\n", static_cast<const IUnknown*> (object), name.c_str()));
775 for (it = mElements.begin(); it != mElements.end(); it++)
776 {
777 LogAleksey(("...matching against(%p, %s)\n", static_cast<const IUnknown*> ((*it).first), (*it).second.c_str()));
778 if ((*it).first.isNull() || (*it).first == object)
779 {
780 // Objects match, compare names
781 if (patternMatch((*it).second.c_str(), name.c_str()))
782 {
783 LogFlowThisFunc(("...found!\n"));
784 return true;
785 }
786 }
787 }
788 LogAleksey(("...no matches!\n"));
789 return false;
790}
791/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use