VirtualBox

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

Last change on this file since 95638 was 93633, checked in by vboxsync, 3 years ago

VMM/PDMNetShaper: Statistics. bugref:5582

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