c++ - ReadDirectoryChangesW fails with error 995 if CancelIo was called before -


i'm puzzled strange behavior of readdirectorychangesw failing error 995. scenario explained below.

  1. filehandle obtained using createfilew.

  2. filehandle obtained in step1 used in readdirectorychangesw. success , sends request server

  3. poll 10 seconds , if no change notify generated server, cancel chnagenotify request using cancelio. sends cancel & server responds.

  4. now again setting change notify readdirectorychangesw using file handle obtained in step1, fails "995 - i/o operation has been aborted because of either thread exit or application request." no actual request sent server step.

  5. immediately again call readdirectorychangesw using file handle obtained in step1 & succeeds , sends request server.

steps 3,4,5 repeated in loop & every alternate readdirectorychangesw fails 995 , immediate next 1 succeeds.

can tell me whats going on ? below code

void setnotify(wchar* _path) {     overlapped _overlapped;     handle     _handle;     char       _buffer[8192] = {0};     dword      _buffersize = 8192;     cnstate    _state = cn_ready;     dword      _inactivitytime = 0;      typedef enum state     {         cn_ready,         cn_request_pending,         cn_response_received,         cn_request_cancelled     } cnstate;      _handle = createfilew(_path,             generic_read, // access             file_share_read |             file_share_write |             file_share_delete, // share             null, // sec             open_existing, // disp             file_flag_backup_semantics | file_flag_overlapped, // flags             0);     if (_handle == invalid_handle_value)     {         exit(-1);     }      memset(&_overlapped, 0, sizeof(overlapped));      if (!readdirectorychangesw(_handle,                 _buffer,                 _buffersize,                 true,                 0x255,                 null,                 &_overlapped,                 null)) {          exit(-1);     } else {         _state = cn_request_pending;         wprintf(l"sent change notify server\n");     }       while (1)     {         if ((_state == cn_request_pending) && (hasoverlappediocompleted(&_overlapped))) {             wprintf(l"response received server\n");             _state = cn_response_received;         }          if ((_state == cn_response_received) || (_state == cn_request_cancelled)) {             memset(&_overlapped, 0, sizeof(overlapped));             _inactivitytime = 0;             if (!readdirectorychangesw(_handle,                         _buffer,                         _buffersize,                         true,                         255,                         null,                         &_overlapped,                         null)) {                  wprintf(l"sent change notify server failed.\n");             } else {                 wprintf(l"sent change notify server\n");                 _state = cn_request_pending;             }         }          if ((_state == changenotifyrequest::cn_request_pending) &&                 (_inactivitytime >= 5000)){             if (cancelio(_handle)) {                 _state = cn_request_cancelled;                 wprintf(l"cancelled pending requests.\n");             } else {                 wprintf(l"cancelled failed");             }          }          sleep(50);         _inactivitytime += 50;      } } 

below sample o/p:

sent change notify server

cancelled pending requests.

sent change notify server

cancelled pending requests.

sent change notify server failed.

sent change notify server

cancelled pending requests.

sent change notify server failed.

sent change notify server

cancelled pending requests.

sent change notify server failed.

sent change notify server

you start operation , cancel it, completion event report error_operation_aborted (995) error. but, starting new operation before have received event. when call cancelio(), request cancel, original operation still pending, , may take awhile cancel (or may complete before cancellation request processed). so, still need wait cancelled operation complete, , handle result whether or bad, before start next operation.

also, there 2 other bugs in code.

when calling readdirectorychangesw() first time, setting dwnotifyfilter parameter 0x255, wrong. requesting these filter bits:

file_notify_change_file_name file_notify_change_attributes file_notify_change_last_write file_notify_change_creation 

subsequent calls setting dwnotiffilter 255 instead, requesting these filter bits:

file_notify_change_file_name file_notify_change_dir_name file_notify_change_attributes file_notify_change_size file_notify_change_last_write file_notify_change_last_access file_notify_change_creation 

so, filtering inconsistent. shouldn't using "magic numbers" in first place. win32 api has #define constants available flags, should using them way intended.

lastly, not associating event object createevent() overlapped structure. requirement stated in readdirectorychangesw() documentation when not using i/o completion port or i/o completion callback.

try more instead:

void setnotify(wchar* _path) {     typedef enum state     {         cn_ready,         cn_request_pending,         cn_request_complete     } cnstate;      overlapped  _overlapped = {0};     handle      _handle;     char        _buffer[8192];     dword       _buffersize;     cnstate     _state = cn_ready;     dword       _inactivitytime;     const dword _filter = file_notify_change_file_name | file_notify_change_dir_name | file_notify_change_attributes | file_notify_change_size | file_notify_change_last_write | file_notify_change_last_access | file_notify_change_creation;      _handle = createfilew(_path,             generic_read, // access             file_share_read |             file_share_write |             file_share_delete, // share             null, // sec             open_existing, // disp             file_flag_backup_semantics | file_flag_overlapped, // flags             0);     if (_handle == invalid_handle_value)     {         wprintf(l"opening server failed. error: %u\n", getlasterror());         exit(-1);     }      _overlapped.hevent = createevent(null, true, false, null);     if (_overlapped.hevent == null)     {         wprintf(l"creating overlapped event failed. error: %u\n", getlasterror());         exit(-1);     }          {         switch (_state)         {             case cn_ready:             {                 _buffersize = 0;                 _inactivitytime = 0;                  if (!readdirectorychangesw(_handle,                         _buffer,                         sizeof(_buffer),                         true,                         _filter,                         &_buffersize,                         &_overlapped,                         null))                 {                     wprintf(l"requesting change notify server failed. error: %u\n", getlasterror());                     exit(-1);                 }                  _state = cn_request_pending;                 wprintf(l"change notify requested server\n");                  break;             }              case cn_request_pending:             {                 if (hasoverlappediocompleted(&_overlapped))                 {                     _state = cn_request_complete;                 }                 else if (_inactivitytime >= 5000)                 {                     if (cancelio(_handle))                     {                         _state = cn_request_complete;                         wprintf(l"no response in 5 seconds. cancelling pending request\n");                     }                     else                         wprintf(l"no response in 5 seconds. cancelling pending request failed. error: %u\n", getlasterror());                 }                 else                 {                     sleep(50);                     _inactivitytime += 50;                 }                  break;             }              case cn_request_complete:             {                 if (getoverlappedresult(_handle, &_overlapped, &_buffersize, true))                 {                     wprintf(l"response received server\n");                     // use _buffer _buffersize bytes needed...                 }                 else if (getlasterror() == error_operation_aborted)                 {                     wprintf(l"pending request cancelled\n");                 }                 else                 {                     wprintf(l"change notify server failed. error: %u\n", getlasterror());                     // handle error needed...                 }                  _state = cn_ready:                 break;             }         }     } } 

however, if not going use i/o completion port or i/o completion callback, can simplify code utilizing fact can more wait on overlapped result waiting on event object signaled, without having poll overlapped status in loop @ all:

void setnotify(wchar* _path) {     overlapped  _overlapped = {0};     handle      _handle;     char        _buffer[8192];     dword       _buffersize;     const dword _filter = file_notify_change_file_name | file_notify_change_dir_name | file_notify_change_attributes | file_notify_change_size | file_notify_change_last_write | file_notify_change_last_access | file_notify_change_creation;      _handle = createfilew(_path,             generic_read, // access             file_share_read |             file_share_write |             file_share_delete, // share             null, // sec             open_existing, // disp             file_flag_backup_semantics | file_flag_overlapped, // flags             0);     if (_handle == invalid_handle_value)     {         wprintf(l"opening server failed. error: %u\n", getlasterror());         exit(-1);     }      _overlapped.hevent = createevent(null, true, false, null);     if (_overlapped.hevent == null)     {         wprintf(l"creating overlapped event failed. error: %u\n", getlasterror());         exit(-1);     }          {         _buffersize = 0;          if (!readdirectorychangesw(_handle,             _buffer,             sizeof(_buffer),             true,             _filter,             &_buffersize,             &_overlapped,             null))         {             wprintf(l"requesting change notify server failed. error: %u\n", getlasterror());             exit(-1);         }          wprintf(l"change notify requested server\n");          // alternatively, use getoverlappedresultex() timeout         // instead of waitforsingleobject() , getoverlappedresult()         // separately...          if (waitforsingleobject(_overlapped.hevent, 5000) == wait_timeout)         {             if (cancelio(_handle))                 wprintf(l"no response in 5 seconds. cancelling pending request\n");             else                 wprintf(l"no response in 5 seconds. cancelling pending request failed. error: %u\n", getlasterror());         }          if (getoverlappedresult(_handle, &_overlapped, &_buffersize, true))         {             wprintf(l"response received server\n");             // use _buffer _buffersize bytes needed...         }         else if (getlasterror() == error_operation_aborted)         {             wprintf(l"pending request cancelled\n");         }         else         {             wprintf(l"change notify server failed. error: %u\n", getlasterror());             // handle error needed...         }     }     while (true); } 

also, see my earlier answer a similar question, explains other gotchas have aware of when using readdirectorychangesw(), particularly handling of error_notify_enum_dir error.


Comments

Popular posts from this blog

What is happening when Matlab is starting a "parallel pool"? -

angular - DownloadURL return null in below code -

php - Cannot override Laravel Spark authentication with own implementation -