1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/io/iomgr/iotimer.c 5 * PURPOSE: I/O Wrappers for Executive Timers 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS *******************************************************************/ 16 17 /* Timer Database */ 18 KSPIN_LOCK IopTimerLock; 19 LIST_ENTRY IopTimerQueueHead; 20 21 /* Timer Firing */ 22 KDPC IopTimerDpc; 23 KTIMER IopTimer; 24 25 /* Keep count of how many timers we have */ 26 ULONG IopTimerCount = 0; 27 28 /* PRIVATE FUNCTIONS *********************************************************/ 29 30 VOID 31 NTAPI 32 IopTimerDispatch(IN PKDPC Dpc, 33 IN PVOID DeferredContext, 34 IN PVOID SystemArgument1, 35 IN PVOID SystemArgument2) 36 { 37 KIRQL OldIrql; 38 PLIST_ENTRY TimerEntry; 39 PIO_TIMER Timer; 40 ULONG i; 41 42 /* Check if any Timers are actualyl enabled as of now */ 43 if (IopTimerCount) 44 { 45 /* Lock the Timers */ 46 KeAcquireSpinLock(&IopTimerLock, &OldIrql); 47 48 /* Call the Timer Routine of each enabled Timer */ 49 for (TimerEntry = IopTimerQueueHead.Flink, i = IopTimerCount; 50 (TimerEntry != &IopTimerQueueHead) && i; 51 TimerEntry = TimerEntry->Flink) 52 { 53 /* Get the timer and check if it's enabled */ 54 Timer = CONTAINING_RECORD(TimerEntry, IO_TIMER, IoTimerList); 55 if (Timer->TimerEnabled) 56 { 57 /* Call the timer routine */ 58 Timer->TimerRoutine(Timer->DeviceObject, Timer->Context); 59 i--; 60 } 61 } 62 63 /* Unlock the Timers */ 64 KeReleaseSpinLock(&IopTimerLock, OldIrql); 65 } 66 } 67 68 VOID 69 NTAPI 70 IopRemoveTimerFromTimerList(IN PIO_TIMER Timer) 71 { 72 KIRQL OldIrql; 73 74 /* Lock Timers */ 75 KeAcquireSpinLock(&IopTimerLock, &OldIrql); 76 77 /* Remove Timer from the List and Drop the Timer Count if Enabled */ 78 RemoveEntryList(&Timer->IoTimerList); 79 if (Timer->TimerEnabled) IopTimerCount--; 80 81 /* Unlock the Timers */ 82 KeReleaseSpinLock(&IopTimerLock, OldIrql); 83 } 84 85 /* PUBLIC FUNCTIONS **********************************************************/ 86 87 /* 88 * @implemented 89 */ 90 NTSTATUS 91 NTAPI 92 IoInitializeTimer(IN PDEVICE_OBJECT DeviceObject, 93 IN PIO_TIMER_ROUTINE TimerRoutine, 94 IN PVOID Context) 95 { 96 PIO_TIMER IoTimer = DeviceObject->Timer; 97 PAGED_CODE(); 98 99 /* Check if we don't have a timer yet */ 100 if (!IoTimer) 101 { 102 /* Allocate Timer */ 103 IoTimer = ExAllocatePoolWithTag(NonPagedPool, 104 sizeof(IO_TIMER), 105 TAG_IO_TIMER); 106 if (!IoTimer) return STATUS_INSUFFICIENT_RESOURCES; 107 108 /* Set up the Timer Structure */ 109 RtlZeroMemory(IoTimer, sizeof(IO_TIMER)); 110 IoTimer->Type = IO_TYPE_TIMER; 111 IoTimer->DeviceObject = DeviceObject; 112 DeviceObject->Timer = IoTimer; 113 } 114 115 /* Setup the timer routine and context */ 116 IoTimer->TimerRoutine = TimerRoutine; 117 IoTimer->Context = Context; 118 119 /* Add it to the Timer List */ 120 ExInterlockedInsertTailList(&IopTimerQueueHead, 121 &IoTimer->IoTimerList, 122 &IopTimerLock); 123 124 /* Return Success */ 125 return STATUS_SUCCESS; 126 } 127 128 /* 129 * @implemented 130 */ 131 VOID 132 NTAPI 133 IoStartTimer(IN PDEVICE_OBJECT DeviceObject) 134 { 135 KIRQL OldIrql; 136 PIO_TIMER IoTimer = DeviceObject->Timer; 137 138 /* Make sure the device isn't unloading */ 139 if (!(((PEXTENDED_DEVOBJ_EXTENSION)(DeviceObject->DeviceObjectExtension))-> 140 ExtensionFlags & (DOE_UNLOAD_PENDING | 141 DOE_DELETE_PENDING | 142 DOE_REMOVE_PENDING | 143 DOE_REMOVE_PROCESSED))) 144 { 145 /* Lock Timers */ 146 KeAcquireSpinLock(&IopTimerLock, &OldIrql); 147 148 /* Check if the timer isn't already enabled */ 149 if (!IoTimer->TimerEnabled) 150 { 151 /* Enable it and increase the timer count */ 152 IoTimer->TimerEnabled = TRUE; 153 IopTimerCount++; 154 } 155 156 /* Unlock Timers */ 157 KeReleaseSpinLock(&IopTimerLock, OldIrql); 158 } 159 } 160 161 /* 162 * @implemented 163 */ 164 VOID 165 NTAPI 166 IoStopTimer(PDEVICE_OBJECT DeviceObject) 167 { 168 KIRQL OldIrql; 169 PIO_TIMER IoTimer = DeviceObject->Timer; 170 171 /* Lock Timers */ 172 KeAcquireSpinLock(&IopTimerLock, &OldIrql); 173 174 /* Check if the timer is enabled */ 175 if (IoTimer->TimerEnabled) 176 { 177 /* Disable it and decrease the timer count */ 178 IoTimer->TimerEnabled = FALSE; 179 IopTimerCount--; 180 } 181 182 /* Unlock Timers */ 183 KeReleaseSpinLock(&IopTimerLock, OldIrql); 184 } 185 186 /* EOF */ 187