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.

432 lines
8.9 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. blocklst.cxx
  5. Abstract:
  6. Contains WinInet async support to allow blocking of unknown threads, on auto-proxy events.
  7. Contents:
  8. BlockThreadOnEvent
  9. SignalThreadOnEvent
  10. AcquireBlockedRequestQueue
  11. ReleaseBlockedRequestQueue
  12. (DestroyBlockedThreadEvent)
  13. Author:
  14. Arthur L Bierer (arthurbi) 15-Feb-1998
  15. Environment:
  16. Win32 user-mode DLL
  17. Revision History:
  18. 15-Feb-1998 arthurbi
  19. Created
  20. --*/
  21. #include <wininetp.h>
  22. #include <perfdiag.hxx>
  23. //
  24. // private data
  25. //
  26. //
  27. // BlockedRequestQueue - when threads need to block on an event they get
  28. // placed in here until their event is signaled. This is needed so threads
  29. // can block on internally kept events without having to be tied
  30. // to keeping track of event handles.
  31. //
  32. // Blocked threads must not be also waiting for a socket to become unblocked
  33. //
  34. GLOBAL SERIALIZED_LIST BlockedRequestQueue = {0};
  35. //
  36. // ARB - information common to all asynchronous blocked events
  37. //
  38. typedef struct {
  39. //
  40. // List - requests are queued on doubly-linked list. N.B. Code that deals
  41. // in ARBs implicitly assumes that List is at offset zero in the ARB. Move
  42. // this and pick up the pieces...
  43. //
  44. LIST_ENTRY List;
  45. //
  46. // hEvent - handle to Event that we are blocked on.
  47. //
  48. HANDLE hEvent;
  49. //
  50. // dwBlockedOnEvent - contains the event this ARB may be blocked
  51. // on. This allows a FIBER to block itself on an Internally kept
  52. // event. When the event is signalled, it will wakeup, and moved
  53. // to the Active Pool of fibers.
  54. //
  55. // A ZERO value means there is NO event that is being blocked on.
  56. //
  57. DWORD_PTR dwBlockedOnEvent;
  58. //
  59. // dwBlockedOnEventReturnCode - contains error code returned from
  60. // fiber or main thread that is doing the unblocking.
  61. //
  62. DWORD dwBlockedOnEventReturnCode;
  63. #if INET_DEBUG
  64. //
  65. // dwSignature - in the debug version, we maintain a signature in the ARB
  66. // for sanity checking
  67. //
  68. DWORD dwSignature;
  69. #endif // INET_DEBUG
  70. } ARB, * LPARB;
  71. //
  72. // functions...
  73. //
  74. PRIVATE
  75. VOID
  76. DestroyBlockedThreadEvent(
  77. IN LPARB lpArb
  78. )
  79. /*++
  80. Routine Description:
  81. Removes lpArb from the blocked request queue if its still there, and
  82. destroys it
  83. Arguments:
  84. lpArb - pointer to AR_SYNC_EVENT ARB
  85. Return Value:
  86. None.
  87. --*/
  88. {
  89. DEBUG_ENTER((DBG_ASYNC,
  90. None,
  91. "DestroyBlockedThreadEvent",
  92. "%#x",
  93. lpArb
  94. ));
  95. AcquireBlockedRequestQueue();
  96. if (lpArb->hEvent != NULL) {
  97. CloseHandle(lpArb->hEvent);
  98. }
  99. if (IsOnSerializedList(&BlockedRequestQueue, &lpArb->List)) {
  100. RemoveFromSerializedList(&BlockedRequestQueue, &lpArb->List);
  101. }
  102. ReleaseBlockedRequestQueue();
  103. DEBUG_LEAVE(0);
  104. }
  105. DWORD
  106. BlockThreadOnEvent(
  107. IN DWORD_PTR dwEventId,
  108. IN DWORD dwTimeout,
  109. IN BOOL bReleaseLock
  110. )
  111. /*++
  112. Routine Description:
  113. Waits for an async event if called in the context of a fiber, else waits for
  114. an event if called in the context of a sync request
  115. Arguments:
  116. dwEventId - event id to wait on
  117. dwTimeout - amount of time to wait
  118. bReleaseLock - TRUE if we need to release the blocked request queue
  119. Return Value:
  120. DWORD
  121. Success - ERROR_SUCCESS
  122. The request/wait completed successfully
  123. Failure - ERROR_INTERNET_TIMEOUT
  124. The request timed out
  125. ERROR_INTERNET_INTERNAL_ERROR
  126. We couldn't get the INTERNET_THREAD_INFO
  127. --*/
  128. {
  129. DEBUG_ENTER((DBG_ASYNC,
  130. Dword,
  131. "BlockThreadOnEvent",
  132. "%#x, %d, %B",
  133. dwEventId,
  134. dwTimeout,
  135. bReleaseLock
  136. ));
  137. DWORD error;
  138. ARB Arb;
  139. ZeroMemory(&Arb, sizeof(Arb));
  140. //
  141. // set up the remaining fields in the ARB - initialize the list pointer,
  142. // set the priority (to default), and the event id
  143. //
  144. Arb.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  145. if (Arb.hEvent == NULL) {
  146. error = GetLastError();
  147. // IE6 BUG #25117
  148. // if we acquired the blocked request queue before calling this function
  149. // then we need to release it
  150. //
  151. if (bReleaseLock) {
  152. ReleaseBlockedRequestQueue();
  153. }
  154. goto quit;
  155. }
  156. Arb.dwBlockedOnEvent = dwEventId;
  157. //
  158. // add the request to the blocked request queue
  159. //
  160. InsertAtTailOfSerializedList(&BlockedRequestQueue, &Arb.List);
  161. //
  162. // if we acquired the blocked request queue before calling this function
  163. // then we need to release it
  164. //
  165. if (bReleaseLock) {
  166. ReleaseBlockedRequestQueue();
  167. }
  168. //
  169. // now wait here for the event to become signalled
  170. //
  171. error = PERF_WaitForSingleObject(Arb.hEvent,
  172. dwTimeout
  173. );
  174. //
  175. // if we timed out then we will remove and destroy the ARB, else the thread
  176. // which signalled the request will have done so
  177. //
  178. if (error == WAIT_TIMEOUT) {
  179. error = ERROR_INTERNET_TIMEOUT;
  180. } else {
  181. error = Arb.dwBlockedOnEventReturnCode;
  182. }
  183. quit:
  184. //
  185. // remove the request from the blocked request queue and destroy it
  186. //
  187. DestroyBlockedThreadEvent(&Arb);
  188. DEBUG_LEAVE(error);
  189. return error;
  190. }
  191. DWORD
  192. SignalThreadOnEvent(
  193. IN DWORD_PTR dwEventId,
  194. IN DWORD dwNumberOfWaiters,
  195. IN DWORD dwReturnCode
  196. )
  197. /*++
  198. Routine Description:
  199. Unblocks a number of fibers that may be waiting for an event to be signalled.
  200. When the fibers unblock they will be rescheduled to the Active Request Queue.
  201. The 'event' is reset automatically back to unsignalled state.
  202. If called outside of the worker thread, this function also handles
  203. interupting the blocked worked thread so it can resume requests.
  204. Arguments:
  205. dwEventId - Event ID to wake up on.
  206. dwNumberOfWaiters - number of waiters to unblock. Choose a large number
  207. to mean 'all'
  208. dwReturnCode - Upon waking up fibers, their blocked called will return
  209. with this error code.
  210. Return Value:
  211. DWORD
  212. Number of waiters unblocked
  213. --*/
  214. {
  215. DEBUG_ENTER((DBG_ASYNC,
  216. Int,
  217. "SignalThreadOnEvent",
  218. "%#x, %d, %d (%s)",
  219. dwEventId,
  220. dwNumberOfWaiters,
  221. dwReturnCode,
  222. InternetMapError(dwReturnCode)
  223. ));
  224. INET_ASSERT(dwNumberOfWaiters > 0);
  225. DWORD dwUnblocked = 0;
  226. AcquireBlockedRequestQueue();
  227. LPARB lpArb = (LPARB)HeadOfSerializedList(&BlockedRequestQueue);
  228. LPARB lpArbPrevious = (LPARB)SlSelf(&BlockedRequestQueue);
  229. while (lpArb != (LPARB)SlSelf(&BlockedRequestQueue)) {
  230. if (lpArb->dwBlockedOnEvent == dwEventId) {
  231. lpArb->dwBlockedOnEventReturnCode = dwReturnCode;
  232. //
  233. // if the ARB is really an async request then add it to the end of
  234. // the async request queue else if it is a sync request then just
  235. // signal the event. The waiter will free the ARB
  236. //
  237. SetEvent(lpArb->hEvent);
  238. DEBUG_PRINT(ASYNC,
  239. INFO,
  240. ("signalled sync request %#x, on %#x\n",
  241. lpArb,
  242. lpArb->dwBlockedOnEvent
  243. ));
  244. //
  245. // if we've hit the number of waiters we were to unblock then
  246. // quit
  247. //
  248. ++dwUnblocked;
  249. if (dwUnblocked == dwNumberOfWaiters) {
  250. break;
  251. }
  252. //
  253. // we moved the ARB
  254. //
  255. lpArb = lpArbPrevious;
  256. }
  257. lpArbPrevious = lpArb;
  258. lpArb = (LPARB)lpArb->List.Flink;
  259. }
  260. ReleaseBlockedRequestQueue();
  261. DEBUG_LEAVE(dwUnblocked);
  262. return dwUnblocked;
  263. }
  264. VOID
  265. AcquireBlockedRequestQueue(
  266. VOID
  267. )
  268. /*++
  269. Routine Description:
  270. Synchronizes access to the blocked request queue
  271. Arguments:
  272. None.
  273. Return Value:
  274. None.
  275. --*/
  276. {
  277. LockSerializedList(&BlockedRequestQueue);
  278. }
  279. VOID
  280. ReleaseBlockedRequestQueue(
  281. VOID
  282. )
  283. /*++
  284. Routine Description:
  285. Releases the lock acquired with AcquireBlockedRequestQueue
  286. Arguments:
  287. None.
  288. Return Value:
  289. None.
  290. --*/
  291. {
  292. UnlockSerializedList(&BlockedRequestQueue);
  293. }