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.

440 lines
9.4 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. bgtask.cxx
  5. Abstract:
  6. Contains background task and support functions
  7. Contents:
  8. LoadBackgroundTaskMgr
  9. UnloadBackgroundTaskMgr
  10. NotifyBackgroundTaskMgr
  11. CreateAndQueueBackgroundWorkItem
  12. BackgroundTaskMgr::QueueBackgroundWorkItem
  13. BackgroundTaskMgr::DeQueueAndRunBackgroundWorkItem
  14. BackgroundTaskMgr::CreateBackgroundFsm
  15. BackgroundTaskMgr::Release
  16. BackgroundTaskMgr::HasBandwidth
  17. CFsm_BackgroundTask::RunSM
  18. CFsm_BackgroundTask::DoSendReq
  19. CFsm_BackgroundTask::~CFsm_BackgroundTask
  20. Author:
  21. Danpo Zhang (danpoz) 06-26-98
  22. Environment:
  23. Win32 user-mode
  24. Revision History:
  25. 06-26-1998 danpoz
  26. Created
  27. --*/
  28. #include <wininetp.h>
  29. #include <perfdiag.hxx>
  30. BackgroundTaskMgr* g_BGTaskMgr = NULL;
  31. //
  32. // API: Init global BackgroundTaskManager
  33. //
  34. BOOL
  35. LoadBackgroundTaskMgr()
  36. {
  37. if( g_BGTaskMgr )
  38. return TRUE;
  39. BackgroundTaskMgr* bgMgr = NULL;
  40. bgMgr = new BackgroundTaskMgr();
  41. if( !bgMgr)
  42. return FALSE;
  43. g_BGTaskMgr = bgMgr;
  44. return TRUE;
  45. }
  46. //
  47. // API: Unload global BackgroundTaskManager
  48. //
  49. void
  50. UnloadBackgroundTaskMgr()
  51. {
  52. if( g_BGTaskMgr )
  53. {
  54. //BUGBUG
  55. //what to do with unfinished task?
  56. delete g_BGTaskMgr;
  57. }
  58. g_BGTaskMgr = NULL;
  59. }
  60. //
  61. // API: Select thread notifis now is a good time to do background task
  62. //
  63. DWORD
  64. NotifyBackgroundTaskMgr()
  65. {
  66. DWORD error;
  67. // can we run another background item?
  68. if( !g_BGTaskMgr->HasBandwidth() )
  69. {
  70. error = ERROR_SUCCESS;
  71. goto quit;
  72. }
  73. // get a background FSM if there is any
  74. g_BGTaskMgr->DeQueueAndRunBackgroundWorkItem();
  75. error = ERROR_SUCCESS;
  76. quit:
  77. return error;
  78. }
  79. //
  80. // create a background task (fsm) and queue it on the background task
  81. // list, the task item will be picked up later by a free async worker
  82. // thread
  83. //
  84. DWORD
  85. CreateAndQueueBackgroundWorkItem(
  86. IN LPCSTR szUrl
  87. )
  88. {
  89. DEBUG_ENTER((DBG_ASYNC,
  90. Dword,
  91. "CreateAndQueueBackgroundWorkItem",
  92. "%q",
  93. szUrl
  94. ));
  95. DWORD error;
  96. CFsm* pFsm = NULL;
  97. INET_ASSERT( szUrl );
  98. // get new fsm
  99. pFsm = g_BGTaskMgr->CreateBackgroundFsm(szUrl);
  100. if( !pFsm )
  101. {
  102. error = ERROR_NOT_ENOUGH_MEMORY;
  103. goto quit;
  104. }
  105. // queue fsm
  106. error = g_BGTaskMgr->QueueBackgroundWorkItem(pFsm);
  107. if( error != ERROR_SUCCESS )
  108. {
  109. // delete the fsm to avoid leak
  110. delete pFsm;
  111. }
  112. quit:
  113. DEBUG_LEAVE(error);
  114. return error;
  115. }
  116. DWORD
  117. BackgroundTaskMgr::QueueBackgroundWorkItem(
  118. IN CFsm* pFsm
  119. )
  120. {
  121. DEBUG_ENTER((DBG_ASYNC,
  122. Dword,
  123. "ICAsyncThread::QueueBackgroundWorkItem",
  124. "%#x",
  125. pFsm
  126. ));
  127. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  128. DWORD error = ERROR_INTERNET_INTERNAL_ERROR;
  129. INET_ASSERT(lpThreadInfo != NULL);
  130. if( lpThreadInfo != NULL )
  131. {
  132. _bgTaskQueue.Acquire();
  133. _bgTaskQueue.Insert((CPriorityListEntry *)pFsm->List());
  134. lpThreadInfo->Fsm = NULL;
  135. _bgTaskQueue.Release();
  136. error = ERROR_SUCCESS;
  137. if (g_bHibernating)
  138. {
  139. InterruptSelect();
  140. }
  141. }
  142. DEBUG_LEAVE(error);
  143. return error;
  144. }
  145. DWORD
  146. BackgroundTaskMgr::DeQueueAndRunBackgroundWorkItem()
  147. {
  148. // LOCK list
  149. _bgTaskQueue.Acquire();
  150. // check the list to see if it is empty
  151. if( _bgTaskQueue.Head() != _bgTaskQueue.Self() )
  152. {
  153. PLIST_ENTRY pEntry = NULL;
  154. PLIST_ENTRY pPrev = NULL;
  155. pPrev = _bgTaskQueue.Self();
  156. pEntry = ((CPriorityListEntry*)pPrev)->Next();
  157. CFsm* pFsm = ContainingFsm(pEntry);
  158. INET_ASSERT(pFsm);
  159. // deQueued, we can remove the task item from the queue
  160. // remove from the blocked list
  161. _bgTaskQueue.Remove((CPriorityListEntry *)pFsm);
  162. // increment the active running fsm count
  163. InterlockedIncrement(&_lActiveFsm);
  164. // this fsm will be picked up by a waken worker thread
  165. pFsm->QueueWorkItem();
  166. }
  167. // UNLOCK list
  168. _bgTaskQueue.Release();
  169. return ERROR_SUCCESS;
  170. }
  171. CFsm*
  172. BackgroundTaskMgr::CreateBackgroundFsm(LPCSTR szUrl)
  173. {
  174. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  175. // HACK - HACK for TESTING...
  176. // correct solution is when lpThreadInfo->Fsm != NULL
  177. // we do not create a fsm so that we always make sure
  178. // there is one fsm on the select thread
  179. //
  180. if( lpThreadInfo != NULL )
  181. {
  182. lpThreadInfo->Fsm = NULL;
  183. }
  184. return new CFsm_BackgroundTask(this, szUrl);
  185. }
  186. BOOL
  187. BackgroundTaskMgr::HasBandwidth()
  188. {
  189. // only one fsm can be picked at anytime
  190. return !_lActiveFsm;
  191. }
  192. BackgroundTaskMgr::BackgroundTaskMgr()
  193. : _lActiveFsm(0)
  194. {
  195. }
  196. void
  197. BackgroundTaskMgr::NotifyFsmDone()
  198. {
  199. InterlockedDecrement(&_lActiveFsm);
  200. }
  201. DWORD
  202. CFsm_BackgroundTask::RunSM(
  203. IN CFsm * Fsm
  204. )
  205. {
  206. DEBUG_ENTER((DBG_ASYNC,
  207. Dword,
  208. "CFsm_BackgroundTask::RunSM",
  209. "%#x",
  210. Fsm
  211. ));
  212. CFsm_BackgroundTask* fsm = (CFsm_BackgroundTask*) Fsm;
  213. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  214. BOOL fIsAsyncWorkerThread = TRUE;
  215. if( lpThreadInfo )
  216. {
  217. fIsAsyncWorkerThread = lpThreadInfo->IsAsyncWorkerThread;
  218. lpThreadInfo->IsAsyncWorkerThread = FALSE;
  219. }
  220. switch( fsm->GetState() ) {
  221. case FSM_STATE_INIT:
  222. case FSM_STATE_CONTINUE:
  223. fsm->DoSendReq();
  224. default:
  225. break;
  226. }
  227. fsm->SetDone(0);
  228. if( lpThreadInfo )
  229. {
  230. lpThreadInfo->IsAsyncWorkerThread = fIsAsyncWorkerThread;
  231. }
  232. DEBUG_LEAVE(0);
  233. return 0;
  234. }
  235. typedef HRESULT (WINAPI * pfnObtainUA)(DWORD, LPSTR, DWORD*);
  236. DWORD
  237. CFsm_BackgroundTask::DoSendReq()
  238. {
  239. HINTERNET hInternet = NULL;
  240. HINTERNET hRequest = NULL;
  241. CHAR szBuffer[4000];
  242. DWORD dwBytesRead;
  243. BOOL fSuccess;
  244. DWORD error = ERROR_INTERNET_INTERNAL_ERROR;
  245. BOOL fUAFromUrlmon = FALSE;
  246. CHAR* pszUA = NULL;
  247. HINSTANCE hinst = GetModuleHandle(URLMON_DLL);
  248. if( hinst )
  249. {
  250. pfnObtainUA pfnUA = (pfnObtainUA)
  251. GetProcAddress(hinst, "ObtainUserAgentString");
  252. if( pfnUA )
  253. {
  254. DWORD dwSize = MAX_PATH;
  255. pszUA = new CHAR[dwSize];
  256. if( pszUA )
  257. {
  258. HRESULT hr = (*pfnUA)(0, pszUA, &dwSize);
  259. if( S_OK == hr )
  260. {
  261. fUAFromUrlmon = TRUE;
  262. }
  263. else if( E_OUTOFMEMORY == hr )
  264. {
  265. // the original pszUA is allocated too small
  266. // we need bigger buffer size (returned by dwSize)
  267. delete [] pszUA;
  268. pszUA = new CHAR[dwSize];
  269. if( pszUA )
  270. {
  271. hr = (*pfnUA)(0, pszUA, &dwSize);
  272. if( S_OK == hr )
  273. {
  274. fUAFromUrlmon = TRUE;
  275. }
  276. }
  277. } // original buffer too small, create bigger one
  278. }
  279. } // get the pFN to UA agent
  280. } // urlmon is loaded
  281. if( fUAFromUrlmon && pszUA)
  282. {
  283. hInternet = InternetOpen(
  284. pszUA,
  285. INTERNET_OPEN_TYPE_PRECONFIG,
  286. NULL,
  287. NULL,
  288. 0 );
  289. }
  290. else
  291. {
  292. hInternet = InternetOpen(
  293. gszDefaultUserAgent,
  294. INTERNET_OPEN_TYPE_PRECONFIG,
  295. NULL,
  296. NULL,
  297. 0 );
  298. }
  299. if( !hInternet )
  300. {
  301. goto quit;
  302. }
  303. hRequest = InternetOpenUrl(
  304. hInternet,
  305. m_lpszUrl,
  306. "Accept: */*\r\n",
  307. (DWORD) -1,
  308. INTERNET_FLAG_RESYNCHRONIZE | INTERNET_FLAG_BGUPDATE | INTERNET_FLAG_KEEP_CONNECTION,
  309. INTERNET_NO_CALLBACK
  310. );
  311. if( !hRequest )
  312. {
  313. DWORD dwLastErr = 0;
  314. dwLastErr = GetLastError();
  315. goto quit;
  316. }
  317. do {
  318. dwBytesRead = 0;
  319. fSuccess = InternetReadFile(
  320. hRequest,
  321. szBuffer,
  322. sizeof(szBuffer)-1,
  323. &dwBytesRead
  324. );
  325. if( !fSuccess )
  326. {
  327. goto quit;
  328. }
  329. } while ( dwBytesRead != 0 );
  330. error = ERROR_SUCCESS;
  331. quit:
  332. if( hRequest )
  333. InternetCloseHandle(hRequest);
  334. if( hInternet )
  335. InternetCloseHandle(hInternet);
  336. if( fUAFromUrlmon && pszUA )
  337. delete [] pszUA;
  338. return error;
  339. }
  340. CFsm_BackgroundTask::~CFsm_BackgroundTask()
  341. {
  342. DELETE_MANDATORY_PARAM(m_lpszUrl);
  343. m_pMgr->NotifyFsmDone();
  344. }