#include #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace efsw { FileWatcherKqueue::FileWatcherKqueue( FileWatcher* parent ) : FileWatcherImpl( parent ), mLastWatchID( 0 ), mThread( NULL ), mFileDescriptorCount( 1 ), mAddingWatcher( false ) { mTimeOut.tv_sec = 0; mTimeOut.tv_nsec = 0; mInitOK = true; } FileWatcherKqueue::~FileWatcherKqueue() { WatchMap::iterator iter = mWatches.begin(); for ( ; iter != mWatches.end(); ++iter ) { efSAFE_DELETE( iter->second ); } mWatches.clear(); mInitOK = false; efSAFE_DELETE( mThread ); } WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, bool recursive ) { static bool s_ug = false; std::string dir( directory ); FileSystem::dirAddSlashAtEnd( dir ); FileInfo fi( dir ); if ( !fi.isDirectory() ) { return Errors::Log::createLastError( Errors::FileNotFound, dir ); } else if ( !fi.isReadable() ) { return Errors::Log::createLastError( Errors::FileNotReadable, dir ); } else if ( pathInWatches( dir ) ) { return Errors::Log::createLastError( Errors::FileRepeated, directory ); } std::string curPath; std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); if ( "" != link ) { if ( pathInWatches( link ) ) { return Errors::Log::createLastError( Errors::FileRepeated, directory ); } else if ( !linkAllowed( curPath, link ) ) { return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); } else { dir = link; } } /// Check first if are enough file descriptors available to create another kqueue watcher, /// otherwise it creates a generic watcher if ( availablesFD() ) { mAddingWatcher = true; WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this ); { Lock lock( mWatchesLock ); mWatches.insert( std::make_pair( mLastWatchID, watch ) ); } watch->addAll(); // if failed to open the directory... erase the watcher if ( !watch->initOK() ) { int le = watch->lastErrno(); mWatches.erase( watch->ID ); efSAFE_DELETE( watch ); mLastWatchID--; // Probably the folder has too many files, create a generic watcher if ( EACCES != le ) { WatcherGeneric* genericWatch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); Lock lock( mWatchesLock ); mWatches.insert( std::make_pair( mLastWatchID, genericWatch ) ); } else { return Errors::Log::createLastError( Errors::Unspecified, link ); } } mAddingWatcher = false; } else { if ( !s_ug ) { efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", mFileDescriptorCount ); s_ug = true; } WatcherGeneric* watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); Lock lock( mWatchesLock ); mWatches.insert( std::make_pair( mLastWatchID, watch ) ); } return mLastWatchID; } void FileWatcherKqueue::removeWatch( const std::string& directory ) { Lock lock( mWatchesLock ); WatchMap::iterator iter = mWatches.begin(); for ( ; iter != mWatches.end(); ++iter ) { if ( directory == iter->second->Directory ) { removeWatch( iter->first ); return; } } } void FileWatcherKqueue::removeWatch( WatchID watchid ) { Lock lock( mWatchesLock ); WatchMap::iterator iter = mWatches.find( watchid ); if ( iter == mWatches.end() ) return; Watcher* watch = iter->second; mWatches.erase( iter ); efSAFE_DELETE( watch ); } bool FileWatcherKqueue::isAddingWatcher() const { return mAddingWatcher; } void FileWatcherKqueue::watch() { if ( NULL == mThread ) { mThread = new Thread( &FileWatcherKqueue::run, this ); mThread->launch(); } } void FileWatcherKqueue::run() { do { { Lock lock( mWatchesLock ); for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { it->second->watch(); } } System::sleep( 500 ); } while ( mInitOK ); } void FileWatcherKqueue::handleAction( Watcher* /*watch*/, const std::string& /*filename*/, unsigned long /*action*/, std::string /*oldFilename*/ ) {} std::list FileWatcherKqueue::directories() { std::list dirs; Lock lock( mWatchesLock ); WatchMap::iterator it = mWatches.begin(); for ( ; it != mWatches.end(); ++it ) { dirs.push_back( it->second->Directory ); } return dirs; } bool FileWatcherKqueue::pathInWatches( const std::string& path ) { WatchMap::iterator it = mWatches.begin(); for ( ; it != mWatches.end(); ++it ) { if ( it->second->Directory == path ) { return true; } } return false; } void FileWatcherKqueue::addFD() { mFileDescriptorCount++; } void FileWatcherKqueue::removeFD() { mFileDescriptorCount--; } bool FileWatcherKqueue::availablesFD() { return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500; } } // namespace efsw #endif