Sync with trunk r63887.
[reactos.git] / drivers / filesystems / npfs / waitsup.c
1 /*
2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/waitsup.c
5 * PURPOSE: Pipes Waiting Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "npfs.h"
12
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_WAITSUP)
15
16 /* FUNCTIONS ******************************************************************/
17
18 VOID
19 NTAPI
20 NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject,
21 IN PIRP Irp)
22 {
23 KIRQL OldIrql;
24 PNP_WAIT_QUEUE_ENTRY WaitEntry;
25 PNP_WAIT_QUEUE WaitQueue;
26
27 IoReleaseCancelSpinLock(Irp->CancelIrql);
28
29 WaitQueue = Irp->Tail.Overlay.DriverContext[0];
30
31 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
32
33 WaitEntry = Irp->Tail.Overlay.DriverContext[1];
34 if (WaitEntry)
35 {
36 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
37 if (!KeCancelTimer(&WaitEntry->Timer))
38 {
39 WaitEntry->Irp = NULL;
40 WaitEntry = NULL;
41 }
42 }
43
44 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
45
46 if (WaitEntry)
47 {
48 ObDereferenceObject(WaitEntry->FileObject);
49 ExFreePool(WaitEntry);
50 }
51
52 Irp->IoStatus.Information = 0;
53 Irp->IoStatus.Status = STATUS_CANCELLED;
54 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
55 }
56
57 VOID
58 NTAPI
59 NpTimerDispatch(IN PKDPC Dpc,
60 IN PVOID Context,
61 IN PVOID Argument1,
62 IN PVOID Argument2)
63 {
64 PIRP Irp;
65 KIRQL OldIrql;
66 PNP_WAIT_QUEUE_ENTRY WaitEntry = Context;
67
68 KeAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock, &OldIrql);
69
70 Irp = WaitEntry->Irp;
71 if (Irp)
72 {
73 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
74
75 if (!IoSetCancelRoutine(Irp, NULL))
76 {
77 Irp->Tail.Overlay.DriverContext[1] = NULL;
78 Irp = NULL;
79 }
80 }
81
82 KeReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql);
83
84 if (Irp)
85 {
86 Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
87 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
88 }
89
90 ObDereferenceObject(WaitEntry->FileObject);
91 ExFreePool(WaitEntry);
92 }
93
94 VOID
95 NTAPI
96 NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue)
97 {
98 InitializeListHead(&WaitQueue->WaitList);
99 KeInitializeSpinLock(&WaitQueue->WaitLock);
100 }
101
102 NTSTATUS
103 NTAPI
104 NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
105 IN PUNICODE_STRING PipePath,
106 IN NTSTATUS Status,
107 IN PLIST_ENTRY List)
108 {
109 UNICODE_STRING PipePathUpper;
110 KIRQL OldIrql;
111 PWCHAR Buffer;
112 PLIST_ENTRY NextEntry;
113 PNP_WAIT_QUEUE_ENTRY WaitEntry, Linkage;
114 PIRP WaitIrp;
115 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
116 UNICODE_STRING WaitName, PipeName;
117
118 Linkage = NULL;
119
120 Buffer = ExAllocatePoolWithTag(NonPagedPool,
121 PipePath->Length,
122 NPFS_WAIT_BLOCK_TAG);
123 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
124
125 RtlInitEmptyUnicodeString(&PipePathUpper, Buffer, PipePath->Length);
126 RtlUpcaseUnicodeString(&PipePathUpper, PipePath, FALSE);
127
128 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
129
130 NextEntry = WaitQueue->WaitList.Flink;
131 while (NextEntry != &WaitQueue->WaitList)
132 {
133 WaitIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
134 NextEntry = NextEntry->Flink;
135 WaitEntry = WaitIrp->Tail.Overlay.DriverContext[1];
136
137 if (WaitEntry->AliasName.Length)
138 {
139 ASSERT(FALSE);
140 /* We have an alias. Use that for comparison */
141 WaitName = WaitEntry->AliasName;
142 PipeName = PipePathUpper;
143 }
144 else
145 {
146 /* Use the name from the wait buffer to compare */
147 WaitBuffer = WaitIrp->AssociatedIrp.SystemBuffer;
148 WaitName.Buffer = WaitBuffer->Name;
149 WaitName.Length = WaitBuffer->NameLength;
150 WaitName.MaximumLength = WaitName.Length;
151
152 /* WaitName doesn't have a leading backslash,
153 * so skip the one in PipePathUpper for the comparison */
154 PipeName.Buffer = PipePathUpper.Buffer + 1;
155 PipeName.Length = PipePathUpper.Length - sizeof(WCHAR);
156 PipeName.MaximumLength = PipeName.Length;
157 }
158
159 if (RtlEqualUnicodeString(&WaitName, &PipeName, FALSE))
160 {
161 /* Found a matching wait. Cancel it */
162 RemoveEntryList(&WaitIrp->Tail.Overlay.ListEntry);
163 if (KeCancelTimer(&WaitEntry->Timer))
164 {
165 WaitEntry->WaitQueue = (PNP_WAIT_QUEUE)Linkage;
166 Linkage = WaitEntry;
167 }
168 else
169 {
170 WaitEntry->Irp = NULL;
171 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
172 }
173
174 if (IoSetCancelRoutine(WaitIrp, NULL))
175 {
176 WaitIrp->IoStatus.Information = 0;
177 WaitIrp->IoStatus.Status = Status;
178 InsertTailList(List, &WaitIrp->Tail.Overlay.ListEntry);
179 }
180 else
181 {
182 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
183 }
184 }
185 }
186
187 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
188
189 ExFreePoolWithTag(Buffer, NPFS_WAIT_BLOCK_TAG);
190
191 while (Linkage)
192 {
193 WaitEntry = Linkage;
194 Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue;
195 ObDereferenceObject(WaitEntry->FileObject);
196 ExFreePool(WaitEntry);
197 }
198
199 return STATUS_SUCCESS;
200 }
201
202 NTSTATUS
203 NTAPI
204 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
205 IN LARGE_INTEGER WaitTime,
206 IN PIRP Irp,
207 IN PUNICODE_STRING AliasName)
208 {
209 PIO_STACK_LOCATION IoStack;
210 KIRQL OldIrql;
211 NTSTATUS Status;
212 PNP_WAIT_QUEUE_ENTRY WaitEntry;
213 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
214 LARGE_INTEGER DueTime;
215 ULONG i;
216
217 IoStack = IoGetCurrentIrpStackLocation(Irp);
218
219 WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
220 sizeof(*WaitEntry),
221 NPFS_WRITE_BLOCK_TAG);
222 if (!WaitEntry)
223 {
224 return STATUS_INSUFFICIENT_RESOURCES;
225 }
226
227 KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
228 KeInitializeTimer(&WaitEntry->Timer);
229
230 if (AliasName)
231 {
232 WaitEntry->AliasName = *AliasName;
233 }
234 else
235 {
236 WaitEntry->AliasName.Length = 0;
237 WaitEntry->AliasName.Buffer = NULL;
238 }
239
240 WaitEntry->WaitQueue = WaitQueue;
241 WaitEntry->Irp = Irp;
242
243 WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
244 if (WaitBuffer->TimeoutSpecified)
245 {
246 DueTime = WaitBuffer->Timeout;
247 }
248 else
249 {
250 DueTime = WaitTime;
251 }
252
253 for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
254 {
255 WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
256 }
257
258 Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
259 Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
260
261 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
262
263 IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
264
265 if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
266 {
267 Status = STATUS_CANCELLED;
268 }
269 else
270 {
271 InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
272
273 IoMarkIrpPending(Irp);
274 Status = STATUS_PENDING;
275
276 WaitEntry->FileObject = IoStack->FileObject;
277 ObReferenceObject(WaitEntry->FileObject);
278
279 KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
280 WaitEntry = NULL;
281 }
282
283 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
284 if (WaitEntry) ExFreePool(WaitEntry);
285
286 return Status;
287 }
288
289 /* EOF */