Source code of Windows XP (NT5)
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.

1048 lines
23 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. wprecycler.cxx
  5. Abstract:
  6. Implementation of WP_RECYCLER. Object handles worker process recycling
  7. - Memory based recycling
  8. - Schedule based recycling
  9. - Elapsed Time based recycling
  10. - Processed Request Count based recycling
  11. Dependencies:
  12. g_pwpContext is used by WP_RECYCLER to be able to send messages
  13. Author:
  14. Jaroslav Dunajsky (JaroslaD) 07-Dec-2000
  15. Environment:
  16. Win32 - User Mode
  17. Project:
  18. W3DT.DLL
  19. --*/
  20. #include "precomp.hxx"
  21. #include "wprecycler.hxx"
  22. #define ONE_DAY_IN_MILLISECONDS (1000 * 60 * 60 * 24)
  23. //
  24. // Static variables
  25. //
  26. CRITICAL_SECTION WP_RECYCLER::sm_CritSec;
  27. //
  28. // Static variables for Memory based recycling
  29. //
  30. HANDLE WP_RECYCLER::sm_hTimerForMemoryBased = NULL;
  31. BOOL WP_RECYCLER::sm_fIsStartedMemoryBased = FALSE;
  32. SIZE_T WP_RECYCLER::sm_MaxValueForMemoryBased = 0;
  33. HANDLE WP_RECYCLER::sm_hCurrentProcess = NULL;
  34. //
  35. // Static variables for Time based recycling
  36. //
  37. HANDLE WP_RECYCLER::sm_hTimerForTimeBased = NULL;
  38. BOOL WP_RECYCLER::sm_fIsStartedTimeBased = FALSE;
  39. //
  40. // Static variables for Schedule based recycling
  41. //
  42. HANDLE WP_RECYCLER::sm_hTimerQueueForScheduleBased = NULL;
  43. BOOL WP_RECYCLER::sm_fIsStartedScheduleBased = FALSE;
  44. //
  45. // Static variables for Request based recycling
  46. //
  47. BOOL WP_RECYCLER::sm_fIsStartedRequestBased = FALSE;
  48. DWORD WP_RECYCLER::sm_dwMaxValueForRequestBased = 0;
  49. LONG WP_RECYCLER::sm_RecyclingMsgSent = 0;
  50. BOOL WP_RECYCLER::sm_fCritSecInit = FALSE;
  51. //
  52. // Static methods for Schedule based recycling
  53. //
  54. //static
  55. HRESULT
  56. WP_RECYCLER::StartScheduleBased(
  57. IN const WCHAR * pwszScheduleTimes
  58. )
  59. /*++
  60. Routine Description:
  61. Start schedule based recycling
  62. Arguments:
  63. pwszScheduleTimes - MULTISZ array of time information
  64. <time>\0<time>\0\0
  65. time is of military format hh:mm
  66. (hh>=0 && hh<=23)
  67. (mm>=0 && hh<=59)
  68. Return Value:
  69. HRESULT
  70. --*/
  71. {
  72. HRESULT hr = E_FAIL;
  73. BOOL fRet = FALSE;
  74. const WCHAR * pwszCurrentChar = pwszScheduleTimes;
  75. HANDLE hTimer;
  76. WORD wHours = 0;
  77. WORD wMinutes = 0;
  78. WORD wDigitCount = 0;
  79. SYSTEMTIME SystemTime;
  80. FILETIME FileTime;
  81. FILETIME CurrentFileTime;
  82. ULARGE_INTEGER largeintCurrentTime;
  83. ULARGE_INTEGER largeintTime;
  84. DWORD dwDueTime = 0;
  85. DBG_ASSERT(TRUE == sm_fCritSecInit);
  86. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  87. IF_DEBUG( WPRECYCLER )
  88. {
  89. DBGPRINTF(( DBG_CONTEXT,
  90. "WP_RECYCLER::StartScheduleBased()\n"));
  91. }
  92. DBG_ASSERT( pwszScheduleTimes != NULL );
  93. //
  94. // If scheduler based recycling has been running already
  95. // terminate it before restarting with new settings
  96. //
  97. if ( WP_RECYCLER::sm_fIsStartedScheduleBased )
  98. {
  99. WP_RECYCLER::TerminateScheduleBased();
  100. }
  101. WP_RECYCLER::sm_hTimerQueueForScheduleBased = CreateTimerQueue();
  102. if ( WP_RECYCLER::sm_hTimerQueueForScheduleBased == NULL )
  103. {
  104. hr = HRESULT_FROM_WIN32( GetLastError() );
  105. goto Failed;
  106. }
  107. //
  108. // Gets current time
  109. //
  110. GetLocalTime( &SystemTime );
  111. SystemTimeToFileTime( &SystemTime,
  112. &CurrentFileTime );
  113. memcpy( &largeintCurrentTime,
  114. &CurrentFileTime,
  115. sizeof( ULARGE_INTEGER ) );
  116. //
  117. // empty string in MULTISZ indicates the end of MULTISZ
  118. //
  119. while ( *pwszCurrentChar != '\0' )
  120. {
  121. //
  122. // Skip white spaces
  123. //
  124. while ( iswspace( (wint_t) *pwszCurrentChar ) )
  125. {
  126. pwszCurrentChar++;
  127. }
  128. //
  129. // Start of the time info
  130. // Expect military format hh:mm
  131. //
  132. //
  133. // Process hours (up to 2 digits is valid)
  134. //
  135. wHours = 0;
  136. wDigitCount = 0;
  137. while ( iswdigit( *pwszCurrentChar ) )
  138. {
  139. wDigitCount++;
  140. wHours = 10 * wHours + (*pwszCurrentChar - '0');
  141. pwszCurrentChar++;
  142. }
  143. if ( wDigitCount > 2 ||
  144. ( wHours > 23 ) )
  145. {
  146. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  147. goto Failed;
  148. }
  149. //
  150. // Hours - minutes separator
  151. // Be liberal - any character that is not a digit or '\0' is OK
  152. //
  153. if ( *pwszCurrentChar == '\0' )
  154. {
  155. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  156. goto Failed;
  157. }
  158. pwszCurrentChar++;
  159. //
  160. // Process minutes (must be exactly 2 digits)
  161. //
  162. wMinutes = 0;
  163. wDigitCount = 0;
  164. while ( iswdigit( (wint_t) *pwszCurrentChar ) )
  165. {
  166. wDigitCount++;
  167. wMinutes = 10 * wMinutes + (*pwszCurrentChar - '0');
  168. pwszCurrentChar++;
  169. }
  170. if ( ( wDigitCount != 2 ) ||
  171. ( wMinutes > 59 ) )
  172. {
  173. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  174. goto Failed;
  175. }
  176. //
  177. // Skip white spaces
  178. //
  179. while ( iswspace( (wint_t)*pwszCurrentChar ) )
  180. {
  181. pwszCurrentChar++;
  182. }
  183. //
  184. // Check for terminating zero
  185. //
  186. if ( *pwszCurrentChar != '\0' )
  187. {
  188. //
  189. // Extra characters in the time string
  190. //
  191. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  192. goto Failed;
  193. }
  194. pwszCurrentChar++;
  195. //
  196. // Convert Hours and Minutes info
  197. //
  198. SystemTime.wHour = wHours;
  199. SystemTime.wMinute = wMinutes;
  200. SystemTime.wSecond = 0;
  201. SystemTime.wMilliseconds = 0;
  202. SystemTimeToFileTime( &SystemTime,
  203. &FileTime );
  204. memcpy( &largeintTime,
  205. &FileTime,
  206. sizeof(ULARGE_INTEGER) );
  207. //
  208. // Issue 12/21/2000 jaroslad:
  209. // This method of setting absolute time with CreateTimerQueueTimer
  210. // is bad since instead of setting absolute time the relative time is
  211. // calculated and used for timer.
  212. // This approach fails badly if someone changes machine
  213. // time. Other Api that enables setting abolute time must be used for proper
  214. // implementation
  215. //
  216. // Get Due Time in milliseconds
  217. //
  218. dwDueTime = static_cast<DWORD>(
  219. ( largeintTime.QuadPart - largeintCurrentTime.QuadPart )/ 10000);
  220. if ( largeintTime.QuadPart < largeintCurrentTime.QuadPart)
  221. {
  222. dwDueTime = ONE_DAY_IN_MILLISECONDS - static_cast<DWORD>(
  223. ( largeintCurrentTime.QuadPart - largeintTime.QuadPart )/ 10000);
  224. }
  225. else
  226. {
  227. dwDueTime = static_cast<DWORD>(
  228. ( largeintTime.QuadPart - largeintCurrentTime.QuadPart )/ 10000);
  229. }
  230. if ( dwDueTime == 0 )
  231. {
  232. //
  233. // this event is to be scheduled for the next day
  234. // one day has 1000 * 60 * 60 * 24 of (100-nanosecond intervals)
  235. //
  236. dwDueTime += ONE_DAY_IN_MILLISECONDS;
  237. }
  238. //
  239. // Schedule event for specified time, repeating once a day
  240. //
  241. IF_DEBUG( WPRECYCLER )
  242. {
  243. DBGPRINTF(( DBG_CONTEXT,
  244. "Schedule recycling for %d:%d (in %d milliseconds)\n",
  245. (int) wHours,
  246. (int) wMinutes,
  247. dwDueTime));
  248. }
  249. fRet = CreateTimerQueueTimer(
  250. &hTimer,
  251. WP_RECYCLER::sm_hTimerQueueForScheduleBased,
  252. WP_RECYCLER::TimerCallbackForScheduleBased,
  253. NULL,
  254. dwDueTime,
  255. // repeat daily (interval in milliseconds)
  256. ONE_DAY_IN_MILLISECONDS,
  257. WT_EXECUTELONGFUNCTION );
  258. if ( !fRet )
  259. {
  260. hr = HRESULT_FROM_WIN32( GetLastError() );
  261. goto Failed;
  262. }
  263. //
  264. // hTimer will not be stored
  265. // sm_hTimerQueueForScheduleBased is going to be used for cleanup
  266. // DeleteTimerQueueEx() should be able to correctly delete all timers
  267. // in the queue
  268. //
  269. }
  270. WP_RECYCLER::sm_fIsStartedScheduleBased = TRUE;
  271. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  272. return S_OK;
  273. Failed:
  274. WP_RECYCLER::TerminateScheduleBased();
  275. DBG_ASSERT( FAILED( hr ) );
  276. IF_DEBUG( WPRECYCLER )
  277. {
  278. DBGPRINTF(( DBG_CONTEXT,
  279. "WP_RECYCLER::StartScheduleBased() failed with error hr=0x%x\n",
  280. hr ));
  281. }
  282. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  283. return hr;
  284. }
  285. //static
  286. VOID
  287. WP_RECYCLER::TerminateScheduleBased(
  288. VOID
  289. )
  290. /*++
  291. Routine Description:
  292. Stops schedule based recycling
  293. Performs cleanup
  294. Note:
  295. It is safe to call this method for cleanup if Start failed
  296. Arguments:
  297. NONE
  298. Return Value:
  299. VOID
  300. --*/
  301. {
  302. HRESULT hr = E_FAIL;
  303. DBG_ASSERT(TRUE == sm_fCritSecInit);
  304. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  305. if( WP_RECYCLER::sm_hTimerQueueForScheduleBased != NULL )
  306. {
  307. if ( !DeleteTimerQueueEx(
  308. WP_RECYCLER::sm_hTimerQueueForScheduleBased,
  309. INVALID_HANDLE_VALUE /* wait for callbacks to complete */
  310. ) )
  311. {
  312. DBGPRINTF(( DBG_CONTEXT,
  313. "failed to call DeleteTimerQueueEx(): hr=0x%x\n",
  314. HRESULT_FROM_WIN32(GetLastError()) ));
  315. }
  316. WP_RECYCLER::sm_hTimerQueueForScheduleBased = NULL;
  317. }
  318. WP_RECYCLER::sm_fIsStartedScheduleBased = FALSE;
  319. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  320. return;
  321. }
  322. //static
  323. VOID
  324. WINAPI
  325. WP_RECYCLER::TimerCallbackForScheduleBased(
  326. PVOID pParam,
  327. BOOLEAN TimerOrWaitFired
  328. )
  329. /*++
  330. Routine Description:
  331. Timer callback for Schedule based recycling
  332. It is passed to CreateTimerQueueTimer()
  333. Routine will inform WAS that process is ready to be recycled
  334. because scheduled time has been reached
  335. Arguments:
  336. see the description of WAITORTIMERCALLBACK type in MSDN
  337. Return Value:
  338. none
  339. --*/
  340. {
  341. DBG_ASSERT( WP_RECYCLER::sm_fIsStartedScheduleBased );
  342. IF_DEBUG( WPRECYCLER )
  343. {
  344. DBGPRINTF(( DBG_CONTEXT,
  345. "WP_RECYCLER::TimerCallbackForScheduleBased()"
  346. " - tell WAS to recycle\n" ));
  347. }
  348. //
  349. // Indicate to WAS that we are ready for recycling
  350. //
  351. WP_RECYCLER::SendRecyclingMsg( IPM_WP_RESTART_SCHEDULED_TIME_REACHED );
  352. }
  353. //
  354. // Static methods for Memory based recycling
  355. //
  356. //static
  357. HRESULT
  358. WP_RECYCLER::StartMemoryBased(
  359. IN DWORD dwMaxVirtualMemoryUsageInKB
  360. )
  361. /*++
  362. Routine Description:
  363. Start virtual memory usage based recycling.
  364. Arguments:
  365. dwMaxVirtualMemoryUsageInKB - If usage of virtual memory reaches this value
  366. worker process is ready for recycling
  367. Note:
  368. VM usage will be checked periodically. See the value of internal constant
  369. CHECK_MEMORY_TIME_PERIOD
  370. Return Value:
  371. HRESULT
  372. --*/
  373. {
  374. HRESULT hr = E_FAIL;
  375. BOOL fRet = FALSE;
  376. DBG_ASSERT(TRUE == sm_fCritSecInit);
  377. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  378. IF_DEBUG( WPRECYCLER )
  379. {
  380. DBGPRINTF(( DBG_CONTEXT,
  381. "WP_RECYCLER::StartMemoryBased(%d kB)\n",
  382. dwMaxVirtualMemoryUsageInKB ));
  383. }
  384. //
  385. // If time based recycling has been running already
  386. // terminate it before restarting with new settings
  387. //
  388. if ( WP_RECYCLER::sm_fIsStartedMemoryBased == TRUE )
  389. {
  390. WP_RECYCLER::TerminateMemoryBased();
  391. }
  392. if ( dwMaxVirtualMemoryUsageInKB == 0 )
  393. {
  394. //
  395. // 0 means not to run memory recycling
  396. //
  397. hr = S_OK;
  398. goto succeeded;
  399. }
  400. fRet = CreateTimerQueueTimer( &WP_RECYCLER::sm_hTimerForMemoryBased,
  401. NULL,
  402. WP_RECYCLER::TimerCallbackForMemoryBased,
  403. NULL,
  404. CHECK_MEMORY_TIME_PERIOD,
  405. CHECK_MEMORY_TIME_PERIOD,
  406. WT_EXECUTELONGFUNCTION );
  407. if ( !fRet )
  408. {
  409. WP_RECYCLER::sm_hTimerForMemoryBased = NULL;
  410. hr = HRESULT_FROM_WIN32( GetLastError() );
  411. goto failed;
  412. }
  413. //
  414. // Get current process handle
  415. // It will be used for NtQueryInformationProcess()
  416. // in the timer callback
  417. // there is no error to check for and handle doesn't need to be closed
  418. // on cleanup
  419. //
  420. sm_hCurrentProcess = GetCurrentProcess();
  421. sm_MaxValueForMemoryBased = 1024 * dwMaxVirtualMemoryUsageInKB;
  422. WP_RECYCLER::sm_fIsStartedMemoryBased = TRUE;
  423. succeeded:
  424. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  425. return S_OK;
  426. failed:
  427. DBG_ASSERT( FAILED( hr ) );
  428. WP_RECYCLER::TerminateMemoryBased();
  429. IF_DEBUG( WPRECYCLER )
  430. {
  431. DBGPRINTF(( DBG_CONTEXT,
  432. "WP_RECYCLER::StartMemoryBased() failed with error hr=0x%x\n",
  433. hr ));
  434. }
  435. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  436. return hr;
  437. }
  438. //static
  439. VOID
  440. WP_RECYCLER::TerminateMemoryBased(
  441. VOID
  442. )
  443. /*++
  444. Routine Description:
  445. Stops virtual memory usage based recycling
  446. Performs cleanup
  447. Note:
  448. It is safe to call this method for cleanup if Start failed
  449. Arguments:
  450. NONE
  451. Return Value:
  452. VOID
  453. --*/
  454. {
  455. HRESULT hr = E_FAIL;
  456. DBG_ASSERT(TRUE == sm_fCritSecInit);
  457. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  458. if ( WP_RECYCLER::sm_hTimerForMemoryBased != NULL )
  459. {
  460. if ( !DeleteTimerQueueTimer(
  461. NULL,
  462. WP_RECYCLER::sm_hTimerForMemoryBased,
  463. INVALID_HANDLE_VALUE /* wait for callbacks to complete */
  464. ) )
  465. {
  466. DBGPRINTF(( DBG_CONTEXT,
  467. "failed to call DeleteTimerQueueTimer(): hr=0x%x\n",
  468. HRESULT_FROM_WIN32(GetLastError()) ));
  469. }
  470. WP_RECYCLER::sm_hTimerForMemoryBased = NULL;
  471. }
  472. WP_RECYCLER::sm_fIsStartedMemoryBased = FALSE;
  473. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  474. return;
  475. }
  476. //static
  477. VOID
  478. WINAPI
  479. WP_RECYCLER::TimerCallbackForMemoryBased(
  480. PVOID pParam,
  481. BOOLEAN TimerOrWaitFired
  482. )
  483. /*++
  484. Routine Description:
  485. Timer callback for Elapsed time based recycling
  486. This Callback is passed to CreateTimerQueueTimer()
  487. Virtual memory usage will be checked and if limit has been reached
  488. then routine will inform WAS that process is ready to be recycled
  489. Arguments:
  490. see description of WAITORTIMERCALLBACK type in MSDN
  491. Return Value:
  492. none
  493. --*/
  494. {
  495. NTSTATUS Status = 0;
  496. VM_COUNTERS VmCounters;
  497. DBG_ASSERT( WP_RECYCLER::sm_fIsStartedMemoryBased );
  498. Status = NtQueryInformationProcess( sm_hCurrentProcess,
  499. ProcessVmCounters,
  500. &VmCounters,
  501. sizeof(VM_COUNTERS),
  502. NULL );
  503. if ( ! NT_SUCCESS ( Status ) )
  504. {
  505. IF_DEBUG( WPRECYCLER )
  506. {
  507. DBGPRINTF(( DBG_CONTEXT,
  508. "NtQueryInformationProcess failed with Status: %d\n",
  509. Status ));
  510. }
  511. return;
  512. }
  513. if ( VmCounters.VirtualSize >= sm_MaxValueForMemoryBased )
  514. {
  515. IF_DEBUG( WPRECYCLER )
  516. {
  517. DBGPRINTF(( DBG_CONTEXT,
  518. "WP_RECYCLER::TimerCallbackForMemoryBased()"
  519. " - current VM:%ld kB, configured max VM:%ld kB"
  520. " - tell WAS to recycle\n",
  521. VmCounters.VirtualSize/1024 ,
  522. sm_MaxValueForMemoryBased/1024 ));
  523. }
  524. //
  525. // we reached Virtual Memory Usage limit
  526. //
  527. WP_RECYCLER::SendRecyclingMsg( IPM_WP_RESTART_MEMORY_LIMIT_REACHED );
  528. }
  529. }
  530. //
  531. // Static methods for Time based recycling
  532. //
  533. //static
  534. HRESULT
  535. WP_RECYCLER::StartTimeBased(
  536. IN DWORD dwPeriodicRestartTimeInMinutes
  537. )
  538. /*++
  539. Routine Description:
  540. Start elapsed time based recycling
  541. Arguments:
  542. dwPeriodicRestartTimeInMinutes - how often to restart (in minutes)
  543. Return Value:
  544. HRESULT
  545. --*/
  546. {
  547. HRESULT hr = E_FAIL;
  548. BOOL fRet = FALSE;
  549. DBG_ASSERT(TRUE == sm_fCritSecInit);
  550. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  551. IF_DEBUG( WPRECYCLER )
  552. {
  553. DBGPRINTF(( DBG_CONTEXT,
  554. "WP_RECYCLER::StartTimeBased(%d min)\n" ,
  555. dwPeriodicRestartTimeInMinutes ));
  556. }
  557. //
  558. // If time based recycling has been running already
  559. // terminate it before restarting with new settings
  560. //
  561. if ( WP_RECYCLER::sm_fIsStartedTimeBased == TRUE )
  562. {
  563. WP_RECYCLER::TerminateTimeBased();
  564. }
  565. if ( dwPeriodicRestartTimeInMinutes == 0 )
  566. {
  567. //
  568. // 0 means not to run time based recycling
  569. //
  570. hr = S_OK;
  571. goto succeeded;
  572. }
  573. fRet = CreateTimerQueueTimer( &WP_RECYCLER::sm_hTimerForTimeBased,
  574. NULL,
  575. WP_RECYCLER::TimerCallbackForTimeBased,
  576. NULL,
  577. dwPeriodicRestartTimeInMinutes * 60000,
  578. // convert to msec
  579. dwPeriodicRestartTimeInMinutes * 60000,
  580. // convert to msec
  581. WT_EXECUTELONGFUNCTION );
  582. if ( !fRet )
  583. {
  584. WP_RECYCLER::sm_hTimerForTimeBased = NULL;
  585. hr = HRESULT_FROM_WIN32( GetLastError() );
  586. goto failed;
  587. }
  588. WP_RECYCLER::sm_fIsStartedTimeBased = TRUE;
  589. succeeded:
  590. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  591. return S_OK;
  592. failed:
  593. DBG_ASSERT( FAILED( hr ) );
  594. WP_RECYCLER::TerminateTimeBased();
  595. IF_DEBUG( WPRECYCLER )
  596. {
  597. DBGPRINTF(( DBG_CONTEXT,
  598. "WP_RECYCLER::StartTimeBased() failed with error hr=0x%x\n",
  599. hr));
  600. }
  601. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  602. return hr;
  603. }
  604. //static
  605. VOID
  606. WP_RECYCLER::TerminateTimeBased(
  607. VOID
  608. )
  609. /*++
  610. Routine Description:
  611. Stops elapsed time based recycling
  612. Performs cleanup
  613. Note:
  614. It is safe to call this method for cleanup if Start failed
  615. Arguments:
  616. NONE
  617. Return Value:
  618. HRESULT
  619. --*/
  620. {
  621. HRESULT hr = E_FAIL;
  622. DBG_ASSERT(TRUE == sm_fCritSecInit);
  623. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  624. if ( WP_RECYCLER::sm_hTimerForTimeBased != NULL )
  625. {
  626. if ( !DeleteTimerQueueTimer(
  627. NULL,
  628. WP_RECYCLER::sm_hTimerForTimeBased,
  629. INVALID_HANDLE_VALUE /* wait for callbacks to complete */
  630. ) )
  631. {
  632. DBGPRINTF(( DBG_CONTEXT,
  633. "failed to call DeleteTimerQueueTimer(): hr=0x%x\n",
  634. HRESULT_FROM_WIN32(GetLastError()) ));
  635. }
  636. WP_RECYCLER::sm_hTimerForTimeBased = NULL;
  637. }
  638. WP_RECYCLER::sm_fIsStartedTimeBased = FALSE;
  639. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  640. return;
  641. }
  642. //static
  643. VOID
  644. WINAPI
  645. WP_RECYCLER::TimerCallbackForTimeBased(
  646. PVOID pParam,
  647. BOOLEAN TimerOrWaitFired
  648. )
  649. /*++
  650. Routine Description:
  651. Timer callback for Elapsed time based recycling
  652. This Callback is passed to CreateTimerQueueTimer()
  653. Routine will inform WAS that process is ready to be recycled
  654. because required elapsed time has been reached
  655. Arguments:
  656. see description of WAITORTIMERCALLBACK type in MSDN
  657. Return Value:
  658. none
  659. --*/
  660. {
  661. DBG_ASSERT( WP_RECYCLER::sm_fIsStartedTimeBased );
  662. IF_DEBUG( WPRECYCLER )
  663. {
  664. DBGPRINTF(( DBG_CONTEXT,
  665. "WP_RECYCLER::TimerCallbackForTimeBased"
  666. " - tell WAS to recycle\n" ));
  667. }
  668. WP_RECYCLER::SendRecyclingMsg( IPM_WP_RESTART_ELAPSED_TIME_REACHED );
  669. }
  670. //
  671. // Static methods for Request based recycling
  672. //
  673. //static
  674. HRESULT
  675. WP_RECYCLER::StartRequestBased(
  676. IN DWORD dwRequests
  677. )
  678. /*++
  679. Routine Description:
  680. Start request based recycling.
  681. Arguments:
  682. dwRequests - If number of requests processed by worker process reaches this value
  683. recycling will be required
  684. Return Value:
  685. HRESULT
  686. --*/
  687. {
  688. HRESULT hr = E_FAIL;
  689. DBG_ASSERT(TRUE == sm_fCritSecInit);
  690. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  691. IF_DEBUG( WPRECYCLER )
  692. {
  693. DBGPRINTF(( DBG_CONTEXT,
  694. "WP_RECYCLER::StartRequestBased(%d kB)\n" ,
  695. dwRequests ));
  696. }
  697. //
  698. // If time based recycling has been running already
  699. // terminate it before restarting with new settings
  700. //
  701. if ( WP_RECYCLER::sm_fIsStartedRequestBased == TRUE )
  702. {
  703. WP_RECYCLER::TerminateRequestBased();
  704. }
  705. if ( dwRequests == 0 )
  706. {
  707. //
  708. // 0 means not to run request based recycling
  709. //
  710. hr = S_OK;
  711. goto succeeded;
  712. }
  713. InterlockedExchange(
  714. reinterpret_cast<LONG *>(&sm_dwMaxValueForRequestBased),
  715. dwRequests );
  716. InterlockedExchange(
  717. reinterpret_cast<LONG *>(&WP_RECYCLER::sm_fIsStartedTimeBased),
  718. TRUE );
  719. hr = S_OK;
  720. succeeded:
  721. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  722. return hr;
  723. }
  724. //static
  725. VOID
  726. WP_RECYCLER::TerminateRequestBased(
  727. VOID
  728. )
  729. /*++
  730. Routine Description:
  731. Stops request based recycling
  732. Performs cleanup
  733. Note:
  734. It is safe to call this method for cleanup if Start failed
  735. Arguments:
  736. NONE
  737. Return Value:
  738. HRESULT
  739. --*/
  740. {
  741. DBG_ASSERT(TRUE == sm_fCritSecInit);
  742. EnterCriticalSection( &WP_RECYCLER::sm_CritSec );
  743. //
  744. // InterlockedExchange is used because Request Based recycling callback
  745. // IsRequestCountLimitReached() is called for each request
  746. // and we don't synchronize it with &WP_RECYCLER::sm_CritSec
  747. //
  748. InterlockedExchange(
  749. reinterpret_cast<LONG *>(&WP_RECYCLER::sm_fIsStartedTimeBased),
  750. FALSE );
  751. LeaveCriticalSection( &WP_RECYCLER::sm_CritSec );
  752. return;
  753. }