scavenge.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 16k
Category:

Windows Develop

Development Platform:

Visual C++

  1. //+---------------------------------------------------------------------------
  2. //
  3. //  Microsoft Windows
  4. //  Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. //  File:       scavenge.c
  7. //
  8. //  Contents:   Home of the scavenger thread
  9. //
  10. //  Classes:
  11. //
  12. //  Functions:
  13. //
  14. //  History:    7-28-97   RichardW   Stolen from lsa
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "winlogon.h"
  18. HANDLE                  hReadScavConfig = NULL;     // Signals to restart wait
  19. HANDLE                  hStateChangeEvent = NULL ;  // Big change
  20. HANDLE                  ScavWaitHandles[MAXIMUM_WAIT_OBJECTS];
  21. ULONG                   cScavWaitHandles;
  22. LIST_ENTRY              TimerList ;
  23. LIST_ENTRY              WaitList[ MAXIMUM_WAIT_OBJECTS ];
  24. RTL_CRITICAL_SECTION    ScavLock ;
  25. typedef enum _WL_SCAV_INSERT {
  26.     ScavInsertHead,
  27.     ScavInsertTail,
  28.     ScavInsertSorted
  29. } WL_SCAV_INSERT ;
  30. #define SCAVENGER_WAIT_INTERVAL 60000L
  31. //
  32. // Internal flags:
  33. //
  34. #define SCAVFLAG_IN_PROGRESS    0x40000000  // Active
  35. #define SCAVFLAG_ABOUT_TO_DIE   0x20000000  // About to be removed
  36. #define SCAVFLAG_IMMEDIATE      0x08000000  // Immediate Execute
  37. #define SCAVFLAG_STATE_CHANGE   0x04000000  // State Change
  38. #define SCAVFLAG_TRIGGER_FREE   0x02000000  // Trigger will free
  39. #define SCAVFLAG_NOTIFY_EVENT   0x01000000
  40. #define SCAVFLAG_EXECUTE_INLINE 0x00800000  // Execute stub directly
  41. #define NOTIFYFLAG_CHILD_SYNC   0x80000000  // All sub funcs are synchronous
  42. #define NOTIFYFLAG_BLOCK_CALLS  0x40000000  // Block calls
  43. #define NOTIFY_FLAG_SYNCHRONOUS 0x00000001
  44. #if DBG
  45. #define SCAVFLAG_ITEM_BREAK     0x10000000
  46. #endif
  47. //
  48. // Define indices for well known events.  Shutdown is triggered when
  49. // the console handler starts a shutdown.  config is when someone adds
  50. // another notifier.  state is when the state of the machine has changed.
  51. //
  52. #define SCAVENGER_SHUTDOWN_EVENT    0
  53. #define SCAVENGER_CONFIG_EVENT      1
  54. #define SCAVENGER_NOTIFY_EVENT      2
  55. #define LockScavenger() RtlEnterCriticalSection( &ScavLock )
  56. #define UnlockScavenger() RtlLeaveCriticalSection( &ScavLock )
  57. #define LockNotify()    RtlEnterCriticalSection( &NotifyLock )
  58. #define UnlockNotify()  RtlLeaveCriticalSection( &NotifyLock )
  59. //
  60. // Define locking macros for the scav list
  61. //
  62. #define WlpRefScavItem( Item )     
  63.         {                           
  64.             RtlEnterCriticalSection( &ScavLock ); 
  65.             ((PWL_SCAVENGER_ITEM) Item)->RefCount++ ; 
  66.             RtlLeaveCriticalSection( &ScavLock ); 
  67.         }
  68. #define WlpRefScavItemUnsafe( Item )    
  69.         {                               
  70.             ((PWL_SCAVENGER_ITEM) Item)->RefCount++ ; 
  71.         }
  72. DWORD
  73. WINAPI
  74. WlpScavengerThread(
  75.     PVOID   Ignored
  76.     );
  77. //+---------------------------------------------------------------------------
  78. //
  79. //  Function:   WlpDerefScavItem
  80. //
  81. //  Synopsis:   Dereference, optionally freeing a scavenger item
  82. //
  83. //  Arguments:  [Item] --
  84. //
  85. //  History:    6-03-97   RichardW   Created
  86. //
  87. //  Notes:
  88. //
  89. //----------------------------------------------------------------------------
  90. VOID
  91. WlpDerefScavItem(
  92.     PWL_SCAVENGER_ITEM Item
  93.     )
  94. {
  95.     LockScavenger();
  96.     Item->RefCount-- ;
  97.     if ( Item->RefCount == 0 )
  98.     {
  99.         if ( Item->List.Flink )
  100.         {
  101.             RemoveEntryList( &Item->List );
  102.             Item->List.Flink = NULL ;
  103.         }
  104.         //
  105.         // Remove the handle from the wait list:
  106.         //
  107.         if ( Item->Type == NOTIFIER_TYPE_HANDLE_WAIT )
  108.         {
  109.             if ( IsListEmpty( &WaitList[ Item->HandleIndex ] ) )
  110.             {
  111.                 //
  112.                 // Big swap action now:
  113.                 //
  114.                 cScavWaitHandles --;
  115.                 if ( Item->HandleIndex == cScavWaitHandles )
  116.                 {
  117.                     //
  118.                     // Easy case:  lower the count
  119.                     //
  120.                     NOTHING ;
  121.                 }
  122.                 else
  123.                 {
  124.                     WaitList[ Item->HandleIndex ] = WaitList[ cScavWaitHandles ];
  125.                     ScavWaitHandles[ Item->HandleIndex ] = ScavWaitHandles[ cScavWaitHandles ] ;
  126.                 }
  127.                 SetEvent( hReadScavConfig );
  128.             }
  129.         }
  130.         LocalFree( Item );
  131.     }
  132.     UnlockScavenger();
  133. }
  134. //+---------------------------------------------------------------------------
  135. //
  136. //  Function:   WlpScavengerTrigger
  137. //
  138. //  Synopsis:   Actual Trigger
  139. //
  140. //  Arguments:  [Parameter] -- Item to call
  141. //
  142. //  History:    5-24-97   RichardW   Created
  143. //
  144. //  Notes:
  145. //
  146. //----------------------------------------------------------------------------
  147. ULONG
  148. WlpScavengerTrigger(
  149.     PVOID   Parameter
  150.     )
  151. {
  152.     PWL_SCAVENGER_ITEM Item ;
  153.     Item = (PWL_SCAVENGER_ITEM) Parameter ;
  154.     __try
  155.     {
  156.         (VOID) Item->Function( Item->Parameter );
  157.     }
  158.     __except( 1 )
  159.     {
  160.         NOTHING ;
  161.     }
  162.     WlpDerefScavItem( Item );
  163.     return 0 ;
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. //  Function:   WlpTriggerScavengerItem
  168. //
  169. //  Synopsis:   Executes, either in line, or on another thread, the
  170. //              Item passed in.
  171. //
  172. //  Arguments:  [Item] -- Item to execute
  173. //
  174. //  History:    5-24-97   RichardW   Created
  175. //
  176. //  Notes:
  177. //
  178. //----------------------------------------------------------------------------
  179. VOID
  180. WlpTriggerScavengerItem(
  181.     PWL_SCAVENGER_ITEM    Item,
  182.     BOOL Ref
  183.     )
  184. {
  185.     HANDLE Thread ;
  186.     DWORD tid ;
  187.     if ( Ref )
  188.     {
  189.         WlpRefScavItem( Item );
  190.     }
  191.     if ( Item->Flags & NOTIFIER_FLAG_NEW_THREAD )
  192.     {
  193.         Thread = CreateThread( 0, 0,
  194.                       WlpScavengerTrigger, Item,
  195.                       0, &tid );
  196.         if ( Thread )
  197.         {
  198.             CloseHandle( Thread );
  199.         }
  200.     }
  201.     else
  202.     {
  203.         WlpScavengerTrigger( Item );
  204.     }
  205. }
  206. DWORD
  207. WINAPI
  208. WlpScavengerHandleChange(
  209.     PVOID Ignored
  210.     )
  211. {
  212.     return 0 ;
  213. }
  214. //+---------------------------------------------------------------------------
  215. //
  216. //  Function:   WlpInsertScavengerItem
  217. //
  218. //  Synopsis:   Insert a scavenger item into the designated list,
  219. //              by one of the methods described.
  220. //
  221. //  Arguments:  [List]       -- Insert List
  222. //              [Item]       -- Item
  223. //              [InsertType] -- Method
  224. //
  225. //  History:    5-23-97   RichardW   Created
  226. //
  227. //  Notes:
  228. //
  229. //----------------------------------------------------------------------------
  230. VOID
  231. WlpInsertScavengerItem(
  232.     PLIST_ENTRY List,
  233.     PWL_SCAVENGER_ITEM Item,
  234.     WL_SCAV_INSERT InsertType
  235.     )
  236. {
  237.     PLIST_ENTRY Scan ;
  238.     PWL_SCAVENGER_ITEM Compare ;
  239.     if (Item->Type == NOTIFIER_TYPE_INTERVAL)
  240.     {
  241.         Item->NextTrigger = GetCurrentTime() + (Item->Interval * 1000);
  242.     }
  243.     else
  244.     {
  245.         Item->NextTrigger = INFINITE;
  246.     }
  247.     LockScavenger();
  248.     switch ( InsertType )
  249.     {
  250.         case ScavInsertHead:
  251.             InsertHeadList( List, &Item->List );
  252.             break;
  253.         case ScavInsertTail:
  254.             InsertTailList( List, &Item->List );
  255.             break;
  256.         case ScavInsertSorted:
  257.             Scan = List->Flink ;
  258.             while ( Scan != List )
  259.             {
  260.                 Compare = CONTAINING_RECORD( Scan, WL_SCAVENGER_ITEM, List );
  261.                 if ( Compare->NextTrigger > Item->NextTrigger )
  262.                 {
  263.                     break;
  264.                 }
  265.                 Scan = Scan->Flink ;
  266.             }
  267.             InsertHeadList( Scan, &Item->List );
  268.             break;
  269.     }
  270.     UnlockScavenger();
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. //  Function:   WlRegisterNotification
  275. //
  276. //  Synopsis:   Create a scavenger entry linked to the common scavenger
  277. //              thread.
  278. //
  279. //  Effects:    Will restart the wait
  280. //
  281. //  Arguments:  [pFunction]   --    Function to call
  282. //              [pvParameter] --    Parameter to pass function
  283. //              [Type]        --    Type of scavenger function
  284. //              [fItem]       --    Flags
  285. //              [Interval]    --    Interval at which to call fn, in minutes
  286. //              [hEvent]      --    Handle of event to wait on
  287. //
  288. //  History:    6-03-97   RichardW   Created
  289. //
  290. //  Notes:
  291. //
  292. //----------------------------------------------------------------------------
  293. PVOID
  294. NTAPI
  295. WlRegisterNotification(
  296.     IN LPTHREAD_START_ROUTINE pFunction,
  297.     IN PVOID pvParameter,
  298.     IN ULONG Type,
  299.     IN ULONG fItem,
  300.     IN ULONG Interval,
  301.     IN HANDLE hEvent)
  302. {
  303.     PWL_SCAVENGER_ITEM Item ;
  304.     PLIST_ENTRY List ;
  305.     WL_SCAV_INSERT InsertPos ;
  306.     Item = (PWL_SCAVENGER_ITEM) LocalAlloc( LMEM_FIXED,
  307.                                     sizeof( WL_SCAVENGER_ITEM ) );
  308.     if ( !Item )
  309.     {
  310.         return NULL ;
  311.     }
  312.     Item->List.Flink = NULL ;
  313.     Item->Type = Type ;
  314.     Item->Function = pFunction ;
  315.     Item->Parameter = pvParameter ;
  316.     Item->RefCount = 1 ;
  317.     Item->ScavCheck = SCAVMAGIC_ACTIVE;
  318.     switch ( Type )
  319.     {
  320.         case NOTIFIER_TYPE_IMMEDIATE:
  321.             Item->Interval = 0 ;
  322.             fItem |= NOTIFIER_FLAG_ONE_SHOT ;
  323.             List = &TimerList ;
  324.             InsertPos = ScavInsertHead ;
  325.             break;
  326.         case NOTIFIER_TYPE_INTERVAL:
  327.             Item->Interval = Interval ;
  328.             List = &TimerList ;
  329.             InsertPos = ScavInsertSorted ;
  330.             break;
  331.         case NOTIFIER_TYPE_HANDLE_WAIT:
  332.             LockScavenger();
  333.             if ( cScavWaitHandles == MAXIMUM_WAIT_OBJECTS )
  334.             {
  335.                 LocalFree( Item );
  336.                 Item = NULL ;
  337.                 break;
  338.             }
  339.             Item->HandleIndex = cScavWaitHandles ;
  340.             List = &WaitList[ cScavWaitHandles ];
  341.             InsertPos = ScavInsertTail ;
  342.             ScavWaitHandles[ cScavWaitHandles ] = hEvent ;
  343.             cScavWaitHandles++ ;
  344.             UnlockScavenger( );
  345.             break;
  346.         default:
  347.             LocalFree( Item );
  348.             Item = NULL ;
  349.             break;
  350.     }
  351.     if ( !Item )
  352.     {
  353.         return NULL ;
  354.     }
  355.     //
  356.     // Okay, we have set up the item, more or less.  Now, insert it
  357.     // into the list we have selected for it.
  358.     //
  359.     Item->Flags = fItem ;
  360.     WlpInsertScavengerItem( List, Item, InsertPos );
  361.     SetEvent( hReadScavConfig );
  362.     return Item ;
  363. }
  364. //+---------------------------------------------------------------------------
  365. //
  366. //  Function:   LsaICancelNotification
  367. //
  368. //  Arguments:  [pvScavHandle] --
  369. //
  370. //  History:    5-26-97   RichardW   Created
  371. //
  372. //  Notes:
  373. //
  374. //----------------------------------------------------------------------------
  375. NTSTATUS
  376. NTAPI
  377. WlCancelNotification(
  378.     PVOID       pvScavHandle
  379.     )
  380. {
  381.     PWL_SCAVENGER_ITEM Item ;
  382.     Item = (PWL_SCAVENGER_ITEM) pvScavHandle ;
  383.     if ( Item->ScavCheck != SCAVMAGIC_ACTIVE )
  384.     {
  385.         return STATUS_INVALID_PARAMETER ;
  386.     }
  387.     WlpDerefScavItem( Item );
  388.     return STATUS_SUCCESS ;
  389. }
  390. //+---------------------------------------------------------------------------
  391. //
  392. //  Function:   WlpInitializeScavenger
  393. //
  394. //  Synopsis:   Initialize Scavenger,
  395. //
  396. //  Arguments:  (none)
  397. //
  398. //  History:    5-26-97   RichardW   Created
  399. //
  400. //  Notes:
  401. //
  402. //----------------------------------------------------------------------------
  403. BOOL
  404. WlpInitializeScavenger(
  405.     VOID
  406.     )
  407. {
  408.     ULONG i ;
  409.     PVOID hNotify ;
  410.     HANDLE hThread ;
  411.     DWORD tid ;
  412.     //
  413.     // Initialize the list of timers
  414.     //
  415.     InitializeListHead( &TimerList );
  416.     for (i = 0 ; i < MAXIMUM_WAIT_OBJECTS ; i++ )
  417.     {
  418.         InitializeListHead( &WaitList[ i ] );
  419.     }
  420.     RtlInitializeCriticalSection( &ScavLock );
  421.     //
  422.     // Event set whenever the list of stuff changes
  423.     //
  424.     hReadScavConfig = CreateEvent(NULL, FALSE, FALSE, NULL);
  425.     //
  426.     // Create basic entries
  427.     //
  428.     hNotify = WlRegisterNotification( WlpScavengerHandleChange,
  429.                                         0,
  430.                                         NOTIFIER_TYPE_HANDLE_WAIT,
  431.                                         SCAVFLAG_EXECUTE_INLINE,
  432.                                         0,
  433.                                         hReadScavConfig );
  434.     hThread = CreateThread( NULL, 0,
  435.                                 WlpScavengerThread, 0,
  436.                                 0, &tid );
  437.     if ( hThread )
  438.     {
  439.         CloseHandle( hThread );
  440.         return TRUE ;
  441.     }
  442.     return FALSE ;
  443. }
  444. //+---------------------------------------------------------------------------
  445. //
  446. //  Function:   WlpScavengerThread
  447. //
  448. //  Synopsis:   Scavenger thread.
  449. //
  450. //  Arguments:  [Ignored] --
  451. //
  452. //  History:    6-03-97   RichardW   Created
  453. //
  454. //  Notes:
  455. //
  456. //----------------------------------------------------------------------------
  457. DWORD
  458. WINAPI
  459. WlpScavengerThread(
  460.     PVOID   Ignored
  461.     )
  462. {
  463.     PWL_SCAVENGER_ITEM CurrentItem ;
  464.     DWORD Timeout ;
  465.     DWORD WaitStatus ;
  466.     PLIST_ENTRY Pop ;
  467.     while ( 1 )
  468.     {
  469.         LockScavenger();
  470.         if ( !IsListEmpty( &TimerList ) )
  471.         {
  472.             CurrentItem = CONTAINING_RECORD( TimerList.Flink, WL_SCAVENGER_ITEM, List );
  473.             if ( CurrentItem->Interval )
  474.             {
  475.                 Timeout = CurrentItem->NextTrigger - GetCurrentTime();
  476.                 if ( Timeout > CurrentItem->NextTrigger ) {
  477.                     Timeout += 0xFFFFFFFF ;
  478.                 }
  479.             }
  480.             else
  481.             {
  482.                 Timeout = 0 ;
  483.             }
  484.         }
  485.         else
  486.         {
  487.             Timeout = INFINITE ;
  488.         }
  489.         UnlockScavenger();
  490.         WaitStatus = WaitForMultipleObjectsEx(
  491.                         cScavWaitHandles,       // # of handles
  492.                         ScavWaitHandles,        // handles
  493.                         FALSE,                  // Wait for all?
  494.                         Timeout,
  495.                         FALSE );
  496.         if ( ( WaitStatus >= WAIT_OBJECT_0 ) &&
  497.              ( WaitStatus <= WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS ) )
  498.         {
  499.             LockScavenger();
  500.             Pop = WaitList[ WaitStatus - WAIT_OBJECT_0 ].Flink ;
  501.             while ( Pop != &WaitList[ WaitStatus - WAIT_OBJECT_0 ] )
  502.             {
  503.                 CurrentItem = CONTAINING_RECORD( Pop, WL_SCAVENGER_ITEM, List );
  504.                 Pop = Pop->Flink ;
  505.                 if ( CurrentItem->Flags & NOTIFIER_FLAG_ONE_SHOT )
  506.                 {
  507.                     RemoveEntryList( &CurrentItem->List );
  508.                     CurrentItem->List.Flink = NULL ;
  509.                 }
  510.                 WlpRefScavItemUnsafe( CurrentItem );
  511.                 UnlockScavenger();
  512.                 WlpTriggerScavengerItem( CurrentItem, FALSE );
  513.                 LockScavenger();
  514.                 if ( CurrentItem->Flags & NOTIFIER_FLAG_ONE_SHOT )
  515.                 {
  516.                     WlpDerefScavItem( CurrentItem );
  517.                 }
  518.             }
  519.             UnlockScavenger();
  520.             continue;
  521.         }
  522.         else
  523.         {
  524.             LockScavenger();
  525.             if ( IsListEmpty( &TimerList ) )
  526.             {
  527.                 continue;
  528.             }
  529.             Pop = RemoveHeadList( &TimerList );
  530.             Pop->Flink = NULL ;
  531.             CurrentItem = CONTAINING_RECORD( Pop, WL_SCAVENGER_ITEM, List );
  532.             WlpRefScavItemUnsafe( CurrentItem );
  533.             UnlockScavenger();
  534.             WlpTriggerScavengerItem( CurrentItem, FALSE );
  535.             if ( CurrentItem->Flags & NOTIFIER_FLAG_ONE_SHOT )
  536.             {
  537.                 WlpDerefScavItem( CurrentItem );
  538.             }
  539.             else
  540.             {
  541.                 WlpInsertScavengerItem( &TimerList, CurrentItem, ScavInsertSorted);
  542.             }
  543.         }
  544.     }
  545.     return 0 ;
  546. }