OLD | NEW |
---|---|
1 // Copyright (c) 2011 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 "content/common/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/message_loop_proxy.h" |
11 #include "base/ref_counted.h" | 11 #include "base/ref_counted.h" |
12 #include "base/time.h" | 12 #include "base/time.h" |
13 #include "base/win/object_watcher.h" | 13 #include "base/win/object_watcher.h" |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 // Deletion of the FilePathWatcher will call Cancel() to dispose of this | |
18 // object in the right thread. In that case, |this| is already cleaned up | |
19 // and |handle_| is INVALID_HANDLE_VALUE when the dtor enters. | |
20 // | |
21 // However, Cancel() might have to switch threads and its Task might never be | |
22 // called during shutdown. In that case, either |this| gets notified that the | |
23 // thread is shutting down and cleans up, or the Task (that wasn't executed) | |
24 // is deleted and releases a handle on |this|, triggering the dtor. | |
25 // In either case, we are on the right thread when cleaning up. | |
Mattias Nissler (ping if slow)
2011/03/21 16:07:45
same question as for the others
Joao da Silva
2011/03/22 10:10:08
Same reply :-)
| |
17 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, | 26 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, |
18 public base::win::ObjectWatcher::Delegate { | 27 public base::win::ObjectWatcher::Delegate, |
28 public MessageLoop::DestructionObserver { | |
19 public: | 29 public: |
20 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} | 30 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} |
21 | 31 |
22 // FilePathWatcher::PlatformDelegate overrides. | 32 // FilePathWatcher::PlatformDelegate overrides. |
23 virtual bool Watch(const FilePath& path, | 33 virtual bool Watch(const FilePath& path, |
24 FilePathWatcher::Delegate* delegate, | 34 FilePathWatcher::Delegate* delegate, |
25 base::MessageLoopProxy* loop) OVERRIDE; | 35 base::MessageLoopProxy* loop) OVERRIDE; |
26 virtual void Cancel() OVERRIDE; | 36 virtual void Cancel() OVERRIDE; |
27 | 37 |
38 // MessageLoop::DestructionObserver overrides. | |
39 // This allows cleaning up when the |message_loop_| thread is shutting down. | |
40 virtual void WillDestroyCurrentMessageLoop(); | |
41 | |
28 // Callback from MessageLoopForIO. | 42 // Callback from MessageLoopForIO. |
29 virtual void OnObjectSignaled(HANDLE object); | 43 virtual void OnObjectSignaled(HANDLE object); |
30 | 44 |
31 private: | 45 private: |
32 virtual ~FilePathWatcherImpl(); | 46 virtual ~FilePathWatcherImpl(); |
33 | 47 |
34 // Setup a watch handle for directory |dir|. Returns true if no fatal error | 48 // Setup a watch handle for directory |dir|. Returns true if no fatal error |
35 // occurs. |handle| will receive the handle value if |dir| is watchable, | 49 // occurs. |handle| will receive the handle value if |dir| is watchable, |
36 // otherwise INVALID_HANDLE_VALUE. | 50 // otherwise INVALID_HANDLE_VALUE. |
37 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle) | 51 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle) |
38 WARN_UNUSED_RESULT; | 52 WARN_UNUSED_RESULT; |
39 | 53 |
40 // (Re-)Initialize the watch handle. | 54 // (Re-)Initialize the watch handle. |
41 bool UpdateWatch() WARN_UNUSED_RESULT; | 55 bool UpdateWatch() WARN_UNUSED_RESULT; |
42 | 56 |
43 // Destroy the watch handle. | 57 // Destroy the watch handle. |
44 void DestroyWatch(); | 58 void DestroyWatch(); |
45 | 59 |
60 // Cleans up and stops observing the |message_loop_| thread. | |
61 void CancelInternal(); | |
62 | |
46 // Delegate to notify upon changes. | 63 // Delegate to notify upon changes. |
47 scoped_refptr<FilePathWatcher::Delegate> delegate_; | 64 scoped_refptr<FilePathWatcher::Delegate> delegate_; |
48 | 65 |
49 // Path we're supposed to watch (passed to delegate). | 66 // Path we're supposed to watch (passed to delegate). |
50 FilePath target_; | 67 FilePath target_; |
51 | 68 |
52 // Handle for FindFirstChangeNotification. | 69 // Handle for FindFirstChangeNotification. |
53 HANDLE handle_; | 70 HANDLE handle_; |
54 | 71 |
55 // ObjectWatcher to watch handle_ for events. | 72 // ObjectWatcher to watch handle_ for events. |
(...skipping 11 matching lines...) Expand all Loading... | |
67 }; | 84 }; |
68 | 85 |
69 bool FilePathWatcherImpl::Watch(const FilePath& path, | 86 bool FilePathWatcherImpl::Watch(const FilePath& path, |
70 FilePathWatcher::Delegate* delegate, | 87 FilePathWatcher::Delegate* delegate, |
71 base::MessageLoopProxy*) { | 88 base::MessageLoopProxy*) { |
72 DCHECK(target_.value().empty()); // Can only watch one path. | 89 DCHECK(target_.value().empty()); // Can only watch one path. |
73 | 90 |
74 set_message_loop(base::MessageLoopProxy::CreateForCurrentThread()); | 91 set_message_loop(base::MessageLoopProxy::CreateForCurrentThread()); |
75 delegate_ = delegate; | 92 delegate_ = delegate; |
76 target_ = path; | 93 target_ = path; |
94 MessageLoop::current()->AddDestructionObserver(this); | |
77 | 95 |
78 if (!UpdateWatch()) | 96 if (!UpdateWatch()) |
79 return false; | 97 return false; |
80 | 98 |
81 watcher_.StartWatching(handle_, this); | 99 watcher_.StartWatching(handle_, this); |
82 | 100 |
83 return true; | 101 return true; |
84 } | 102 } |
85 | 103 |
86 void FilePathWatcherImpl::Cancel() { | 104 void FilePathWatcherImpl::Cancel() { |
87 if (!message_loop().get()) { | 105 if (!delegate_) { |
88 // Watch was never called, so exit. | 106 // Watch was never called, or the |message_loop_| has already quit. |
89 return; | 107 return; |
90 } | 108 } |
91 | 109 |
92 // Switch to the file thread if necessary so we can stop |watcher_|. | 110 // Switch to the file thread if necessary so we can stop |watcher_|. |
93 if (!message_loop()->BelongsToCurrentThread()) { | 111 if (!message_loop()->BelongsToCurrentThread()) { |
94 message_loop()->PostTask(FROM_HERE, | 112 message_loop()->PostTask(FROM_HERE, |
95 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel)); | 113 NewRunnableMethod(this, &FilePathWatcherImpl::CancelInternal)); |
96 return; | 114 } else { |
115 CancelInternal(); | |
97 } | 116 } |
117 } | |
98 | 118 |
119 void FilePathWatcherImpl::CancelInternal() { | |
99 if (handle_ != INVALID_HANDLE_VALUE) | 120 if (handle_ != INVALID_HANDLE_VALUE) |
100 DestroyWatch(); | 121 DestroyWatch(); |
122 | |
123 if (delegate_) { | |
124 MessageLoop::current()->RemoveDestructionObserver(this); | |
125 delegate_ = NULL; | |
126 } | |
127 } | |
128 | |
129 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { | |
130 CancelInternal(); | |
131 } | |
132 | |
133 FilePathWatcherImpl::~FilePathWatcherImpl() { | |
134 CancelInternal(); | |
101 } | 135 } |
102 | 136 |
103 void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { | 137 void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { |
104 DCHECK(object == handle_); | 138 DCHECK(object == handle_); |
105 // Make sure we stay alive through the body of this function. | 139 // Make sure we stay alive through the body of this function. |
106 scoped_refptr<FilePathWatcherImpl> keep_alive(this); | 140 scoped_refptr<FilePathWatcherImpl> keep_alive(this); |
107 | 141 |
108 if (!UpdateWatch()) { | 142 if (!UpdateWatch()) { |
109 delegate_->OnError(); | 143 delegate_->OnError(); |
110 return; | 144 return; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
142 } else if (!file_exists && !last_modified_.is_null()) { | 176 } else if (!file_exists && !last_modified_.is_null()) { |
143 last_modified_ = base::Time(); | 177 last_modified_ = base::Time(); |
144 delegate_->OnFilePathChanged(target_); | 178 delegate_->OnFilePathChanged(target_); |
145 } | 179 } |
146 | 180 |
147 // The watch may have been cancelled by the callback. | 181 // The watch may have been cancelled by the callback. |
148 if (handle_ != INVALID_HANDLE_VALUE) | 182 if (handle_ != INVALID_HANDLE_VALUE) |
149 watcher_.StartWatching(handle_, this); | 183 watcher_.StartWatching(handle_, this); |
150 } | 184 } |
151 | 185 |
152 FilePathWatcherImpl::~FilePathWatcherImpl() { | |
153 if (handle_ != INVALID_HANDLE_VALUE) | |
154 DestroyWatch(); | |
155 } | |
156 | |
157 // static | 186 // static |
158 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, | 187 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, |
159 HANDLE* handle) { | 188 HANDLE* handle) { |
160 *handle = FindFirstChangeNotification( | 189 *handle = FindFirstChangeNotification( |
161 dir.value().c_str(), | 190 dir.value().c_str(), |
162 false, // Don't watch subtrees | 191 false, // Don't watch subtrees |
163 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | | 192 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | |
164 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | | 193 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | |
165 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); | 194 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); |
166 if (*handle != INVALID_HANDLE_VALUE) { | 195 if (*handle != INVALID_HANDLE_VALUE) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 watcher_.StopWatching(); | 276 watcher_.StopWatching(); |
248 FindCloseChangeNotification(handle_); | 277 FindCloseChangeNotification(handle_); |
249 handle_ = INVALID_HANDLE_VALUE; | 278 handle_ = INVALID_HANDLE_VALUE; |
250 } | 279 } |
251 | 280 |
252 } // namespace | 281 } // namespace |
253 | 282 |
254 FilePathWatcher::FilePathWatcher() { | 283 FilePathWatcher::FilePathWatcher() { |
255 impl_ = new FilePathWatcherImpl(); | 284 impl_ = new FilePathWatcherImpl(); |
256 } | 285 } |
OLD | NEW |