Getting your driver to handle more than one I/O Request

Source: Internet
Author: User
Tags readfile
Getting your driver to handle more than one I/O request at a time

Updated: May 25,200 7

Your User-mode application is sending your driver lots of I/O requests, but the driver insists on handling the requests one at a time. What's the problem?

You might think that your driver is blocking in some obscure way or that you need more threads in your application, but the solution is often much simpler: make sure your application has opened the device for overlapped I/O. otherwise, the I/O manager serializes I/O requests by synchronizing through a lock in the file object before dispatching the IRP. even if your application uses multiple threads, only one request at a time (per file handle) will get through.

Enabling overlapped I/O in an application
To enable overlapped I/O in an application, SetDwflagsandattributesWith file_flag_overlapped when you callCreatefileTo open the device. (If you skip this step you won't get overlapped I/O, even if you do everything else right .)

CreatefileReturns a handle that can be used to access the device. When you callReadfile,Writefile, OrDeviceiocontrolWith the file handle createdCreatefile, Supply a pointer to an overlapped structure that contains a handle to an event object to signal when the operation completes. these functions return immediately for Overlapped operations; the event object is signaled when the operation is completed.

Be sure to initialize the overlapped structure to zero before using it in a function call, and set only the Members that are needed by the function. For example, the offset member shocould be setReadfileAndWritefileCILS, but this member shoshould be zeroDeviceiocontrol. Also, be sure to use a separate overlapped structure for each request; re-using the structure before the previous asynchronous operation has been completed can cause errors. besides, your application will need the original structure to callHasoverlappediocompletedOrGetoverlappedresultFor the request.

After you 've opened a device for overlapped I/O, can you simply omit the overlapped structure to get synchronous I/O? No, you must supply an overlapped structure for all function CALS (read, write, or device control) with that handle. passing null can 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 the I/O to complete before returning.

The following code snippet shows how to open a file for writing overlapped 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 up the overlapped structure, cballsReadfile, And then checks the status of an 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

Handling overlapped I/O in your driver
From a driver's perspective, all I/O Requests shoshould be considered asynchronous. the driver does not need to check whether an I/O request actually is asynchronous, it shoshould simply assume that it is and avoid blocking any I/O Request. (The driver can block for other reasons such as acquiring a lock, but it shouldn't block just on the basis of processing an I/O request .) if the application needs to use synchronous I/O, it simply opens the device without specifying overlapped I/O; the I/O manager then serializes requests as described earlier, without special action on the part of the driver.

When the I/O manager has es an I/O request from an application, the I/O manager creates an IRP and CILS your driver's dispatch routine. the role of the dispatch routine is to present the request to the driver for processing, not necessarily to handle all of the processing itself. if your driver does not complete the IRP in the dispatch routine, callIomarkirppendingAnd return status_pending. (remember that if you mark an IRP as pending by callingIomarkirppending, The only status code you can return is status_pending. You must not return any other status code. You can, however, mark an IRP as pending, complete it synchronously, and returnStatus_pending.)

For example, considerReadfileRequest sent by an application. On login ing the irp_mj_read IRP from the I/O manager, your dispatch routine might simply mark the IRP as pending, callIostartpacket, And then return status_pending. (The order is important here. if you put the request on the queue first, it cocould get picked up by another part of the driver, processed, completed and freed all before the first thread gets around to marking it pending. this wowould confuse the I/O system and wowould also crash the system when you tried to callIomarkirppendingOn what is now a pointer to a free pool block .)

YourStartioRoutine kicks off the operation by sending a command to the Controller. When the controller has finished the command, Your interrupt service routine (ISR) is signaled. It runs and queues A deferred Procedure Call (Dpcforisr).DpcforisrPuts the appropriate status values in the IRP and CILSIocompleterequestTo actually complete the operation.DpcforisrThen CILSIostartnextpacket, At which point yourStartioRoutine will be called again, in the context of the thread handlingDpcforisr, To start another request.

Meanwhile, control returns to the application as soon as your driver's dispatch routine returns, so the application isn't blocked waiting for your driver to complete the I/O request. The status fromReadfileIndicates that the request is in progress (ReadfileReturns zero andGetlasterrorReturns error_io_pending), so the application can continue to do other work (send more I/O requests, perhaps). After your driver CILSIocompleterequest, The application is notified that the operation has completed through the event object specified in the overlapped structure, and it can check that structure for status information.

One last point: if you pend IRPs, you shoshould support I/O cancellation, so the caller can cancel an I/O request if it's going to take too long. it's best to use the cancel-safe IRP queuing routines (IocsqXxxRoutines), especially if your driver performs I/O frequently, because these routines provide a framework that handles cancellation properly so that race conditions do not occur.CancelSample in the Windows DDK (% winddk %/src/General/cancel) shows the use of these routines.

Otherwise, you'll need to implementCancelRoutine in your driver and pass a pointer to this routine when you callIostartpacket, So the I/O manager will call yourStartioRoutine with the IRP in a cancelable state. In yourStartioRoutine, you'll need to check for cancellation and protect against related race conditions. this approach is not recommended for drivers that perform I/O frequently, because the I/O manager holds the global cancel spin lock while it inserts and removes IRPs from the device queue, which can affect system performance.

See the cancel logic in Windows drivers paper on WHDC for a detailed discussion of these and other IRP cancellation techniques.

What should you do?

In your application:

  • When callingCreatefileTo open a device, SetDwflagsandattributesWith file_flag_overlapped.

  • When callingReadfile,Writefile, OrDeviceiocontrol, Supply a pointer to a properly initialized overlapped structure. never omit the overlapped structure when using a handle to a device opened with file_flag_overlapped.

  • Never re-use an overlapped structure for subsequent requests.

In your driver:

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

  • Unless you are completing IRPs in your dispatch routine, Mark IRPs pending so the application isn't blocked waiting for the request to complete. Remember to return only status_pending if you mark an pendiring.

  • Support IRP cancellation, preferably by using the cancel-safe IRP queuing routines (IocsqXxx), So the application can cancel an I/O request that is taking too long.

For more information:

Platform SDK: Storage
Creating and opening files
Synchronization and overlapped Input and Output

WHDC
Handling IRPs: What every driver writer needs to know
Cancel logic in Windows drivers
Flow of control for cancel-safe IRP queuing

Windows Driver kit (wdk): kernel-mode driver architecture
Handling IRPs

Top of pagehttp: // msdn.microsoft.com/en-us/windows/hardware/gg463203

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.