|
|
1.1 ! root 1: #define STRICT ! 2: #define NOMINMAX ! 3: #include <windows.h> ! 4: ! 5: #include <stdlib.h> ! 6: #include <stdio.h> ! 7: #include <memory.h> ! 8: #include <string.h> ! 9: ! 10: #define DEFAULT 0L ! 11: #define SUCCESS 0L ! 12: #define IO_ERROR (HANDLE)0xFFFFFFFF ! 13: #define WAIT_ERROR 0xFFFFFFFF ! 14: #define SECTOR_SIZE 1024 ! 15: #define RETURN_IMEDIATELY 0L ! 16: ! 17: #if !defined(HEVENT) ! 18: typedef HANDLE HEVENT; ! 19: #endif ! 20: ! 21: #if !defined(HFILEEX) ! 22: typedef HANDLE HFILEEX; ! 23: #endif ! 24: ! 25: VOID ErrorMsg ( PSZ psz ) ; ! 26: VOID Do_BackgroundTask ( VOID ) ; ! 27: ! 28: ! 29: ! 30: /***************************************************************************\ ! 31: ** ** ! 32: ** PROGRAM: IO.C ** ! 33: ** ** ! 34: ** PURPOSE: Demonstrates the basic concepts envolved when using ** ! 35: ** asynchronous IO. In particular the main advantage is your ** ! 36: ** app more correctly thread can go about doing useful work ** ! 37: ** while waiting for IO. The main disadvantage is you must keep ** ! 38: ** track of the file pointer. ** ! 39: ** ** ! 40: ** INPUT: Both the File to read and File to write to must be entered ** ! 41: ** on via the command line. Note the file to write to must be ** ! 42: ** unique. ** ! 43: ** ** ! 44: ** FUNCTIONS: ** ! 45: ** ** ! 46: ** Do_BackgroundTask() ** ! 47: ** ** ! 48: ** ** ! 49: ** COMMENTS: Reads a file asynchronously writes to another synchronously ** ! 50: ** ** ! 51: ** ** ! 52: \***************************************************************************/ ! 53: ! 54: ! 55: void main ( int argc, char *argv[] ) ! 56: ! 57: { ! 58: ! 59: ! 60: HFILEEX hInfile, // Handle to the file to read ! 61: hOutfile; // Handle to the file to write to ! 62: ! 63: HEVENT hEvent ; // Handle to the synchronization Event ! 64: ! 65: OVERLAPPED ! 66: OverLapped ; // The operating system does not automatically ! 67: // track the current file position of a file ! 68: // open for asynchroous I/O. Instead one must ! 69: // manually track this by updating the OVERLAPPED ! 70: // structure. To update this structure one uses ! 71: // the result returned by GetOverLappedResults(). ! 72: ! 73: ! 74: CHAR buf[SECTOR_SIZE] ; // Buffer used by either ! 75: // ReadFile() or WriteFile() ! 76: ! 77: DWORD cbBytesRead, // count of bytes read by ReadFile() ! 78: // When asynchonous I/O is performed ! 79: // one must check how many bytes were ! 80: // read by calling GetOverLappedResults(). ! 81: ! 82: ! 83: cbBytesWritten, // count of bytes written by WriteFile() ! 84: ! 85: cbBytesTransfered ; // this value is returned by ! 86: // GetOverLappedResults() represents the ! 87: // count of bytes transfered asynchronous ! 88: ! 89: DWORD dwStatus, // value returned by GetLastError() ! 90: dwSuccess ; // return code of last API called ! 91: ! 92: BOOL bSuccess ; // return code of last API called ! 93: ! 94: CHAR buffer[80] ; ! 95: ! 96: /***************************************************************************\ ! 97: ** ** ! 98: ** This block of code initalizes all the necessary variables needed to do ** ! 99: ** asynchronous IO. Specfically it opens the files and initializes the ** ! 100: ** synchronization EVENT and OVERLAPPED structure needed to keep track ** ! 101: ** of asynchronous file I/O ** ! 102: ** ** ! 103: \***************************************************************************/ ! 104: ! 105: ! 106: if ( argc != 3 ) ! 107: { ! 108: printf ( "\nUsage: IO1 input_file output_file\n" ) ; ! 109: exit ( EXIT_FAILURE ) ; ! 110: } ! 111: ! 112: ! 113: ! 114: /* ! 115: * Open file which we will be copying. Note we are opening this ! 116: * asynchronously. ! 117: */ ! 118: ! 119: hInfile = CreateFile ! 120: ( ! 121: argv[1] // File to read ! 122: ,GENERIC_READ // Open file for reading only ! 123: ,FILE_SHARE_READ // Allow others to read file ! 124: ,NULL // No security ! 125: ,OPEN_EXISTING // Fail if file doesn't exit ! 126: ,FILE_FLAG_OVERLAPPED // Async I/o ! 127: ,DEFAULT ! 128: ) ; ! 129: ! 130: ! 131: if ( hInfile == IO_ERROR ) ! 132: { ! 133: strcpy ( buffer, "Error opening" ) ; ! 134: strcat ( buffer, argv[1] ) ; ! 135: ErrorMsg ( buffer ) ; ! 136: } ! 137: ! 138: ! 139: /* ! 140: * Create the file to write to; here we have opened it for synchronous IO. ! 141: */ ! 142: ! 143: hOutfile = CreateFile ! 144: ( ! 145: argv[2] // File to write to ! 146: ,GENERIC_WRITE // Open file only to write to ! 147: ,DEFAULT // No sharing allowed ! 148: ,NULL // No security ! 149: ,CREATE_NEW // Fail if file exists ! 150: ,FILE_ATTRIBUTE_NORMAL // No attributes ! 151: ,DEFAULT ! 152: ) ; ! 153: ! 154: ! 155: if ( hOutfile == IO_ERROR ) ! 156: { ! 157: strcpy ( buffer, "Error opening" ) ; ! 158: strcat ( buffer, argv[1] ) ; ! 159: ErrorMsg ( buffer ) ; ! 160: } ! 161: ! 162: ! 163: ! 164: /* ! 165: * Create Synchronoizing Event ! 166: */ ! 167: ! 168: hEvent = CreateEvent ! 169: ( ! 170: NULL // No security ! 171: ,TRUE // Manual reset ! 172: ,FALSE // Initially Event set to non-signaled state ! 173: ,NULL // No name ! 174: ) ; ! 175: if ( !hEvent ) ! 176: ErrorMsg ( "Error creating Event" ) ; ! 177: ! 178: ! 179: /* ! 180: * Intialize OverLapped structure. We will be using an Event instead ! 181: * of the file handle for synchronizing I/O. One reason to use a unique ! 182: * event instead of the file handle would be a so multi-threaded app ! 183: * would know which thread to unblock when the handle is set to the ! 184: * signaled state. ! 185: */ ! 186: ! 187: memset ( &OverLapped, 0, sizeof ( OVERLAPPED ) ) ; ! 188: OverLapped.hEvent = hEvent ; ! 189: ! 190: ! 191: bSuccess = TRUE ; ! 192: ! 193: ! 194: /***************************************************************************\ ! 195: ** ** ! 196: ** This is the main function of this program. Here we loop until the file ** ! 197: ** has been copied. Notice that even though we are using asynchronous I/O ** ! 198: ** ReadFile() may still return sychronously if it can be done fast enough ** ! 199: ** ** ! 200: \***************************************************************************/ ! 201: ! 202: while ( bSuccess ) ! 203: { ! 204: ! 205: /* ! 206: * Read file asynchronously ! 207: */ ! 208: ! 209: bSuccess = ReadFile ! 210: ( ! 211: hInfile // Handle of file to read ! 212: ,buf // Buffer to store input ! 213: ,SECTOR_SIZE // Number of bytes to read ! 214: ,&cbBytesRead // Number of bytes read. See note] ! 215: // above in delcaration ! 216: ,&OverLapped // Used for asynchronous I/O ! 217: ) ; ! 218: ! 219: ! 220: ! 221: /* ! 222: * Check whether ReadFile() has completed yet ! 223: */ ! 224: if ( !bSuccess && (( dwStatus = GetLastError ()) == ERROR_IO_PENDING ) ) ! 225: { ! 226: printf ( "\nIO Pending" ) ; ! 227: /* ! 228: * Read not complete yet first execute the background task then check ! 229: * to the if event "hEvent" set to the signaled state. If the event is ! 230: * not set signaled state then loop through again - run the background ! 231: * task and check the event. ! 232: * ! 233: */ ! 234: ! 235: Do_BackgroundTask () ; ! 236: ! 237: dwSuccess = WaitForSingleObject ( hEvent, RETURN_IMEDIATELY ) ; ! 238: ! 239: if ( dwSuccess == WAIT_ERROR ) ! 240: ErrorMsg("Error in WaitForSingleObject") ; ! 241: else if ( dwSuccess == SUCCESS ) ! 242: { ! 243: ! 244: bSuccess = GetOverlappedResult( ! 245: hInfile, &OverLapped, &cbBytesTransfered, FALSE) ; ! 246: if ( !bSuccess ) ! 247: ErrorMsg ( "Error in GetOverLappedResult" ) ; ! 248: else ! 249: { ! 250: // Read has completed now find out how many bytes have been read ! 251: ! 252: printf ( "\nNumber of bytes transfered is %d\n", cbBytesTransfered ) ; ! 253: OverLapped.Offset += cbBytesTransfered ; ! 254: cbBytesRead = cbBytesTransfered ; ! 255: } ! 256: } ! 257: else if ( dwSuccess == WAIT_TIMEOUT ) ! 258: Do_BackgroundTask () ; ! 259: } ! 260: /* ! 261: * ReadFile() read file synchronously; update Overlapped structure ! 262: */ ! 263: else if ( bSuccess && cbBytesRead != 0 ) ! 264: { ! 265: printf ( "\nNumber of bytes transfered is %d\n", cbBytesRead ) ; ! 266: OverLapped.Offset += cbBytesRead ; ! 267: } ! 268: /* ! 269: * ReadFile() has found the end of the file; exit loop ! 270: */ ! 271: else if ( bSuccess && cbBytesRead == 0 ) ! 272: { ! 273: printf ( "End of file read\n" ) ; ! 274: break ; ! 275: } ! 276: /* ! 277: * An error occured while reading, print out status and exit loop. ! 278: */ ! 279: else ! 280: ErrorMsg ( "Error reading to file" ) ; ! 281: ! 282: ! 283: ! 284: /* ! 285: * Write to file synchronously ! 286: */ ! 287: bSuccess = WriteFile ! 288: ( ! 289: hOutfile // Handle of file to write to ! 290: ,buf // Data to write to file ! 291: ,cbBytesRead // Number of bytes to write ! 292: ,&cbBytesWritten // Number of bytes written ! 293: ,NULL // Only need for asynchonous output ! 294: ) ; ! 295: ! 296: ! 297: if ( !bSuccess ) ! 298: ErrorMsg ( "Error writing to file" ) ; ! 299: ! 300: } // End of WHILE loop ! 301: ! 302: ! 303: ! 304: CloseHandle ( hInfile ) ; // Close handle to input file ! 305: FlushFileBuffers ( hOutfile ) ; // Make sure all data written to file first ! 306: CloseHandle ( hOutfile ) ; // Close handle to output file ! 307: exit ( EXIT_SUCCESS ) ; ! 308: ! 309: } ! 310: ! 311: ! 312: ! 313: /***************************************************************************\ ! 314: ** ** ! 315: ** FUNCTION: ErrorMsg(LPTSTR) ** ! 316: ** ** ! 317: ** PURPOSE: Prints out an error message the return code of the last API ** ! 318: ** to fail. ** ! 319: ** ** ! 320: ** INPUT: psz: This string is a description of where the code failed in ** ! 321: ** the module ** ! 322: ** ** ! 323: ** OUTPUT: None ** ! 324: ** ** ! 325: \****************************************************************************/ ! 326: ! 327: VOID ErrorMsg ( PSZ psz ) ! 328: { ! 329: ! 330: printf ("\n%s: return code = %d\n", psz, GetLastError()) ; ! 331: exit ( EXIT_FAILURE ) ; ! 332: } ! 333: ! 334: /***************************************************************************\ ! 335: ** ** ! 336: ** FUNCTION: Do_BackgroundTask ( VOID ) ** ! 337: ** ** ! 338: ** PURPOSE: Works in the background while IO sytems ** ! 339: ** ** ! 340: ** COMMENTS: ** ! 341: ** ** ! 342: ** Currently this does nothing if I have the time I will come up ** ! 343: ** with some silly task to keep the user entertained. ** ! 344: ** ** ! 345: ** INPUT: None ** ! 346: ** ** ! 347: ** OUTPUT: None ** ! 348: ** ** ! 349: \***************************************************************************/ ! 350: ! 351: VOID Do_BackgroundTask ( VOID ) ! 352: { ! 353: Sleep ( 5000L ) ; ! 354: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.