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