[NPFS_NEW]
[reactos.git] / reactos / drivers / filesystems / npfs_new / 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 = (PNP_WAIT_QUEUE)Irp->Tail.Overlay.DriverContext[0];
30
31 OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
32
33 WaitEntry = (PNP_WAIT_QUEUE_ENTRY)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 KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
45
46 if (WaitEntry)
47 {
48 ObfDereferenceObject(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 OldIrql = KfAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock);
69 Irp = WaitEntry->Irp;
70 if (Irp)
71 {
72 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
73 if (!IoSetCancelRoutine(Irp, NULL))
74 {
75 Irp->Tail.Overlay.DriverContext[1] = NULL;
76 Irp = NULL;
77 }
78 }
79 KfReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql);
80 if (Irp)
81 {
82 Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
83 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
84 }
85 ObfDereferenceObject(WaitEntry->FileObject);
86 ExFreePool(WaitEntry);
87 }
88
89 VOID
90 NTAPI
91 NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue)
92 {
93 InitializeListHead(&WaitQueue->WaitList);
94 KeInitializeSpinLock(&WaitQueue->WaitLock);
95 }
96
97 NTSTATUS
98 NTAPI
99 NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
100 IN PUNICODE_STRING PipeName,
101 IN NTSTATUS Status,
102 IN PLIST_ENTRY ListEntry)
103 {
104 UNICODE_STRING DestinationString;
105 KIRQL OldIrql;
106 PWCHAR Buffer;
107
108 Buffer = ExAllocatePoolWithTag(NonPagedPool, PipeName->Length, NPFS_WAIT_BLOCK_TAG);
109 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
110
111 RtlInitEmptyUnicodeString(&DestinationString, Buffer, PipeName->Length);
112 RtlUpcaseUnicodeString(&DestinationString, PipeName, FALSE);
113
114 OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
115
116 ASSERT(IsListEmpty(&WaitQueue->WaitList) == TRUE);
117
118 KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
119 ExFreePool(DestinationString.Buffer);
120 return STATUS_SUCCESS;
121 }
122
123 NTSTATUS
124 NTAPI
125 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
126 IN LARGE_INTEGER WaitTime,
127 IN PIRP Irp,
128 IN PUNICODE_STRING Name)
129 {
130 PIO_STACK_LOCATION IoStack;
131 KIRQL OldIrql;
132 NTSTATUS Status;
133 PNP_WAIT_QUEUE_ENTRY WaitEntry;
134 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
135 LARGE_INTEGER DueTime;
136 ULONG i;
137
138 IoStack = IoGetCurrentIrpStackLocation(Irp);
139
140 WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool, sizeof(*WaitEntry), NPFS_WRITE_BLOCK_TAG);
141 if (WaitEntry)
142 {
143 KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
144 KeInitializeTimer(&WaitEntry->Timer);
145
146 if (Name)
147 {
148 WaitEntry->String = *Name;
149 }
150 else
151 {
152 WaitEntry->String.Length = 0;
153 WaitEntry->String.Buffer = 0;
154 }
155
156 WaitEntry->WaitQueue = WaitQueue;
157 WaitEntry->Irp = Irp;
158
159 WaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
160 if (WaitBuffer->TimeoutSpecified)
161 {
162 DueTime = WaitBuffer->Timeout;
163 }
164 else
165 {
166 DueTime = WaitTime;
167 }
168
169 for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
170 {
171 WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
172 }
173
174 Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
175 Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
176 OldIrql = KfAcquireSpinLock(&WaitQueue->WaitLock);
177
178 IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
179
180 if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
181 {
182 Status = STATUS_CANCELLED;
183 }
184 else
185 {
186 InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
187
188 IoMarkIrpPending(Irp);
189 Status = STATUS_PENDING;
190
191 WaitEntry->FileObject = IoStack->FileObject;
192 ObfReferenceObject(WaitEntry->FileObject);
193
194 KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
195 WaitEntry = NULL;
196
197 }
198 KfReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
199 if (WaitEntry) ExFreePool(WaitEntry);
200 }
201 else
202 {
203 Status = STATUS_INSUFFICIENT_RESOURCES;
204 }
205 return Status;
206 }
207
208 /* EOF */