Let your driver process multiple I/O requests at a time

Source: Internet
Author: User
Let your driver process multiple I/O requests at a time

Your User-mode application sends a large number of I/O requests to your driver, but the driver keeps processing one request at a time. What is the problem?

You may think that the driver is blocked in some fuzzy ways or the application requires more multithreading, but the solution is often much simpler: make sure that your application has enabled the device for overlapping I/O. Otherwise, the I/O manager serializes the I/O request before the scheduled IRP by synchronizing (using the lock in the file object. Even if your application uses multiple threads, only one request (each file handle) can pass.

Enable overlapping I/O in the Application
To enable overlapping I/O in the application, SetDwflagsandattributesSet to file_flag_overlapped (when you callCreatefile). (If you skip this step, you will not get overlapping I/O, even if other aspects are correct .)

CreatefileReturns a handle that can be used to access the device. When you useCreatefileThe created file handle to callReadfile,WritefileOrDeviceiocontrolProvides a pointer to the overlapped structure (including the handle of an event object, which is issued when the operation is complete. For overlapping operations, these functions are immediately returned; when the operation is completed, event objects are issued.

Make sure that the overlapped structure is initialized to zero before being used in the function call, and only set the members required by the function. For exampleReadfileAndWritefileCall to set the offset member, butDeviceiocontrolThis member should be zero. In addition, make sure that a separate overlapped structure is used for each request. Reusing this structure before the previous asynchronous operation is completed will cause errors. In addition, your application will need the original structure for request callsHasoverlappediocompletedOrGetoverlappedresult.

After opening the device for overlapping I/O, can I simply ignore the overlapped structure to get synchronous I/O? No. You must provide an overlapped structure for all function calls (read, write, or device control) using the handle. Passing null will lead to undefined behavior even if the driver completes the request synchronously. For synchronous I/O, the overlapped structure can be declared on the stack as long as the application waits for I/O to be completed before the return.

The following code snippet shows how to open a file used to write overlapping I/O:


  
  
  1. #include <windows.h>
  2. #include <stdio.h>
  3.  
  4. HANDLE hFile; 
  5.  
  6. hFile = CreateFile(TEXT("myfile.txt"),     // file to create
  7.                    GENERIC_WRITE,          // open for writing
  8.                    0,                      // do not share
  9.                    NULL,                   // default security
  10.                    CREATE_ALWAYS,          // overwrite existing
  11.                    FILE_ATTRIBUTE_NORMAL | // normal file
  12.                    FILE_FLAG_OVERLAPPED,   // asynchronous I/O
  13.                    NULL);                  // no attr. template
  14.  
  15. if (hFile == INVALID_HANDLE_VALUE) 
  16.     printf("Could not open file (error %d)/n", GetLastError());
  17.     return 0;
  18. }

The following code snippet sets the overlapped structure and callsReadfileAnd then check the status of the I/O request:


  
  
  1. OVERLAPPED gOverlapped;
  2.  
  3. // set up overlapped structure fields
  4. gOverLapped.Offset     = 0; 
  5. gOverLapped.OffsetHigh = 0; 
  6. gOverLapped.hEvent     = hEvent; 
  7.  
  8. // verify that sizeof(inBuffer >= nBytestoRead)
  9.  
  10. // attempt an asynchronous read operation
  11. bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, 
  12.     &gOverlapped) ; 
  13.  
  14. // if there was a problem, or the async. operation's still pending ... 
  15. if (!bResult) 
  16.     // deal with the error code 
  17.     switch (dwError = GetLastError()) 
  18.     { 
  19.         case ERROR_HANDLE_EOF: 
  20.         { 
  21.             // we have reached the end of the file 
  22.             // during the call to ReadFile 
  23.  
  24.             // code to handle that 
  25.         } 
  26.  
  27.         case ERROR_IO_PENDING: 
  28.         { 
  29.             // asynchronous i/o is still in progress 
  30.  
  31.             // do something else for a while 
  32.             GoDoSomethingElse() ; 
  33.  
  34.             // check on the results of the asynchronous read 
  35.             bResult = GetOverlappedResult(hFile, &gOverlapped, 
  36.                 &nBytesRead, FALSE) ; 
  37.  
  38.             // if there was a problem ... 
  39.             if (!bResult) 
  40.             { 
  41.                 // deal with the error code 
  42.                 switch (dwError = GetLastError()) 
  43.                 { 
  44.                     case ERROR_HANDLE_EOF: 
  45.                     { 
  46.                         // we have reached the end of
  47.                         // the file during asynchronous
  48.                         // operation
  49.                     } 
  50.  
  51.                     // deal with other error cases 
  52.                 }   //end switch (dwError = GetLastError()) 
  53.              } 
  54.         } // end case 
  55.  
  56.         // deal with other error cases, such as the default 
  57.  
  58.     } // end switch (dwError = GetLastError()) 
  59.  } // end if

Process overlapping I/O in the driver
From the driver perspective, all I/O requests should be considered asynchronous. The driver does not need to check whether I/O requests are actually asynchronous. It should simply assume that I/O requests are asynchronous and avoid blocking any I/O requests. (The driver can be blocked for other reasons such as obtaining the lock, but it should not be blocked only by receiving I/O requests .) If the application needs to use synchronous I/O, it simply opens the device without specifying overlapping I/O. Then, the I/O manager serializes the request as described earlier, no special operations are required for the driver.

When I/O manager receives an I/O request from an application, I/O manager creates an IRP and calls the scheduling routine of your driver. The role of the scheduler is to send requests to the driver for processing, and you do not have to process all the processes on your own. If your driver does not complete the IRP in the scheduling routine, callIomarkirppendingAnd return status_pending. (Remember, if you callIomarkirppendingIf you mark the IRP as pending, the only status code that can be returned is status_pending. No other status codes are returned. However, you can mark the IRP as pending, synchronize it, and returnStatus_pending.)

For example, considerReadfileRequest. When you receive irp_mj_read IRP from the I/O manager, your scheduling routine can simply mark the IRP as pending and callIostartpacketAnd returns status_pending. (The order here is very important. If you put the request in the queue first, it can be used, processed, completed, and released by another part of the driver before the first thread is considered to be suspended. This will interfere with the I/O system and will also be called on the pointer of the memory pool block that you are trying to releaseIomarkirppendingSystem crash.

YourStartioThe routine starts operations by sending commands to the Controller. When the Controller completes the command, Your interrupt service routine (ISR) is issued. It runs and queues A delayed process call (Dpcforisr).DpcforisrPlace appropriate status values in IRP and callIocompleterequestTo complete the operation.DpcforisrThe call is located in the ProcessingDpcforisrIn the thread contextIostartnextpacket(Here YourStartioTo start another request.

At the same time, once your driver's scheduling routine returns, the control will return to the application, so the application will not block while waiting for the driver to complete the I/O Request. FromReadfileThe status indicates that the request is in progress (ReadfileReturns zero,GetlasterrorReturns error_io_pending), so the application can continue other work (more I/O requests may be sent ). Your driver callsIocompleterequestThen, the application is notified that the operation has been completed (through the event object specified in the overlapped structure). It can check this structure to obtain the status information.

Last point: if you suspend the IRP, you should support I/O cancellation so that the caller can cancel the I/O Request (if it takes too long ). It is best to use IRP queuing routines that can be safely canceled (IocsqXxxRoutines) (especially if your driver frequently executes I/O), because these routines provide a framework for correctly processing cancellation so that the competition condition does not occur. In Windows DDK (% winddk %/src/General/cancel ),CancelThe example shows how to use these routines:

Otherwise, you will need to implementCancelAndIostartpacketTherefore, the I/O manager will call yourStartioRoutine. In yourStartioIn the routine, you will need to check the cancellation and prevent the related race condition. This method is not recommended for drivers that frequently execute I/O, because the I/O manager holds a global spin lock when inserting and deleting IRPs from the device queue, which affects system performance.

For more information about these and other IRP cancellation techniques, see "cancelling logic in Windows drivers" on WHDC.

What should you do?

In your application:

  • WhenCreatefileTo open the deviceDwflagsandattributesSet to file_flag_overlapped.

  • WhenReadfile,WritefileOrDeviceiocontrolProvide a pointer to the overlapped structure correctly initialized. When using the handle of a device opened with file_flag_overlapped, the overlapped structure is never ignored.

  • Never reuse the overlapped structure for subsequent requests.

In your driver:

  • Assume that all incoming I/O requests are asynchronous.

  • Unless you complete the IRP in the scheduling routine, you should mark the IRP as pending, so that the application will not be blocked to wait for the request to complete. If you mark the IRP as pending, remember to return only status_pending.

  • Supports IRP cancellation. You are preferred to use IRP queuing routines that can be safely canceled (IocsqXxx), So that the application can cancel the I/O requests that take too long.

For more information:

Platform SDK: Storage
Create and open a file
Synchronous and overlapping Input and Output

WHDC
Processing IRP: skills that every driver writer needs to know
Cancel logic in Windows Driver
Control Process of IRP queues that can be safely canceled

Windows Driver kit (wdk): kernel-mode driver architecture
Processing IRP

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.