[ReadDirectoryChangesW et IoCompletionPort] Double notification
Bonjour a tous,
je suis en train de realiser une classe de monitoring de fichier multi plateforme.
je l'ai realise sous BSD, Linux et la sous windows j'ai un petit probleme.
J'utilise la fonction ReadDirectoryChangesW pour lire les changements de maniere asynchrone avec les IOCompletionPorts.
Voici les grandes lignes de ma classe:
Ouverture du dossier:
Code:
1 2 3 4 5 6 7 8
|
hndl = CreateFile(dir.toString().c_str(),
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL); |
Association avec l'iocp:
Code:
1 2 3 4 5 6 7 8 9
|
HANDLE sub_iocp = CreateIoCompletionPort(hndl, this->_iocp, 0, 0);
if (sub_iocp == NULL)
{
delete o;
Debug(Debug::error) << "[Windir] Cannot create sub IOCP" << std::endl;
// XXX: Exception ?
return false;
} |
Fonction qui ajoute une operation de lecture:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
bool startReadFor(Operation* o)
{
memset(&o->overlapped, 0, sizeof(o->overlapped));
DWORD read = ReadDirectoryChangesW(o->dir,
o->changes, sizeof(o->changes),
FALSE,
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME,
NULL,
&o->overlapped,
NULL);
if (read == 0)
{
Debug(Debug::error) << "[WinDir] Error in ReadDirectoryChangesW: " <<
GetLastError() << std::endl;
return false;
}
return true;
} |
dans ma methode run:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
void run()
{
DWORD nByte = 0;
ULONG_PTR key = 0;
LPOVERLAPPED overlapped = NULL;
Operation *op = NULL;
Debug(Debug::info) << "[WinDir] Start Monitoring"
<< std::endl;
while (true)
{
BOOL ret = GetQueuedCompletionStatus(this->_iocp, &nByte, &key, &overlapped, INFINITE);
if (key == ~(0))
{ /* ...Stop...*/ }
if (overlapped == NULL)
{ /* ..........*/ }
int error;
/* ..........*/
op = CONTAINING_RECORD(overlapped, Operation, overlapped);
std::string filename;
std::wstring wfilename;
Operation::FileDatas::iterator it;
if (nByte == 0)
{/* ..........*/}
PFILE_NOTIFY_INFORMATION notify = reinterpret_cast< PFILE_NOTIFY_INFORMATION >(op->changes);
/* .....Get filename.....*/
it = op->watchedFiles.find(filename);
if (it != op->watchedFiles.end())
{
Operation::FileData& data = it->second;
bool has_next = true;
do
{
switch (notify->Action)
{
case FILE_ACTION_MODIFIED:
if (data.mode & NOTIFY_WRITE)
(*data.callable)();
break;
case FILE_ACTION_REMOVED:
if (data.mode & NOTIFY_DELETE)
(*data.callable)();
break;
default:
Debug(Debug::error) << "[WinDir] Receive not supported notification: "
<< notify->Action
<< std::endl;
}
if(notify->NextEntryOffset)
{
Debug(Debug::info) << "[WinDir] There is another notification to read" << std::endl;
notify = (PFILE_NOTIFY_INFORMATION)(((DWORD) notify) + notify->NextEntryOffset);
has_next = true;
}
else
{
Debug(Debug::debug) << "[WinDir] All event are consumed" << std::endl;
has_next = false;
}
} while (has_next);
}
else
{
Debug(Debug::info) << "[WinDir] Notification for not watched file received: "
<< filename << std::endl;
}
// restart a read with current Operation
if (!this->startReadFor(op))
{
Debug(Debug::error) << "[WinDir] Cannot restart a read: " << GetLastError()
<< std::endl;
throw GetLastError();
}
}
} |
Le probleme c'est que lorsque j'ajoute un fichier a monitorer, je recois DEUX notifications.
Lorsque j'enregistre un fichier j'ai donc deux notifications, par contre quand je le supprime je n'en ai qu'une.
Auriez vous des informations sur pourquoi ca reagis comme ca ?
Si vous avez besoin du code complet ...
Merci.
PS:
Voici le operation:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| struct Operation
{
Operation()
{}
~Operation()
{}
struct FileData
{
FileData()
{}
FileData(shared_ptr< ICallable > d, int m) :
callable(d), mode(m)
{}
FileData(const FileData& f) :
callable(f.callable), mode(f.mode)
{}
shared_ptr< ICallable > callable;
int mode;
};
typedef std::map <Path, FileData> FileDatas;
FileDatas watchedFiles;
OVERLAPPED overlapped;
CHAR changes[4096];
HANDLE dir;
Path path;
}; |