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.

375 lines
9.3 KiB

  1. /*
  2. - THREAD.CPP
  3. -
  4. * Microsoft NetMeeting
  5. * Quality of Service DLL
  6. * Quality of Service Notification Thread
  7. *
  8. * Revision History:
  9. *
  10. * When Who What
  11. * -------- ------------------ ---------------------------------------
  12. * 10.30.96 Yoram Yaacovi Created
  13. *
  14. * Functions:
  15. * CQoS::StartQoSThread
  16. * CQoS::StopQoSThread
  17. * CQoS::QoSThread
  18. * QoSThreadWrapper
  19. */
  20. #include "precomp.h"
  21. /***************************************************************************
  22. Name : CQoS::StartQoSThread
  23. Purpose : Starts a QoS notification thread
  24. Parameters: None
  25. Returns : HRESULT
  26. Comment :
  27. ***************************************************************************/
  28. HRESULT CQoS::StartQoSThread(void)
  29. {
  30. HRESULT hr=NOERROR;
  31. HANDLE hThread;
  32. DWORD idThread;
  33. // prepare the structrue for the thread
  34. // now spwan the thread
  35. hThread = CreateThread (NULL,
  36. 0, // Default (same as main thread) stack size
  37. (LPTHREAD_START_ROUTINE) QoSThreadWrapper,
  38. (LPVOID) this, // Pass the object pointer to thread
  39. 0, // Run thread now
  40. &idThread);
  41. ASSERT(hThread);
  42. if (!hThread)
  43. {
  44. ERRORMSG(("StartQoSThread: failed to create thread: %x\n", GetLastError()));
  45. hr = E_FAIL;
  46. }
  47. m_hThread = hThread;
  48. return hr;
  49. }
  50. /***************************************************************************
  51. Name : CQoS::StopQoSThread
  52. Purpose : Stops a QoS notification thread
  53. Parameters: None
  54. Returns : HRESULT
  55. Comment : It is assumed that when the thread that calls StopQoSThread
  56. has the QoS mutex.
  57. ***************************************************************************/
  58. HRESULT CQoS::StopQoSThread(void)
  59. {
  60. HRESULT hr=NOERROR;
  61. HANDLE evExitSignal=m_evThreadExitSignal;
  62. DWORD dwExitCode=0;
  63. ULONG i=0;
  64. HANDLE hThread=NULL;
  65. if (m_hThread)
  66. {
  67. // tell the thread to exit
  68. SetEvent(evExitSignal);
  69. hThread = m_hThread;
  70. m_hThread = NULL;
  71. // the thread might need the mutex to exit
  72. RELMUTEX(g_hQoSMutex);
  73. // wait for the thread to terminate
  74. if (WaitForSingleObject(hThread, 1000) == WAIT_TIMEOUT)
  75. {
  76. // if it didn't take its own life, you take it...
  77. DEBUGMSG(ZONE_THREAD,("StopQoSThread: QoS thread didn't properly terminate within 1 second. Terminating it\n"));
  78. TerminateThread(hThread, 0);
  79. }
  80. // re-acquire the mutex (for balance)
  81. ACQMUTEX(g_hQoSMutex);
  82. CloseHandle(hThread);
  83. }
  84. return hr;
  85. }
  86. /***************************************************************************
  87. Name : CQoS::NotifyQoSClient
  88. Purpose : Notifies a QoS client on change in resource availability
  89. Parameters:
  90. Returns : HRESULT
  91. Comment : prrl is a pointer to a list of resource requests. This
  92. list has two purposes:
  93. 1. The QoS module will fill the list with the current
  94. availability of resources
  95. 2. The client will fill the list with its resource requests
  96. The QoS module is allocating the memory for the resource
  97. requests list. It will allocate one resource request per
  98. each available resource.
  99. ***************************************************************************/
  100. HRESULT CQoS::NotifyQoSClient(void)
  101. {
  102. HRESULT hr=NOERROR;
  103. LPRESOURCEREQUESTLIST prrl=NULL;
  104. LPRESOURCEINT pr=NULL;
  105. LPCLIENTINT pc=NULL;
  106. ULONG cResources=m_cResources;
  107. LPRESOURCEINT pResourceList=m_pResourceList;
  108. /*
  109. * here's what happens:
  110. *
  111. * the QoS module creates a new resource list from the old one,
  112. * making all resources fully available. It satisfies the new
  113. * client resource requests from this new list.
  114. */
  115. // don't bother if no clients or no resources
  116. if (!m_pClientList || !m_pResourceList)
  117. {
  118. goto out;
  119. }
  120. // first update the request list for all clients
  121. pc = m_pClientList;
  122. while (pc)
  123. {
  124. UpdateRequestsForClient (&(pc->client.guidClientGUID));
  125. pc = pc->fLink;
  126. }
  127. // we are going to wipe all requests from the resource
  128. // lists, and set all resources back to full availability
  129. pr = m_pResourceList;
  130. while (pr)
  131. {
  132. // free the request list
  133. FreeListOfRequests(&(pr->pRequestList));
  134. // set the resource back to full availability
  135. pr->nNowAvailUnits = pr->resource.nUnits;
  136. // next resource
  137. pr = pr->fLink;
  138. }
  139. /*
  140. * Build resource request lists for each client and call it
  141. */
  142. // allocate space for the resource list (which already includes
  143. // space for one resource), plus (cResources-1) more resources
  144. prrl = (LPRESOURCEREQUESTLIST) MEMALLOC(sizeof(RESOURCEREQUESTLIST) +
  145. (cResources-1)*sizeof(RESOURCEREQUEST));
  146. if (!prrl)
  147. {
  148. hr = E_OUTOFMEMORY;
  149. ERRORMSG(("NotifyQoSClient: MEMALLOC failed in NotifyQoSClient\n"));
  150. goto out;
  151. }
  152. RtlZeroMemory((PVOID) prrl, sizeof(RESOURCEREQUESTLIST) +
  153. (cResources-1)*sizeof(RESOURCEREQUEST));
  154. // call each client, in order of priority, with the available resource list
  155. pc = m_pClientList;
  156. while (pc)
  157. {
  158. LPFNQOSNOTIFY pNotifyProc=NULL;
  159. DWORD_PTR dwParam=0;
  160. LPGUID lpGUID=NULL;
  161. ULONG i=0;
  162. LPRESOURCEREQUESTINT pcrr=NULL;
  163. ULONG nSamePriClients=1;
  164. ULONG nLowerPriClients=0;
  165. /*
  166. * Building the request list
  167. */
  168. pcrr = pc->pRequestList;
  169. while (pcrr)
  170. {
  171. // remember the address of the notify proc for this client and its GUID
  172. pNotifyProc = pcrr->pfnQoSNotify;
  173. dwParam = pcrr->dwParam;
  174. lpGUID = &(pcrr->guidClientGUID);
  175. // add the resource to the requestlist we'll send to this client
  176. prrl->aRequests[i].resourceID = pcrr->sResourceRequest.resourceID;
  177. // find current availability of the resource
  178. pr = m_pResourceList;
  179. while (pr)
  180. {
  181. if (pr->resource.resourceID == pcrr->sResourceRequest.resourceID)
  182. {
  183. ULONG nNowAvailUnits=pr->nNowAvailUnits;
  184. // find if there are other clients for this resource
  185. FindClientsForResource( pr->resource.resourceID,
  186. pc,
  187. &nSamePriClients,
  188. &nLowerPriClients);
  189. // leave some of the resource for the next priority clients, if any
  190. if (nLowerPriClients)
  191. nNowAvailUnits = (nNowAvailUnits * (100 - m_nLeaveForNextPri)) / 100;
  192. prrl->aRequests[i].nUnitsMin = nNowAvailUnits / nSamePriClients;
  193. prrl->aRequests[i].nUnitsMax = nNowAvailUnits;
  194. break;
  195. }
  196. // next resource
  197. pr = pr->fLink;
  198. }
  199. // next request in the list we're making
  200. i++;
  201. // next request
  202. pcrr = pcrr->fLink;
  203. }
  204. // if we have requests from this client, call its notify callback
  205. prrl->cRequests = i;
  206. if (pNotifyProc)
  207. {
  208. // call the notify callback
  209. hr = (pNotifyProc)(prrl, dwParam);
  210. if (SUCCEEDED(hr))
  211. {
  212. // the returned request list contains what the client wants
  213. // request them on behalf of the client
  214. // let RequestResources know that we're calling from the notify proc
  215. m_bInNotify = TRUE;
  216. hr = RequestResources(lpGUID, prrl, pNotifyProc, dwParam);
  217. if (FAILED(hr))
  218. {
  219. ERRORMSG(("NotifyQoSClient: client returned bad resource request list\n"));
  220. }
  221. m_bInNotify = FALSE;
  222. }
  223. }
  224. pc = pc->fLink;
  225. }
  226. out:
  227. if (prrl)
  228. MEMFREE(prrl);
  229. return hr;
  230. }
  231. /***************************************************************************
  232. Name : CQoS::QoSThread
  233. Purpose : QoS notification thread
  234. Parameters: None
  235. Returns :
  236. Comment :
  237. ***************************************************************************/
  238. DWORD CQoS::QoSThread(void)
  239. {
  240. int nTimeout;
  241. ULONG rc=0;
  242. HANDLE evSignalExit=m_evThreadExitSignal;
  243. HANDLE aHandles[2] = {m_evThreadExitSignal, m_evImmediateNotify};
  244. // wake up every N seconds and notify clients
  245. RegEntry reQoS(QOS_KEY,
  246. HKEY_LOCAL_MACHINE,
  247. FALSE,
  248. KEY_READ);
  249. nTimeout = reQoS.GetNumberIniStyle(TEXT("Timeout"), 3000);
  250. while (1)
  251. {
  252. rc = WaitForMultipleObjects(2, aHandles, FALSE, nTimeout);
  253. // if a timeout or a signal to do an immediate notify cycle...
  254. if ((rc == WAIT_TIMEOUT) || ((rc - WAIT_OBJECT_0) == 1))
  255. { // ..do it
  256. ACQMUTEX(g_hQoSMutex);
  257. // NOTE: it is possible that while waiting on the mutex, the thread
  258. // was stopped (no more requests). In this case, the thread will do
  259. // a unnecessary (though harmless, since no requests) notify cycle
  260. DEBUGMSG(ZONE_THREAD,("QoSThread: Notify thread heartbeat, why=%s\n",
  261. (rc == WAIT_TIMEOUT ? "timeout" : "notify")));
  262. // notify clients, unless this heartbeat should be skipped
  263. if (m_nSkipHeartBeats == 0)
  264. {
  265. DEBUGMSG(ZONE_THREAD,("QoSThread: Notifying client\n"));
  266. NotifyQoSClient();
  267. }
  268. // update the skip counter
  269. (m_nSkipHeartBeats ? m_nSkipHeartBeats-- : 0);
  270. RELMUTEX(g_hQoSMutex);
  271. }
  272. // anything else (WAIT_FAILED, Exit signal), bail out
  273. else
  274. break;
  275. }
  276. // this is just like ExitThread()
  277. DEBUGMSG(ZONE_THREAD,("QoSThread: Notify thread exiting...\n"));
  278. return 0L;
  279. }
  280. /***************************************************************************
  281. Name : QoSThreadWrapper
  282. Purpose : Wrapper for the QoS notification thread
  283. Parameters: pQoS - pointer to the QoS object
  284. Returns :
  285. Comment :
  286. ***************************************************************************/
  287. DWORD QoSThreadWrapper(CQoS *pQoS)
  288. {
  289. return pQoS->QoSThread();
  290. }
  291.