aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/efsw/FileWatcherInotify.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdParty/efsw/FileWatcherInotify.cpp')
-rw-r--r--[-rwxr-xr-x]src/3rdParty/efsw/FileWatcherInotify.cpp140
1 files changed, 58 insertions, 82 deletions
diff --git a/src/3rdParty/efsw/FileWatcherInotify.cpp b/src/3rdParty/efsw/FileWatcherInotify.cpp
index e0da76b..1ec3d48 100755..100644
--- a/src/3rdParty/efsw/FileWatcherInotify.cpp
+++ b/src/3rdParty/efsw/FileWatcherInotify.cpp
@@ -1,3 +1,4 @@
1#include <algorithm>
1#include <efsw/FileWatcherInotify.hpp> 2#include <efsw/FileWatcherInotify.hpp>
2 3
3#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 4#if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY
@@ -26,7 +27,7 @@
26namespace efsw { 27namespace efsw {
27 28
28FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) : 29FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) :
29 FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ) { 30 FileWatcherImpl( parent ), mFD( -1 ), mThread( NULL ), mIsTakingAction( false ) {
30 mFD = inotify_init(); 31 mFD = inotify_init();
31 32
32 if ( mFD < 0 ) { 33 if ( mFD < 0 ) {
@@ -38,13 +39,20 @@ FileWatcherInotify::FileWatcherInotify( FileWatcher* parent ) :
38 39
39FileWatcherInotify::~FileWatcherInotify() { 40FileWatcherInotify::~FileWatcherInotify() {
40 mInitOK = false; 41 mInitOK = false;
41 42 // There is deadlock when release FileWatcherInotify instance since its handAction
43 // function is still running and hangs in requiring lock without init lock captured.
44 while ( mIsTakingAction ) {
45 // It'd use condition-wait instead of sleep. Actually efsw has no such
46 // implementation so we just skip and sleep while for that to avoid deadlock.
47 usleep( 1000 );
48 };
42 Lock initLock( mInitLock ); 49 Lock initLock( mInitLock );
43 50
44 efSAFE_DELETE( mThread ); 51 efSAFE_DELETE( mThread );
45 52
46 Lock l( mWatchesLock ); 53 Lock l( mWatchesLock );
47 Lock l2( mRealWatchesLock ); 54 Lock l2( mRealWatchesLock );
55
48 WatchMap::iterator iter = mWatches.begin(); 56 WatchMap::iterator iter = mWatches.begin();
49 WatchMap::iterator end = mWatches.end(); 57 WatchMap::iterator end = mWatches.end();
50 58
@@ -61,15 +69,17 @@ FileWatcherInotify::~FileWatcherInotify() {
61} 69}
62 70
63WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, 71WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
64 bool recursive ) { 72 bool recursive, const std::vector<WatcherOption>& options ) {
65 if ( !mInitOK ) 73 if ( !mInitOK )
66 return Errors::Log::createLastError( Errors::Unspecified, directory ); 74 return Errors::Log::createLastError( Errors::Unspecified, directory );
67 Lock initLock( mInitLock ); 75 Lock initLock( mInitLock );
68 return addWatch( directory, watcher, recursive, NULL ); 76 bool syntheticEvents = getOptionValue( options, Options::LinuxProduceSyntheticEvents, 0 ) != 0;
77 return addWatch( directory, watcher, recursive, syntheticEvents, NULL );
69} 78}
70 79
71WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher, 80WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchListener* watcher,
72 bool recursive, WatcherInotify* parent ) { 81 bool recursive, bool syntheticEvents,
82 WatcherInotify* parent, bool fromInternalEvent ) {
73 std::string dir( directory ); 83 std::string dir( directory );
74 84
75 FileSystem::dirAddSlashAtEnd( dir ); 85 FileSystem::dirAddSlashAtEnd( dir );
@@ -133,6 +143,7 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
133 { 143 {
134 Lock lock( mWatchesLock ); 144 Lock lock( mWatchesLock );
135 mWatches.insert( std::make_pair( wd, pWatch ) ); 145 mWatches.insert( std::make_pair( wd, pWatch ) );
146 mWatchesRef[pWatch->Directory] = wd;
136 } 147 }
137 148
138 if ( NULL == pWatch->Parent ) { 149 if ( NULL == pWatch->Parent ) {
@@ -151,7 +162,17 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
151 const FileInfo& cfi = it->second; 162 const FileInfo& cfi = it->second;
152 163
153 if ( cfi.isDirectory() && cfi.isReadable() ) { 164 if ( cfi.isDirectory() && cfi.isReadable() ) {
154 addWatch( cfi.Filepath, watcher, recursive, pWatch ); 165 addWatch( cfi.Filepath, watcher, recursive, syntheticEvents, pWatch );
166 }
167 }
168
169 if ( fromInternalEvent && parent != NULL && syntheticEvents ) {
170 for ( const auto& file : files ) {
171 if ( file.second.isRegularFile() ) {
172 pWatch->Listener->handleFileAction(
173 pWatch->ID, pWatch->Directory,
174 FileSystem::fileNameFromPath( file.second.Filepath ), Actions::Add );
175 }
155 } 176 }
156 } 177 }
157 } 178 }
@@ -161,6 +182,8 @@ WatchID FileWatcherInotify::addWatch( const std::string& directory, FileWatchLis
161 182
162void FileWatcherInotify::removeWatchLocked( WatchID watchid ) { 183void FileWatcherInotify::removeWatchLocked( WatchID watchid ) {
163 WatchMap::iterator iter = mWatches.find( watchid ); 184 WatchMap::iterator iter = mWatches.find( watchid );
185 if ( iter == mWatches.end() )
186 return;
164 187
165 WatcherInotify* watch = iter->second; 188 WatcherInotify* watch = iter->second;
166 189
@@ -173,22 +196,21 @@ void FileWatcherInotify::removeWatchLocked( WatchID watchid ) {
173 } 196 }
174 } 197 }
175 198
176 if ( watch->Recursive ) { 199 if ( watch->Recursive && NULL == watch->Parent ) {
177 WatchMap::iterator it = mWatches.begin(); 200 WatchMap::iterator it = mWatches.begin();
178 std::list<WatchID> eraseWatches; 201 std::vector<WatchID> eraseWatches;
179 202
180 for ( ; it != mWatches.end(); ++it ) { 203 for ( ; it != mWatches.end(); ++it )
181 if ( it->second != watch && it->second->inParentTree( watch ) ) { 204 if ( it->second != watch && it->second->inParentTree( watch ) )
182 eraseWatches.push_back( it->second->InotifyID ); 205 eraseWatches.push_back( it->second->InotifyID );
183 }
184 }
185 206
186 for ( std::list<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end(); 207 for ( std::vector<WatchID>::iterator eit = eraseWatches.begin(); eit != eraseWatches.end();
187 ++eit ) { 208 ++eit ) {
188 removeWatch( *eit ); 209 removeWatch( *eit );
189 } 210 }
190 } 211 }
191 212
213 mWatchesRef.erase( watch->Directory );
192 mWatches.erase( iter ); 214 mWatches.erase( iter );
193 215
194 if ( NULL == watch->Parent ) { 216 if ( NULL == watch->Parent ) {
@@ -217,52 +239,11 @@ void FileWatcherInotify::removeWatch( const std::string& directory ) {
217 Lock lock( mWatchesLock ); 239 Lock lock( mWatchesLock );
218 Lock l( mRealWatchesLock ); 240 Lock l( mRealWatchesLock );
219 241
220 WatchMap::iterator iter = mWatches.begin(); 242 std::unordered_map<std::string, WatchID>::iterator ref = mWatchesRef.find( directory );
221 243 if ( ref == mWatchesRef.end() )
222 for ( ; iter != mWatches.end(); ++iter ) { 244 return;
223 if ( directory == iter->second->Directory ) {
224 WatcherInotify* watch = iter->second;
225
226 if ( watch->Recursive ) {
227 WatchMap::iterator it = mWatches.begin();
228 std::list<WatchID> eraseWatches;
229
230 for ( ; it != mWatches.end(); ++it ) {
231 if ( it->second->inParentTree( watch ) ) {
232 eraseWatches.push_back( it->second->InotifyID );
233 }
234 }
235
236 for ( std::list<WatchID>::iterator eit = eraseWatches.begin();
237 eit != eraseWatches.end(); ++eit ) {
238 removeWatchLocked( *eit );
239 }
240 }
241
242 mWatches.erase( iter );
243
244 if ( NULL == watch->Parent ) {
245 WatchMap::iterator eraseit = mRealWatches.find( watch->InotifyID );
246
247 if ( eraseit != mRealWatches.end() ) {
248 mRealWatches.erase( eraseit );
249 }
250 }
251
252 int err = inotify_rm_watch( mFD, watch->InotifyID );
253
254 if ( err < 0 ) {
255 efDEBUG( "Error removing watch %d: %s\n", watch->InotifyID, strerror( errno ) );
256 } else {
257 efDEBUG( "Removed watch %s with id: %d\n", watch->Directory.c_str(),
258 watch->InotifyID );
259 }
260
261 efSAFE_DELETE( watch );
262 245
263 break; 246 removeWatchLocked( ref->second );
264 }
265 }
266} 247}
267 248
268void FileWatcherInotify::removeWatch( WatchID watchid ) { 249void FileWatcherInotify::removeWatch( WatchID watchid ) {
@@ -270,13 +251,6 @@ void FileWatcherInotify::removeWatch( WatchID watchid ) {
270 return; 251 return;
271 Lock initLock( mInitLock ); 252 Lock initLock( mInitLock );
272 Lock lock( mWatchesLock ); 253 Lock lock( mWatchesLock );
273
274 WatchMap::iterator iter = mWatches.find( watchid );
275
276 if ( iter == mWatches.end() ) {
277 return;
278 }
279
280 removeWatchLocked( watchid ); 254 removeWatchLocked( watchid );
281} 255}
282 256
@@ -295,10 +269,8 @@ Watcher* FileWatcherInotify::watcherContainsDirectory( std::string dir ) {
295 269
296 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { 270 for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) {
297 Watcher* watcher = it->second; 271 Watcher* watcher = it->second;
298 272 if ( watcher->Directory == watcherPath )
299 if ( watcher->Directory == watcherPath ) {
300 return watcher; 273 return watcher;
301 }
302 } 274 }
303 275
304 return NULL; 276 return NULL;
@@ -422,7 +394,7 @@ void FileWatcherInotify::run() {
422 const std::string& oldFileName = ( *it ).second; 394 const std::string& oldFileName = ( *it ).second;
423 395
424 /// Check if the file move was a folder already being watched 396 /// Check if the file move was a folder already being watched
425 std::list<Watcher*> eraseWatches; 397 std::vector<Watcher*> eraseWatches;
426 398
427 { 399 {
428 Lock lock( mWatchesLock ); 400 Lock lock( mWatchesLock );
@@ -439,12 +411,15 @@ void FileWatcherInotify::run() {
439 } 411 }
440 412
441 /// Remove invalid watches 413 /// Remove invalid watches
442 eraseWatches.sort(); 414 std::stable_sort( eraseWatches.begin(), eraseWatches.end(),
415 []( const Watcher* left, const Watcher* right ) {
416 return left->Directory < right->Directory;
417 } );
443 418
444 if ( eraseWatches.empty() ) { 419 if ( eraseWatches.empty() ) {
445 handleAction( watch, oldFileName, IN_DELETE ); 420 handleAction( watch, oldFileName, IN_DELETE );
446 } else { 421 } else {
447 for ( std::list<Watcher*>::reverse_iterator eit = eraseWatches.rbegin(); 422 for ( std::vector<Watcher*>::reverse_iterator eit = eraseWatches.rbegin();
448 eit != eraseWatches.rend(); ++eit ) { 423 eit != eraseWatches.rend(); ++eit ) {
449 Watcher* rmWatch = *eit; 424 Watcher* rmWatch = *eit;
450 425
@@ -485,8 +460,9 @@ void FileWatcherInotify::checkForNewWatcher( Watcher* watch, std::string fpath )
485 } 460 }
486 461
487 if ( !found ) { 462 if ( !found ) {
488 addWatch( fpath, watch->Listener, watch->Recursive, 463 WatcherInotify* iWatch = static_cast<WatcherInotify*>( watch );
489 static_cast<WatcherInotify*>( watch ) ); 464 addWatch( fpath, watch->Listener, watch->Recursive, iWatch->syntheticEvents,
465 static_cast<WatcherInotify*>( watch ), true );
490 } 466 }
491 } 467 }
492} 468}
@@ -496,7 +472,7 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena
496 if ( !watch || !watch->Listener || !mInitOK ) { 472 if ( !watch || !watch->Listener || !mInitOK ) {
497 return; 473 return;
498 } 474 }
499 475 mIsTakingAction = true;
500 Lock initLock( mInitLock ); 476 Lock initLock( mInitLock );
501 477
502 std::string fpath( watch->Directory + filename ); 478 std::string fpath( watch->Directory + filename );
@@ -563,18 +539,20 @@ void FileWatcherInotify::handleAction( Watcher* watch, const std::string& filena
563 } 539 }
564 } 540 }
565 } 541 }
542 mIsTakingAction = false;
566} 543}
567 544
568std::list<std::string> FileWatcherInotify::directories() { 545std::vector<std::string> FileWatcherInotify::directories() {
569 std::list<std::string> dirs; 546 std::vector<std::string> dirs;
570 547
571 Lock l( mRealWatchesLock ); 548 Lock l( mRealWatchesLock );
572 549
550 dirs.reserve( mRealWatches.size() );
551
573 WatchMap::iterator it = mRealWatches.begin(); 552 WatchMap::iterator it = mRealWatches.begin();
574 553
575 for ( ; it != mRealWatches.end(); ++it ) { 554 for ( ; it != mRealWatches.end(); ++it )
576 dirs.push_back( it->second->Directory ); 555 dirs.push_back( it->second->Directory );
577 }
578 556
579 return dirs; 557 return dirs;
580} 558}
@@ -585,11 +563,9 @@ bool FileWatcherInotify::pathInWatches( const std::string& path ) {
585 /// Search in the real watches, since it must allow adding a watch already watched as a subdir 563 /// Search in the real watches, since it must allow adding a watch already watched as a subdir
586 WatchMap::iterator it = mRealWatches.begin(); 564 WatchMap::iterator it = mRealWatches.begin();
587 565
588 for ( ; it != mRealWatches.end(); ++it ) { 566 for ( ; it != mRealWatches.end(); ++it )
589 if ( it->second->Directory == path ) { 567 if ( it->second->Directory == path )
590 return true; 568 return true;
591 }
592 }
593 569
594 return false; 570 return false;
595} 571}