ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

iocomp.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/io/iocomp.c
00005  * PURPOSE:         I/O Wrappers (called Completion Ports) for Kernel Queues
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  *                  Thomas Weidenmueller (w3seek@reactos.org)
00008  */
00009 
00010 /* INCLUDES *****************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 POBJECT_TYPE IoCompletionType;
00017 
00018 GENERAL_LOOKASIDE IoCompletionPacketLookaside;
00019 
00020 GENERIC_MAPPING IopCompletionMapping =
00021 {
00022     STANDARD_RIGHTS_READ    | IO_COMPLETION_QUERY_STATE,
00023     STANDARD_RIGHTS_WRITE   | IO_COMPLETION_MODIFY_STATE,
00024     STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
00025     IO_COMPLETION_ALL_ACCESS
00026 };
00027 
00028 static const INFORMATION_CLASS_INFO IoCompletionInfoClass[] =
00029 {
00030      /* IoCompletionBasicInformation */
00031     ICI_SQ_SAME(sizeof(IO_COMPLETION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
00032 };
00033 
00034 /* PRIVATE FUNCTIONS *********************************************************/
00035 
00036 NTSTATUS
00037 NTAPI
00038 IopUnloadSafeCompletion(IN PDEVICE_OBJECT DeviceObject,
00039                         IN PIRP Irp,
00040                         IN PVOID Context)
00041 {
00042     NTSTATUS Status;
00043     PIO_UNLOAD_SAFE_COMPLETION_CONTEXT UnsafeContext = Context;
00044 
00045     /* Reference the device object */
00046     ObReferenceObject(UnsafeContext->DeviceObject);
00047 
00048     /* Call the completion routine */
00049     Status= UnsafeContext->CompletionRoutine(DeviceObject,
00050                                              Irp,
00051                                              UnsafeContext->Context);
00052 
00053     /* Dereference the device object */
00054     ObDereferenceObject(UnsafeContext->DeviceObject);
00055 
00056     /* Free our context */
00057     ExFreePool(UnsafeContext);
00058     return Status;
00059 }
00060 
00061 VOID
00062 NTAPI
00063 IopFreeMiniPacket(PIOP_MINI_COMPLETION_PACKET Packet)
00064 {
00065     PKPRCB Prcb = KeGetCurrentPrcb();
00066     PNPAGED_LOOKASIDE_LIST List;
00067 
00068     /* Use the P List */
00069     List = (PNPAGED_LOOKASIDE_LIST)Prcb->
00070             PPLookasideList[LookasideCompletionList].P;
00071     List->L.TotalFrees++;
00072 
00073     /* Check if the Free was within the Depth or not */
00074     if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
00075     {
00076         /* Let the balancer know */
00077         List->L.FreeMisses++;
00078 
00079         /* Use the L List */
00080         List = (PNPAGED_LOOKASIDE_LIST)Prcb->
00081                 PPLookasideList[LookasideCompletionList].L;
00082         List->L.TotalFrees++;
00083 
00084         /* Check if the Free was within the Depth or not */
00085         if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
00086         {
00087             /* All lists failed, use the pool */
00088             List->L.FreeMisses++;
00089             ExFreePool(Packet);
00090             return;
00091         }
00092     }
00093 
00094     /* The free was within dhe Depth */
00095     InterlockedPushEntrySList(&List->L.ListHead, (PSLIST_ENTRY)Packet);
00096 }
00097 
00098 VOID
00099 NTAPI
00100 IopDeleteIoCompletion(PVOID ObjectBody)
00101 {
00102     PKQUEUE Queue = ObjectBody;
00103     PLIST_ENTRY FirstEntry;
00104     PLIST_ENTRY CurrentEntry;
00105     PIRP Irp;
00106     PIOP_MINI_COMPLETION_PACKET Packet;
00107 
00108     /* Rundown the Queue */
00109     FirstEntry = KeRundownQueue(Queue);
00110     if (FirstEntry)
00111     {
00112         /* Loop the packets */
00113         CurrentEntry = FirstEntry;
00114         do
00115         {
00116             /* Get the Packet */
00117             Packet = CONTAINING_RECORD(CurrentEntry,
00118                                        IOP_MINI_COMPLETION_PACKET,
00119                                        ListEntry);
00120 
00121             /* Go to next Entry */
00122             CurrentEntry = CurrentEntry->Flink;
00123 
00124             /* Check if it's part of an IRP, or a separate packet */
00125             if (Packet->PacketType == IopCompletionPacketIrp)
00126             {
00127                 /* Get the IRP and free it */
00128                 Irp = CONTAINING_RECORD(Packet, IRP, Tail.Overlay.ListEntry);
00129                 IoFreeIrp(Irp);
00130             }
00131             else
00132             {
00133                 /* Use common routine */
00134                 IopFreeMiniPacket(Packet);
00135             }
00136         } while (FirstEntry != CurrentEntry);
00137     }
00138 }
00139 
00140 /* PUBLIC FUNCTIONS **********************************************************/
00141 
00142 /*
00143  * @implemented
00144  */
00145 NTSTATUS
00146 NTAPI
00147 IoSetIoCompletion(IN PVOID IoCompletion,
00148                   IN PVOID KeyContext,
00149                   IN PVOID ApcContext,
00150                   IN NTSTATUS IoStatus,
00151                   IN ULONG_PTR IoStatusInformation,
00152                   IN BOOLEAN Quota)
00153 {
00154     PKQUEUE Queue = (PKQUEUE)IoCompletion;
00155     PNPAGED_LOOKASIDE_LIST List;
00156     PKPRCB Prcb = KeGetCurrentPrcb();
00157     PIOP_MINI_COMPLETION_PACKET Packet;
00158 
00159     /* Get the P List */
00160     List = (PNPAGED_LOOKASIDE_LIST)Prcb->
00161             PPLookasideList[LookasideCompletionList].P;
00162 
00163     /* Try to allocate the Packet */
00164     List->L.TotalAllocates++;
00165     Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
00166 
00167     /* Check if that failed, use the L list if it did */
00168     if (!Packet)
00169     {
00170         /* Let the balancer know */
00171         List->L.AllocateMisses++;
00172 
00173         /* Get L List */
00174         List = (PNPAGED_LOOKASIDE_LIST)Prcb->
00175                 PPLookasideList[LookasideCompletionList].L;
00176 
00177         /* Try to allocate the Packet */
00178         List->L.TotalAllocates++;
00179         Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
00180     }
00181 
00182     /* Still failed, use pool */
00183     if (!Packet)
00184     {
00185         /* Let the balancer know */
00186         List->L.AllocateMisses++;
00187 
00188         /* Allocate from Nonpaged Pool */
00189         Packet = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Packet), IOC_TAG);
00190     }
00191 
00192     /* Make sure we have one by now... */
00193     if (Packet)
00194     {
00195         /* Set up the Packet */
00196         Packet->PacketType = IopCompletionPacketMini;
00197         Packet->KeyContext = KeyContext;
00198         Packet->ApcContext = ApcContext;
00199         Packet->IoStatus = IoStatus;
00200         Packet->IoStatusInformation = IoStatusInformation;
00201 
00202         /* Insert the Queue */
00203         KeInsertQueue(Queue, &Packet->ListEntry);
00204     }
00205     else
00206     {
00207         /* Out of memory, fail */
00208         return STATUS_INSUFFICIENT_RESOURCES;
00209     }
00210 
00211     /* Return Success */
00212     return STATUS_SUCCESS;
00213 }
00214 
00215 /*
00216  * @implemented
00217  */
00218 NTSTATUS
00219 NTAPI
00220 IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject,
00221                          IN PIRP Irp,
00222                          IN PIO_COMPLETION_ROUTINE CompletionRoutine,
00223                          IN PVOID Context,
00224                          IN BOOLEAN InvokeOnSuccess,
00225                          IN BOOLEAN InvokeOnError,
00226                          IN BOOLEAN InvokeOnCancel)
00227 {
00228     PIO_UNLOAD_SAFE_COMPLETION_CONTEXT UnloadContext;
00229 
00230     /* Allocate the context */
00231     UnloadContext = ExAllocatePoolWithTag(NonPagedPool,
00232                                           sizeof(*UnloadContext),
00233                                           'sUoI');
00234     if (!UnloadContext) return STATUS_INSUFFICIENT_RESOURCES;
00235 
00236     /* Set up the context */
00237     UnloadContext->DeviceObject = DeviceObject;
00238     UnloadContext->Context = Context;
00239     UnloadContext->CompletionRoutine = CompletionRoutine;
00240 
00241     /* Now set the completion routine */
00242     IoSetCompletionRoutine(Irp,
00243                            IopUnloadSafeCompletion,
00244                            UnloadContext,
00245                            InvokeOnSuccess,
00246                            InvokeOnError,
00247                            InvokeOnCancel);
00248     return STATUS_SUCCESS;
00249 }
00250 
00251 NTSTATUS
00252 NTAPI
00253 NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle,
00254                      IN ACCESS_MASK DesiredAccess,
00255                      IN POBJECT_ATTRIBUTES ObjectAttributes,
00256                      IN ULONG NumberOfConcurrentThreads)
00257 {
00258     PKQUEUE Queue;
00259     HANDLE hIoCompletionHandle;
00260     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00261     NTSTATUS Status;
00262     PAGED_CODE();
00263 
00264     /* Check if this was a user-mode call */
00265     if (PreviousMode != KernelMode)
00266     {
00267         /* Wrap probing in SEH */
00268         _SEH2_TRY
00269         {
00270             /* Probe the handle */
00271             ProbeForWriteHandle(IoCompletionHandle);
00272         }
00273         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00274         {
00275             /* Return the exception code */
00276             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00277         }
00278         _SEH2_END;
00279     }
00280 
00281     /* Create the Object */
00282     Status = ObCreateObject(PreviousMode,
00283                             IoCompletionType,
00284                             ObjectAttributes,
00285                             PreviousMode,
00286                             NULL,
00287                             sizeof(KQUEUE),
00288                             0,
00289                             0,
00290                             (PVOID*)&Queue);
00291     if (NT_SUCCESS(Status))
00292     {
00293         /* Initialize the Queue */
00294         KeInitializeQueue(Queue, NumberOfConcurrentThreads);
00295 
00296         /* Insert it */
00297         Status = ObInsertObject(Queue,
00298                                 NULL,
00299                                 DesiredAccess,
00300                                 0,
00301                                 NULL,
00302                                 &hIoCompletionHandle);
00303         if (NT_SUCCESS(Status))
00304         {
00305             /* Protect writing the handle in SEH */
00306             _SEH2_TRY
00307             {
00308                 /* Write the handle back */
00309                 *IoCompletionHandle = hIoCompletionHandle;
00310             }
00311             _SEH2_EXCEPT(ExSystemExceptionFilter())
00312             {
00313                 /* Get the exception code */
00314                 Status = _SEH2_GetExceptionCode();
00315             }
00316             _SEH2_END;
00317         }
00318    }
00319 
00320    /* Return Status */
00321    return Status;
00322 }
00323 
00324 NTSTATUS
00325 NTAPI
00326 NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle,
00327                    IN ACCESS_MASK DesiredAccess,
00328                    IN POBJECT_ATTRIBUTES ObjectAttributes)
00329 {
00330     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00331     HANDLE hIoCompletionHandle;
00332     NTSTATUS Status;
00333     PAGED_CODE();
00334 
00335     /* Check if this was a user-mode call */
00336     if (PreviousMode != KernelMode)
00337     {
00338         /* Wrap probing in SEH */
00339         _SEH2_TRY
00340         {
00341             /* Probe the handle */
00342             ProbeForWriteHandle(IoCompletionHandle);
00343         }
00344         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00345         {
00346             /* Return the exception code */
00347             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00348         }
00349         _SEH2_END;
00350     }
00351 
00352     /* Open the Object */
00353     Status = ObOpenObjectByName(ObjectAttributes,
00354                                 IoCompletionType,
00355                                 PreviousMode,
00356                                 NULL,
00357                                 DesiredAccess,
00358                                 NULL,
00359                                 &hIoCompletionHandle);
00360     if (NT_SUCCESS(Status))
00361     {
00362         /* Protect writing the handle in SEH */
00363         _SEH2_TRY
00364         {
00365             /* Write the handle back */
00366             *IoCompletionHandle = hIoCompletionHandle;
00367         }
00368         _SEH2_EXCEPT(ExSystemExceptionFilter())
00369         {
00370             /* Get the exception code */
00371             Status = _SEH2_GetExceptionCode();
00372         }
00373         _SEH2_END;
00374     }
00375 
00376     /* Return Status */
00377     return Status;
00378 }
00379 
00380 NTSTATUS
00381 NTAPI
00382 NtQueryIoCompletion(IN  HANDLE IoCompletionHandle,
00383                     IN  IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
00384                     OUT PVOID IoCompletionInformation,
00385                     IN  ULONG IoCompletionInformationLength,
00386                     OUT PULONG ResultLength OPTIONAL)
00387 {
00388     PKQUEUE Queue;
00389     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00390     NTSTATUS Status;
00391     PAGED_CODE();
00392 
00393     /* Check buffers and parameters */
00394     Status = DefaultQueryInfoBufferCheck(IoCompletionInformationClass,
00395                                          IoCompletionInfoClass,
00396                                          sizeof(IoCompletionInfoClass) /
00397                                          sizeof(IoCompletionInfoClass[0]),
00398                                          IoCompletionInformation,
00399                                          IoCompletionInformationLength,
00400                                          ResultLength,
00401                                          NULL,
00402                                          PreviousMode);
00403     if (!NT_SUCCESS(Status)) return Status;
00404 
00405     /* Get the Object */
00406     Status = ObReferenceObjectByHandle(IoCompletionHandle,
00407                                        IO_COMPLETION_QUERY_STATE,
00408                                        IoCompletionType,
00409                                        PreviousMode,
00410                                        (PVOID*)&Queue,
00411                                        NULL);
00412     if (NT_SUCCESS(Status))
00413     {
00414         /* Protect write in SEH */
00415         _SEH2_TRY
00416         {
00417             /* Return Info */
00418             ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->
00419                 Depth = KeReadStateQueue(Queue);
00420 
00421             /* Return Result Length if needed */
00422             if (ResultLength)
00423             {
00424                 *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
00425             }
00426         }
00427         _SEH2_EXCEPT(ExSystemExceptionFilter())
00428         {
00429             /* Get exception code */
00430             Status = _SEH2_GetExceptionCode();
00431         }
00432         _SEH2_END;
00433 
00434         /* Dereference the queue */
00435         ObDereferenceObject(Queue);
00436     }
00437 
00438     /* Return Status */
00439     return Status;
00440 }
00441 
00442 NTSTATUS
00443 NTAPI
00444 NtRemoveIoCompletion(IN HANDLE IoCompletionHandle,
00445                      OUT PVOID *KeyContext,
00446                      OUT PVOID *ApcContext,
00447                      OUT PIO_STATUS_BLOCK IoStatusBlock,
00448                      IN PLARGE_INTEGER Timeout OPTIONAL)
00449 {
00450     LARGE_INTEGER SafeTimeout;
00451     PKQUEUE Queue;
00452     PIOP_MINI_COMPLETION_PACKET Packet;
00453     PLIST_ENTRY ListEntry;
00454     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00455     NTSTATUS Status;
00456     PIRP Irp;
00457     PVOID Apc, Key;
00458     IO_STATUS_BLOCK IoStatus;
00459     PAGED_CODE();
00460 
00461     /* Check if the call was from user mode */
00462     if (PreviousMode != KernelMode)
00463     {
00464         /* Protect probes in SEH */
00465         _SEH2_TRY
00466         {
00467             /* Probe the pointers */
00468             ProbeForWritePointer(KeyContext);
00469             ProbeForWritePointer(ApcContext);
00470 
00471             /* Probe the I/O Status Block */
00472             ProbeForWriteIoStatusBlock(IoStatusBlock);
00473             if (Timeout)
00474             {
00475                 /* Probe and capture the timeout */
00476                 SafeTimeout = ProbeForReadLargeInteger(Timeout);
00477                 Timeout = &SafeTimeout;
00478             }
00479         }
00480         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00481         {
00482             /* Return the exception code */
00483             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00484         }
00485         _SEH2_END;
00486     }
00487 
00488     /* Open the Object */
00489     Status = ObReferenceObjectByHandle(IoCompletionHandle,
00490                                        IO_COMPLETION_MODIFY_STATE,
00491                                        IoCompletionType,
00492                                        PreviousMode,
00493                                        (PVOID*)&Queue,
00494                                        NULL);
00495     if (NT_SUCCESS(Status))
00496     {
00497         /* Remove queue */
00498         ListEntry = KeRemoveQueue(Queue, PreviousMode, Timeout);
00499 
00500         /* If we got a timeout or user_apc back, return the status */
00501         if (((NTSTATUS)(ULONG_PTR)ListEntry == STATUS_TIMEOUT) ||
00502             ((NTSTATUS)(ULONG_PTR)ListEntry == STATUS_USER_APC))
00503         {
00504             /* Set this as the status */
00505             Status = (NTSTATUS)(ULONG_PTR)ListEntry;
00506         }
00507         else
00508         {
00509             /* Get the Packet Data */
00510             Packet = CONTAINING_RECORD(ListEntry,
00511                                        IOP_MINI_COMPLETION_PACKET,
00512                                        ListEntry);
00513 
00514             /* Check if this is piggybacked on an IRP */
00515             if (Packet->PacketType == IopCompletionPacketIrp)
00516             {
00517                 /* Get the IRP */
00518                 Irp = CONTAINING_RECORD(ListEntry,
00519                                         IRP,
00520                                         Tail.Overlay.ListEntry);
00521 
00522                 /* Save values */
00523                 Key = Irp->Tail.CompletionKey;
00524                 Apc = Irp->Overlay.AsynchronousParameters.UserApcContext;
00525                 IoStatus = Irp->IoStatus;
00526 
00527                 /* Free the IRP */
00528                 IoFreeIrp(Irp);
00529             }
00530             else
00531             {
00532                 /* Save values */
00533                 Key = Packet->KeyContext;
00534                 Apc = Packet->ApcContext;
00535                 IoStatus.Status = Packet->IoStatus;
00536                 IoStatus.Information = Packet->IoStatusInformation;
00537 
00538                 /* Free the packet */
00539                 IopFreeMiniPacket(Packet);
00540             }
00541 
00542             /* Enter SEH to write back the values */
00543             _SEH2_TRY
00544             {
00545                 /* Write the values to caller */
00546                 *ApcContext = Apc;
00547                 *KeyContext = Key;
00548                 *IoStatusBlock = IoStatus;
00549             }
00550             _SEH2_EXCEPT(ExSystemExceptionFilter())
00551             {
00552                 /* Get the exception code */
00553                 Status = _SEH2_GetExceptionCode();
00554             }
00555             _SEH2_END;
00556         }
00557 
00558         /* Dereference the Object */
00559         ObDereferenceObject(Queue);
00560     }
00561 
00562     /* Return status */
00563     return Status;
00564 }
00565 
00566 NTSTATUS
00567 NTAPI
00568 NtSetIoCompletion(IN HANDLE IoCompletionPortHandle,
00569                   IN PVOID CompletionKey,
00570                   IN PVOID CompletionContext,
00571                   IN NTSTATUS CompletionStatus,
00572                   IN ULONG CompletionInformation)
00573 {
00574     NTSTATUS Status;
00575     PKQUEUE Queue;
00576     PAGED_CODE();
00577 
00578     /* Get the Object */
00579     Status = ObReferenceObjectByHandle(IoCompletionPortHandle,
00580                                        IO_COMPLETION_MODIFY_STATE,
00581                                        IoCompletionType,
00582                                        ExGetPreviousMode(),
00583                                        (PVOID*)&Queue,
00584                                        NULL);
00585     if (NT_SUCCESS(Status))
00586     {
00587         /* Set the Completion */
00588         Status = IoSetIoCompletion(Queue,
00589                                    CompletionKey,
00590                                    CompletionContext,
00591                                    CompletionStatus,
00592                                    CompletionInformation,
00593                                    TRUE);
00594 
00595         /* Dereference the object */
00596         ObDereferenceObject(Queue);
00597     }
00598 
00599     /* Return status */
00600     return Status;
00601 }

Generated on Sun May 27 2012 04:37:16 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.