win-pvdrivers

view xenpci/xenpci_highsync.c @ 900:938de6b8623d

fix memory leak on suspend/resume
author James Harper <james.harper@bendigoit.com.au>
date Thu Mar 31 20:20:36 2011 +1100 (2011-03-31)
parents e315b8490131
children 70738d39e3cc
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
22 /* Not really necessary but keeps PREfast happy */
23 #if (NTDDI_VERSION >= NTDDI_WINXP)
24 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunction0;
25 static KDEFERRED_ROUTINE XenPci_HighSyncCallFunctionN;
26 #endif
28 /*
29 we need these intrinsics as even going to HIGH_LEVEL doesn't ensure that interrupts are completely disabled
30 */
31 #pragma intrinsic(_disable)
32 #pragma intrinsic(_enable)
34 struct {
35 volatile ULONG do_spin;
36 volatile LONG nr_procs_at_dispatch_level;
37 volatile LONG nr_spinning_at_sync_level;
38 KDPC dpcs[MAX_VIRT_CPUS];
39 KEVENT highsync_complete_event;
40 KIRQL sync_level;
41 PXENPCI_HIGHSYNC_FUNCTION function0;
42 PXENPCI_HIGHSYNC_FUNCTION functionN;
43 PVOID context;
44 } typedef highsync_info_t;
46 static VOID
47 XenPci_HighSyncCallFunction0(
48 PRKDPC Dpc,
49 PVOID Context,
50 PVOID SystemArgument1,
51 PVOID SystemArgument2)
52 {
53 highsync_info_t *highsync_info = Context;
54 ULONG ActiveProcessorCount;
55 KIRQL old_irql;
57 UNREFERENCED_PARAMETER(Dpc);
58 UNREFERENCED_PARAMETER(SystemArgument1);
59 UNREFERENCED_PARAMETER(SystemArgument2);
61 FUNCTION_ENTER();
62 #if (NTDDI_VERSION >= NTDDI_WINXP)
63 ActiveProcessorCount = (ULONG)KeNumberProcessors;
64 #else
65 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
66 #endif
67 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
68 if (highsync_info->sync_level > DISPATCH_LEVEL)
69 {
70 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount)
71 {
72 KeStallExecutionProcessor(1);
73 KeMemoryBarrier();
74 }
75 }
76 _disable(); //__asm cli;
77 KeRaiseIrql(highsync_info->sync_level, &old_irql);
78 while (highsync_info->nr_spinning_at_sync_level < (LONG)ActiveProcessorCount - 1)
79 {
80 KeStallExecutionProcessor(1);
81 KeMemoryBarrier();
82 }
83 highsync_info->function0(highsync_info->context);
84 KeLowerIrql(old_irql);
85 _enable(); //__asm sti;
86 highsync_info->do_spin = FALSE;
87 KeMemoryBarrier();
88 /* wait for all the other processors to complete spinning, just in case it matters */
89 while (highsync_info->nr_spinning_at_sync_level)
90 {
91 KeStallExecutionProcessor(1);
92 KeMemoryBarrier();
93 }
94 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
95 KeSetEvent(&highsync_info->highsync_complete_event, IO_NO_INCREMENT, FALSE);
97 FUNCTION_EXIT();
98 }
100 static VOID
101 XenPci_HighSyncCallFunctionN(
102 PRKDPC Dpc,
103 PVOID Context,
104 PVOID SystemArgument1,
105 PVOID SystemArgument2)
106 {
107 highsync_info_t *highsync_info = Context;
108 ULONG ActiveProcessorCount;
109 KIRQL old_irql;
111 UNREFERENCED_PARAMETER(Dpc);
112 UNREFERENCED_PARAMETER(SystemArgument1);
113 UNREFERENCED_PARAMETER(SystemArgument2);
115 FUNCTION_ENTER();
116 FUNCTION_MSG("(CPU = %d)\n", KeGetCurrentProcessorNumber());
118 KdPrint((__DRIVER_NAME " CPU %d spinning...\n", KeGetCurrentProcessorNumber()));
119 InterlockedIncrement(&highsync_info->nr_procs_at_dispatch_level);
120 if (highsync_info->sync_level > DISPATCH_LEVEL)
121 {
122 #if (NTDDI_VERSION >= NTDDI_WINXP)
123 ActiveProcessorCount = (ULONG)KeNumberProcessors;
124 #else
125 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
126 #endif
127 while (highsync_info->nr_procs_at_dispatch_level < (LONG)ActiveProcessorCount)
128 {
129 KeStallExecutionProcessor(1);
130 KeMemoryBarrier();
131 }
132 }
133 _disable(); //__asm cli;
134 KeRaiseIrql(highsync_info->sync_level, &old_irql);
135 InterlockedIncrement(&highsync_info->nr_spinning_at_sync_level);
136 while(highsync_info->do_spin)
137 {
138 KeStallExecutionProcessor(1);
139 KeMemoryBarrier();
140 }
141 highsync_info->functionN(highsync_info->context);
142 KeLowerIrql(old_irql);
143 _enable(); //__asm sti;
144 InterlockedDecrement(&highsync_info->nr_spinning_at_sync_level);
145 InterlockedDecrement(&highsync_info->nr_procs_at_dispatch_level);
146 FUNCTION_EXIT();
147 return;
148 }
150 VOID
151 XenPci_HighSync(PXENPCI_HIGHSYNC_FUNCTION function0, PXENPCI_HIGHSYNC_FUNCTION functionN, PVOID context)
152 {
153 ULONG ActiveProcessorCount;
154 ULONG i;
155 highsync_info_t *highsync_info;
156 KIRQL old_irql;
158 UNREFERENCED_PARAMETER(context);
159 FUNCTION_ENTER();
161 highsync_info = ExAllocatePoolWithTag(NonPagedPool, sizeof(highsync_info_t), XENPCI_POOL_TAG);
162 RtlZeroMemory(highsync_info, sizeof(highsync_info_t));
163 KeInitializeEvent(&highsync_info->highsync_complete_event, SynchronizationEvent, FALSE);
164 highsync_info->function0 = function0;
165 highsync_info->functionN = functionN;
166 highsync_info->context = context;
167 highsync_info->sync_level = HIGH_LEVEL;
169 #if (NTDDI_VERSION >= NTDDI_WINXP)
170 ActiveProcessorCount = (ULONG)KeNumberProcessors;
171 #else
172 ActiveProcessorCount = (ULONG)*KeNumberProcessors;
173 #endif
175 /* Go to HIGH_LEVEL to prevent any races with Dpc's on the current processor */
176 KeRaiseIrql(highsync_info->sync_level, &old_irql);
178 highsync_info->do_spin = TRUE;
179 for (i = 0; i < ActiveProcessorCount; i++)
180 {
181 if (i == 0)
182 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunction0, highsync_info);
183 else
184 KeInitializeDpc(&highsync_info->dpcs[i], XenPci_HighSyncCallFunctionN, highsync_info);
185 KeSetTargetProcessorDpc(&highsync_info->dpcs[i], (CCHAR)i);
186 KeSetImportanceDpc(&highsync_info->dpcs[i], HighImportance);
187 KdPrint((__DRIVER_NAME " queuing Dpc for CPU %d\n", i));
188 KeInsertQueueDpc(&highsync_info->dpcs[i], NULL, NULL);
189 }
190 KdPrint((__DRIVER_NAME " All Dpc's queued\n"));
192 KeMemoryBarrier();
193 KeLowerIrql(old_irql);
195 KdPrint((__DRIVER_NAME " Waiting for highsync_complete_event\n"));
196 KeWaitForSingleObject(&highsync_info->highsync_complete_event, Executive, KernelMode, FALSE, NULL);
197 /* wait until nr_procs_at_dispatch_level drops to 0 indicating that nothing else requires highsync_info */
198 while (highsync_info->nr_procs_at_dispatch_level)
199 {
200 KeStallExecutionProcessor(1);
201 KeMemoryBarrier();
202 }
203 ExFreePoolWithTag(highsync_info, XENPCI_POOL_TAG);
204 FUNCTION_EXIT();
205 }