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+
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
12 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
22 /* FUNCTIONS *****************************************************************/
26 KiIpiSendRequest(KAFFINITY TargetSet
, ULONG IpiRequest
)
32 for (i
= 0, Current
= 1; i
< KeNumberProcessors
; i
++, Current
<<= 1)
34 if (TargetSet
& Current
)
36 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
37 Ke386TestAndSetBit(IpiRequest
, &Pcr
->Prcb
->IpiFrozen
);
48 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame
,
49 IN PKEXCEPTION_FRAME ExceptionFrame
)
52 LARGE_INTEGER StartTime
, CurrentTime
, Frequency
;
57 ASSERT(KeGetCurrentIrql() == IPI_LEVEL
);
59 DPRINT("KiIpiServiceRoutine\n");
61 Prcb
= KeGetCurrentPrcb();
63 if (Ke386TestAndClearBit(IPI_APC
, &Prcb
->IpiFrozen
))
65 HalRequestSoftwareInterrupt(APC_LEVEL
);
68 if (Ke386TestAndClearBit(IPI_DPC
, &Prcb
->IpiFrozen
))
70 Prcb
->DpcInterruptRequested
= TRUE
;
71 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
74 if (Ke386TestAndClearBit(IPI_SYNCH_REQUEST
, &Prcb
->IpiFrozen
))
76 InterlockedDecrementUL(&Prcb
->SignalDone
->CurrentPacket
[1]);
77 if (InterlockedCompareExchangeUL(&Prcb
->SignalDone
->CurrentPacket
[2], 0, 0))
80 StartTime
= KeQueryPerformanceCounter(&Frequency
);
82 while (0 != InterlockedCompareExchangeUL(&Prcb
->SignalDone
->CurrentPacket
[1], 0, 0))
85 CurrentTime
= KeQueryPerformanceCounter(NULL
);
86 if (CurrentTime
.QuadPart
> StartTime
.QuadPart
+ Count
* Frequency
.QuadPart
)
88 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds to start the ipi routine\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), Count
);
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))
99 StartTime
= KeQueryPerformanceCounter(&Frequency
);
101 while (0 != InterlockedCompareExchangeUL(&Prcb
->SignalDone
->TargetSet
, 0, 0))
104 CurrentTime
= KeQueryPerformanceCounter(NULL
);
105 if (CurrentTime
.QuadPart
> StartTime
.QuadPart
+ Count
* Frequency
.QuadPart
)
107 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds after executing the ipi routine\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), Count
);
113 InterlockedExchangePointer(&Prcb
->SignalDone
, NULL
);
115 DPRINT("KiIpiServiceRoutine done\n");
121 KiIpiSendPacket(KAFFINITY TargetSet
, VOID (STDCALL
*WorkerRoutine
)(PVOID
), PVOID Argument
, ULONG Count
, BOOLEAN Synchronize
)
125 PKPRCB Prcb
, CurrentPrcb
;
129 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL
);
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);
138 for (i
= 0, Processor
= 1; i
< KeNumberProcessors
; i
++, Processor
<<= 1)
140 if (TargetSet
& Processor
)
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
)
151 if (TargetSet
& CurrentPrcb
->SetMember
)
153 KeRaiseIrql(IPI_LEVEL
, &oldIrql
);
154 KiIpiServiceRoutine(NULL
, NULL
);
155 KeLowerIrql(oldIrql
);
161 KeIpiGenericCall(VOID (STDCALL
*Function
)(PVOID
), PVOID Argument
)
166 DPRINT("KeIpiGenericCall on CPU%d\n", KeGetCurrentProcessorNumber());
168 KeRaiseIrql(SYNCH_LEVEL
, &oldIrql
);
170 KiAcquireSpinLock(&KiIpiLock
);
172 TargetSet
= (1 << KeNumberProcessors
) - 1;
174 KiIpiSendPacket(TargetSet
, Function
, Argument
, KeNumberProcessors
, TRUE
);
176 KiReleaseSpinLock(&KiIpiLock
);
178 KeLowerIrql(oldIrql
);
180 DPRINT("KeIpiGenericCall on CPU%d done\n", KeGetCurrentProcessorNumber());