Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(572)

Side by Side Diff: base/files/file_path_watcher_linux.cc

Issue 89523002: Move Posix file utils to the base namespace. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/files/file_path_watcher_browsertest.cc ('k') | base/linux_util.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/file_path_watcher.h" 5 #include "base/files/file_path_watcher.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <string.h> 8 #include <string.h>
9 #include <sys/inotify.h> 9 #include <sys/inotify.h>
10 #include <sys/ioctl.h> 10 #include <sys/ioctl.h>
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 // change. Returns kInvalidWatch on failure. 49 // change. Returns kInvalidWatch on failure.
50 Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher); 50 Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher);
51 51
52 // Remove |watch|. Returns true on success. 52 // Remove |watch|. Returns true on success.
53 bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher); 53 bool RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
54 54
55 // Callback for InotifyReaderTask. 55 // Callback for InotifyReaderTask.
56 void OnInotifyEvent(const inotify_event* event); 56 void OnInotifyEvent(const inotify_event* event);
57 57
58 private: 58 private:
59 friend struct ::base::DefaultLazyInstanceTraits<InotifyReader>; 59 friend struct DefaultLazyInstanceTraits<InotifyReader>;
60 60
61 typedef std::set<FilePathWatcherImpl*> WatcherSet; 61 typedef std::set<FilePathWatcherImpl*> WatcherSet;
62 62
63 InotifyReader(); 63 InotifyReader();
64 ~InotifyReader(); 64 ~InotifyReader();
65 65
66 // We keep track of which delegates want to be notified on which watches. 66 // We keep track of which delegates want to be notified on which watches.
67 base::hash_map<Watch, WatcherSet> watchers_; 67 hash_map<Watch, WatcherSet> watchers_;
68 68
69 // Lock to protect watchers_. 69 // Lock to protect watchers_.
70 base::Lock lock_; 70 Lock lock_;
71 71
72 // Separate thread on which we run blocking read for inotify events. 72 // Separate thread on which we run blocking read for inotify events.
73 base::Thread thread_; 73 Thread thread_;
74 74
75 // File descriptor returned by inotify_init. 75 // File descriptor returned by inotify_init.
76 const int inotify_fd_; 76 const int inotify_fd_;
77 77
78 // Use self-pipe trick to unblock select during shutdown. 78 // Use self-pipe trick to unblock select during shutdown.
79 int shutdown_pipe_[2]; 79 int shutdown_pipe_[2];
80 80
81 // Flag set to true when startup was successful. 81 // Flag set to true when startup was successful.
82 bool valid_; 82 bool valid_;
83 83
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 }; 152 };
153 153
154 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd, 154 void InotifyReaderCallback(InotifyReader* reader, int inotify_fd,
155 int shutdown_fd) { 155 int shutdown_fd) {
156 // Make sure the file descriptors are good for use with select(). 156 // Make sure the file descriptors are good for use with select().
157 CHECK_LE(0, inotify_fd); 157 CHECK_LE(0, inotify_fd);
158 CHECK_GT(FD_SETSIZE, inotify_fd); 158 CHECK_GT(FD_SETSIZE, inotify_fd);
159 CHECK_LE(0, shutdown_fd); 159 CHECK_LE(0, shutdown_fd);
160 CHECK_GT(FD_SETSIZE, shutdown_fd); 160 CHECK_GT(FD_SETSIZE, shutdown_fd);
161 161
162 base::debug::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop(); 162 debug::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
163 163
164 while (true) { 164 while (true) {
165 fd_set rfds; 165 fd_set rfds;
166 FD_ZERO(&rfds); 166 FD_ZERO(&rfds);
167 FD_SET(inotify_fd, &rfds); 167 FD_SET(inotify_fd, &rfds);
168 FD_SET(shutdown_fd, &rfds); 168 FD_SET(shutdown_fd, &rfds);
169 169
170 // Wait until some inotify events are available. 170 // Wait until some inotify events are available.
171 int select_result = 171 int select_result =
172 HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1, 172 HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1,
(...skipping 30 matching lines...) Expand all
203 while (i < bytes_read) { 203 while (i < bytes_read) {
204 inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]); 204 inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
205 size_t event_size = sizeof(inotify_event) + event->len; 205 size_t event_size = sizeof(inotify_event) + event->len;
206 DCHECK(i + event_size <= static_cast<size_t>(bytes_read)); 206 DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
207 reader->OnInotifyEvent(event); 207 reader->OnInotifyEvent(event);
208 i += event_size; 208 i += event_size;
209 } 209 }
210 } 210 }
211 } 211 }
212 212
213 static base::LazyInstance<InotifyReader>::Leaky g_inotify_reader = 213 static LazyInstance<InotifyReader>::Leaky g_inotify_reader =
214 LAZY_INSTANCE_INITIALIZER; 214 LAZY_INSTANCE_INITIALIZER;
215 215
216 InotifyReader::InotifyReader() 216 InotifyReader::InotifyReader()
217 : thread_("inotify_reader"), 217 : thread_("inotify_reader"),
218 inotify_fd_(inotify_init()), 218 inotify_fd_(inotify_init()),
219 valid_(false) { 219 valid_(false) {
220 if (inotify_fd_ < 0) 220 if (inotify_fd_ < 0)
221 PLOG(ERROR) << "inotify_init() failed"; 221 PLOG(ERROR) << "inotify_init() failed";
222 222
223 shutdown_pipe_[0] = -1; 223 shutdown_pipe_[0] = -1;
224 shutdown_pipe_[1] = -1; 224 shutdown_pipe_[1] = -1;
225 if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) { 225 if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
226 thread_.message_loop()->PostTask( 226 thread_.message_loop()->PostTask(
227 FROM_HERE, base::Bind(&InotifyReaderCallback, this, inotify_fd_, 227 FROM_HERE, Bind(&InotifyReaderCallback, this, inotify_fd_,
228 shutdown_pipe_[0])); 228 shutdown_pipe_[0]));
229 valid_ = true; 229 valid_ = true;
230 } 230 }
231 } 231 }
232 232
233 InotifyReader::~InotifyReader() { 233 InotifyReader::~InotifyReader() {
234 if (valid_) { 234 if (valid_) {
235 // Write to the self-pipe so that the select call in InotifyReaderTask 235 // Write to the self-pipe so that the select call in InotifyReaderTask
236 // returns. 236 // returns.
237 ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1)); 237 ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
238 DPCHECK(ret > 0); 238 DPCHECK(ret > 0);
239 DCHECK_EQ(ret, 1); 239 DCHECK_EQ(ret, 1);
240 thread_.Stop(); 240 thread_.Stop();
241 } 241 }
242 if (inotify_fd_ >= 0) 242 if (inotify_fd_ >= 0)
243 close(inotify_fd_); 243 close(inotify_fd_);
244 if (shutdown_pipe_[0] >= 0) 244 if (shutdown_pipe_[0] >= 0)
245 close(shutdown_pipe_[0]); 245 close(shutdown_pipe_[0]);
246 if (shutdown_pipe_[1] >= 0) 246 if (shutdown_pipe_[1] >= 0)
247 close(shutdown_pipe_[1]); 247 close(shutdown_pipe_[1]);
248 } 248 }
249 249
250 InotifyReader::Watch InotifyReader::AddWatch( 250 InotifyReader::Watch InotifyReader::AddWatch(
251 const FilePath& path, FilePathWatcherImpl* watcher) { 251 const FilePath& path, FilePathWatcherImpl* watcher) {
252 if (!valid_) 252 if (!valid_)
253 return kInvalidWatch; 253 return kInvalidWatch;
254 254
255 base::AutoLock auto_lock(lock_); 255 AutoLock auto_lock(lock_);
256 256
257 Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(), 257 Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
258 IN_CREATE | IN_DELETE | 258 IN_CREATE | IN_DELETE |
259 IN_CLOSE_WRITE | IN_MOVE | 259 IN_CLOSE_WRITE | IN_MOVE |
260 IN_ONLYDIR); 260 IN_ONLYDIR);
261 261
262 if (watch == kInvalidWatch) 262 if (watch == kInvalidWatch)
263 return kInvalidWatch; 263 return kInvalidWatch;
264 264
265 watchers_[watch].insert(watcher); 265 watchers_[watch].insert(watcher);
266 266
267 return watch; 267 return watch;
268 } 268 }
269 269
270 bool InotifyReader::RemoveWatch(Watch watch, 270 bool InotifyReader::RemoveWatch(Watch watch,
271 FilePathWatcherImpl* watcher) { 271 FilePathWatcherImpl* watcher) {
272 if (!valid_) 272 if (!valid_)
273 return false; 273 return false;
274 274
275 base::AutoLock auto_lock(lock_); 275 AutoLock auto_lock(lock_);
276 276
277 watchers_[watch].erase(watcher); 277 watchers_[watch].erase(watcher);
278 278
279 if (watchers_[watch].empty()) { 279 if (watchers_[watch].empty()) {
280 watchers_.erase(watch); 280 watchers_.erase(watch);
281 return (inotify_rm_watch(inotify_fd_, watch) == 0); 281 return (inotify_rm_watch(inotify_fd_, watch) == 0);
282 } 282 }
283 283
284 return true; 284 return true;
285 } 285 }
286 286
287 void InotifyReader::OnInotifyEvent(const inotify_event* event) { 287 void InotifyReader::OnInotifyEvent(const inotify_event* event) {
288 if (event->mask & IN_IGNORED) 288 if (event->mask & IN_IGNORED)
289 return; 289 return;
290 290
291 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); 291 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
292 base::AutoLock auto_lock(lock_); 292 AutoLock auto_lock(lock_);
293 293
294 for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); 294 for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
295 watcher != watchers_[event->wd].end(); 295 watcher != watchers_[event->wd].end();
296 ++watcher) { 296 ++watcher) {
297 (*watcher)->OnFilePathChanged(event->wd, 297 (*watcher)->OnFilePathChanged(event->wd,
298 child, 298 child,
299 event->mask & (IN_CREATE | IN_MOVED_TO)); 299 event->mask & (IN_CREATE | IN_MOVED_TO));
300 } 300 }
301 } 301 }
302 302
303 FilePathWatcherImpl::FilePathWatcherImpl() { 303 FilePathWatcherImpl::FilePathWatcherImpl() {
304 } 304 }
305 305
306 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, 306 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
307 const FilePath::StringType& child, 307 const FilePath::StringType& child,
308 bool created) { 308 bool created) {
309 if (!message_loop()->BelongsToCurrentThread()) { 309 if (!message_loop()->BelongsToCurrentThread()) {
310 // Switch to message_loop_ to access watches_ safely. 310 // Switch to message_loop_ to access watches_ safely.
311 message_loop()->PostTask(FROM_HERE, 311 message_loop()->PostTask(FROM_HERE,
312 base::Bind(&FilePathWatcherImpl::OnFilePathChanged, 312 Bind(&FilePathWatcherImpl::OnFilePathChanged,
313 this, 313 this,
314 fired_watch, 314 fired_watch,
315 child, 315 child,
316 created)); 316 created));
317 return; 317 return;
318 } 318 }
319 319
320 DCHECK(MessageLoopForIO::current()); 320 DCHECK(MessageLoopForIO::current());
321 321
322 // Find the entry in |watches_| that corresponds to |fired_watch|. 322 // Find the entry in |watches_| that corresponds to |fired_watch|.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 bool recursive, 369 bool recursive,
370 const FilePathWatcher::Callback& callback) { 370 const FilePathWatcher::Callback& callback) {
371 DCHECK(target_.empty()); 371 DCHECK(target_.empty());
372 DCHECK(MessageLoopForIO::current()); 372 DCHECK(MessageLoopForIO::current());
373 if (recursive) { 373 if (recursive) {
374 // Recursive watch is not supported on this platform. 374 // Recursive watch is not supported on this platform.
375 NOTIMPLEMENTED(); 375 NOTIMPLEMENTED();
376 return false; 376 return false;
377 } 377 }
378 378
379 set_message_loop(base::MessageLoopProxy::current().get()); 379 set_message_loop(MessageLoopProxy::current().get());
380 callback_ = callback; 380 callback_ = callback;
381 target_ = path; 381 target_ = path;
382 MessageLoop::current()->AddDestructionObserver(this); 382 MessageLoop::current()->AddDestructionObserver(this);
383 383
384 std::vector<FilePath::StringType> comps; 384 std::vector<FilePath::StringType> comps;
385 target_.GetComponents(&comps); 385 target_.GetComponents(&comps);
386 DCHECK(!comps.empty()); 386 DCHECK(!comps.empty());
387 std::vector<FilePath::StringType>::const_iterator comp = comps.begin(); 387 std::vector<FilePath::StringType>::const_iterator comp = comps.begin();
388 for (++comp; comp != comps.end(); ++comp) 388 for (++comp; comp != comps.end(); ++comp)
389 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp)); 389 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
390 390
391 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, 391 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
392 FilePath::StringType())); 392 FilePath::StringType()));
393 return UpdateWatches(); 393 return UpdateWatches();
394 } 394 }
395 395
396 void FilePathWatcherImpl::Cancel() { 396 void FilePathWatcherImpl::Cancel() {
397 if (callback_.is_null()) { 397 if (callback_.is_null()) {
398 // Watch was never called, or the |message_loop_| thread is already gone. 398 // Watch was never called, or the |message_loop_| thread is already gone.
399 set_cancelled(); 399 set_cancelled();
400 return; 400 return;
401 } 401 }
402 402
403 // Switch to the message_loop_ if necessary so we can access |watches_|. 403 // Switch to the message_loop_ if necessary so we can access |watches_|.
404 if (!message_loop()->BelongsToCurrentThread()) { 404 if (!message_loop()->BelongsToCurrentThread()) {
405 message_loop()->PostTask(FROM_HERE, 405 message_loop()->PostTask(FROM_HERE,
406 base::Bind(&FilePathWatcher::CancelWatch, 406 Bind(&FilePathWatcher::CancelWatch,
407 make_scoped_refptr(this))); 407 make_scoped_refptr(this)));
408 } else { 408 } else {
409 CancelOnMessageLoopThread(); 409 CancelOnMessageLoopThread();
410 } 410 }
411 } 411 }
412 412
413 void FilePathWatcherImpl::CancelOnMessageLoopThread() { 413 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
414 if (!is_cancelled()) 414 if (!is_cancelled())
415 set_cancelled(); 415 set_cancelled();
416 416
(...skipping 24 matching lines...) Expand all
441 FilePath path(FILE_PATH_LITERAL("/")); 441 FilePath path(FILE_PATH_LITERAL("/"));
442 bool path_valid = true; 442 bool path_valid = true;
443 for (WatchVector::iterator watch_entry(watches_.begin()); 443 for (WatchVector::iterator watch_entry(watches_.begin());
444 watch_entry != watches_.end(); ++watch_entry) { 444 watch_entry != watches_.end(); ++watch_entry) {
445 InotifyReader::Watch old_watch = watch_entry->watch_; 445 InotifyReader::Watch old_watch = watch_entry->watch_;
446 if (path_valid) { 446 if (path_valid) {
447 watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this); 447 watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
448 if ((watch_entry->watch_ == InotifyReader::kInvalidWatch) && 448 if ((watch_entry->watch_ == InotifyReader::kInvalidWatch) &&
449 file_util::IsLink(path)) { 449 file_util::IsLink(path)) {
450 FilePath link; 450 FilePath link;
451 if (file_util::ReadSymbolicLink(path, &link)) { 451 if (ReadSymbolicLink(path, &link)) {
452 if (!link.IsAbsolute()) 452 if (!link.IsAbsolute())
453 link = path.DirName().Append(link); 453 link = path.DirName().Append(link);
454 // Try watching symlink target directory. If the link target is "/", 454 // Try watching symlink target directory. If the link target is "/",
455 // then we shouldn't get here in normal situations and if we do, we'd 455 // then we shouldn't get here in normal situations and if we do, we'd
456 // watch "/" for changes to a component "/" which is harmless so no 456 // watch "/" for changes to a component "/" which is harmless so no
457 // special treatment of this case is required. 457 // special treatment of this case is required.
458 watch_entry->watch_ = 458 watch_entry->watch_ =
459 g_inotify_reader.Get().AddWatch(link.DirName(), this); 459 g_inotify_reader.Get().AddWatch(link.DirName(), this);
460 if (watch_entry->watch_ != InotifyReader::kInvalidWatch) { 460 if (watch_entry->watch_ != InotifyReader::kInvalidWatch) {
461 watch_entry->linkname_ = link.BaseName().value(); 461 watch_entry->linkname_ = link.BaseName().value();
(...skipping 22 matching lines...) Expand all
484 return true; 484 return true;
485 } 485 }
486 486
487 } // namespace 487 } // namespace
488 488
489 FilePathWatcher::FilePathWatcher() { 489 FilePathWatcher::FilePathWatcher() {
490 impl_ = new FilePathWatcherImpl(); 490 impl_ = new FilePathWatcherImpl();
491 } 491 }
492 492
493 } // namespace base 493 } // namespace base
OLDNEW
« no previous file with comments | « base/files/file_path_watcher_browsertest.cc ('k') | base/linux_util.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698