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.

921 lines
22 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2001
  6. //
  7. // File: kerbscav.cxx
  8. //
  9. // Contents: Scavenger (task automation) code
  10. //
  11. //
  12. // History: 22-April-2001 Created MarkPu
  13. //
  14. //-----------------------------------------------------------------------------
  15. #ifndef WIN32_CHICAGO
  16. extern "C"
  17. {
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <dsysdbg.h>
  23. }
  24. #else
  25. #include <kerb.hxx>
  26. #include <kerbp.h>
  27. #endif
  28. #include <kerbcomm.h>
  29. #include <kerbscav.h>
  30. #include <kerbpq.h>
  31. //
  32. // FESTER: not a good idea to have these as globals, in case the application
  33. // would want multiple scavenger instances. This will do for now.
  34. //
  35. BOOLEAN ScavengerInitialized = FALSE;
  36. RTL_CRITICAL_SECTION ScavengerLock;
  37. HANDLE ScavengerTimerQueue = NULL;
  38. HANDLE ScavengerTimerShutdownEvent = NULL;
  39. LIST_ENTRY ScavengerTaskQueue = {0};
  40. LIST_ENTRY ScavengerDeadPool = {0};
  41. ULONG ScavengerDeadPoolSize = 0;
  42. #define LockScavengerQueue() RtlEnterCriticalSection( &ScavengerLock )
  43. #define UnlockScavengerQueue() RtlLeaveCriticalSection( &ScavengerLock )
  44. struct SCAVENGER_TASK
  45. {
  46. LIST_ENTRY m_ListEntry;
  47. //
  48. // Periodicity control code
  49. //
  50. DWORD m_InsideTrigger; // Set to the ID of the callback thread
  51. BOOLEAN m_Changed; // TRUE if periodicity was changed
  52. BOOLEAN m_Canceled; // TRUE if task was canceled
  53. BOOLEAN m_Periodic; // TRUE if periodic
  54. LONG m_Interval; // recurrence interval, in milliseconds
  55. //
  56. // Task management
  57. //
  58. HANDLE m_Timer; // Timer handle
  59. ULONG m_Flags; // Timer flags (see CreateTimerQueueTimer)
  60. HANDLE m_ShutdownEvent; // Shutdown event
  61. LONG m_Processing; // Set to TRUE while inside the trigger
  62. KERB_TASK_TRIGGER m_pfnTrigger; // Invocation callback
  63. KERB_TASK_DESTROY m_pfnDestroy; // Destruction callback
  64. void * m_Context; // User-supplied task context
  65. };
  66. typedef SCAVENGER_TASK * PSCAVENGER_TASK;
  67. // ----------------------------------------------------------------------------
  68. //
  69. // Internal scavenger routines
  70. //
  71. // ----------------------------------------------------------------------------
  72. VOID
  73. ScavengerTimerCallback(
  74. IN PVOID Parameter,
  75. IN BOOLEAN Reason
  76. );
  77. //+----------------------------------------------------------------------------
  78. //
  79. // Function: ScavengerFreeTask
  80. //
  81. // Synopsis: Task 'destructor'
  82. //
  83. // Arguments: Task - task to be freed
  84. //
  85. // Returns: Nothing
  86. //
  87. //-----------------------------------------------------------------------------
  88. void
  89. ScavengerFreeTask(
  90. IN PSCAVENGER_TASK Task
  91. )
  92. {
  93. if ( Task != NULL ) {
  94. if ( Task->m_pfnDestroy ) {
  95. Task->m_pfnDestroy( Task->m_Context );
  96. }
  97. NtClose( Task->m_ShutdownEvent );
  98. MIDL_user_free( Task );
  99. }
  100. return;
  101. }
  102. //+----------------------------------------------------------------------------
  103. //
  104. // Function: ScavengerPurgeDeadPool
  105. //
  106. // Synopsis: Disposes of items in the deadpool
  107. //
  108. // Arguments: TaskToAvoid - Task to leave hanging around (because
  109. // it corresponds to the current timer callback)
  110. // This parameter can be NULL
  111. //
  112. // Returns: Nothing
  113. //
  114. //-----------------------------------------------------------------------------
  115. void
  116. ScavengerPurgeDeadPool(
  117. IN OPTIONAL PSCAVENGER_TASK TaskToAvoid
  118. )
  119. {
  120. ULONG TasksLeftOver = 0;
  121. LockScavengerQueue();
  122. while ( !IsListEmpty( &ScavengerDeadPool ) &&
  123. TasksLeftOver < ScavengerDeadPoolSize ) {
  124. //
  125. // Get a task out of the list
  126. //
  127. BOOLEAN PutItBack = FALSE;
  128. PSCAVENGER_TASK Task = CONTAINING_RECORD(
  129. RemoveHeadList( &ScavengerDeadPool ),
  130. SCAVENGER_TASK,
  131. m_ListEntry
  132. );
  133. //
  134. // Only canceled tasks are allowed in the deadpool
  135. //
  136. DsysAssert( Task->m_Canceled );
  137. DsysAssert( ScavengerDeadPoolSize > 0 );
  138. ScavengerDeadPoolSize -= 1;
  139. UnlockScavengerQueue();
  140. if ( Task == TaskToAvoid ) {
  141. //
  142. // If this is the task associated with the current callback, skip it
  143. //
  144. PutItBack = TRUE;
  145. } else {
  146. //
  147. // Destroy the timer handle if it still exists
  148. //
  149. if ( Task->m_Timer != NULL ) {
  150. BOOL Success;
  151. Success = DeleteTimerQueueTimer(
  152. ScavengerTimerQueue,
  153. Task->m_Timer,
  154. Task->m_ShutdownEvent
  155. );
  156. DsysAssert( Success );
  157. Task->m_Timer = NULL;
  158. }
  159. //
  160. // If the shutdown event is signaled,
  161. // it is safe to dispose of the task;
  162. // Otherwise, someone else will have to garbage collect this one
  163. //
  164. if ( WAIT_OBJECT_0 == WaitForSingleObject(
  165. Task->m_ShutdownEvent,
  166. 0 )) {
  167. ScavengerFreeTask( Task );
  168. } else {
  169. PutItBack = TRUE;
  170. }
  171. }
  172. LockScavengerQueue();
  173. //
  174. // If this is 'our' task, or there was trouble, insert it at the tail
  175. // so we can continue with tasks at the head of the deadpool list
  176. //
  177. if ( PutItBack ) {
  178. InsertTailList( &ScavengerDeadPool, &Task->m_ListEntry );
  179. ScavengerDeadPoolSize += 1;
  180. TasksLeftOver += 1;
  181. }
  182. }
  183. UnlockScavengerQueue();
  184. return;
  185. }
  186. //+----------------------------------------------------------------------------
  187. //
  188. // Function: ScavengerCancelTask
  189. //
  190. // Synopsis: Stops a task's timer for subsequent removal
  191. //
  192. // Arguments: Task - Task to cancel
  193. //
  194. // Returns: Nothing
  195. //
  196. //-----------------------------------------------------------------------------
  197. void
  198. ScavengerCancelTask(
  199. IN PSCAVENGER_TASK Task
  200. )
  201. {
  202. DsysAssert( Task );
  203. LockScavengerQueue();
  204. //
  205. // Only canceled tasks are allowed in the deadpool
  206. //
  207. DsysAssert( Task->m_Canceled );
  208. //
  209. // Move the task from the active task list to the deadpool
  210. //
  211. RemoveEntryList( &Task->m_ListEntry );
  212. InsertTailList( &ScavengerDeadPool, &Task->m_ListEntry );
  213. ScavengerDeadPoolSize += 1;
  214. UnlockScavengerQueue();
  215. return;
  216. }
  217. //+----------------------------------------------------------------------------
  218. //
  219. // Function: ScavengerAddTask
  220. //
  221. // Synopsis: Common logic involved in scheduling a new task
  222. //
  223. // Arguments: Parameter - Task being scheduled
  224. //
  225. // Returns: STATUS_SUCCESS if happy
  226. // STATUS_ error code otherwise
  227. //
  228. //-----------------------------------------------------------------------------
  229. NTSTATUS
  230. ScavengerAddTask(
  231. IN PSCAVENGER_TASK Task
  232. )
  233. {
  234. NTSTATUS Status = STATUS_SUCCESS;
  235. BOOL Success;
  236. DsysAssert( Task );
  237. LockScavengerQueue();
  238. //
  239. // Assumptions: properly configured task, ready to be scheduled
  240. //
  241. DsysAssert( Task->m_InsideTrigger == 0 );
  242. DsysAssert( !Task->m_Changed );
  243. DsysAssert( !Task->m_Canceled );
  244. DsysAssert( Task->m_Timer == NULL );
  245. DsysAssert( Task->m_ShutdownEvent != NULL );
  246. DsysAssert( Task->m_Processing == FALSE );
  247. //
  248. // Schedule the task by creating its timer
  249. //
  250. Success = CreateTimerQueueTimer(
  251. &Task->m_Timer,
  252. ScavengerTimerQueue,
  253. ScavengerTimerCallback,
  254. Task,
  255. Task->m_Interval,
  256. Task->m_Periodic ? Task->m_Interval : 0,
  257. Task->m_Flags
  258. );
  259. if ( !Success ) {
  260. //
  261. // FESTER: map GetLastError() to an NT status code maybe?
  262. //
  263. Status = STATUS_UNSUCCESSFUL;
  264. DsysAssert( FALSE );
  265. } else {
  266. InsertHeadList( &ScavengerTaskQueue, &Task->m_ListEntry );
  267. }
  268. UnlockScavengerQueue();
  269. return Status;
  270. }
  271. //+----------------------------------------------------------------------------
  272. //
  273. // Function: ScavengerRescheduleTask
  274. //
  275. // Synopsis: Waits for a changed task to finish then reschedules it
  276. //
  277. // Arguments: Parameter - Task being rescheduled
  278. //
  279. // Returns: STATUS_SUCCESS if happy
  280. // STATUS_ error code otherwise
  281. //
  282. //-----------------------------------------------------------------------------
  283. DWORD
  284. WINAPI
  285. ScavengerRescheduleTask(
  286. LPVOID Parameter
  287. )
  288. {
  289. NTSTATUS Status;
  290. PSCAVENGER_TASK Task = ( PSCAVENGER_TASK )Parameter;
  291. BOOL Success;
  292. //
  293. // Assumptions: this is a properly configured 'changed' task
  294. //
  295. DsysAssert( Task );
  296. DsysAssert( Task->m_Timer );
  297. DsysAssert( Task->m_ShutdownEvent );
  298. DsysAssert( Task->m_Changed );
  299. DsysAssert( !Task->m_Canceled );
  300. //
  301. // Cancel the timer
  302. //
  303. Success = DeleteTimerQueueTimer(
  304. ScavengerTimerQueue,
  305. Task->m_Timer,
  306. Task->m_ShutdownEvent
  307. );
  308. DsysAssert( Success );
  309. Task->m_Timer = NULL;
  310. //
  311. // Wait for all outstanding timer callbacks to finish
  312. //
  313. WaitForSingleObject( Task->m_ShutdownEvent, INFINITE );
  314. InterlockedExchange( &Task->m_Processing, FALSE );
  315. //
  316. // Reset the shutdown event so it can be recycled
  317. //
  318. Status = NtResetEvent( Task->m_ShutdownEvent, NULL );
  319. DsysAssert( NT_SUCCESS( Status ));
  320. //
  321. // Now reschedule the task
  322. //
  323. Task->m_Changed = FALSE;
  324. Status = ScavengerAddTask( Task );
  325. if ( !NT_SUCCESS( Status )) {
  326. ScavengerFreeTask( Task );
  327. }
  328. return Status;
  329. }
  330. //+----------------------------------------------------------------------------
  331. //
  332. // Function: ScavengerTimerCallback
  333. //
  334. // Synopsis: Scavenger worker routine
  335. //
  336. // Arguments: Parameter - Task handle
  337. // Reason - see definition of WAITORTIMERCALLBACK
  338. //
  339. // Returns: Nothing
  340. //
  341. //-----------------------------------------------------------------------------
  342. VOID
  343. ScavengerTimerCallback(
  344. IN PVOID Parameter,
  345. IN BOOLEAN Reason
  346. )
  347. {
  348. PSCAVENGER_TASK Task = ( PSCAVENGER_TASK )Parameter;
  349. DsysAssert( Task );
  350. DsysAssert( Reason == TRUE );
  351. DsysAssert( Task->m_pfnTrigger );
  352. //
  353. // Callbacks that step on each others' heels are thrown out
  354. //
  355. if ( FALSE != InterlockedCompareExchange(
  356. &Task->m_Processing,
  357. TRUE,
  358. FALSE )) {
  359. return;
  360. }
  361. //
  362. // Invoke the trigger
  363. //
  364. DsysAssert( Task->m_InsideTrigger == 0 );
  365. DsysAssert( !Task->m_Changed );
  366. DsysAssert( !Task->m_Canceled );
  367. Task->m_InsideTrigger = GetCurrentThreadId();
  368. Task->m_pfnTrigger( Task, Task->m_Context );
  369. Task->m_InsideTrigger = 0;
  370. if ( Task->m_Changed && !Task->m_Canceled ) {
  371. //
  372. // If the task's periodicity has changed, reschedule it.
  373. //
  374. // Can't create a timer inside a timer callback routine, so do it
  375. // asynchronously
  376. //
  377. if ( FALSE == QueueUserWorkItem(
  378. ScavengerRescheduleTask,
  379. Task,
  380. WT_EXECUTEDEFAULT )) {
  381. //
  382. // A task that cannot be rescheduled has to die
  383. //
  384. Task->m_Canceled = TRUE;
  385. }
  386. } else if ( !Task->m_Periodic ) {
  387. //
  388. // Non-periodic tasks get removed right away
  389. //
  390. Task->m_Canceled = TRUE;
  391. }
  392. //
  393. // If the task has been canceled, move it to the deadpool
  394. //
  395. if ( Task->m_Canceled ) {
  396. ScavengerCancelTask( Task );
  397. } else {
  398. //
  399. // Task has not been canceled, so open it up to timer callbacks
  400. //
  401. InterlockedExchange( &Task->m_Processing, FALSE );
  402. }
  403. //
  404. // A timer callback is a good place to bury some bodies
  405. //
  406. ScavengerPurgeDeadPool( Task );
  407. return;
  408. }
  409. // ----------------------------------------------------------------------------
  410. //
  411. // External scavenger interfaces
  412. //
  413. // ----------------------------------------------------------------------------
  414. //+----------------------------------------------------------------------------
  415. //
  416. // Function: KerbInitializeScavenger
  417. //
  418. // Synopsis: Initializes the scavenger
  419. //
  420. // Arguments: None
  421. //
  422. // Returns: STATUS_SUCCESS if happy
  423. // STATUS_ error code otherwise
  424. //
  425. //-----------------------------------------------------------------------------
  426. NTSTATUS
  427. KerbInitializeScavenger()
  428. {
  429. NTSTATUS Status;
  430. DsysAssert( !ScavengerInitialized );
  431. //
  432. // Task queue and dead pool could be protected by different
  433. // locks, but the amount of time spent inside those locks is minimal,
  434. // so the same lock is used
  435. //
  436. Status = RtlInitializeCriticalSection( &ScavengerLock );
  437. if ( !NT_SUCCESS( Status )) {
  438. return Status;
  439. }
  440. InitializeListHead( &ScavengerTaskQueue );
  441. InitializeListHead( &ScavengerDeadPool );
  442. ScavengerDeadPoolSize = 0;
  443. DsysAssert( ScavengerTimerShutdownEvent == NULL );
  444. Status = NtCreateEvent(
  445. &ScavengerTimerShutdownEvent,
  446. EVENT_QUERY_STATE |
  447. EVENT_MODIFY_STATE |
  448. SYNCHRONIZE,
  449. NULL,
  450. SynchronizationEvent,
  451. FALSE
  452. );
  453. if ( !NT_SUCCESS( Status )) {
  454. goto Error;
  455. }
  456. DsysAssert( ScavengerTimerQueue == NULL );
  457. Status = RtlCreateTimerQueue( &ScavengerTimerQueue );
  458. if ( !NT_SUCCESS( Status )) {
  459. goto Error;
  460. }
  461. //
  462. // We're ready to rock-n-roll
  463. //
  464. ScavengerInitialized = TRUE;
  465. Status = STATUS_SUCCESS;
  466. Cleanup:
  467. return Status;
  468. Error:
  469. DsysAssert( !NT_SUCCESS( Status ));
  470. if ( ScavengerTimerQueue != NULL ) {
  471. RtlDeleteTimerQueue( ScavengerTimerQueue );
  472. ScavengerTimerQueue = NULL;
  473. }
  474. if ( ScavengerTimerShutdownEvent != NULL ) {
  475. NtClose( ScavengerTimerShutdownEvent );
  476. ScavengerTimerShutdownEvent = NULL;
  477. }
  478. RtlDeleteCriticalSection( &ScavengerLock );
  479. ScavengerInitialized = FALSE;
  480. goto Cleanup;
  481. }
  482. //+----------------------------------------------------------------------------
  483. //
  484. // Function: KerbShutdownScavenger
  485. //
  486. // Synopsis: Shuts down the scavenger
  487. //
  488. // Arguments: None
  489. //
  490. // Returns: STATUS_SUCCESS if everything cleaned up properly
  491. // STATUS_ error code otherwise
  492. //
  493. // Note: If errors are encountered, the scavenger will not be destroyed,
  494. // but the task queue will be emptied.
  495. //
  496. //-----------------------------------------------------------------------------
  497. NTSTATUS
  498. KerbShutdownScavenger()
  499. {
  500. NTSTATUS Status;
  501. DsysAssert( ScavengerInitialized );
  502. Status = RtlDeleteTimerQueueEx(
  503. ScavengerTimerQueue,
  504. ScavengerTimerShutdownEvent
  505. );
  506. ScavengerPurgeDeadPool( NULL );
  507. WaitForSingleObject( ScavengerTimerShutdownEvent, INFINITE );
  508. //
  509. // Purge the contents of the scavenger queue
  510. // NOTE: no need to lock the queue anymore, as the timer has been shut down
  511. //
  512. while ( !IsListEmpty( &ScavengerTaskQueue )) {
  513. PSCAVENGER_TASK Task = CONTAINING_RECORD(
  514. RemoveHeadList( &ScavengerTaskQueue ),
  515. SCAVENGER_TASK,
  516. m_ListEntry
  517. );
  518. ScavengerFreeTask( Task );
  519. }
  520. if ( NT_SUCCESS( Status )) {
  521. NtClose( ScavengerTimerShutdownEvent );
  522. ScavengerTimerShutdownEvent = NULL;
  523. ScavengerTimerQueue = NULL;
  524. RtlDeleteCriticalSection( &ScavengerLock );
  525. ScavengerInitialized = FALSE;
  526. }
  527. return Status;
  528. }
  529. //+----------------------------------------------------------------------------
  530. //
  531. // Function: KerbAddScavengerTask
  532. //
  533. // Synopsis: Adds a task to the list of those managed by the scavenger object
  534. //
  535. // Arguments: Periodic - If TRUE, this is to be a recurring task
  536. // Interval - Execution interval in milliseconds
  537. // Flags - WT_ flags (see CreateTimerQueueTimer)
  538. // pfnTrigger - Trigger callback
  539. // pfnDestroy - Destruction callback (OPTIONAL)
  540. // TaskItem - Task context (OPTIONAL)
  541. //
  542. // Returns: STATUS_SUCCESS if everything cleaned up properly
  543. // STATUS_ error code otherwise
  544. //
  545. //-----------------------------------------------------------------------------
  546. NTSTATUS
  547. KerbAddScavengerTask(
  548. IN BOOLEAN Periodic,
  549. IN LONG Interval,
  550. IN ULONG Flags,
  551. IN KERB_TASK_TRIGGER pfnTrigger,
  552. IN KERB_TASK_DESTROY pfnDestroy,
  553. IN void * TaskItem
  554. )
  555. {
  556. NTSTATUS Status;
  557. PSCAVENGER_TASK Task;
  558. DsysAssert( ScavengerInitialized );
  559. //
  560. // Validate the passed in parameters
  561. //
  562. if ( pfnTrigger == NULL ||
  563. ( Periodic && Interval == 0 )) {
  564. DsysAssert( FALSE && "RTFM: Invalid parameter passed in to KerbAddScavengerTask." );
  565. return STATUS_INVALID_PARAMETER;
  566. }
  567. Task = ( PSCAVENGER_TASK )MIDL_user_allocate( sizeof( SCAVENGER_TASK ));
  568. if ( Task == NULL ) {
  569. return STATUS_INSUFFICIENT_RESOURCES;
  570. }
  571. Task->m_InsideTrigger = 0;
  572. Task->m_Changed = FALSE;
  573. Task->m_Canceled = FALSE;
  574. Task->m_Periodic = Periodic;
  575. Task->m_Interval = Interval;
  576. Task->m_Timer = NULL;
  577. Task->m_Flags = Flags;
  578. Task->m_ShutdownEvent = NULL;
  579. Task->m_Processing = FALSE;
  580. Task->m_pfnTrigger = pfnTrigger;
  581. Task->m_pfnDestroy = pfnDestroy;
  582. Task->m_Context = TaskItem;
  583. Status = NtCreateEvent(
  584. &Task->m_ShutdownEvent,
  585. EVENT_QUERY_STATE |
  586. EVENT_MODIFY_STATE |
  587. SYNCHRONIZE,
  588. NULL,
  589. SynchronizationEvent,
  590. FALSE
  591. );
  592. if ( !NT_SUCCESS( Status )) {
  593. MIDL_user_free( Task );
  594. return Status;
  595. }
  596. Status = ScavengerAddTask( Task );
  597. if ( !NT_SUCCESS( Status )) {
  598. Task->m_pfnDestroy = NULL; // Didn't take ownership yet, caller will destroy
  599. ScavengerFreeTask( Task );
  600. }
  601. return Status;
  602. }
  603. //+----------------------------------------------------------------------------
  604. //
  605. // Function: KerbTaskIsPeriodic
  606. //
  607. // Synopsis: Tells whether a given task is a periodic task
  608. //
  609. // Arguments: TaskHandle - Task handle
  610. //
  611. // Returns: TRUE if the task is periodic, FALSE otherwise
  612. //
  613. // NOTE: this function can only be called from inside a task trigger callback
  614. //
  615. //-----------------------------------------------------------------------------
  616. BOOLEAN
  617. KerbTaskIsPeriodic(
  618. IN void * TaskHandle
  619. )
  620. {
  621. PSCAVENGER_TASK Task = ( PSCAVENGER_TASK )TaskHandle;
  622. DsysAssert( Task );
  623. DsysAssert( Task->m_InsideTrigger == GetCurrentThreadId());
  624. return Task->m_Periodic;
  625. }
  626. //+----------------------------------------------------------------------------
  627. //
  628. // Function: KerbTaskGetInterval
  629. //
  630. // Synopsis: Retrieves the interval of a periodic task
  631. //
  632. // Arguments: TaskHandle - Task handle
  633. //
  634. // Returns: Interval associated with the task, in milliseconds
  635. //
  636. // NOTE: this function can only be called from inside a task trigger callback
  637. //
  638. //-----------------------------------------------------------------------------
  639. LONG
  640. KerbTaskGetInterval(
  641. IN void * TaskHandle
  642. )
  643. {
  644. PSCAVENGER_TASK Task = ( PSCAVENGER_TASK )TaskHandle;
  645. DsysAssert( Task );
  646. DsysAssert( Task->m_InsideTrigger == GetCurrentThreadId());
  647. return Task->m_Interval;
  648. }
  649. //+----------------------------------------------------------------------------
  650. //
  651. // Function: KerbTaskReschedule
  652. //
  653. // Synopsis: Sets periodicity of a task
  654. //
  655. // Arguments: TaskHandle - Task handle
  656. // Periodic - if TRUE, this is going to be a periodic task
  657. // Interval - recurrence interval, in milliseconds
  658. //
  659. // Returns: Nothing
  660. //
  661. // NOTE: this function can only be called from inside a task trigger callback
  662. //
  663. //-----------------------------------------------------------------------------
  664. void
  665. KerbTaskReschedule(
  666. IN void * TaskHandle,
  667. IN BOOLEAN Periodic,
  668. IN LONG Interval
  669. )
  670. {
  671. PSCAVENGER_TASK Task = ( PSCAVENGER_TASK )TaskHandle;
  672. DsysAssert( Task );
  673. DsysAssert( Task->m_InsideTrigger == GetCurrentThreadId());
  674. if ( Periodic && Interval == 0 ) {
  675. DsysAssert( FALSE && "Invalid parameter passed in to KerbTaskReschedule\n" );
  676. } else {
  677. Task->m_Changed = TRUE;
  678. Task->m_Periodic = Periodic;
  679. Task->m_Interval = Interval;
  680. }
  681. return;
  682. }
  683. //+----------------------------------------------------------------------------
  684. //
  685. // Function: KerbTaskCancel
  686. //
  687. // Synopsis: Cancels the task
  688. //
  689. // Arguments: TaskHandle - Task handle
  690. //
  691. // Returns: Nothing
  692. //
  693. // NOTE: this function can only be called from inside a task trigger callback
  694. //
  695. //-----------------------------------------------------------------------------
  696. void
  697. KerbTaskCancel(
  698. IN void * TaskHandle
  699. )
  700. {
  701. PSCAVENGER_TASK Task = ( PSCAVENGER_TASK )TaskHandle;
  702. DsysAssert( Task );
  703. DsysAssert( Task->m_InsideTrigger == GetCurrentThreadId());
  704. Task->m_Canceled = TRUE;
  705. return;
  706. }