VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMNetShaper.cpp@ 96854

Last change on this file since 96854 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.8 KB
Line 
1/* $Id: PDMNetShaper.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * PDM Network Shaper - Limit network traffic according to bandwidth group settings.
4 */
5
6/*
7 * Copyright (C) 2011-2022 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/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_NET_SHAPER
33#include <VBox/vmm/pdm.h>
34#include "PDMInternal.h"
35#include <VBox/vmm/vm.h>
36#include <VBox/vmm/uvm.h>
37#include <VBox/err.h>
38
39#include <VBox/log.h>
40#include <iprt/asm.h>
41#include <iprt/assert.h>
42#include <iprt/critsect.h>
43#include <iprt/string.h>
44#include <iprt/semaphore.h>
45#include <iprt/thread.h>
46
47#include <VBox/vmm/pdmnetshaper.h>
48
49
50
51
52/**
53 * Looks up a network bandwidth group by it's name.
54 *
55 * @returns Pointer to the group if found, NULL if not.
56 * @param pVM The cross context VM structure.
57 * @param pszName The name of the group to find.
58 */
59static PPDMNSBWGROUP pdmNsBwGroupFindByName(PVM pVM, const char *pszName)
60{
61 AssertPtrReturn(pszName, NULL);
62 AssertReturn(*pszName != '\0', NULL);
63
64 size_t const cGroups = RT_MIN(pVM->pdm.s.cNsGroups, RT_ELEMENTS(pVM->pdm.s.aNsGroups));
65 for (size_t i = 0; i < cGroups; i++)
66 if (RTStrCmp(pVM->pdm.s.aNsGroups[i].szName, pszName) == 0)
67 return &pVM->pdm.s.aNsGroups[i];
68 return NULL;
69}
70
71
72#ifdef VBOX_STRICT
73/**
74 * Checks if pFilter is attached to the given group by walking the list.
75 */
76DECLINLINE(bool) pdmR3NsIsFilterAttached(PPDMNSBWGROUP pGroup, PPDMNSFILTER pFilter)
77{
78 PPDMNSFILTER pCur;
79 RTListForEach(&pGroup->FilterList, pCur, PDMNSFILTER, ListEntry)
80 {
81 if (pCur == pFilter)
82 return true;
83 }
84 return false;
85}
86#endif
87
88/**
89 * Attaches a network filter driver to the named bandwidth group.
90 *
91 * @returns VBox status code.
92 * @retval VERR_ALREADY_INITIALIZED if already attached.
93 * @retval VERR_NOT_FOUND if the bandwidth wasn't found.
94 *
95 * @param pVM The cross context VM structure.
96 * @param pDrvIns The driver instance.
97 * @param pszName Name of the bandwidth group to attach to.
98 * @param pFilter Pointer to the filter to attach.
99 */
100VMMR3_INT_DECL(int) PDMR3NsAttach(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, PPDMNSFILTER pFilter)
101{
102 /*
103 * Validate input.
104 */
105 RT_NOREF(pDrvIns);
106 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
107 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
108
109 uint32_t iGroup = pFilter->iGroup;
110 AssertMsgReturn(iGroup == 0, ("iGroup=%d\n", iGroup), VERR_ALREADY_INITIALIZED);
111 Assert(pFilter->ListEntry.pNext == NULL);
112 Assert(pFilter->ListEntry.pPrev == NULL);
113
114 /* Resolve the group. */
115 PPDMNSBWGROUP pGroup = pdmNsBwGroupFindByName(pVM, pszName);
116 AssertMsgReturn(pGroup, ("'%s'\n", pszName), VERR_NOT_FOUND);
117
118 /*
119 * The attach is protected by PDM::NsLock and by updating iGroup atomatically.
120 */
121 int rc = RTCritSectEnter(&pVM->pdm.s.NsLock);
122 if (RT_SUCCESS(rc))
123 {
124 if (ASMAtomicCmpXchgU32(&pFilter->iGroup, (uint32_t)(pGroup - &pVM->pdm.s.aNsGroups[0]) + 1, 0))
125 {
126 Assert(pFilter->ListEntry.pNext == NULL);
127 Assert(pFilter->ListEntry.pPrev == NULL);
128 RTListAppend(&pGroup->FilterList, &pFilter->ListEntry);
129
130 uint32_t cRefs = ASMAtomicIncU32(&pGroup->cRefs);
131 AssertMsg(cRefs > 0 && cRefs < _16K, ("%u\n", cRefs));
132 RT_NOREF_PV(cRefs);
133
134 LogFlow(("PDMR3NsAttach: Attached '%s'/%u to %s (cRefs=%u)\n",
135 pDrvIns->pReg->szName, pDrvIns->iInstance, pGroup->szName, cRefs));
136 rc = VINF_SUCCESS;
137 }
138 else
139 {
140 AssertMsgFailed(("iGroup=%d (attach race)\n", pFilter->iGroup));
141 rc = VERR_ALREADY_INITIALIZED;
142 }
143
144 int rc2 = RTCritSectLeave(&pVM->pdm.s.NsLock);
145 AssertRC(rc2);
146 }
147
148 return rc;
149}
150
151
152/**
153 * Detaches a network filter driver from its current bandwidth group (if any).
154 *
155 * @returns VBox status code.
156 * @param pVM The cross context VM structure.
157 * @param pDrvIns The driver instance.
158 * @param pFilter Pointer to the filter to detach.
159 */
160VMMR3_INT_DECL(int) PDMR3NsDetach(PVM pVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
161{
162 /*
163 * Validate input.
164 */
165 RT_NOREF(pDrvIns);
166 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
167 AssertPtrReturn(pFilter, VERR_INVALID_POINTER);
168
169 /* Now, return quietly if the filter isn't attached since driver/device
170 destructors are called on constructor failure. */
171 uint32_t const iGroup = ASMAtomicUoReadU32(&pFilter->iGroup);
172 if (!iGroup)
173 return VINF_SUCCESS;
174 AssertMsgReturn(iGroup - 1 < RT_MIN(pVM->pdm.s.cNsGroups, RT_ELEMENTS(pVM->pdm.s.aNsGroups)), ("iGroup=%#x\n", iGroup),
175 VERR_INVALID_HANDLE);
176 PPDMNSBWGROUP const pGroup = &pVM->pdm.s.aNsGroups[iGroup - 1];
177
178 /*
179 * The detaching is protected by PDM::NsLock and by atomically updating iGroup.
180 */
181 int rc = RTCritSectEnter(&pVM->pdm.s.NsLock);
182 if (RT_SUCCESS(rc))
183 {
184 if (ASMAtomicCmpXchgU32(&pFilter->iGroup, 0, iGroup))
185 {
186 Assert(pdmR3NsIsFilterAttached(pGroup, pFilter));
187 RTListNodeRemove(&pFilter->ListEntry);
188 Assert(pFilter->ListEntry.pNext == NULL);
189 Assert(pFilter->ListEntry.pPrev == NULL);
190 ASMAtomicWriteU32(&pFilter->iGroup, 0);
191
192 uint32_t cRefs = ASMAtomicDecU32(&pGroup->cRefs);
193 Assert(cRefs < _16K);
194 RT_NOREF_PV(cRefs);
195
196 LogFlow(("PDMR3NsDetach: Detached '%s'/%u from %s (cRefs=%u)\n",
197 pDrvIns->pReg->szName, pDrvIns->iInstance, pGroup->szName, cRefs));
198 rc = VINF_SUCCESS;
199 }
200 else
201 AssertFailedStmt(rc = VERR_WRONG_ORDER);
202
203 int rc2 = RTCritSectLeave(&pVM->pdm.s.NsLock);
204 AssertRC(rc2);
205 }
206 else
207 AssertRC(rc);
208 return rc;
209}
210
211
212/**
213 * This is used both by pdmR3NsUnchokeThread and PDMR3NsBwGroupSetLimit,
214 * the latter only when setting cbPerSecMax to zero.
215 *
216 * @param pGroup The group which filters should be unchoked.
217 * @note Caller owns the PDM::NsLock critsect.
218 */
219static void pdmR3NsUnchokeGroupFilters(PPDMNSBWGROUP pGroup)
220{
221 PPDMNSFILTER pFilter;
222 RTListForEach(&pGroup->FilterList, pFilter, PDMNSFILTER, ListEntry)
223 {
224 bool fChoked = ASMAtomicXchgBool(&pFilter->fChoked, false);
225 if (fChoked)
226 {
227 PPDMINETWORKDOWN pIDrvNet = pFilter->pIDrvNetR3;
228 if (pIDrvNet && pIDrvNet->pfnXmitPending != NULL)
229 {
230 Log3(("pdmR3NsUnchokeGroupFilters: Unchoked %p in %s, calling %p\n",
231 pFilter, pGroup->szName, pIDrvNet->pfnXmitPending));
232 pIDrvNet->pfnXmitPending(pIDrvNet);
233 }
234 else
235 Log3(("pdmR3NsUnchokeGroupFilters: Unchoked %p in %s (no callback)\n", pFilter, pGroup->szName));
236 }
237 }
238}
239
240
241/**
242 * Worker for PDMR3NsBwGroupSetLimit and pdmR3NetShaperInit.
243 *
244 * @returns New bucket size.
245 * @param pGroup The group to update.
246 * @param cbPerSecMax The new max bytes per second.
247 */
248static uint32_t pdmNsBwGroupSetLimit(PPDMNSBWGROUP pGroup, uint64_t cbPerSecMax)
249{
250 uint32_t const cbRet = RT_MAX(PDM_NETSHAPER_MIN_BUCKET_SIZE, cbPerSecMax * PDM_NETSHAPER_MAX_LATENCY / RT_MS_1SEC);
251 pGroup->cbBucket = cbRet;
252 pGroup->cbPerSecMax = cbPerSecMax;
253 LogFlow(("pdmNsBwGroupSetLimit: New rate limit is %#RX64 bytes per second, adjusted bucket size to %#x bytes\n",
254 cbPerSecMax, cbRet));
255 return cbRet;
256}
257
258
259/**
260 * Adjusts the maximum rate for the bandwidth group.
261 *
262 * @returns VBox status code.
263 * @param pUVM The user mode VM handle.
264 * @param pszName Name of the bandwidth group to attach to.
265 * @param cbPerSecMax Maximum number of bytes per second to be transmitted.
266 */
267VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PUVM pUVM, const char *pszName, uint64_t cbPerSecMax)
268{
269 /*
270 * Validate input.
271 */
272 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
273 PVM const pVM = pUVM->pVM;
274 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
275
276 int rc;
277 PPDMNSBWGROUP pGroup = pdmNsBwGroupFindByName(pVM, pszName);
278 if (pGroup)
279 {
280 /*
281 * Lock the group while we effect the changes.
282 */
283 rc = PDMCritSectEnter(pVM, &pGroup->Lock, VERR_IGNORED);
284 if (RT_SUCCESS(rc))
285 {
286 uint32_t const cbBucket = pdmNsBwGroupSetLimit(pGroup, cbPerSecMax);
287
288 /* Drop extra tokens */
289 if (pGroup->cbTokensLast > cbBucket)
290 pGroup->cbTokensLast = cbBucket;
291 Log(("PDMR3NsBwGroupSetLimit/%s: cbBucket=%#x cbPerSecMax=%#RX64\n", pGroup->szName, cbBucket, cbPerSecMax));
292
293 int rc2 = PDMCritSectLeave(pVM, &pGroup->Lock);
294 AssertRC(rc2);
295
296 /*
297 * If we disabled the group, we must make sure to unchoke all filter
298 * as the thread will ignore the group from now on.
299 *
300 * We do this after leaving the group lock to keep the locking simple.
301 * Extra pfnXmitPending calls should be harmless, of course ASSUMING
302 * nobody take offence to being called on this thread.
303 */
304 if (cbPerSecMax == 0)
305 {
306 Log(("PDMR3NsBwGroupSetLimit: cbPerSecMax was set to zero, so unchoking filters...\n"));
307 rc = RTCritSectEnter(&pVM->pdm.s.NsLock);
308 AssertRC(rc);
309
310 pdmR3NsUnchokeGroupFilters(pGroup);
311
312 rc2 = RTCritSectLeave(&pVM->pdm.s.NsLock);
313 AssertRC(rc2);
314 }
315 }
316 else
317 AssertRC(rc);
318 }
319 else
320 rc = VERR_NOT_FOUND;
321 return rc;
322}
323
324
325/**
326 * I/O thread for pending unchoking and associating transmitting.
327 *
328 * @returns VINF_SUCCESS (ignored).
329 * @param pVM The cross context VM structure.
330 * @param pThread The PDM thread data.
331 */
332static DECLCALLBACK(int) pdmR3NsUnchokeThread(PVM pVM, PPDMTHREAD pThread)
333{
334 LogFlow(("pdmR3NsUnchokeThread: pVM=%p\n", pVM));
335 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
336 {
337 int rc = RTSemEventWait(pVM->pdm.s.hNsUnchokeEvt, RT_INDEFINITE_WAIT);
338 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
339 break;
340 AssertMsgStmt(RT_SUCCESS(rc) || rc == VERR_TIMEOUT /* paranioa*/, ("%Rrc\n", rc),
341 RTThreadSleep(PDM_NETSHAPER_MAX_LATENCY));
342
343 /*
344 * Go over all bandwidth groups/filters and unchoke their filters.
345 *
346 * We take the main lock here to prevent any detaching or attaching
347 * from taking place while we're traversing the filter lists.
348 */
349 rc = RTCritSectEnter(&pVM->pdm.s.NsLock);
350 AssertRC(rc);
351
352 size_t const cGroups = RT_MIN(pVM->pdm.s.cNsGroups, RT_ELEMENTS(pVM->pdm.s.aNsGroups));
353 for (size_t i = 0; i < cGroups; i++)
354 {
355 PPDMNSBWGROUP const pGroup = &pVM->pdm.s.aNsGroups[i];
356 if ( pGroup->cRefs > 0
357 && pGroup->cbPerSecMax > 0)
358 pdmR3NsUnchokeGroupFilters(pGroup);
359 }
360
361 rc = RTCritSectLeave(&pVM->pdm.s.NsLock);
362 AssertRC(rc);
363 }
364 return VINF_SUCCESS;
365}
366
367
368/**
369 * @copydoc FNPDMTHREADWAKEUPINT
370 */
371static DECLCALLBACK(int) pdmR3NsUnchokeWakeUp(PVM pVM, PPDMTHREAD pThread)
372{
373 LogFlow(("pdmR3NsUnchokeWakeUp:\n"));
374
375 /* Wake up the thread. */
376 int rc = RTSemEventSignal(pVM->pdm.s.hNsUnchokeEvt);
377 AssertRC(rc);
378
379 RT_NOREF(pThread);
380 return VINF_SUCCESS;
381}
382
383
384/**
385 * @callback_method_impl{FNTMTIMERINT, Wakes up pdmR3NsUnchokeThread.}
386 */
387static DECLCALLBACK(void) pdmR3NsUnchokeTimer(PVM pVM, TMTIMERHANDLE hTimer, void *pvUser)
388{
389 ASMAtomicWriteBool(&pVM->pdm.s.fNsUnchokeTimerArmed, false);
390
391 /* Wake up the thread. */
392 int rc = RTSemEventSignal(pVM->pdm.s.hNsUnchokeEvt);
393 AssertRC(rc);
394
395 RT_NOREF(hTimer, pvUser);
396}
397
398
399/**
400 * Terminate the network shaper, groups, lock and everything.
401 *
402 * @returns VBox error code.
403 * @param pVM The cross context VM structure.
404 */
405void pdmR3NetShaperTerm(PVM pVM)
406{
407 size_t const cGroups = RT_MIN(pVM->pdm.s.cNsGroups, RT_ELEMENTS(pVM->pdm.s.aNsGroups));
408 for (size_t i = 0; i < cGroups; i++)
409 {
410 PPDMNSBWGROUP const pGroup = &pVM->pdm.s.aNsGroups[i];
411 AssertMsg(pGroup->cRefs == 0, ("cRefs=%s '%s'\n", pGroup->cRefs, pGroup->szName));
412 AssertContinue(PDMCritSectIsInitialized(&pGroup->Lock));
413 PDMR3CritSectDelete(pVM, &pGroup->Lock);
414 }
415
416 RTCritSectDelete(&pVM->pdm.s.NsLock);
417}
418
419
420/**
421 * Initialize the network shaper.
422 *
423 * @returns VBox status code
424 * @param pVM The cross context VM structure.
425 */
426int pdmR3NetShaperInit(PVM pVM)
427{
428 LogFlow(("pdmR3NetShaperInit: pVM=%p\n", pVM));
429 VM_ASSERT_EMT(pVM);
430
431 Assert(pVM->pdm.s.cNsGroups == 0);
432 pVM->pdm.s.hNsUnchokeEvt = NIL_RTSEMEVENT;
433 pVM->pdm.s.hNsUnchokeTimer = NIL_TMTIMERHANDLE;
434
435 /*
436 * Initialize the critical section protecting attaching, detaching and unchoking.
437 *
438 * This is a non-recursive lock to make sure nobody tries to mess with the groups
439 * from the pfnXmitPending callback.
440 */
441 int rc = RTCritSectInitEx(&pVM->pdm.s.NsLock, RTCRITSECT_FLAGS_NO_NESTING,
442 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "PDMNetShaper");
443 AssertRCReturn(rc, rc);
444
445 /*
446 * Initialize all bandwidth groups.
447 */
448 PCFGMNODE pCfgNetShaper = CFGMR3GetChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM"), "NetworkShaper");
449 PCFGMNODE pCfgBwGrp = CFGMR3GetChild(pCfgNetShaper, "BwGroups");
450 if (pCfgBwGrp)
451 {
452 uint32_t iGroup = 0;
453 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pCfgBwGrp); pCur; pCur = CFGMR3GetNextChild(pCur))
454 {
455 /*
456 * Get the config data.
457 */
458 size_t cchName = CFGMR3GetNameLen(pCur);
459 AssertBreakStmt(cchName <= PDM_NET_SHAPER_MAX_NAME_LEN,
460 rc = VMR3SetError(pVM->pUVM, VERR_INVALID_NAME, RT_SRC_POS,
461 N_("Network shaper group name #%u is too long: %zu, max %u"),
462 iGroup, cchName, PDM_NET_SHAPER_MAX_NAME_LEN));
463 char szName[PDM_NET_SHAPER_MAX_NAME_LEN + 1];
464 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
465 AssertRCBreak(rc);
466 AssertBreakStmt(szName[0] != '\0',
467 rc = VMR3SetError(pVM->pUVM, VERR_INVALID_NAME, RT_SRC_POS,
468 N_("Empty network shaper group name #%u"), iGroup));
469
470 uint64_t cbMax;
471 rc = CFGMR3QueryU64(pCur, "Max", &cbMax);
472 AssertRCBreakStmt(rc, rc = VMR3SetError(pVM->pUVM, rc, RT_SRC_POS,
473 N_("Failed to read 'Max' value for network shaper group '%s': %Rrc"),
474 szName, rc));
475
476 /*
477 * Initialize the group table entry.
478 */
479 AssertBreakStmt(iGroup < RT_ELEMENTS(pVM->pdm.s.aNsGroups),
480 rc = VMR3SetError(pVM->pUVM, VERR_TOO_MUCH_DATA, RT_SRC_POS, N_("Too many bandwidth groups (max %zu)"),
481 RT_ELEMENTS(pVM->pdm.s.aNsGroups)));
482
483 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.aNsGroups[iGroup].Lock, RT_SRC_POS, "BWGRP%02u-%s", iGroup, szName);
484 AssertRCBreak(rc);
485
486 RTListInit(&pVM->pdm.s.aNsGroups[iGroup].FilterList);
487 pVM->pdm.s.aNsGroups[iGroup].cRefs = 0;
488 RTStrCopy(pVM->pdm.s.aNsGroups[iGroup].szName, sizeof(pVM->pdm.s.aNsGroups[iGroup].szName), szName);
489 pVM->pdm.s.aNsGroups[iGroup].cbTokensLast = pdmNsBwGroupSetLimit(&pVM->pdm.s.aNsGroups[iGroup], cbMax);
490 pVM->pdm.s.aNsGroups[iGroup].tsUpdatedLast = RTTimeSystemNanoTS();
491 LogFlowFunc(("PDM NetShaper Group #%u: %s - cbPerSecMax=%#RU64 cbBucket=%#x\n",
492 iGroup, pVM->pdm.s.aNsGroups[iGroup].szName, pVM->pdm.s.aNsGroups[iGroup].cbPerSecMax,
493 pVM->pdm.s.aNsGroups[iGroup].cbBucket));
494
495 /*
496 * Register statistics.
497 */
498 STAMR3RegisterF(pVM, (void *)&pVM->pdm.s.aNsGroups[iGroup].cbPerSecMax, STAMTYPE_U64, STAMVISIBILITY_ALWAYS,
499 STAMUNIT_BYTES, "", "/PDM/NetShaper/%u-%s/cbPerSecMax", iGroup, szName);
500 STAMR3RegisterF(pVM, (void *)&pVM->pdm.s.aNsGroups[iGroup].cRefs, STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
501 STAMUNIT_BYTES, "", "/PDM/NetShaper/%u-%s/cRefs", iGroup, szName);
502 STAMR3RegisterF(pVM, (void *)&pVM->pdm.s.aNsGroups[iGroup].cbBucket, STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
503 STAMUNIT_BYTES, "", "/PDM/NetShaper/%u-%s/cbBucket", iGroup, szName);
504 STAMR3RegisterF(pVM, (void *)&pVM->pdm.s.aNsGroups[iGroup].cbTokensLast, STAMTYPE_U32, STAMVISIBILITY_ALWAYS,
505 STAMUNIT_BYTES, "", "/PDM/NetShaper/%u-%s/cbTokensLast", iGroup, szName);
506 STAMR3RegisterF(pVM, (void *)&pVM->pdm.s.aNsGroups[iGroup].tsUpdatedLast, STAMTYPE_U64, STAMVISIBILITY_ALWAYS,
507 STAMUNIT_NS, "", "/PDM/NetShaper/%u-%s/tsUpdatedLast", iGroup, szName);
508 STAMR3RegisterF(pVM, (void *)&pVM->pdm.s.aNsGroups[iGroup].cTotalChokings, STAMTYPE_U64_RESET, STAMVISIBILITY_ALWAYS,
509 STAMUNIT_OCCURENCES, "", "/PDM/NetShaper/%u-%s/TotalChokings", iGroup, szName);
510
511 pVM->pdm.s.cNsGroups = ++iGroup;
512 }
513 }
514 if (RT_SUCCESS(rc))
515 {
516 /*
517 * If there are any groups configured, create a unchoke thread and an
518 * associated timer for waking it up when needed. The timer runs on
519 * the real time clock.
520 */
521 if (pVM->pdm.s.cNsGroups == 0)
522 {
523 LogFlowFunc(("returns VINF_SUCCESS - no groups\n"));
524 return VINF_SUCCESS;
525 }
526
527 rc = RTSemEventCreate(&pVM->pdm.s.hNsUnchokeEvt);
528 if (RT_SUCCESS(rc))
529 {
530 rc = TMR3TimerCreate(pVM, TMCLOCK_REAL, pdmR3NsUnchokeTimer, NULL, TMTIMER_FLAGS_NO_RING0,
531 "PDMNetShaperUnchoke", &pVM->pdm.s.hNsUnchokeTimer);
532 if (RT_SUCCESS(rc))
533 {
534 rc = PDMR3ThreadCreate(pVM, &pVM->pdm.s.pNsUnchokeThread, NULL, pdmR3NsUnchokeThread, pdmR3NsUnchokeWakeUp,
535 0 /*cbStack*/, RTTHREADTYPE_IO, "PDMNsUnchoke");
536 if (RT_SUCCESS(rc))
537 {
538
539 LogFlowFunc(("returns VINF_SUCCESS (%u groups)\n", pVM->pdm.s.cNsGroups));
540 return VINF_SUCCESS;
541 }
542 }
543 }
544 }
545
546 RTCritSectDelete(&pVM->pdm.s.NsLock);
547 LogRel(("pdmR3NetShaperInit: failed rc=%Rrc\n", rc));
548 return rc;
549}
550
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