diff options
Diffstat (limited to 'src/3rdParty/efsw/FileWatcherKqueue.cpp')
-rwxr-xr-x | src/3rdParty/efsw/FileWatcherKqueue.cpp | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/3rdParty/efsw/FileWatcherKqueue.cpp b/src/3rdParty/efsw/FileWatcherKqueue.cpp new file mode 100755 index 0000000..9c86755 --- /dev/null +++ b/src/3rdParty/efsw/FileWatcherKqueue.cpp | |||
@@ -0,0 +1,227 @@ | |||
1 | #include <efsw/FileWatcherKqueue.hpp> | ||
2 | |||
3 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS | ||
4 | |||
5 | #include <dirent.h> | ||
6 | #include <efsw/Debug.hpp> | ||
7 | #include <efsw/FileSystem.hpp> | ||
8 | #include <efsw/Lock.hpp> | ||
9 | #include <efsw/System.hpp> | ||
10 | #include <efsw/WatcherGeneric.hpp> | ||
11 | #include <errno.h> | ||
12 | #include <fcntl.h> | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <string.h> | ||
16 | #include <sys/stat.h> | ||
17 | #include <sys/time.h> | ||
18 | #include <unistd.h> | ||
19 | |||
20 | namespace efsw { | ||
21 | |||
22 | FileWatcherKqueue::FileWatcherKqueue( FileWatcher* parent ) : | ||
23 | FileWatcherImpl( parent ), | ||
24 | mLastWatchID( 0 ), | ||
25 | mThread( NULL ), | ||
26 | mFileDescriptorCount( 1 ), | ||
27 | mAddingWatcher( false ) { | ||
28 | mTimeOut.tv_sec = 0; | ||
29 | mTimeOut.tv_nsec = 0; | ||
30 | mInitOK = true; | ||
31 | } | ||
32 | |||
33 | FileWatcherKqueue::~FileWatcherKqueue() { | ||
34 | WatchMap::iterator iter = mWatches.begin(); | ||
35 | |||
36 | for ( ; iter != mWatches.end(); ++iter ) { | ||
37 | efSAFE_DELETE( iter->second ); | ||
38 | } | ||
39 | |||
40 | mWatches.clear(); | ||
41 | |||
42 | mInitOK = false; | ||
43 | |||
44 | efSAFE_DELETE( mThread ); | ||
45 | } | ||
46 | |||
47 | WatchID FileWatcherKqueue::addWatch( const std::string& directory, FileWatchListener* watcher, | ||
48 | bool recursive ) { | ||
49 | static bool s_ug = false; | ||
50 | |||
51 | std::string dir( directory ); | ||
52 | |||
53 | FileSystem::dirAddSlashAtEnd( dir ); | ||
54 | |||
55 | FileInfo fi( dir ); | ||
56 | |||
57 | if ( !fi.isDirectory() ) { | ||
58 | return Errors::Log::createLastError( Errors::FileNotFound, dir ); | ||
59 | } else if ( !fi.isReadable() ) { | ||
60 | return Errors::Log::createLastError( Errors::FileNotReadable, dir ); | ||
61 | } else if ( pathInWatches( dir ) ) { | ||
62 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
63 | } | ||
64 | |||
65 | std::string curPath; | ||
66 | std::string link( FileSystem::getLinkRealPath( dir, curPath ) ); | ||
67 | |||
68 | if ( "" != link ) { | ||
69 | if ( pathInWatches( link ) ) { | ||
70 | return Errors::Log::createLastError( Errors::FileRepeated, directory ); | ||
71 | } else if ( !linkAllowed( curPath, link ) ) { | ||
72 | return Errors::Log::createLastError( Errors::FileOutOfScope, dir ); | ||
73 | } else { | ||
74 | dir = link; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /// Check first if are enough file descriptors available to create another kqueue watcher, | ||
79 | /// otherwise it creates a generic watcher | ||
80 | if ( availablesFD() ) { | ||
81 | mAddingWatcher = true; | ||
82 | |||
83 | WatcherKqueue* watch = new WatcherKqueue( ++mLastWatchID, dir, watcher, recursive, this ); | ||
84 | |||
85 | { | ||
86 | Lock lock( mWatchesLock ); | ||
87 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
88 | } | ||
89 | |||
90 | watch->addAll(); | ||
91 | |||
92 | // if failed to open the directory... erase the watcher | ||
93 | if ( !watch->initOK() ) { | ||
94 | int le = watch->lastErrno(); | ||
95 | |||
96 | mWatches.erase( watch->ID ); | ||
97 | |||
98 | efSAFE_DELETE( watch ); | ||
99 | |||
100 | mLastWatchID--; | ||
101 | |||
102 | // Probably the folder has too many files, create a generic watcher | ||
103 | if ( EACCES != le ) { | ||
104 | WatcherGeneric* genericWatch = | ||
105 | new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); | ||
106 | |||
107 | Lock lock( mWatchesLock ); | ||
108 | mWatches.insert( std::make_pair( mLastWatchID, genericWatch ) ); | ||
109 | } else { | ||
110 | return Errors::Log::createLastError( Errors::Unspecified, link ); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | mAddingWatcher = false; | ||
115 | } else { | ||
116 | if ( !s_ug ) { | ||
117 | efDEBUG( "Started using generic watcher, file descriptor limit reached: %ld\n", | ||
118 | mFileDescriptorCount ); | ||
119 | s_ug = true; | ||
120 | } | ||
121 | |||
122 | WatcherGeneric* watch = new WatcherGeneric( ++mLastWatchID, dir, watcher, this, recursive ); | ||
123 | |||
124 | Lock lock( mWatchesLock ); | ||
125 | mWatches.insert( std::make_pair( mLastWatchID, watch ) ); | ||
126 | } | ||
127 | |||
128 | return mLastWatchID; | ||
129 | } | ||
130 | |||
131 | void FileWatcherKqueue::removeWatch( const std::string& directory ) { | ||
132 | Lock lock( mWatchesLock ); | ||
133 | |||
134 | WatchMap::iterator iter = mWatches.begin(); | ||
135 | |||
136 | for ( ; iter != mWatches.end(); ++iter ) { | ||
137 | if ( directory == iter->second->Directory ) { | ||
138 | removeWatch( iter->first ); | ||
139 | return; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | void FileWatcherKqueue::removeWatch( WatchID watchid ) { | ||
145 | Lock lock( mWatchesLock ); | ||
146 | |||
147 | WatchMap::iterator iter = mWatches.find( watchid ); | ||
148 | |||
149 | if ( iter == mWatches.end() ) | ||
150 | return; | ||
151 | |||
152 | Watcher* watch = iter->second; | ||
153 | |||
154 | mWatches.erase( iter ); | ||
155 | |||
156 | efSAFE_DELETE( watch ); | ||
157 | } | ||
158 | |||
159 | bool FileWatcherKqueue::isAddingWatcher() const { | ||
160 | return mAddingWatcher; | ||
161 | } | ||
162 | |||
163 | void FileWatcherKqueue::watch() { | ||
164 | if ( NULL == mThread ) { | ||
165 | mThread = new Thread( &FileWatcherKqueue::run, this ); | ||
166 | mThread->launch(); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void FileWatcherKqueue::run() { | ||
171 | do { | ||
172 | { | ||
173 | Lock lock( mWatchesLock ); | ||
174 | |||
175 | for ( WatchMap::iterator it = mWatches.begin(); it != mWatches.end(); ++it ) { | ||
176 | it->second->watch(); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | System::sleep( 500 ); | ||
181 | } while ( mInitOK ); | ||
182 | } | ||
183 | |||
184 | void FileWatcherKqueue::handleAction( Watcher* watch, const std::string& filename, | ||
185 | unsigned long action, std::string oldFilename ) {} | ||
186 | |||
187 | std::list<std::string> FileWatcherKqueue::directories() { | ||
188 | std::list<std::string> dirs; | ||
189 | |||
190 | Lock lock( mWatchesLock ); | ||
191 | |||
192 | WatchMap::iterator it = mWatches.begin(); | ||
193 | |||
194 | for ( ; it != mWatches.end(); ++it ) { | ||
195 | dirs.push_back( it->second->Directory ); | ||
196 | } | ||
197 | |||
198 | return dirs; | ||
199 | } | ||
200 | |||
201 | bool FileWatcherKqueue::pathInWatches( const std::string& path ) { | ||
202 | WatchMap::iterator it = mWatches.begin(); | ||
203 | |||
204 | for ( ; it != mWatches.end(); ++it ) { | ||
205 | if ( it->second->Directory == path ) { | ||
206 | return true; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | return false; | ||
211 | } | ||
212 | |||
213 | void FileWatcherKqueue::addFD() { | ||
214 | mFileDescriptorCount++; | ||
215 | } | ||
216 | |||
217 | void FileWatcherKqueue::removeFD() { | ||
218 | mFileDescriptorCount--; | ||
219 | } | ||
220 | |||
221 | bool FileWatcherKqueue::availablesFD() { | ||
222 | return mFileDescriptorCount <= (Int64)System::getMaxFD() - 500; | ||
223 | } | ||
224 | |||
225 | } // namespace efsw | ||
226 | |||
227 | #endif | ||