forget update de.rc
[reactos.git] / reactos / ntoskrnl / ke / ipi.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/ipi.c
6 * PURPOSE: IPI Routines (Inter-Processor Interrupts). NT5+
7 *
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 * Hartmut Birr
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 KSPIN_LOCK KiIpiLock;
21
22 /* FUNCTIONS *****************************************************************/
23
24 VOID
25 NTAPI
26 KiIpiSendRequest(KAFFINITY TargetSet, ULONG IpiRequest)
27 {
28 LONG i;
29 PKPCR Pcr;
30 KAFFINITY Current;
31
32 for (i = 0, Current = 1; i < KeNumberProcessors; i++, Current <<= 1)
33 {
34 if (TargetSet & Current)
35 {
36 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
37 Ke386TestAndSetBit(IpiRequest, &Pcr->Prcb->IpiFrozen);
38 HalRequestIpi(i);
39 }
40 }
41 }
42
43 /*
44 * @implemented
45 */
46 BOOLEAN
47 STDCALL
48 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame,
49 IN PKEXCEPTION_FRAME ExceptionFrame)
50 {
51 #ifdef DBG
52 LARGE_INTEGER StartTime, CurrentTime, Frequency;
53 ULONG Count = 5;
54 #endif
55 PKPRCB Prcb;
56
57 ASSERT(KeGetCurrentIrql() == IPI_LEVEL);
58
59 DPRINT("KiIpiServiceRoutine\n");
60
61 Prcb = KeGetCurrentPrcb();
62
63 if (Ke386TestAndClearBit(IPI_APC, &Prcb->IpiFrozen))
64 {
65 HalRequestSoftwareInterrupt(APC_LEVEL);
66 }
67
68 if (Ke386TestAndClearBit(IPI_DPC, &Prcb->IpiFrozen))
69 {
70 Prcb->DpcInterruptRequested = TRUE;
71 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
72 }
73
74 if (Ke386TestAndClearBit(IPI_SYNCH_REQUEST, &Prcb->IpiFrozen))
75 {
76 InterlockedDecrementUL(&Prcb->SignalDone->CurrentPacket[1]);
77 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
78 {
79 #ifdef DBG
80 StartTime = KeQueryPerformanceCounter(&Frequency);
81 #endif
82 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[1], 0, 0))
83 {
84 #ifdef DBG
85 CurrentTime = KeQueryPerformanceCounter(NULL);
86 if (CurrentTime.QuadPart > StartTime.QuadPart + Count * Frequency.QuadPart)
87 {
88 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds to start the ipi routine\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber(), Count);
89 KEBUGCHECK(0);
90 }
91 #endif
92 }
93 }
94 ((VOID (STDCALL*)(PVOID))(Prcb->SignalDone->WorkerRoutine))(Prcb->SignalDone->CurrentPacket[0]);
95 Ke386TestAndClearBit(KeGetCurrentProcessorNumber(), &Prcb->SignalDone->TargetSet);
96 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
97 {
98 #ifdef DBG
99 StartTime = KeQueryPerformanceCounter(&Frequency);
100 #endif
101 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->TargetSet, 0, 0))
102 {
103 #ifdef DBG
104 CurrentTime = KeQueryPerformanceCounter(NULL);
105 if (CurrentTime.QuadPart > StartTime.QuadPart + Count * Frequency.QuadPart)
106 {
107 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds after executing the ipi routine\n", __FILE__,__LINE__, KeGetCurrentProcessorNumber(), Count);
108 KEBUGCHECK(0);
109 }
110 #endif
111 }
112 }
113 InterlockedExchangePointer(&Prcb->SignalDone, NULL);
114 }
115 DPRINT("KiIpiServiceRoutine done\n");
116 return TRUE;
117 }
118
119 VOID
120 STDCALL
121 KiIpiSendPacket(KAFFINITY TargetSet, VOID (STDCALL*WorkerRoutine)(PVOID), PVOID Argument, ULONG Count, BOOLEAN Synchronize)
122 {
123 KAFFINITY Processor;
124 LONG i;
125 PKPRCB Prcb, CurrentPrcb;
126 KIRQL oldIrql;
127
128
129 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
130
131 CurrentPrcb = KeGetCurrentPrcb();
132 InterlockedExchangeUL(&CurrentPrcb->TargetSet, TargetSet);
133 InterlockedExchangeUL(&CurrentPrcb->WorkerRoutine, (ULONG_PTR)WorkerRoutine);
134 InterlockedExchangePointer(&CurrentPrcb->CurrentPacket[0], Argument);
135 InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[1], Count);
136 InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[2], Synchronize ? 1 : 0);
137
138 for (i = 0, Processor = 1; i < KeNumberProcessors; i++, Processor <<= 1)
139 {
140 if (TargetSet & Processor)
141 {
142 Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
143 while(0 != InterlockedCompareExchangeUL(&Prcb->SignalDone, (LONG)CurrentPrcb, 0));
144 Ke386TestAndSetBit(IPI_SYNCH_REQUEST, &Prcb->IpiFrozen);
145 if (Processor != CurrentPrcb->SetMember)
146 {
147 HalRequestIpi(i);
148 }
149 }
150 }
151 if (TargetSet & CurrentPrcb->SetMember)
152 {
153 KeRaiseIrql(IPI_LEVEL, &oldIrql);
154 KiIpiServiceRoutine(NULL, NULL);
155 KeLowerIrql(oldIrql);
156 }
157 }
158
159 VOID
160 NTAPI
161 KeIpiGenericCall(VOID (STDCALL *Function)(PVOID), PVOID Argument)
162 {
163 KIRQL oldIrql;
164 KAFFINITY TargetSet;
165
166 DPRINT("KeIpiGenericCall on CPU%d\n", KeGetCurrentProcessorNumber());
167
168 KeRaiseIrql(SYNCH_LEVEL, &oldIrql);
169
170 KiAcquireSpinLock(&KiIpiLock);
171
172 TargetSet = (1 << KeNumberProcessors) - 1;
173
174 KiIpiSendPacket(TargetSet, Function, Argument, KeNumberProcessors, TRUE);
175
176 KiReleaseSpinLock(&KiIpiLock);
177
178 KeLowerIrql(oldIrql);
179
180 DPRINT("KeIpiGenericCall on CPU%d done\n", KeGetCurrentProcessorNumber());
181 }
182
183
184 /* EOF */