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

Side by Side Diff: content/common/file_path_watcher/file_path_watcher_inotify.cc

Issue 6670081: Move FilePathWatcher class from browser/... to common/... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments Created 9 years, 9 months 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/file_path_watcher/file_path_watcher.h" 5 #include "content/common/file_path_watcher/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>
11 #include <sys/select.h> 11 #include <sys/select.h>
12 #include <unistd.h> 12 #include <unistd.h>
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <set> 15 #include <set>
16 #include <utility> 16 #include <utility>
17 #include <vector> 17 #include <vector>
18 18
19 #include "base/eintr_wrapper.h" 19 #include "base/eintr_wrapper.h"
20 #include "base/file_path.h" 20 #include "base/file_path.h"
21 #include "base/file_util.h" 21 #include "base/file_util.h"
22 #include "base/hash_tables.h" 22 #include "base/hash_tables.h"
23 #include "base/lazy_instance.h" 23 #include "base/lazy_instance.h"
24 #include "base/logging.h" 24 #include "base/logging.h"
25 #include "base/message_loop.h" 25 #include "base/message_loop.h"
26 #include "base/message_loop_proxy.h"
26 #include "base/scoped_ptr.h" 27 #include "base/scoped_ptr.h"
27 #include "base/synchronization/lock.h" 28 #include "base/synchronization/lock.h"
28 #include "base/task.h" 29 #include "base/task.h"
29 #include "base/threading/thread.h" 30 #include "base/threading/thread.h"
30 31
31 namespace { 32 namespace {
32 33
33 class FilePathWatcherImpl; 34 class FilePathWatcherImpl;
34 35
35 // Singleton to manage all inotify watches. 36 // Singleton to manage all inotify watches.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 // the currently watched path for |fired_watch|. The flag |created| is true if 89 // the currently watched path for |fired_watch|. The flag |created| is true if
89 // the object appears, and |is_directory| is set when the event refers to a 90 // the object appears, and |is_directory| is set when the event refers to a
90 // directory. 91 // directory.
91 void OnFilePathChanged(InotifyReader::Watch fired_watch, 92 void OnFilePathChanged(InotifyReader::Watch fired_watch,
92 const FilePath::StringType& child, 93 const FilePath::StringType& child,
93 bool created, 94 bool created,
94 bool is_directory); 95 bool is_directory);
95 96
96 // Start watching |path| for changes and notify |delegate| on each change. 97 // Start watching |path| for changes and notify |delegate| on each change.
97 // Returns true if watch for |path| has been added successfully. 98 // Returns true if watch for |path| has been added successfully.
98 virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate); 99 virtual bool Watch(const FilePath& path,
100 FilePathWatcher::Delegate* delegate,
101 scoped_refptr<base::MessageLoopProxy> loop) OVERRIDE;
99 102
100 // Cancel the watch. This unregisters the instance with InotifyReader. 103 // Cancel the watch. This unregisters the instance with InotifyReader.
101 virtual void Cancel(); 104 virtual void Cancel() OVERRIDE;
102 105
103 private: 106 private:
104 virtual ~FilePathWatcherImpl() {} 107 virtual ~FilePathWatcherImpl() {}
105 108
106 // Inotify watches are installed for all directory components of |target_|. A 109 // Inotify watches are installed for all directory components of |target_|. A
107 // WatchEntry instance holds the watch descriptor for a component and the 110 // WatchEntry instance holds the watch descriptor for a component and the
108 // subdirectory for that identifies the next component. 111 // subdirectory for that identifies the next component.
109 struct WatchEntry { 112 struct WatchEntry {
110 WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir) 113 WatchEntry(InotifyReader::Watch watch, const FilePath::StringType& subdir)
111 : watch_(watch), 114 : watch_(watch),
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 void InotifyReader::OnInotifyEvent(const inotify_event* event) { 276 void InotifyReader::OnInotifyEvent(const inotify_event* event) {
274 if (event->mask & IN_IGNORED) 277 if (event->mask & IN_IGNORED)
275 return; 278 return;
276 279
277 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL("")); 280 FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
278 base::AutoLock auto_lock(lock_); 281 base::AutoLock auto_lock(lock_);
279 282
280 for (WatcherSet::iterator watcher = watchers_[event->wd].begin(); 283 for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
281 watcher != watchers_[event->wd].end(); 284 watcher != watchers_[event->wd].end();
282 ++watcher) { 285 ++watcher) {
283 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 286 (*watcher)->message_loop()->PostTask(FROM_HERE,
Mattias Nissler (ping if slow) 2011/03/17 18:14:27 This is what I was referring to in my other commen
284 NewRunnableMethod(*watcher, 287 NewRunnableMethod(*watcher,
285 &FilePathWatcherImpl::OnFilePathChanged, 288 &FilePathWatcherImpl::OnFilePathChanged,
286 event->wd, 289 event->wd,
287 child, 290 child,
288 event->mask & (IN_CREATE | IN_MOVED_TO), 291 event->mask & (IN_CREATE | IN_MOVED_TO),
289 event->mask & IN_ISDIR)); 292 event->mask & IN_ISDIR));
290 } 293 }
291 } 294 }
292 295
293 FilePathWatcherImpl::FilePathWatcherImpl() 296 FilePathWatcherImpl::FilePathWatcherImpl()
294 : delegate_(NULL) { 297 : delegate_(NULL) {
295 } 298 }
296 299
297 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch, 300 void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
298 const FilePath::StringType& child, 301 const FilePath::StringType& child,
299 bool created, 302 bool created,
300 bool is_directory) { 303 bool is_directory) {
301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 304 DCHECK(MessageLoopForIO::current());
302 305
303 // Find the entry in |watches_| that corresponds to |fired_watch|. 306 // Find the entry in |watches_| that corresponds to |fired_watch|.
304 WatchVector::const_iterator watch_entry(watches_.begin()); 307 WatchVector::const_iterator watch_entry(watches_.begin());
305 for ( ; watch_entry != watches_.end(); ++watch_entry) { 308 for ( ; watch_entry != watches_.end(); ++watch_entry) {
306 if (fired_watch == watch_entry->watch_) 309 if (fired_watch == watch_entry->watch_)
307 break; 310 break;
308 } 311 }
309 312
310 // If this notification is from a previous generation of watches or the watch 313 // If this notification is from a previous generation of watches or the watch
311 // has been cancelled (|watches_| is empty then), bail out. 314 // has been cancelled (|watches_| is empty then), bail out.
(...skipping 22 matching lines...) Expand all
334 // - One of the parent directories appears. The event corresponding to the 337 // - One of the parent directories appears. The event corresponding to the
335 // target appearing might have been missed in this case, so recheck. 338 // target appearing might have been missed in this case, so recheck.
336 if (target_changed || 339 if (target_changed ||
337 (change_on_target_path && !created) || 340 (change_on_target_path && !created) ||
338 (change_on_target_path && file_util::PathExists(target_))) { 341 (change_on_target_path && file_util::PathExists(target_))) {
339 delegate_->OnFilePathChanged(target_); 342 delegate_->OnFilePathChanged(target_);
340 } 343 }
341 } 344 }
342 345
343 bool FilePathWatcherImpl::Watch(const FilePath& path, 346 bool FilePathWatcherImpl::Watch(const FilePath& path,
344 FilePathWatcher::Delegate* delegate) { 347 FilePathWatcher::Delegate* delegate,
345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 348 scoped_refptr<base::MessageLoopProxy>) {
346 DCHECK(target_.empty()); 349 DCHECK(target_.empty());
350 DCHECK(MessageLoopForIO::current());
347 351
348 delegate_ = delegate; 352 delegate_ = delegate;
349 target_ = path; 353 target_ = path;
350 std::vector<FilePath::StringType> comps; 354 std::vector<FilePath::StringType> comps;
351 target_.GetComponents(&comps); 355 target_.GetComponents(&comps);
352 DCHECK(!comps.empty()); 356 DCHECK(!comps.empty());
353 for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin()); 357 for (std::vector<FilePath::StringType>::const_iterator comp(++comps.begin());
354 comp != comps.end(); ++comp) { 358 comp != comps.end(); ++comp) {
355 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp)); 359 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, *comp));
356 } 360 }
357 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch, 361 watches_.push_back(WatchEntry(InotifyReader::kInvalidWatch,
358 FilePath::StringType())); 362 FilePath::StringType()));
359 return UpdateWatches(); 363 return UpdateWatches();
360 } 364 }
361 365
362 void FilePathWatcherImpl::Cancel() { 366 void FilePathWatcherImpl::Cancel() {
363 // Switch to the file thread if necessary so we can access |watches_|. 367 if (!message_loop().get()) {
364 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 368 // Watch was never called, so exit.
365 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 369 return;
370 }
371 // Switch to the file thread if necessary so we can access |watches_|.
Mattias Nissler (ping if slow) 2011/03/17 18:14:27 indentation
372 if (!message_loop()->BelongsToCurrentThread()) {
373 message_loop()->PostTask(FROM_HERE,
366 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel)); 374 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
367 return; 375 return;
368 } 376 }
369 377
370 for (WatchVector::iterator watch_entry(watches_.begin()); 378 for (WatchVector::iterator watch_entry(watches_.begin());
371 watch_entry != watches_.end(); ++watch_entry) { 379 watch_entry != watches_.end(); ++watch_entry) {
372 if (watch_entry->watch_ != InotifyReader::kInvalidWatch) 380 if (watch_entry->watch_ != InotifyReader::kInvalidWatch)
373 g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this); 381 g_inotify_reader.Get().RemoveWatch(watch_entry->watch_, this);
374 } 382 }
375 watches_.clear(); 383 watches_.clear();
376 delegate_ = NULL; 384 delegate_ = NULL;
377 target_.clear(); 385 target_.clear();
378 } 386 }
379 387
380 bool FilePathWatcherImpl::UpdateWatches() { 388 bool FilePathWatcherImpl::UpdateWatches() {
381 // Ensure this runs on the file thread exclusively in order to avoid 389 // Ensure this runs on the file thread exclusively in order to avoid
382 // concurrency issues. 390 // concurrency issues.
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 391 DCHECK(message_loop()->BelongsToCurrentThread());
384 392
385 // Walk the list of watches and update them as we go. 393 // Walk the list of watches and update them as we go.
386 FilePath path(FILE_PATH_LITERAL("/")); 394 FilePath path(FILE_PATH_LITERAL("/"));
387 bool path_valid = true; 395 bool path_valid = true;
388 for (WatchVector::iterator watch_entry(watches_.begin()); 396 for (WatchVector::iterator watch_entry(watches_.begin());
389 watch_entry != watches_.end(); ++watch_entry) { 397 watch_entry != watches_.end(); ++watch_entry) {
390 InotifyReader::Watch old_watch = watch_entry->watch_; 398 InotifyReader::Watch old_watch = watch_entry->watch_;
391 if (path_valid) { 399 if (path_valid) {
392 watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this); 400 watch_entry->watch_ = g_inotify_reader.Get().AddWatch(path, this);
393 if (watch_entry->watch_ == InotifyReader::kInvalidWatch) { 401 if (watch_entry->watch_ == InotifyReader::kInvalidWatch) {
(...skipping 10 matching lines...) Expand all
404 } 412 }
405 413
406 return true; 414 return true;
407 } 415 }
408 416
409 } // namespace 417 } // namespace
410 418
411 FilePathWatcher::FilePathWatcher() { 419 FilePathWatcher::FilePathWatcher() {
412 impl_ = new FilePathWatcherImpl(); 420 impl_ = new FilePathWatcherImpl();
413 } 421 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698