Catched STDCALL IRP (*CompletionRoutine)() and (*CancelRoutine)().
[reactos.git] / ntoskrnl / io / irp.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/irp.c
6  * PURPOSE:         Handle IRPs
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY: 
9  *                  24/05/98: Created 
10  */
11
12 /* NOTES *******************************************************************
13  * 
14  * Layout of an IRP 
15  * 
16  *             ################
17  *             #    Headers   #
18  *             ################
19  *             #              #
20  *             #   Variable   #
21  *             # length list  #
22  *             # of io stack  #
23  *             #  locations   #
24  *             #              #
25  *             ################
26  * 
27  * 
28  * 
29  */
30
31 /* INCLUDES ****************************************************************/
32
33 #include <ddk/ntddk.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* GLOBALS *******************************************************************/
42
43 #define TAG_IRP     TAG('I', 'R', 'P', ' ')
44
45
46 /* FUNCTIONS ****************************************************************/
47
48
49 /*
50  * @implemented
51  */
52 VOID STDCALL
53 IoFreeIrp(PIRP Irp)
54 /*
55  * FUNCTION: Releases a caller allocated irp
56  * ARGUMENTS:
57  *      Irp = Irp to free
58  */
59 {
60   ExFreePool(Irp);
61 }
62
63 #ifndef LIBCAPTIVE
64
65 /*
66  * @unimplemented
67  */
68 PIRP STDCALL
69 IoMakeAssociatedIrp(PIRP Irp,
70                     CCHAR StackSize)
71 /*
72  * FUNCTION: Allocates and initializes an irp to associated with a master irp
73  * ARGUMENTS:
74  *       Irp = Master irp
75  *       StackSize = Number of stack locations to be allocated in the irp
76  * RETURNS: The irp allocated
77  */
78 {
79   PIRP AssocIrp;
80   
81   AssocIrp = IoAllocateIrp(StackSize,FALSE);
82   UNIMPLEMENTED;
83   return NULL;
84 }
85
86 #endif /* LIBCAPTIVE */
87
88 /*
89  * @implemented
90  */
91 VOID STDCALL
92 IoInitializeIrp(PIRP Irp,
93                 USHORT PacketSize,
94                 CCHAR StackSize)
95 /*
96  * FUNCTION: Initalizes an irp allocated by the caller
97  * ARGUMENTS:
98  *          Irp = IRP to initalize
99  *          PacketSize = Size in bytes of the IRP
100  *          StackSize = Number of stack locations in the IRP
101  */
102 {
103   assert(Irp != NULL);
104
105   memset(Irp, 0, PacketSize);
106   Irp->Type = IO_TYPE_IRP;
107   Irp->Size = PacketSize;
108   Irp->StackCount = StackSize;
109   Irp->CurrentLocation = StackSize;
110   Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
111 }
112
113
114 /*
115  * @implemented
116  */
117 NTSTATUS FASTCALL
118 IofCallDriver(PDEVICE_OBJECT DeviceObject,
119               PIRP Irp)
120 /*
121   * FUNCTION: Sends an IRP to the next lower driver
122  */
123 {
124   PDRIVER_OBJECT DriverObject;
125   PIO_STACK_LOCATION Param;
126   
127   DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
128   
129   assert(Irp);
130   assert(DeviceObject);
131
132   DriverObject = DeviceObject->DriverObject;
133
134   assert(DriverObject);
135
136   IoSetNextIrpStackLocation(Irp);
137   Param = IoGetCurrentIrpStackLocation(Irp);
138
139   DPRINT("IrpSp 0x%X\n", Param);
140   
141   Param->DeviceObject = DeviceObject;
142
143   DPRINT("MajorFunction %d\n", Param->MajorFunction);
144   DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
145     DriverObject->MajorFunction[Param->MajorFunction]);
146
147   if (!DriverObject->MajorFunction[Param->MajorFunction])
148     {
149       if (Param->MajorFunction==IRP_MJ_FLUSH_BUFFERS)
150         {
151           ObDereferenceObject(Param->FileObject);
152           return STATUS_SUCCESS;
153         }
154       KeBugCheck(0);
155     }
156
157 #ifndef LIBCAPTIVE
158   return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
159 #else /* !LIBCAPTIVE */
160         return (NTSTATUS)captive_stdcall_call_8(
161                         (CaptiveStdCallFunc8)DriverObject->MajorFunction[Param->MajorFunction],
162                         DeviceObject,
163                         Irp);
164 #endif /* LIBCAPTIVE */
165 }
166
167
168 /*
169  * @implemented
170  */
171 NTSTATUS
172 STDCALL
173 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
174 {
175   return(IofCallDriver(DeviceObject,
176                        Irp));
177 }
178
179
180 /*
181  * @implemented
182  */
183 PIRP STDCALL
184 IoAllocateIrp(CCHAR StackSize,
185               BOOLEAN ChargeQuota)
186 /*
187  * FUNCTION: Allocates an IRP
188  * ARGUMENTS:
189  *          StackSize = the size of the stack required for the irp
190  *          ChargeQuota = Charge allocation to current threads quota
191  * RETURNS: Irp allocated
192  */
193 {
194   PIRP Irp;
195
196 #if 0
197   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
198            StackSize,
199            ChargeQuota);
200   KeDumpStackFrames(0,8);
201 #endif
202   
203   if (ChargeQuota)
204     {
205 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
206       Irp = ExAllocatePoolWithTag(NonPagedPool,
207                                   IoSizeOfIrp(StackSize),
208                                   TAG_IRP);
209     }
210   else
211     {
212       Irp = ExAllocatePoolWithTag(NonPagedPool,
213                                   IoSizeOfIrp(StackSize),
214                                   TAG_IRP);
215     }
216
217   if (Irp==NULL)
218     {
219       return(NULL);
220     }
221
222   IoInitializeIrp(Irp,
223                   IoSizeOfIrp(StackSize),
224                   StackSize);
225
226 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
227
228   return(Irp);
229 }
230
231
232 #ifdef LIBCAPTIVE
233 /* file-scope of libcaptive/io/irp.c: */
234 extern void IofCompleteRequest_register_APC(PFILE_OBJECT OriginalFileObject,PIRP Irp,CCHAR PriorityBoost);
235 #endif /* LIBCAPTIVE */
236
237 /*
238  * @implemented
239  */
240 VOID FASTCALL
241 IofCompleteRequest(PIRP Irp,
242          CCHAR PriorityBoost)
243 /*
244  * FUNCTION: Indicates the caller has finished all processing for a given
245  * I/O request and is returning the given IRP to the I/O manager
246  * ARGUMENTS:
247  *         Irp = Irp to be cancelled
248  *         PriorityBoost = Increment by which to boost the priority of the
249  *                         thread making the request
250  */
251 {
252    ULONG             i;
253    NTSTATUS          Status;
254    PDEVICE_OBJECT    DeviceObject;
255    PFILE_OBJECT      OriginalFileObject;
256
257    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
258       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
259
260    assert(Irp->CancelRoutine == NULL);
261    assert(Irp->IoStatus.Status != STATUS_PENDING);
262
263    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
264    {
265       Irp->PendingReturned = TRUE;
266    }
267
268    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
269    {
270       /*
271       Completion routines expect the current irp stack location to be the same as when
272       IoSetCompletionRoutine was called to set them. A side effect is that completion
273       routines set by highest level drivers without their own stack location will receive
274       an invalid current stack location (at least it should be considered as invalid).
275       Since the DeviceObject argument passed is taken from the current stack, this value
276       is also invalid (NULL).
277       */
278       if (Irp->CurrentLocation < Irp->StackCount - 1)
279       {
280          IoSetPreviousIrpStackLocation(Irp);
281          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
282       }
283       else
284       {
285          DeviceObject = NULL;
286       }
287
288       if (Irp->Stack[i].CompletionRoutine != NULL &&
289          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
290          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
291          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
292       {
293 #ifndef LIBCAPTIVE
294          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
295                                                   Irp,
296                                                   Irp->Stack[i].Context);
297 #else /* !LIBCAPTIVE */
298          Status = (NTSTATUS)captive_stdcall_call_12((CaptiveStdCallFunc12)Irp->Stack[i].CompletionRoutine,
299                                                     DeviceObject,
300                                                     Irp,
301                                                     Irp->Stack[i].Context);
302 #endif /* LIBCAPTIVE */
303
304          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
305          {
306             if (Irp->UserIosb)
307                {
308                   *Irp->UserIosb=Irp->IoStatus;
309                }
310             return;
311          }
312       }
313    
314       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
315       {
316          Irp->PendingReturned = TRUE;
317       }
318    }
319
320    //Windows NT File System Internals, page 154
321    OriginalFileObject = Irp->Tail.Overlay.OriginalFileObject;
322
323    if (Irp->PendingReturned)
324    {
325 #ifndef LIBCAPTIVE
326       BOOLEAN bStatus;
327 #endif /* LIBCAPTIVE */
328
329 #ifdef LIBCAPTIVE
330       /* FIXME: Why the hell should we bother with some damned APCs?!?
331        * Call it directly below!
332        */
333       DPRINT("IofCompleteRequest() dispatching APC: using g_idle_add_full()\n");
334       IofCompleteRequest_register_APC(OriginalFileObject,Irp,PriorityBoost);
335 #else /* !LIBCAPTIVE */
336       DPRINT("Dispatching APC\n");
337       KeInitializeApc(  &Irp->Tail.Apc,
338                         &Irp->Tail.Overlay.Thread->Tcb,
339                         OriginalApcEnvironment,
340                         IoSecondStageCompletion,
341                         NULL,
342                         (PKNORMAL_ROUTINE) NULL,
343                         KernelMode,
344                         OriginalFileObject);
345       
346       bStatus = KeInsertQueueApc(&Irp->Tail.Apc,
347                                  (PVOID)Irp,
348                                  (PVOID)(ULONG)PriorityBoost,
349                                  PriorityBoost);
350
351       if (bStatus == FALSE)
352       {
353          DPRINT1("Error queueing APC for thread. Thread has probably exited.\n");
354       }
355 #endif /* !LIBCAPTIVE */
356
357       DPRINT("Finished dispatching APC\n");
358    }
359    else
360    {
361       DPRINT("Calling IoSecondStageCompletion routine directly\n");
362       IoSecondStageCompletion(NULL,NULL,(PVOID)&OriginalFileObject,(PVOID) &Irp,(PVOID) &PriorityBoost);
363       DPRINT("Finished completition routine\n");
364    }
365
366 }
367
368
369 /*
370  * @implemented
371  */
372 VOID STDCALL
373 IoCompleteRequest(PIRP Irp,
374                   CCHAR PriorityBoost)
375 {
376   IofCompleteRequest(Irp,
377                      PriorityBoost);
378 }
379
380
381 /**********************************************************************
382  * NAME                                                 EXPORTED
383  *      IoIsOperationSynchronous@4
384  *
385  * DESCRIPTION
386  *      Check if the I/O operation associated with the given IRP
387  *      is synchronous.
388  *
389  * ARGUMENTS
390  *      Irp     Packet to check.
391  *
392  * RETURN VALUE
393  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
394  *
395  * @implemented
396  */
397 BOOLEAN STDCALL
398 IoIsOperationSynchronous(IN PIRP Irp)
399 {
400    PFILE_OBJECT FileObject = NULL;
401    ULONG Flags;
402
403   /* Check the FILE_OBJECT's flags first. */
404   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
405   if (FileObject == NULL)
406     KeBugCheck(0);
407   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
408     {
409       /* Check IRP's flags. */
410       Flags = Irp->Flags;
411       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
412         {
413 #ifdef LIBCAPTIVE
414           /* libcaptive is fully single-thread/single-process synchronous model. */
415           return TRUE;
416 #endif /* LIBCAPTIVE */
417           return(FALSE);
418         }
419     }
420   
421    if (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO)
422    {
423       return TRUE;
424    }
425
426    if (Irp->Flags & IRP_PAGING_IO)
427    {
428 #ifdef LIBCAPTIVE
429       /* libcaptive is fully single-thread/single-process synchronous model. */
430       return TRUE;
431 #endif /* LIBCAPTIVE */
432       return FALSE;
433    }
434
435    //NOTE: Windows 2000 crash if IoStack->FileObject == NULL, so I guess we should too;-)
436    if (Irp->Flags & IRP_SYNCHRONOUS_API || FileObject->Flags & FO_SYNCHRONOUS_IO)
437    {
438       return TRUE;
439    }
440
441    /* Otherwise, it is an asynchronous operation. */
442 #ifdef LIBCAPTIVE
443   /* libcaptive is fully single-thread/single-process synchronous model. */
444   return TRUE;
445 #endif /* LIBCAPTIVE */
446    return FALSE;
447 }
448
449 #ifndef LIBCAPTIVE
450
451 /*
452  * @unimplemented
453  */
454 VOID STDCALL
455 IoEnqueueIrp(IN PIRP Irp)
456 {
457   UNIMPLEMENTED;
458 }
459
460 #endif /* LIBCAPTIVE */
461
462 /*
463  * @implemented
464  */
465 VOID STDCALL
466 IoSetTopLevelIrp(IN PIRP Irp)
467 {
468   PETHREAD Thread;
469
470   Thread = PsGetCurrentThread();
471   Thread->TopLevelIrp->TopLevelIrp = Irp;
472 }
473
474
475 /*
476  * @implemented
477  */
478 PIRP STDCALL
479 IoGetTopLevelIrp(VOID)
480 {
481   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
482 }
483
484 #ifndef LIBCAPTIVE
485
486 /*
487  * @unimplemented
488  */
489 VOID STDCALL
490 IoQueueThreadIrp(IN PIRP Irp)
491 {
492   UNIMPLEMENTED;
493 }
494
495 #endif /* LIBCAPTIVE */
496
497 /* EOF */