Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1693 lines
41 KiB

  1. /*
  2. - QOS.CPP
  3. -
  4. * Microsoft NetMeeting
  5. * Quality of Service DLL
  6. * IQoS interfaces
  7. *
  8. * Revision History:
  9. *
  10. * When Who What
  11. * -------- ------------------ ---------------------------------------
  12. * 10.23.96 Yoram Yaacovi Created
  13. *
  14. * Functions:
  15. * IQoS
  16. * CQoS::QueryInterface
  17. * CQoS::AddRef
  18. * CQoS::Release
  19. * CQoS::RequestResources
  20. * CQoS::ReleaseResources
  21. * CQoS::SetClients
  22. * CQoS::SetResources
  23. * CQoS::GetResources
  24. * CQoS::FreeBuffer
  25. * Public:
  26. * CQoS::CQoS
  27. * CQoS::~CQoS
  28. * CQoS::Initialize
  29. * Private
  30. * CQoS::AnyRequests
  31. * CQoS::FindClientsForResource
  32. * CQoS::StoreResourceRequest
  33. * CQoS::FreeResourceRequest
  34. * CQoS::UpdateClientInfo
  35. * CQoS::QoSCleanup
  36. * CQoS::FindClient
  37. * CQoS::UpdateRequestsForClient
  38. * External
  39. * CreateQoS
  40. * QoSEntryPoint
  41. */
  42. #include "precomp.h"
  43. EXTERN_C int g_cQoSObjects=0;
  44. EXTERN_C HANDLE g_hQoSMutex=NULL;
  45. class CQoS *g_pQoS;
  46. #ifdef DEBUG
  47. HDBGZONE ghDbgZoneQoS = NULL;
  48. static PTCHAR _rgZonesQos[] = {
  49. TEXT("qos"),
  50. TEXT("Init"),
  51. TEXT("IQoS"),
  52. TEXT("Thread"),
  53. TEXT("Structures"),
  54. TEXT("Parameters"),
  55. };
  56. #endif /* DEBUG */
  57. /***************************************************************************
  58. Name : QoSCleanup
  59. Purpose : Cleans up a QoS object before releasing (free memory, etc)
  60. Parameters: pqos - pointer to a QoS pbject
  61. Returns : HRESULT
  62. Comment :
  63. ***************************************************************************/
  64. HRESULT CQoS::QoSCleanup ()
  65. {
  66. HRESULT hr=NOERROR;
  67. LPRESOURCEINT pr=NULL;
  68. LPCLIENTINT pc=NULL;
  69. ACQMUTEX(g_hQoSMutex);
  70. /*
  71. * Free memory
  72. */
  73. // traverse and free all the memory allocated by the QoS object
  74. // resources and requests first
  75. pr = m_pResourceList;
  76. while (pr)
  77. {
  78. LPRESOURCEINT prNext=pr->fLink;
  79. // first, delete the request list for this resource
  80. FreeListOfRequests(&(pr->pRequestList));
  81. MEMFREE(pr);
  82. pr = prNext;
  83. }
  84. m_pResourceList = 0;
  85. // next is clients
  86. pc = m_pClientList;
  87. while (pc)
  88. {
  89. LPCLIENTINT pcNext=pc->fLink;
  90. // delete the request list for this client
  91. FreeListOfRequests(&(pc->pRequestList));
  92. // now delete the client itself
  93. MEMFREE(pc);
  94. pc = pcNext;
  95. }
  96. m_pClientList = 0;
  97. // terminate the QoS thread and let it exit
  98. // the thread should really be terminated when the last request
  99. // is released, so this is just a safety measure
  100. StopQoSThread();
  101. // delete the events
  102. if (m_evImmediateNotify)
  103. CloseHandle(m_evImmediateNotify);
  104. m_evImmediateNotify = NULL;
  105. if (m_evThreadExitSignal)
  106. CloseHandle(m_evThreadExitSignal);
  107. m_evThreadExitSignal = NULL;
  108. RELMUTEX(g_hQoSMutex);
  109. return hr;
  110. }
  111. /***************************************************************************
  112. Name : AnyRequests
  113. Purpose : Finds out if there are any resource requests
  114. Parameters: none
  115. Returns : TRUE - there is at least one request
  116. Comment :
  117. ***************************************************************************/
  118. BOOL CQoS::AnyRequests(void)
  119. {
  120. LPRESOURCEINT pr=NULL;
  121. BOOL bAnyRequests=FALSE;
  122. pr = m_pResourceList;
  123. while (pr)
  124. {
  125. if (pr->pRequestList)
  126. {
  127. bAnyRequests=TRUE;
  128. break;
  129. }
  130. // next resource
  131. pr = pr->fLink;
  132. }
  133. return bAnyRequests;
  134. }
  135. /***************************************************************************
  136. Name : FindClientsForResource
  137. Purpose : Finds if there are clients for a specific resource
  138. Parameters: [in] dwResourceID = the ID of the resource
  139. [in] pc = client pointer to start searching from
  140. [out] puSamePriClients = number of clients with the same
  141. priority for this resource is returned here
  142. [out] puLowerPriClients = number of clients with lower
  143. priority for this resource is returned here
  144. Returns : HRESULT
  145. Comment : This function is NOT general purpose. It only counts clients
  146. with the same priority DOWN the list.
  147. ***************************************************************************/
  148. HRESULT CQoS::FindClientsForResource( DWORD dwResourceID,
  149. LPCLIENTINT pc,
  150. ULONG *puSamePriClients,
  151. ULONG *puLowerPriClients)
  152. {
  153. LPCLIENTINT pctemp=pc->fLink;
  154. LPRESOURCEREQUESTINT pcrr=NULL;
  155. *puLowerPriClients = 0;
  156. *puSamePriClients = 1; // the first client (at 'pc')
  157. while (pctemp)
  158. {
  159. LPRESOURCEINT pr=NULL;
  160. // does this client need this specific resource ?
  161. pcrr = pctemp->pRequestList;
  162. while (pcrr)
  163. {
  164. if (pcrr->sResourceRequest.resourceID == dwResourceID)
  165. {
  166. // it is either a same priority client or a lower priority
  167. // client (the list is sorted)
  168. (pctemp->client.priority == pc->client.priority ?
  169. (*puSamePriClients)++ :
  170. (*puLowerPriClients)++);
  171. break;
  172. }
  173. // next request for this client
  174. pcrr = pcrr->fLink;
  175. }
  176. pctemp = pctemp->fLink;
  177. }
  178. return NOERROR;
  179. }
  180. /***************************************************************************
  181. Name : FreeListOfRequests
  182. Purpose : Free all records of a linked list of requests, given the
  183. address of the list pointer. Zero's the list pointer
  184. Parameters: lppRequestList - address of the pointer to the beginning
  185. of the list
  186. Returns : HRESULT
  187. Comment :
  188. ***************************************************************************/
  189. HRESULT CQoS::FreeListOfRequests(LPRESOURCEREQUESTINT *lppRequestList)
  190. {
  191. LPRESOURCEREQUESTINT prr=*lppRequestList;
  192. HRESULT hr=NOERROR;
  193. while (prr)
  194. {
  195. LPRESOURCEREQUESTINT prrNext=prr->fLink;
  196. MEMFREE(prr);
  197. prr = prrNext;
  198. }
  199. *lppRequestList = NULL;
  200. return hr;
  201. }
  202. /***************************************************************************
  203. Name : FreeResourceRequest
  204. Purpose : Frees resource units and respective resource requests
  205. Parameters: pClientGUID - the GUID of the calling client (stream)
  206. pnUnits - a pointer of where to return the number of units freed
  207. pResourceInt - pointer to the resource being freed
  208. Returns : HRESULT
  209. Comment :
  210. ***************************************************************************/
  211. HRESULT CQoS::FreeResourceRequest ( LPGUID pClientGUID,
  212. LPRESOURCEINT pResourceInt,
  213. int *pnUnits)
  214. {
  215. HRESULT hr=NOERROR;
  216. LPRESOURCEREQUESTINT prr=NULL, *prrPrev=NULL;
  217. // find the request from this client
  218. prr = pResourceInt->pRequestList;
  219. prrPrev = &(pResourceInt->pRequestList);
  220. while (prr)
  221. {
  222. if (COMPARE_GUIDS(&(prr->guidClientGUID), pClientGUID))
  223. {
  224. // we do have a request from this client.
  225. // reclaim the units...
  226. *pnUnits = prr->sResourceRequest.nUnitsMin;
  227. // ...and remove it
  228. *prrPrev = prr->fLink;
  229. MEMFREE(prr);
  230. // we're done.
  231. hr = NOERROR;
  232. goto out;
  233. }
  234. prrPrev = &(prr->fLink);
  235. prr = prr->fLink;
  236. }
  237. hr = QOS_E_NO_SUCH_REQUEST;
  238. out:
  239. return hr;
  240. }
  241. /***************************************************************************
  242. Name : StoreResourceRequest
  243. Purpose : Stores a resource request with the resource
  244. Parameters: pClientGUID - the GUID of the calling client (stream)
  245. pResourceRequest - the request to store
  246. pfnQoSNotify - a pointer to a notification function for the
  247. requesting client
  248. pResourceInt - pointer to the resource on which to store the
  249. request
  250. Returns : HRESULT
  251. Comment :
  252. ***************************************************************************/
  253. HRESULT CQoS::StoreResourceRequest (LPGUID pClientGUID,
  254. LPRESOURCEREQUEST pResourceRequest,
  255. LPFNQOSNOTIFY pfnQoSNotify,
  256. DWORD_PTR dwParam,
  257. LPRESOURCEINT pResourceInt)
  258. {
  259. HRESULT hr=NOERROR;
  260. LPRESOURCEREQUESTINT prr=NULL, *prrPrev=NULL;
  261. BOOL fRequestFound=FALSE;
  262. /*
  263. * Store the request
  264. */
  265. // do we already have a request from this client ?
  266. prr = pResourceInt->pRequestList;
  267. prrPrev = &(pResourceInt->pRequestList);
  268. while (prr)
  269. {
  270. if (COMPARE_GUIDS(&(prr->guidClientGUID), pClientGUID))
  271. {
  272. // we do have a request from this client. override it.
  273. RtlCopyMemory( &(prr->sResourceRequest),
  274. pResourceRequest,
  275. sizeof(RESOURCEREQUEST));
  276. RtlCopyMemory(&(prr->guidClientGUID), pClientGUID, sizeof(GUID));
  277. prr->pfnQoSNotify = pfnQoSNotify;
  278. prr->dwParam = dwParam;
  279. // we're done.
  280. hr = NOERROR;
  281. fRequestFound = TRUE;
  282. break;
  283. }
  284. prrPrev = &(prr->fLink);
  285. prr = prr->fLink;
  286. }
  287. if (!fRequestFound)
  288. {
  289. // not found. make one
  290. prr = (LPRESOURCEREQUESTINT) MEMALLOC(sizeof(RESOURCEREQUESTINT));
  291. ASSERT(prr);
  292. if (!prr)
  293. {
  294. ERRORMSG(("StoreResourceRequest: MEMALLOC failed on RESOURCEREQUESTINT\n"));
  295. hr = E_OUTOFMEMORY;
  296. goto out;
  297. }
  298. *prrPrev = prr;
  299. prr->fLink = NULL;
  300. }
  301. // whether found or made, copy the contents in
  302. RtlCopyMemory( &(prr->sResourceRequest),
  303. pResourceRequest,
  304. sizeof(RESOURCEREQUEST));
  305. RtlCopyMemory(&(prr->guidClientGUID), pClientGUID, sizeof(GUID));
  306. prr->pfnQoSNotify = pfnQoSNotify;
  307. prr->dwParam = dwParam;
  308. out:
  309. return hr;
  310. }
  311. /***************************************************************************
  312. Name : UpdateClientInfo
  313. Purpose : Updates the client info when a resource request is granted
  314. Parameters: pClientGUID - the GUID of the calling client (stream)
  315. pfnQoSNotify - a pointer to a notification function for the
  316. requesting client
  317. Returns : HRESULT
  318. Comment :
  319. ***************************************************************************/
  320. HRESULT CQoS::UpdateClientInfo (LPGUID pClientGUID,
  321. LPFNQOSNOTIFY pfnQoSNotify)
  322. {
  323. HRESULT hr=NOERROR;
  324. LPCLIENTLIST pcl=NULL;
  325. /*
  326. * Update client info
  327. */
  328. // we'll do this through calling the SetClients method
  329. // allocate and fill a CLIENTLIST structure
  330. pcl = (LPCLIENTLIST) MEMALLOC(sizeof(CLIENTLIST));
  331. if (!pcl)
  332. {
  333. ERRORMSG(("UpdateClientInfo: MEMALLOC failed\n"));
  334. hr = E_OUTOFMEMORY;
  335. goto out;
  336. }
  337. RtlZeroMemory((PVOID) pcl, sizeof(CLIENTLIST));
  338. // fill in the resource list
  339. pcl->cClients = 1;
  340. RtlCopyMemory(&(pcl->aClients[0].guidClientGUID), pClientGUID, sizeof(GUID));
  341. pcl->aClients[0].priority = QOS_LOWEST_PRIORITY;
  342. // set the clients info on the QoS module
  343. hr = SetClients(pcl);
  344. out:
  345. if (pcl)
  346. MEMFREE(pcl);
  347. return hr;
  348. }
  349. /***************************************************************************
  350. Name : UpdateRequestsForClient
  351. Purpose : Update a client's request list by finding all existing resource
  352. requests for this client
  353. Parameters: pClientGUID - the GUID of the calling client (stream)
  354. Returns : HRESULT
  355. Comment :
  356. ***************************************************************************/
  357. HRESULT CQoS::UpdateRequestsForClient (LPGUID pClientGUID)
  358. {
  359. HRESULT hr=NOERROR;
  360. LPRESOURCEINT pr=NULL;
  361. LPCLIENTINT pc=NULL;
  362. LPRESOURCEREQUESTINT prr=NULL, *pcrrfLink=NULL, pcrr=NULL;
  363. /*
  364. * get rid of the current request list for this client
  365. */
  366. // find the client first
  367. hr = FindClient(pClientGUID, &pc);
  368. if (FAILED(hr) || !pc)
  369. {
  370. hr = QOS_E_NO_SUCH_CLIENT;
  371. goto out;
  372. }
  373. // now delete old request list
  374. FreeListOfRequests(&(pc->pRequestList));
  375. /*
  376. * create and add the new request list
  377. */
  378. pr = m_pResourceList;
  379. pcrrfLink = &(pc->pRequestList);
  380. while (pr)
  381. {
  382. prr = pr->pRequestList;
  383. while (prr)
  384. {
  385. if (COMPARE_GUIDS(&(prr->guidClientGUID), pClientGUID))
  386. {
  387. // we found a request from this client.
  388. // allocate memory for it, and copy it in
  389. pcrr = (LPRESOURCEREQUESTINT) MEMALLOC(sizeof(RESOURCEREQUESTINT));
  390. ASSERT(pcrr);
  391. if (!pcrr)
  392. {
  393. ERRORMSG(("UpdateRequestsForClient: MEMALLOC failed on RESOURCEREQUESTINT\n"));
  394. hr = E_OUTOFMEMORY;
  395. goto out;
  396. }
  397. // copy the contents in
  398. RtlCopyMemory(pcrr, prr, sizeof(RESOURCEREQUESTINT));
  399. // need a different fLink for the client request list
  400. *pcrrfLink = pcrr;
  401. pcrr->fLink = NULL;
  402. pcrrfLink = &(pcrr->fLink);
  403. }
  404. // next request
  405. prr = prr->fLink;
  406. }
  407. // next resource
  408. pr = pr->fLink;
  409. }
  410. out:
  411. return hr;
  412. }
  413. /***************************************************************************
  414. Name : FindClient
  415. Purpose : Finds and returns a client record
  416. Parameters: pClientGUID - the GUID whose record to find
  417. ppClient - address of where to put a pointer to the client found
  418. Returns : HRESULT
  419. Comment :
  420. ***************************************************************************/
  421. HRESULT CQoS::FindClient(LPGUID pClientGUID, LPCLIENTINT *ppClient)
  422. {
  423. LPCLIENTINT pc=NULL;
  424. HRESULT hr=NOERROR;
  425. *ppClient = NULL;
  426. pc = m_pClientList;
  427. while (pc)
  428. {
  429. if (COMPARE_GUIDS(&(pc->client.guidClientGUID), pClientGUID))
  430. {
  431. *ppClient = pc;
  432. goto out;
  433. }
  434. // next client
  435. pc = pc->fLink;
  436. }
  437. hr = QOS_E_NO_SUCH_CLIENT;
  438. out:
  439. return hr;
  440. }
  441. /***************************************************************************
  442. IUnknown Methods
  443. ***************************************************************************/
  444. HRESULT CQoS::QueryInterface (REFIID riid, LPVOID *lppNewObj)
  445. {
  446. HRESULT hr = NOERROR;
  447. DEBUGMSG(ZONE_IQOS,("IQoS::QueryInterface\n"));
  448. if (IsBadReadPtr(&riid, (UINT) sizeof(IID)))
  449. {
  450. hr = ResultFromScode(E_INVALIDARG);
  451. goto out;
  452. }
  453. if (IsBadWritePtr(lppNewObj, sizeof(LPVOID)))
  454. {
  455. hr = ResultFromScode(E_INVALIDARG);
  456. goto out;
  457. }
  458. *lppNewObj = 0;
  459. if (riid == IID_IUnknown || riid == IID_IQoS)
  460. *lppNewObj = (IQoS *) this;
  461. else
  462. {
  463. hr = E_NOINTERFACE;
  464. goto out;
  465. }
  466. ((IUnknown *)*lppNewObj)->AddRef ();
  467. out:
  468. DEBUGMSG(ZONE_IQOS,("IQoS::QueryInterface - leave, hr=0x%x\n", hr));
  469. return hr;
  470. }
  471. ULONG CQoS::AddRef (void)
  472. {
  473. DEBUGMSG(ZONE_IQOS,("IQoS::AddRef\n"));
  474. InterlockedIncrement((long *) &m_cRef);
  475. DEBUGMSG(ZONE_IQOS,("IQoS::AddRef - leave, m_cRef=%d\n", m_cRef));
  476. return m_cRef;
  477. }
  478. ULONG CQoS::Release (void)
  479. {
  480. DEBUGMSG(ZONE_IQOS,("IQoS::Release\n"));
  481. // if the cRef is already 0 (shouldn't happen), assert, but let it through
  482. ASSERT(m_cRef);
  483. if (InterlockedDecrement((long *) &m_cRef) == 0)
  484. {
  485. if (m_bQoSEnabled)
  486. QoSCleanup();
  487. delete this;
  488. DEBUGMSG(ZONE_IQOS,("IQoS::Final Release\n"));
  489. return 0;
  490. }
  491. DEBUGMSG(ZONE_IQOS,("IQoS::Release - leave, m_cRef=%d\n", m_cRef));
  492. return m_cRef;
  493. }
  494. /***************************************************************************
  495. Name : CQoS::RequestResources
  496. Purpose : Requests resources
  497. Parameters: lpStreamGUID - the GUID of the calling client (stream)
  498. lpResourceRequestList - a list of resource requests that
  499. the caller wants to reserve
  500. lpfnQoSNotify - a pointer to a notification function for the
  501. requesting client
  502. Returns : HRESULT
  503. Comment :
  504. ***************************************************************************/
  505. HRESULT CQoS::RequestResources (LPGUID lpClientGUID,
  506. LPRESOURCEREQUESTLIST lpResourceRequestList,
  507. LPFNQOSNOTIFY lpfnQoSNotify,
  508. DWORD_PTR dwParam)
  509. {
  510. HRESULT hr = NOERROR;
  511. ULONG i;
  512. BOOL fResourceFound=FALSE, fRequestGranted=FALSE;
  513. LPRESOURCEINT pResourceInt=NULL, *pPrevResourcefLink=NULL;
  514. RESOURCEREQUEST *pResourceRequest=NULL;
  515. DEBUGMSG(ZONE_IQOS,("IQoS::RequestResources\n"));
  516. /*
  517. * Parameter validation
  518. */
  519. // lpResourceRequestList should at least have a count DWORD
  520. // must have a GUID and a notify callback
  521. if (!lpResourceRequestList ||
  522. IsBadReadPtr(lpResourceRequestList, (UINT) sizeof(DWORD)) ||
  523. !lpClientGUID ||
  524. !lpfnQoSNotify)
  525. {
  526. hr = E_INVALIDARG;
  527. goto out_nomutex;
  528. }
  529. DISPLAYPARAMETERS( REQUEST_RESOURCES_ID,
  530. lpClientGUID,
  531. lpResourceRequestList,
  532. lpfnQoSNotify,
  533. dwParam,
  534. 0);
  535. ACQMUTEX(g_hQoSMutex);
  536. if (!m_bQoSEnabled)
  537. // just return
  538. goto out;
  539. /*
  540. * Find and allocate the resources
  541. */
  542. // for each requested resource
  543. pResourceRequest=lpResourceRequestList->aRequests;
  544. for (i=0; i < lpResourceRequestList->cRequests; i++)
  545. {
  546. pResourceInt = m_pResourceList;
  547. fResourceFound = FALSE;
  548. // find the resource
  549. while (pResourceInt)
  550. {
  551. if (pResourceInt->resource.resourceID == pResourceRequest[i].resourceID)
  552. { // resource found
  553. // see if the resource is available
  554. // priority will be handled at the first notify callback
  555. // CHECK: add nUnitsMax handling
  556. if (pResourceRequest[i].nUnitsMin <= pResourceInt->nNowAvailUnits)
  557. {
  558. // resource is available. take the requested share.
  559. pResourceInt->nNowAvailUnits -= pResourceRequest[i].nUnitsMin;
  560. // store a local copy of the request
  561. pResourceRequest[i].hResult = StoreResourceRequest(lpClientGUID,
  562. &(pResourceRequest[i]),
  563. lpfnQoSNotify,
  564. dwParam,
  565. pResourceInt);
  566. // if we failed storing, propagate the result to the bottom line
  567. // returned result
  568. if (FAILED(pResourceRequest[i].hResult))
  569. {
  570. hr = pResourceRequest[i].hResult;
  571. }
  572. else
  573. { // at least one request was granted to this client
  574. fRequestGranted = TRUE;
  575. }
  576. }
  577. else // resource not available
  578. {
  579. // let the client know how much is available
  580. pResourceRequest[i].nUnitsMin = pResourceInt->nNowAvailUnits;
  581. pResourceRequest[i].hResult = QOS_E_RES_NOT_ENOUGH_UNITS;
  582. hr = QOS_E_REQ_ERRORS;
  583. }
  584. fResourceFound = TRUE;
  585. break;
  586. }
  587. // not this one. try next one.
  588. pResourceInt = pResourceInt->fLink;
  589. } // while
  590. if (!fResourceFound)
  591. {
  592. pResourceRequest[i].hResult = QOS_E_RES_NOT_AVAILABLE;
  593. hr = QOS_E_REQ_ERRORS;
  594. }
  595. // next request
  596. } // for
  597. // if we allocated resources to this client, add it to the client list,
  598. // provided that it is not already in the list
  599. // special case: if the call to RequestResources was made from the QoS
  600. // notification proc, no need to update the client info. Actually, it will
  601. // be bad to do this, since we are traversing the client list in the
  602. // notify proc right at this moment...
  603. if (fRequestGranted && !m_bInNotify)
  604. { // add (or update) the client list with this client
  605. HRESULT hrTemp=NOERROR;
  606. LPCLIENTINT pc=NULL;
  607. // if the client is not already in the client list - add it
  608. FindClient(lpClientGUID, &pc);
  609. if (!pc)
  610. {
  611. hrTemp = UpdateClientInfo (lpClientGUID, lpfnQoSNotify);
  612. if (FAILED(hrTemp))
  613. hr = hrTemp;
  614. }
  615. // also, make a note that RequestResources has been called. This will
  616. // make the QoS thread skip one heartbeat in order not call a client
  617. // too early
  618. m_nSkipHeartBeats = 1;
  619. // we have at least one request, so spawn the QoS thread, if not
  620. // already running
  621. if (!m_hThread)
  622. hrTemp = StartQoSThread();
  623. }
  624. out:
  625. DISPLAYQOSOBJECT();
  626. RELMUTEX(g_hQoSMutex);
  627. out_nomutex:
  628. DEBUGMSG(ZONE_IQOS,("IQoS::RequestResources - leave, hr=0x%x\n", hr));
  629. return hr;
  630. }
  631. /***************************************************************************
  632. Name : CQoS::ReleaseResources
  633. Purpose : Releases resources
  634. Parameters: lpClientGUID - the GUID of the calling client (stream)
  635. lpResourceRequestList - a list of resource requests that
  636. the caller wants to reserve
  637. Returns : HRESULT
  638. Comment : The values in the resource list are ignored. The resources
  639. specified are freed.
  640. ***************************************************************************/
  641. HRESULT CQoS::ReleaseResources (LPGUID lpClientGUID,
  642. LPRESOURCEREQUESTLIST lpResourceRequestList)
  643. {
  644. ULONG i;
  645. int nUnits=0;
  646. BOOL fResourceFound=FALSE;
  647. LPRESOURCEINT pResourceInt=NULL, *pPrevResourcefLink=NULL;
  648. RESOURCEREQUEST *pResourceRequest=NULL;
  649. HRESULT hr = NOERROR;
  650. DEBUGMSG(ZONE_IQOS,("IQoS::ReleaseResources\n"));
  651. /*
  652. * parameter validation
  653. */
  654. // lpResourceRequestList should at least have a count DWORD
  655. if (!lpResourceRequestList ||
  656. IsBadReadPtr(lpResourceRequestList, (UINT) sizeof(DWORD)))
  657. {
  658. hr = E_INVALIDARG;
  659. goto out_nomutex;
  660. }
  661. DISPLAYPARAMETERS( RELEASE_RESOURCES_ID,
  662. lpClientGUID,
  663. lpResourceRequestList,
  664. 0,
  665. 0,
  666. 0);
  667. ACQMUTEX(g_hQoSMutex);
  668. if (!m_bQoSEnabled)
  669. // just return
  670. goto out;
  671. // for each requested resource
  672. pResourceRequest=lpResourceRequestList->aRequests;
  673. for (i=0; i < lpResourceRequestList->cRequests; i++)
  674. {
  675. // make sure we start with no error (caller might not cleared last hresult)
  676. pResourceRequest[i].hResult = NOERROR;
  677. pResourceInt = m_pResourceList;
  678. fResourceFound = FALSE;
  679. // find the resource
  680. while (pResourceInt)
  681. {
  682. if (pResourceInt->resource.resourceID == pResourceRequest[i].resourceID)
  683. { // resource found
  684. // free the local copy of the request
  685. pResourceRequest[i].hResult = FreeResourceRequest(lpClientGUID,
  686. pResourceInt,
  687. &nUnits);
  688. // if succeeded, claim the units back
  689. if (SUCCEEDED(pResourceRequest[i].hResult) && (nUnits >= 0))
  690. {
  691. // add the freed units
  692. pResourceInt->nNowAvailUnits += nUnits;
  693. // in case something went wrong and we now have more available units
  694. // than total ones
  695. // NOTE: the ASSERT below is no longer proper. If SetResources was called,
  696. // and decreased the total units for a resource while there were
  697. // requests on this resource, the available units for this resource
  698. // might exceed the total one if released. Since QoS will auto-repair
  699. // this in the next notify cycle, the window for this is very small
  700. // ASSERT(!(pResourceInt->nNowAvailUnits > pResourceInt->resource.nUnits));
  701. if (pResourceInt->nNowAvailUnits > pResourceInt->resource.nUnits)
  702. { // we don't want to have more available units than total
  703. pResourceInt->nNowAvailUnits = pResourceInt->resource.nUnits;
  704. }
  705. }
  706. else
  707. {
  708. // no such request
  709. pResourceRequest[i].hResult = QOS_E_NO_SUCH_REQUEST;
  710. hr = QOS_E_REQ_ERRORS;
  711. }
  712. fResourceFound = TRUE;
  713. break;
  714. }
  715. // not this one. try next one.
  716. pResourceInt = pResourceInt->fLink;
  717. } // while
  718. if (!fResourceFound)
  719. {
  720. pResourceRequest[i].hResult = QOS_E_NO_SUCH_RESOURCE;
  721. hr = QOS_E_REQ_ERRORS;
  722. }
  723. // next request
  724. }
  725. // if no requests left, can let the notification thread go...
  726. if (m_hThread &&
  727. !AnyRequests())
  728. {
  729. // stop the thread
  730. StopQoSThread();
  731. }
  732. out:
  733. DISPLAYQOSOBJECT();
  734. RELMUTEX(g_hQoSMutex);
  735. out_nomutex:
  736. DEBUGMSG(ZONE_IQOS,("IQoS::ReleaseResources - leave, hr=0x%x\n", hr));
  737. return hr;
  738. }
  739. /***************************************************************************
  740. Name : CQoS::SetResources
  741. Purpose : Sets the available resources on the QoS module
  742. Parameters: lpResourceList - list of resources and their availability
  743. Returns : HRESULT
  744. Comment :
  745. ***************************************************************************/
  746. HRESULT CQoS::SetResources (LPRESOURCELIST lpResourceList)
  747. {
  748. HRESULT hr = NOERROR;
  749. ULONG i;
  750. BOOL fResourceFound=FALSE;
  751. LPRESOURCEINT pResourceInt=NULL, *pPrevResourcefLink=NULL;
  752. RESOURCE *pResource=NULL;
  753. RegEntry reQoSResourceRoot(REGKEY_QOS_RESOURCES,
  754. HKEY_LOCAL_MACHINE,
  755. FALSE,
  756. KEY_READ);
  757. DEBUGMSG(ZONE_IQOS,("IQoS::SetResources\n"));
  758. /*
  759. * parameter validation
  760. */
  761. // lpResourceList should at least have a count DWORD
  762. if (!lpResourceList || IsBadReadPtr(lpResourceList, (UINT) sizeof(DWORD)))
  763. {
  764. hr = E_INVALIDARG;
  765. goto out_nomutex;
  766. }
  767. DISPLAYPARAMETERS( SET_RESOURCES_ID,
  768. lpResourceList,
  769. 0,
  770. 0,
  771. 0,
  772. 0);
  773. ACQMUTEX(g_hQoSMutex);
  774. if (!m_bQoSEnabled)
  775. // just return
  776. goto out;
  777. /*
  778. * Get configurable resource info
  779. */
  780. pResource=lpResourceList->aResources;
  781. for (i=0; i < lpResourceList->cResources; i++)
  782. {
  783. TCHAR szKey[10]; // should be way enough for a resource ID
  784. int nUnits=INT_MAX;
  785. int nLeaveUnused=0;
  786. // build and open the key
  787. wsprintf(szKey, "%d", pResource[i].resourceID);
  788. RegEntry reQosResource(szKey, reQoSResourceRoot.GetKey(), FALSE, KEY_READ);
  789. // MaxUnits:
  790. // run through the list of resources and make sure none of the
  791. // resources was set to a number of units above the allowed maximum
  792. // if it was, trim and warn
  793. // get maximum numbers for the resource, if any, from the registry
  794. nUnits = reQosResource.GetNumberIniStyle(TEXT("MaxUnits"), INT_MAX);
  795. // is the client trying to set the resource to a higher value ?
  796. if (pResource[i].nUnits > nUnits)
  797. {
  798. pResource[i].nUnits = nUnits;
  799. hr = QOS_W_MAX_UNITS_EXCEEDED;
  800. }
  801. // LeaveUnused:
  802. // leave some of the resource unused, as configured
  803. // use different default value depending on the resource
  804. switch (pResource[i].resourceID)
  805. {
  806. case RESOURCE_OUTGOING_BANDWIDTH:
  807. nLeaveUnused = 30;
  808. break;
  809. default:
  810. nLeaveUnused = 10;
  811. break;
  812. }
  813. nLeaveUnused = reQosResource.GetNumberIniStyle( TEXT("LeaveUnused"),
  814. nLeaveUnused);
  815. pResource[i].nUnits = (pResource[i].nUnits * (100 - nLeaveUnused)) / 100;
  816. }
  817. /*
  818. * Add the resource to the list
  819. */
  820. // run through the input resource list and store the resources
  821. // resource availability is NOT accumulative
  822. pResource=lpResourceList->aResources;
  823. for (i=0; i < lpResourceList->cResources; i++)
  824. {
  825. pResourceInt = m_pResourceList;
  826. pPrevResourcefLink = &m_pResourceList;
  827. fResourceFound = FALSE;
  828. while (pResourceInt != 0)
  829. {
  830. if (pResourceInt->resource.resourceID == pResource[i].resourceID)
  831. { // found a match
  832. // did the total number of units change for this resource ?
  833. if (pResourceInt->resource.nUnits != pResource[i].nUnits)
  834. {
  835. // update the now available units
  836. // since we could end up with less units than what was allocated
  837. // we are issuing a NotifyNow at the end of this call
  838. pResourceInt->nNowAvailUnits = pResource[i].nUnits -
  839. (pResourceInt->resource.nUnits -
  840. pResourceInt->nNowAvailUnits);
  841. if (pResourceInt->nNowAvailUnits < 0)
  842. pResourceInt->nNowAvailUnits = 0;
  843. }
  844. // override the previous setting
  845. RtlCopyMemory( &(pResourceInt->resource),
  846. &(pResource[i]),
  847. sizeof(RESOURCE));
  848. fResourceFound = TRUE;
  849. break;
  850. }
  851. // not this one. try next one.
  852. pPrevResourcefLink = &(pResourceInt->fLink);
  853. pResourceInt = pResourceInt->fLink;
  854. } // while
  855. if (fResourceFound)
  856. continue;
  857. // not found. add the resource
  858. pResourceInt = (LPRESOURCEINT) MEMALLOC(sizeof(RESOURCEINT));
  859. ASSERT(pResourceInt);
  860. if (!pResourceInt)
  861. {
  862. ERRORMSG(("IQoS::SetResources: MEMALLOC failed on RESOURCEINT\n"));
  863. hr = E_OUTOFMEMORY;
  864. goto out;
  865. }
  866. // copy the resource in
  867. RtlCopyMemory( &(pResourceInt->resource),
  868. &(pResource[i]),
  869. sizeof(RESOURCE));
  870. pResourceInt->fLink = NULL;
  871. pResourceInt->nNowAvailUnits = pResourceInt->resource.nUnits;
  872. *pPrevResourcefLink = pResourceInt;
  873. // increment the number of resources we're tracking
  874. // this number will never go down
  875. m_cResources++;
  876. // next resource
  877. } // for
  878. // since there was a possible change in the resource availability,
  879. // run an immediate notification cycle
  880. if (SUCCEEDED(hr))
  881. NotifyNow();
  882. out:
  883. DISPLAYQOSOBJECT();
  884. RELMUTEX(g_hQoSMutex);
  885. out_nomutex:
  886. DEBUGMSG(ZONE_IQOS,("IQoS::SetResources - leave, hr=0x%x\n", hr));
  887. return hr;
  888. }
  889. /***************************************************************************
  890. Name : CQoS::GetResources
  891. Purpose : Gets the list of resources available to the QoS module
  892. Parameters: lppResourceList - an address where QoS will place a pointer
  893. to a buffer with the list of resources available to QoS.
  894. The caller must use CQoS::FreeBuffer to free this buffer.
  895. Returns : HRESULT
  896. Comment :
  897. ***************************************************************************/
  898. HRESULT CQoS::GetResources (LPRESOURCELIST *lppResourceList)
  899. {
  900. HRESULT hr = NOERROR;
  901. ULONG i;
  902. LPRESOURCELIST prl=NULL;
  903. LPRESOURCEINT pResourceInt=NULL;
  904. RESOURCE *pResource=NULL;
  905. DEBUGMSG(ZONE_IQOS,("IQoS::GetResources\n"));
  906. /*
  907. * parameter validation
  908. */
  909. // lpResourceList should at least have a count DWORD
  910. if (!lppResourceList || IsBadWritePtr(lppResourceList, (UINT) sizeof(DWORD)))
  911. {
  912. hr = E_INVALIDARG;
  913. goto out_nomutex;
  914. }
  915. // no list yet
  916. *lppResourceList = NULL;
  917. if (!m_bQoSEnabled)
  918. // just return
  919. goto out_nomutex;
  920. ACQMUTEX(g_hQoSMutex);
  921. /*
  922. * Get resource info
  923. */
  924. // allocate a buffer for the resources info
  925. prl = (LPRESOURCELIST) MEMALLOC(sizeof(RESOURCELIST) +
  926. ((LONG_PTR)m_cResources-1)*sizeof(RESOURCE));
  927. if (!prl)
  928. {
  929. hr = E_OUTOFMEMORY;
  930. ERRORMSG(("GetResources: MEMALLOC failed\n"));
  931. goto out;
  932. }
  933. RtlZeroMemory((PVOID) prl, sizeof(RESOURCELIST) +
  934. ((LONG_PTR)m_cResources-1)*sizeof(RESOURCE));
  935. // now fill in the information
  936. prl->cResources = m_cResources;
  937. pResourceInt=m_pResourceList;
  938. for (i=0; i < m_cResources; i++)
  939. {
  940. ASSERT(pResourceInt);
  941. // see if we have a NULL resource pointer
  942. // shouldn't happen, but we shouldn't crash if it does
  943. if (!pResourceInt)
  944. {
  945. hr = QOS_E_INTERNAL_ERROR;
  946. ERRORMSG(("GetResources: bad QoS internal resource list\n"));
  947. goto out;
  948. }
  949. // copy the resource info into the buffer
  950. RtlCopyMemory( &(prl->aResources[i]),
  951. &(pResourceInt->resource),
  952. sizeof(RESOURCE));
  953. // next resource
  954. pResourceInt = pResourceInt->fLink;
  955. } // for
  956. *lppResourceList = prl;
  957. out:
  958. DISPLAYQOSOBJECT();
  959. RELMUTEX(g_hQoSMutex);
  960. out_nomutex:
  961. DEBUGMSG(ZONE_IQOS,("IQoS::GetResources - leave, hr=0x%x\n", hr));
  962. return hr;
  963. }
  964. /***************************************************************************
  965. Name : CQoS::SetClients
  966. Purpose : Tells the QoS module what are the priorities of the requesting
  967. streams. This allows the QoS module to allocate resources
  968. appropriately.
  969. Parameters: lpClientList - list of clients and their respective
  970. priorities
  971. Returns : HRESULT
  972. Comment : client info will override an already existing info for this
  973. client
  974. ***************************************************************************/
  975. HRESULT CQoS::SetClients(LPCLIENTLIST lpClientList)
  976. {
  977. HRESULT hr = NOERROR;
  978. ULONG i;
  979. BOOL fClientFound=FALSE;
  980. LPCLIENTINT pClientInt=NULL, *pPrevClientfLink=NULL, pClientNew=NULL;;
  981. LPCLIENT pClient=NULL;
  982. DEBUGMSG(ZONE_IQOS,("IQoS::SetClients\n"));
  983. /*
  984. * parameter validation
  985. */
  986. // lpClientList should at least have a count DWORD
  987. if (!lpClientList || IsBadReadPtr(lpClientList, (UINT) sizeof(DWORD)))
  988. {
  989. hr = E_INVALIDARG;
  990. goto out_nomutex;
  991. }
  992. DISPLAYPARAMETERS( SET_CLIENTS_ID,
  993. lpClientList,
  994. 0,
  995. 0,
  996. 0,
  997. 0);
  998. ACQMUTEX(g_hQoSMutex);
  999. if (!m_bQoSEnabled)
  1000. // just return
  1001. goto out;
  1002. // first remove existing clients that are being set again
  1003. // this will make it easier to store clients in a priority order
  1004. pClient=lpClientList->aClients;
  1005. for (i=0; i < lpClientList->cClients; i++)
  1006. {
  1007. pClientInt = m_pClientList;
  1008. pPrevClientfLink = &m_pClientList;
  1009. fClientFound = FALSE;
  1010. while (pClientInt != 0)
  1011. {
  1012. if (COMPARE_GUIDS( &(pClientInt->client.guidClientGUID),
  1013. &(pClient[i].guidClientGUID)))
  1014. { // found a match
  1015. LPCLIENTINT pClientIntNext=pClientInt->fLink;
  1016. // special case for internal calls from RequestResources
  1017. // we want to preserve the original priority before freeing
  1018. if (pClient[i].priority == QOS_LOWEST_PRIORITY)
  1019. pClient[i].priority = pClientInt->client.priority;
  1020. // free the requests for this client
  1021. // NOTE: we're not going to recreate the request list from
  1022. // the one in the resource list. it will be created on the
  1023. // fly when needed.
  1024. FreeListOfRequests(&(pClientInt->pRequestList));
  1025. // free the client record
  1026. MEMFREE(pClientInt);
  1027. *pPrevClientfLink = pClientIntNext;
  1028. fClientFound = TRUE;
  1029. break;
  1030. }
  1031. // not this one. try next one.
  1032. pPrevClientfLink = &(pClientInt->fLink);
  1033. pClientInt = pClientInt->fLink;
  1034. } // while
  1035. // next resource
  1036. } // for
  1037. // now store the clients in the input list in priority order
  1038. pClient=lpClientList->aClients;
  1039. for (i=0; i < lpClientList->cClients; i++)
  1040. {
  1041. pClientInt = m_pClientList;
  1042. pPrevClientfLink = &m_pClientList;
  1043. while (pClientInt != 0)
  1044. {
  1045. // as long as the priority of the new client is higher than or equal to the one
  1046. // in the list, we continue to traverse the list
  1047. if (pClient[i].priority < pClientInt->client.priority)
  1048. { // this is the place to insert this client
  1049. break;
  1050. }
  1051. // not time to insert yet. next client
  1052. pPrevClientfLink = &(pClientInt->fLink);
  1053. pClientInt = pClientInt->fLink;
  1054. } // while
  1055. // not found. add the client
  1056. pClientNew = (LPCLIENTINT) MEMALLOC(sizeof(CLIENTINT));
  1057. ASSERT(pClientNew);
  1058. if (!pClientNew)
  1059. {
  1060. ERRORMSG(("IQoS::SetClients: MEMALLOC failed on CLIENTINT\n"));
  1061. hr = E_OUTOFMEMORY;
  1062. goto out;
  1063. }
  1064. // copy the resource in
  1065. RtlCopyMemory( &(pClientNew->client),
  1066. &(pClient[i]),
  1067. sizeof(CLIENT));
  1068. pClientNew->fLink = pClientInt;
  1069. *pPrevClientfLink = pClientNew;
  1070. // next resource
  1071. } // for
  1072. out:
  1073. DISPLAYQOSOBJECT();
  1074. RELMUTEX(g_hQoSMutex);
  1075. out_nomutex:
  1076. DEBUGMSG(ZONE_IQOS,("IQoS::SetClients -leave, hr=0x%x\n", hr));
  1077. return hr;
  1078. }
  1079. /***************************************************************************
  1080. Name : CQoS::NotifyNow
  1081. Purpose : Tells the QoS module to initiate a notification cycle as
  1082. soon as possible.
  1083. Parameters: None
  1084. Returns : HRESULT
  1085. Comment : Don't call from within a notify proc.
  1086. ***************************************************************************/
  1087. HRESULT CQoS::NotifyNow(void)
  1088. {
  1089. HRESULT hr = NOERROR;
  1090. DEBUGMSG(ZONE_IQOS,("IQoS::NotifyNow\n"));
  1091. SetEvent(m_evImmediateNotify);
  1092. DEBUGMSG(ZONE_IQOS,("IQoS::NotifyNow - leave, hr=0x%x\n", hr));
  1093. return hr;
  1094. }
  1095. /***************************************************************************
  1096. Name : CQoS::FreeBuffer
  1097. Purpose : Frees a buffer allocated by the QoS module.
  1098. Parameters: lpBuffer - a pointer to the buffer to free. This buffer must
  1099. have been allocated by QoS
  1100. Returns : HRESULT
  1101. Comment :
  1102. ***************************************************************************/
  1103. HRESULT CQoS::FreeBuffer(LPVOID lpBuffer)
  1104. {
  1105. HRESULT hr = NOERROR;
  1106. DEBUGMSG(ZONE_IQOS,("IQoS::FreeBuffer\n"));
  1107. if (lpBuffer)
  1108. MEMFREE(lpBuffer);
  1109. DEBUGMSG(ZONE_IQOS,("IQoS::FreeBuffer - leave, hr=0x%x\n", hr));
  1110. return hr;
  1111. }
  1112. /***************************************************************************
  1113. Name : CQoS::CQoS
  1114. Purpose : The CQoS object constructor
  1115. Parameters: none
  1116. Returns : None
  1117. Comment :
  1118. ***************************************************************************/
  1119. inline CQoS::CQoS (void)
  1120. {
  1121. m_cRef = 0; // will be bumped to 1 by the explicit QI in CreateQoS
  1122. m_pResourceList = NULL;
  1123. m_cResources = 0;
  1124. m_pClientList = NULL;
  1125. m_evThreadExitSignal = NULL;
  1126. m_evImmediateNotify = NULL;
  1127. m_hThread = NULL;
  1128. m_bQoSEnabled = TRUE;
  1129. m_bInNotify = FALSE;
  1130. m_nSkipHeartBeats = 0;
  1131. m_hWnd = NULL;
  1132. m_nLeaveForNextPri = 5;
  1133. // can't use ++ because RISC processors may translate to several instructions
  1134. InterlockedIncrement((long *) &g_cQoSObjects);
  1135. }
  1136. /***************************************************************************
  1137. Name : CQoS::~CQoS
  1138. Purpose : The CQoS object destructor
  1139. Parameters: none
  1140. Returns : None
  1141. Comment :
  1142. ***************************************************************************/
  1143. inline CQoS::~CQoS (void)
  1144. {
  1145. // can't use ++ because RISC processors may translate to several instructions
  1146. InterlockedDecrement((long *) &g_cQoSObjects);
  1147. g_pQoS = (CQoS *)NULL;
  1148. }
  1149. /***************************************************************************
  1150. Name : CQoS::Initialize
  1151. Purpose : Initializes the QoS object
  1152. Parameters: None
  1153. Returns : HRESULT
  1154. Comment :
  1155. ***************************************************************************/
  1156. HRESULT CQoS::Initialize(void)
  1157. {
  1158. HRESULT hr=NOERROR;
  1159. OSVERSIONINFO tVersionInfo;
  1160. /*
  1161. * Initialize the object
  1162. */
  1163. ACQMUTEX(g_hQoSMutex);
  1164. // first see if QoS is enabled
  1165. RegEntry reQoS(QOS_KEY,
  1166. HKEY_LOCAL_MACHINE,
  1167. FALSE,
  1168. KEY_READ);
  1169. m_bQoSEnabled = reQoS.GetNumberIniStyle(TEXT("Enable"), TRUE);
  1170. if (!m_bQoSEnabled)
  1171. {
  1172. // don't create a thread, but return success
  1173. DEBUGMSG(ZONE_IQOS,("Initialize: QoS not enabled\n"));
  1174. hr = NOERROR;
  1175. goto out;
  1176. }
  1177. /*
  1178. * QoS notification thread
  1179. */
  1180. // create an event that will be used to signal the thread to terminate
  1181. // CreateEvent(No security attr's, no manual reset, not signalled, no name)
  1182. m_evThreadExitSignal = CreateEvent(NULL, FALSE, FALSE, NULL);
  1183. ASSERT(m_evThreadExitSignal);
  1184. if (!(m_evThreadExitSignal))
  1185. {
  1186. ERRORMSG(("Initialize: Exit event creation failed: %x\n", GetLastError()));
  1187. hr = E_FAIL;
  1188. goto out;
  1189. }
  1190. // create an event that will be used to signal the thread to initiate
  1191. // an immediate notify cycle
  1192. // CreateEvent(No security attr's, no manual reset, not signalled, no name)
  1193. m_evImmediateNotify = CreateEvent(NULL, FALSE, FALSE, NULL);
  1194. ASSERT(m_evImmediateNotify);
  1195. if (!(m_evImmediateNotify))
  1196. {
  1197. ERRORMSG(("Initialize: Immediate notify event creation failed: %x\n", GetLastError()));
  1198. hr = E_FAIL;
  1199. goto out;
  1200. }
  1201. //Set the OS flag
  1202. tVersionInfo.dwOSVersionInfoSize=sizeof (OSVERSIONINFO);
  1203. if (!(GetVersionEx (&tVersionInfo))) {
  1204. ERRORMSG(("Initialize: Couldn't get version info: %x\n", GetLastError()));
  1205. hr = E_FAIL;
  1206. goto out;
  1207. }
  1208. if (tVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  1209. bWin9x=TRUE;
  1210. }else {
  1211. if (tVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1212. bWin9x=FALSE;
  1213. }else {
  1214. //How on earth did we get here?
  1215. ASSERT (0);
  1216. hr=E_FAIL;
  1217. goto out;
  1218. }
  1219. }
  1220. out:
  1221. RELMUTEX(g_hQoSMutex);
  1222. return hr;
  1223. }
  1224. /***************************************************************************
  1225. Name : CreateQoS
  1226. Purpose : Creates the QoS object and return an IQoS interface pointer
  1227. Parameters:
  1228. Returns : HRESULT
  1229. Comment : CreateQoS will only create one instance of the QoS object.
  1230. Additional calls will return the same interface pointer
  1231. ***************************************************************************/
  1232. extern "C" HRESULT WINAPI CreateQoS ( IUnknown *punkOuter,
  1233. REFIID riid,
  1234. void **ppv)
  1235. {
  1236. CQoS *pQoS;
  1237. HRESULT hr = NOERROR;
  1238. *ppv = 0;
  1239. if (punkOuter)
  1240. return CLASS_E_NOAGGREGATION;
  1241. /*
  1242. * instantiate the QoS object
  1243. */
  1244. ACQMUTEX(g_hQoSMutex);
  1245. // only instantiate a new object if it doesn't already exist
  1246. if (g_cQoSObjects == 0)
  1247. {
  1248. if (!(pQoS = new CQoS))
  1249. {
  1250. hr = E_OUTOFMEMORY;
  1251. goto out;
  1252. }
  1253. // Save pointer
  1254. g_pQoS = pQoS;
  1255. // initialize the QoS object
  1256. hr = pQoS->Initialize();
  1257. }
  1258. else
  1259. {
  1260. // this is the case when the object was already instantiaed in this
  1261. // process, so we only want to return the object pointer.
  1262. pQoS = g_pQoS;
  1263. }
  1264. // must have only one QoS object at this point
  1265. ASSERT(g_cQoSObjects == 1);
  1266. RELMUTEX(g_hQoSMutex);
  1267. // get the IQoS interface for the caller
  1268. if (pQoS)
  1269. {
  1270. // QueryInterface will get us the interface pointer and will AddRef
  1271. // the object
  1272. hr = pQoS->QueryInterface (riid, ppv);
  1273. }
  1274. else
  1275. hr = E_FAIL;
  1276. out:
  1277. return hr;
  1278. }
  1279. /***************************************************************************
  1280. Name : QoSEntryPoint
  1281. Purpose : Called by nac.dll (where the QoS lives these days) to make
  1282. the necessary process attach and detach initializations
  1283. Parameters: same as a standard DllEntryPoint
  1284. Returns :
  1285. ***************************************************************************/
  1286. extern "C" BOOL APIENTRY QoSEntryPoint( HINSTANCE hInstDLL,
  1287. DWORD dwReason,
  1288. LPVOID lpReserved)
  1289. {
  1290. BOOL fRet=TRUE;
  1291. switch (dwReason)
  1292. {
  1293. case DLL_PROCESS_ATTACH:
  1294. QOSDEBUGINIT();
  1295. // create a no-name mutex to control access to QoS object data
  1296. if (!g_hQoSMutex)
  1297. {
  1298. g_hQoSMutex = CreateMutex(NULL, FALSE, NULL);
  1299. ASSERT(g_hQoSMutex);
  1300. if (!g_hQoSMutex)
  1301. {
  1302. ERRORMSG(("QoSEntryPoint: CreateMutex failed, 0x%x\n", GetLastError()));
  1303. fRet = FALSE;
  1304. }
  1305. }
  1306. break;
  1307. case DLL_PROCESS_DETACH:
  1308. if (g_hQoSMutex)
  1309. CloseHandle(g_hQoSMutex);
  1310. g_hQoSMutex = NULL;
  1311. DBGDEINIT(&ghDbgZoneQoS);
  1312. break;
  1313. default:
  1314. break;
  1315. }
  1316. return fRet;
  1317. }