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

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

Issue 6825063: Patch for bug 74983 (among others) to be applied to M11 696 branch. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/696/src
Patch Set: intentionally disabled mac tests. tested by hand. Created 9 years, 8 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
« no previous file with comments | « content/common/file_path_watcher/file_path_watcher_stub.cc ('k') | content/content_common.gypi » ('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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "base/file_path.h" 7 #include "base/file_path.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop_proxy.h"
10 #include "base/ref_counted.h" 11 #include "base/ref_counted.h"
11 #include "base/time.h" 12 #include "base/time.h"
12 #include "base/win/object_watcher.h" 13 #include "base/win/object_watcher.h"
13 14
14 namespace { 15 namespace {
15 16
16 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, 17 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
17 public base::win::ObjectWatcher::Delegate { 18 public base::win::ObjectWatcher::Delegate,
19 public MessageLoop::DestructionObserver {
18 public: 20 public:
19 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} 21 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
20 22
21 virtual bool Watch(const FilePath& path, FilePathWatcher::Delegate* delegate); 23 // FilePathWatcher::PlatformDelegate overrides.
22 virtual void Cancel(); 24 virtual bool Watch(const FilePath& path,
25 FilePathWatcher::Delegate* delegate) OVERRIDE;
26 virtual void Cancel() OVERRIDE;
27
28 // Deletion of the FilePathWatcher will call Cancel() to dispose of this
29 // object in the right thread. This also observes destruction of the required
30 // cleanup thread, in case it quits before Cancel() is called.
31 virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
23 32
24 // Callback from MessageLoopForIO. 33 // Callback from MessageLoopForIO.
25 virtual void OnObjectSignaled(HANDLE object); 34 virtual void OnObjectSignaled(HANDLE object);
26 35
27 private: 36 private:
28 virtual ~FilePathWatcherImpl(); 37 virtual ~FilePathWatcherImpl() {}
29 38
30 // Setup a watch handle for directory |dir|. Returns true if no fatal error 39 // Setup a watch handle for directory |dir|. Returns true if no fatal error
31 // occurs. |handle| will receive the handle value if |dir| is watchable, 40 // occurs. |handle| will receive the handle value if |dir| is watchable,
32 // otherwise INVALID_HANDLE_VALUE. 41 // otherwise INVALID_HANDLE_VALUE.
33 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle) 42 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle)
34 WARN_UNUSED_RESULT; 43 WARN_UNUSED_RESULT;
35 44
36 // (Re-)Initialize the watch handle. 45 // (Re-)Initialize the watch handle.
37 bool UpdateWatch() WARN_UNUSED_RESULT; 46 bool UpdateWatch() WARN_UNUSED_RESULT;
38 47
39 // Destroy the watch handle. 48 // Destroy the watch handle.
40 void DestroyWatch(); 49 void DestroyWatch();
41 50
51 // Cleans up and stops observing the |message_loop_| thread.
52 void CancelOnMessageLoopThread() OVERRIDE;
53
42 // Delegate to notify upon changes. 54 // Delegate to notify upon changes.
43 scoped_refptr<FilePathWatcher::Delegate> delegate_; 55 scoped_refptr<FilePathWatcher::Delegate> delegate_;
44 56
45 // Path we're supposed to watch (passed to delegate). 57 // Path we're supposed to watch (passed to delegate).
46 FilePath target_; 58 FilePath target_;
47 59
48 // Handle for FindFirstChangeNotification. 60 // Handle for FindFirstChangeNotification.
49 HANDLE handle_; 61 HANDLE handle_;
50 62
51 // ObjectWatcher to watch handle_ for events. 63 // ObjectWatcher to watch handle_ for events.
52 base::win::ObjectWatcher watcher_; 64 base::win::ObjectWatcher watcher_;
53 65
54 // Keep track of the last modified time of the file. We use nulltime 66 // Keep track of the last modified time of the file. We use nulltime
55 // to represent the file not existing. 67 // to represent the file not existing.
56 base::Time last_modified_; 68 base::Time last_modified_;
57 69
58 // The time at which we processed the first notification with the 70 // The time at which we processed the first notification with the
59 // |last_modified_| time stamp. 71 // |last_modified_| time stamp.
60 base::Time first_notification_; 72 base::Time first_notification_;
61 73
62 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); 74 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
63 }; 75 };
64 76
65 bool FilePathWatcherImpl::Watch(const FilePath& path, 77 bool FilePathWatcherImpl::Watch(const FilePath& path,
66 FilePathWatcher::Delegate* delegate) { 78 FilePathWatcher::Delegate* delegate) {
67 DCHECK(target_.value().empty()); // Can only watch one path. 79 DCHECK(target_.value().empty()); // Can only watch one path.
80
81 set_message_loop(base::MessageLoopProxy::CreateForCurrentThread());
68 delegate_ = delegate; 82 delegate_ = delegate;
69 target_ = path; 83 target_ = path;
84 MessageLoop::current()->AddDestructionObserver(this);
70 85
71 if (!UpdateWatch()) 86 if (!UpdateWatch())
72 return false; 87 return false;
73 88
74 watcher_.StartWatching(handle_, this); 89 watcher_.StartWatching(handle_, this);
75 90
76 return true; 91 return true;
77 } 92 }
78 93
79 void FilePathWatcherImpl::Cancel() { 94 void FilePathWatcherImpl::Cancel() {
80 // Switch to the file thread if necessary so we can stop |watcher_|. 95 if (!delegate_) {
81 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 96 // Watch was never called, or the |message_loop_| has already quit.
82 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 97 set_cancelled();
83 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel));
84 return; 98 return;
85 } 99 }
86 100
101 // Switch to the file thread if necessary so we can stop |watcher_|.
102 if (!message_loop()->BelongsToCurrentThread()) {
103 message_loop()->PostTask(FROM_HERE,
104 new FilePathWatcher::CancelTask(this));
105 } else {
106 CancelOnMessageLoopThread();
107 }
108 }
109
110 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
111 set_cancelled();
112
87 if (handle_ != INVALID_HANDLE_VALUE) 113 if (handle_ != INVALID_HANDLE_VALUE)
88 DestroyWatch(); 114 DestroyWatch();
115
116 if (delegate_) {
117 MessageLoop::current()->RemoveDestructionObserver(this);
118 delegate_ = NULL;
119 }
120 }
121
122 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
123 CancelOnMessageLoopThread();
89 } 124 }
90 125
91 void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { 126 void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
92 DCHECK(object == handle_); 127 DCHECK(object == handle_);
93 // Make sure we stay alive through the body of this function. 128 // Make sure we stay alive through the body of this function.
94 scoped_refptr<FilePathWatcherImpl> keep_alive(this); 129 scoped_refptr<FilePathWatcherImpl> keep_alive(this);
95 130
96 if (!UpdateWatch()) { 131 if (!UpdateWatch()) {
97 delegate_->OnError(); 132 delegate_->OnFilePathError(target_);
98 return; 133 return;
99 } 134 }
100 135
101 // Check whether the event applies to |target_| and notify the delegate. 136 // Check whether the event applies to |target_| and notify the delegate.
102 base::PlatformFileInfo file_info; 137 base::PlatformFileInfo file_info;
103 bool file_exists = file_util::GetFileInfo(target_, &file_info); 138 bool file_exists = file_util::GetFileInfo(target_, &file_info);
104 if (file_exists && (last_modified_.is_null() || 139 if (file_exists && (last_modified_.is_null() ||
105 last_modified_ != file_info.last_modified)) { 140 last_modified_ != file_info.last_modified)) {
106 last_modified_ = file_info.last_modified; 141 last_modified_ = file_info.last_modified;
107 first_notification_ = base::Time::Now(); 142 first_notification_ = base::Time::Now();
(...skipping 22 matching lines...) Expand all
130 } else if (!file_exists && !last_modified_.is_null()) { 165 } else if (!file_exists && !last_modified_.is_null()) {
131 last_modified_ = base::Time(); 166 last_modified_ = base::Time();
132 delegate_->OnFilePathChanged(target_); 167 delegate_->OnFilePathChanged(target_);
133 } 168 }
134 169
135 // The watch may have been cancelled by the callback. 170 // The watch may have been cancelled by the callback.
136 if (handle_ != INVALID_HANDLE_VALUE) 171 if (handle_ != INVALID_HANDLE_VALUE)
137 watcher_.StartWatching(handle_, this); 172 watcher_.StartWatching(handle_, this);
138 } 173 }
139 174
140 FilePathWatcherImpl::~FilePathWatcherImpl() {
141 if (handle_ != INVALID_HANDLE_VALUE)
142 DestroyWatch();
143 }
144
145 // static 175 // static
146 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, 176 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
147 HANDLE* handle) { 177 HANDLE* handle) {
148 *handle = FindFirstChangeNotification( 178 *handle = FindFirstChangeNotification(
149 dir.value().c_str(), 179 dir.value().c_str(),
150 false, // Don't watch subtrees 180 false, // Don't watch subtrees
151 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | 181 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
152 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | 182 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
153 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); 183 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
154 if (*handle != INVALID_HANDLE_VALUE) { 184 if (*handle != INVALID_HANDLE_VALUE) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 watcher_.StopWatching(); 265 watcher_.StopWatching();
236 FindCloseChangeNotification(handle_); 266 FindCloseChangeNotification(handle_);
237 handle_ = INVALID_HANDLE_VALUE; 267 handle_ = INVALID_HANDLE_VALUE;
238 } 268 }
239 269
240 } // namespace 270 } // namespace
241 271
242 FilePathWatcher::FilePathWatcher() { 272 FilePathWatcher::FilePathWatcher() {
243 impl_ = new FilePathWatcherImpl(); 273 impl_ = new FilePathWatcherImpl();
244 } 274 }
OLDNEW
« no previous file with comments | « content/common/file_path_watcher/file_path_watcher_stub.cc ('k') | content/content_common.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698