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
9 /* INCLUDES *******************************************************************/
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_WAITSUP)
16 /* FUNCTIONS ******************************************************************/
20 NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject
,
24 PNP_WAIT_QUEUE_ENTRY WaitEntry
;
25 PNP_WAIT_QUEUE WaitQueue
;
27 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
29 WaitQueue
= Irp
->Tail
.Overlay
.DriverContext
[0];
31 KeAcquireSpinLock(&WaitQueue
->WaitLock
, &OldIrql
);
33 WaitEntry
= Irp
->Tail
.Overlay
.DriverContext
[1];
36 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
37 if (!KeCancelTimer(&WaitEntry
->Timer
))
39 WaitEntry
->Irp
= NULL
;
44 KeReleaseSpinLock(&WaitQueue
->WaitLock
, OldIrql
);
48 ObDereferenceObject(WaitEntry
->FileObject
);
49 ExFreePool(WaitEntry
);
52 Irp
->IoStatus
.Information
= 0;
53 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
54 IoCompleteRequest(Irp
, IO_NAMED_PIPE_INCREMENT
);
59 NpTimerDispatch(IN PKDPC Dpc
,
66 PNP_WAIT_QUEUE_ENTRY WaitEntry
= Context
;
68 KeAcquireSpinLock(&WaitEntry
->WaitQueue
->WaitLock
, &OldIrql
);
73 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
75 if (!IoSetCancelRoutine(Irp
, NULL
))
77 Irp
->Tail
.Overlay
.DriverContext
[1] = NULL
;
82 KeReleaseSpinLock(&WaitEntry
->WaitQueue
->WaitLock
, OldIrql
);
86 Irp
->IoStatus
.Status
= STATUS_IO_TIMEOUT
;
87 IoCompleteRequest(Irp
, IO_NAMED_PIPE_INCREMENT
);
90 ObDereferenceObject(WaitEntry
->FileObject
);
91 ExFreePool(WaitEntry
);
96 NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue
)
98 InitializeListHead(&WaitQueue
->WaitList
);
99 KeInitializeSpinLock(&WaitQueue
->WaitLock
);
104 NpEqualUnicodeString(IN PCUNICODE_STRING String1
,
105 IN PCUNICODE_STRING String2
)
109 if (String1
->Length
!= String2
->Length
)
112 EqualLength
= RtlCompareMemory(String1
->Buffer
,
115 return EqualLength
== String1
->Length
;
120 NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue
,
121 IN PUNICODE_STRING PipePath
,
125 UNICODE_STRING PipePathUpper
;
128 PLIST_ENTRY NextEntry
;
129 PNP_WAIT_QUEUE_ENTRY WaitEntry
, Linkage
;
131 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer
;
132 UNICODE_STRING WaitName
, PipeName
;
136 Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
138 NPFS_WAIT_BLOCK_TAG
);
139 if (!Buffer
) return STATUS_INSUFFICIENT_RESOURCES
;
141 RtlInitEmptyUnicodeString(&PipePathUpper
, Buffer
, PipePath
->Length
);
142 RtlUpcaseUnicodeString(&PipePathUpper
, PipePath
, FALSE
);
144 KeAcquireSpinLock(&WaitQueue
->WaitLock
, &OldIrql
);
146 NextEntry
= WaitQueue
->WaitList
.Flink
;
147 while (NextEntry
!= &WaitQueue
->WaitList
)
149 WaitIrp
= CONTAINING_RECORD(NextEntry
, IRP
, Tail
.Overlay
.ListEntry
);
150 NextEntry
= NextEntry
->Flink
;
151 WaitEntry
= WaitIrp
->Tail
.Overlay
.DriverContext
[1];
153 if (WaitEntry
->AliasName
.Length
)
156 /* We have an alias. Use that for comparison */
157 WaitName
= WaitEntry
->AliasName
;
158 PipeName
= PipePathUpper
;
162 /* Use the name from the wait buffer to compare */
163 WaitBuffer
= WaitIrp
->AssociatedIrp
.SystemBuffer
;
164 WaitName
.Buffer
= WaitBuffer
->Name
;
165 WaitName
.Length
= WaitBuffer
->NameLength
;
166 WaitName
.MaximumLength
= WaitName
.Length
;
168 /* WaitName doesn't have a leading backslash,
169 * so skip the one in PipePathUpper for the comparison */
170 PipeName
.Buffer
= PipePathUpper
.Buffer
+ 1;
171 PipeName
.Length
= PipePathUpper
.Length
- sizeof(WCHAR
);
172 PipeName
.MaximumLength
= PipeName
.Length
;
175 /* Can't use RtlEqualUnicodeString with a spinlock held */
176 if (NpEqualUnicodeString(&WaitName
, &PipeName
))
178 /* Found a matching wait. Cancel it */
179 RemoveEntryList(&WaitIrp
->Tail
.Overlay
.ListEntry
);
180 if (KeCancelTimer(&WaitEntry
->Timer
))
182 WaitEntry
->WaitQueue
= (PNP_WAIT_QUEUE
)Linkage
;
187 WaitEntry
->Irp
= NULL
;
188 WaitIrp
->Tail
.Overlay
.DriverContext
[1] = NULL
;
191 if (IoSetCancelRoutine(WaitIrp
, NULL
))
193 WaitIrp
->IoStatus
.Information
= 0;
194 WaitIrp
->IoStatus
.Status
= Status
;
195 InsertTailList(List
, &WaitIrp
->Tail
.Overlay
.ListEntry
);
199 WaitIrp
->Tail
.Overlay
.DriverContext
[1] = NULL
;
204 KeReleaseSpinLock(&WaitQueue
->WaitLock
, OldIrql
);
206 ExFreePoolWithTag(Buffer
, NPFS_WAIT_BLOCK_TAG
);
211 Linkage
= (PNP_WAIT_QUEUE_ENTRY
)Linkage
->WaitQueue
;
212 ObDereferenceObject(WaitEntry
->FileObject
);
213 ExFreePool(WaitEntry
);
216 return STATUS_SUCCESS
;
221 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue
,
222 IN LARGE_INTEGER WaitTime
,
224 IN PUNICODE_STRING AliasName
)
226 PIO_STACK_LOCATION IoStack
;
229 PNP_WAIT_QUEUE_ENTRY WaitEntry
;
230 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer
;
231 LARGE_INTEGER DueTime
;
234 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
236 WaitEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
238 NPFS_WRITE_BLOCK_TAG
);
241 return STATUS_INSUFFICIENT_RESOURCES
;
244 KeInitializeDpc(&WaitEntry
->Dpc
, NpTimerDispatch
, WaitEntry
);
245 KeInitializeTimer(&WaitEntry
->Timer
);
249 WaitEntry
->AliasName
= *AliasName
;
253 WaitEntry
->AliasName
.Length
= 0;
254 WaitEntry
->AliasName
.Buffer
= NULL
;
257 WaitEntry
->WaitQueue
= WaitQueue
;
258 WaitEntry
->Irp
= Irp
;
260 WaitBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
261 if (WaitBuffer
->TimeoutSpecified
)
263 DueTime
= WaitBuffer
->Timeout
;
270 for (i
= 0; i
< WaitBuffer
->NameLength
/ sizeof(WCHAR
); i
++)
272 WaitBuffer
->Name
[i
] = RtlUpcaseUnicodeChar(WaitBuffer
->Name
[i
]);
275 Irp
->Tail
.Overlay
.DriverContext
[0] = WaitQueue
;
276 Irp
->Tail
.Overlay
.DriverContext
[1] = WaitEntry
;
278 KeAcquireSpinLock(&WaitQueue
->WaitLock
, &OldIrql
);
280 IoSetCancelRoutine(Irp
, NpCancelWaitQueueIrp
);
282 if (Irp
->Cancel
&& IoSetCancelRoutine(Irp
, NULL
))
284 Status
= STATUS_CANCELLED
;
288 InsertTailList(&WaitQueue
->WaitList
, &Irp
->Tail
.Overlay
.ListEntry
);
290 IoMarkIrpPending(Irp
);
291 Status
= STATUS_PENDING
;
293 WaitEntry
->FileObject
= IoStack
->FileObject
;
294 ObReferenceObject(WaitEntry
->FileObject
);
296 KeSetTimer(&WaitEntry
->Timer
, DueTime
, &WaitEntry
->Dpc
);
300 KeReleaseSpinLock(&WaitQueue
->WaitLock
, OldIrql
);
301 if (WaitEntry
) ExFreePool(WaitEntry
);