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

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

Issue 6697020: Fixed shutdown concurrency issues in FilePathWatcher. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Introduced CancelTask to simplify cleanup. 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) 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 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, 17 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
18 public base::win::ObjectWatcher::Delegate { 18 public base::win::ObjectWatcher::Delegate,
19 public MessageLoop::DestructionObserver {
19 public: 20 public:
20 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {} 21 FilePathWatcherImpl() : delegate_(NULL), handle_(INVALID_HANDLE_VALUE) {}
21 22
22 // FilePathWatcher::PlatformDelegate overrides. 23 // FilePathWatcher::PlatformDelegate overrides.
23 virtual bool Watch(const FilePath& path, 24 virtual bool Watch(const FilePath& path,
24 FilePathWatcher::Delegate* delegate, 25 FilePathWatcher::Delegate* delegate,
25 base::MessageLoopProxy* loop) OVERRIDE; 26 base::MessageLoopProxy* loop) OVERRIDE;
26 virtual void Cancel() OVERRIDE; 27 virtual void Cancel() OVERRIDE;
27 28
29 // Deletion of the FilePathWatcher will call Cancel() to dispose of this
30 // object in the right thread. This also observes destruction of the required
31 // cleanup thread, in case it quits before Cancel() is called.
32 virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
33
28 // Callback from MessageLoopForIO. 34 // Callback from MessageLoopForIO.
29 virtual void OnObjectSignaled(HANDLE object); 35 virtual void OnObjectSignaled(HANDLE object);
30 36
31 private: 37 private:
32 virtual ~FilePathWatcherImpl(); 38 virtual ~FilePathWatcherImpl() {}
33 39
34 // Setup a watch handle for directory |dir|. Returns true if no fatal error 40 // 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, 41 // occurs. |handle| will receive the handle value if |dir| is watchable,
36 // otherwise INVALID_HANDLE_VALUE. 42 // otherwise INVALID_HANDLE_VALUE.
37 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle) 43 static bool SetupWatchHandle(const FilePath& dir, HANDLE* handle)
38 WARN_UNUSED_RESULT; 44 WARN_UNUSED_RESULT;
39 45
40 // (Re-)Initialize the watch handle. 46 // (Re-)Initialize the watch handle.
41 bool UpdateWatch() WARN_UNUSED_RESULT; 47 bool UpdateWatch() WARN_UNUSED_RESULT;
42 48
43 // Destroy the watch handle. 49 // Destroy the watch handle.
44 void DestroyWatch(); 50 void DestroyWatch();
45 51
52 // Cleans up and stops observing the |message_loop_| thread.
53 void CancelOnMessageLoopThread() OVERRIDE;
54
46 // Delegate to notify upon changes. 55 // Delegate to notify upon changes.
47 scoped_refptr<FilePathWatcher::Delegate> delegate_; 56 scoped_refptr<FilePathWatcher::Delegate> delegate_;
48 57
49 // Path we're supposed to watch (passed to delegate). 58 // Path we're supposed to watch (passed to delegate).
50 FilePath target_; 59 FilePath target_;
51 60
52 // Handle for FindFirstChangeNotification. 61 // Handle for FindFirstChangeNotification.
53 HANDLE handle_; 62 HANDLE handle_;
54 63
55 // ObjectWatcher to watch handle_ for events. 64 // ObjectWatcher to watch handle_ for events.
(...skipping 11 matching lines...) Expand all
67 }; 76 };
68 77
69 bool FilePathWatcherImpl::Watch(const FilePath& path, 78 bool FilePathWatcherImpl::Watch(const FilePath& path,
70 FilePathWatcher::Delegate* delegate, 79 FilePathWatcher::Delegate* delegate,
71 base::MessageLoopProxy*) { 80 base::MessageLoopProxy*) {
72 DCHECK(target_.value().empty()); // Can only watch one path. 81 DCHECK(target_.value().empty()); // Can only watch one path.
73 82
74 set_message_loop(base::MessageLoopProxy::CreateForCurrentThread()); 83 set_message_loop(base::MessageLoopProxy::CreateForCurrentThread());
75 delegate_ = delegate; 84 delegate_ = delegate;
76 target_ = path; 85 target_ = path;
86 MessageLoop::current()->AddDestructionObserver(this);
77 87
78 if (!UpdateWatch()) 88 if (!UpdateWatch())
79 return false; 89 return false;
80 90
81 watcher_.StartWatching(handle_, this); 91 watcher_.StartWatching(handle_, this);
82 92
83 return true; 93 return true;
84 } 94 }
85 95
86 void FilePathWatcherImpl::Cancel() { 96 void FilePathWatcherImpl::Cancel() {
87 if (!message_loop().get()) { 97 if (!delegate_) {
88 // Watch was never called, so exit. 98 // Watch was never called, or the |message_loop_| has already quit.
99 set_cancelled();
89 return; 100 return;
90 } 101 }
91 102
92 // Switch to the file thread if necessary so we can stop |watcher_|. 103 // Switch to the file thread if necessary so we can stop |watcher_|.
93 if (!message_loop()->BelongsToCurrentThread()) { 104 if (!message_loop()->BelongsToCurrentThread()) {
94 message_loop()->PostTask(FROM_HERE, 105 message_loop()->PostTask(FROM_HERE,
95 NewRunnableMethod(this, &FilePathWatcherImpl::Cancel)); 106 new FilePathWatcher::CancelTask(this));
96 return; 107 } else {
108 CancelOnMessageLoopThread();
97 } 109 }
110 }
111
112 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
113 set_cancelled();
98 114
99 if (handle_ != INVALID_HANDLE_VALUE) 115 if (handle_ != INVALID_HANDLE_VALUE)
100 DestroyWatch(); 116 DestroyWatch();
117
118 if (delegate_) {
119 MessageLoop::current()->RemoveDestructionObserver(this);
120 delegate_ = NULL;
121 }
122 }
123
124 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
125 CancelOnMessageLoopThread();
101 } 126 }
102 127
103 void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) { 128 void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
104 DCHECK(object == handle_); 129 DCHECK(object == handle_);
105 // Make sure we stay alive through the body of this function. 130 // Make sure we stay alive through the body of this function.
106 scoped_refptr<FilePathWatcherImpl> keep_alive(this); 131 scoped_refptr<FilePathWatcherImpl> keep_alive(this);
107 132
108 if (!UpdateWatch()) { 133 if (!UpdateWatch()) {
109 delegate_->OnError(); 134 delegate_->OnError();
110 return; 135 return;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 } else if (!file_exists && !last_modified_.is_null()) { 167 } else if (!file_exists && !last_modified_.is_null()) {
143 last_modified_ = base::Time(); 168 last_modified_ = base::Time();
144 delegate_->OnFilePathChanged(target_); 169 delegate_->OnFilePathChanged(target_);
145 } 170 }
146 171
147 // The watch may have been cancelled by the callback. 172 // The watch may have been cancelled by the callback.
148 if (handle_ != INVALID_HANDLE_VALUE) 173 if (handle_ != INVALID_HANDLE_VALUE)
149 watcher_.StartWatching(handle_, this); 174 watcher_.StartWatching(handle_, this);
150 } 175 }
151 176
152 FilePathWatcherImpl::~FilePathWatcherImpl() {
153 if (handle_ != INVALID_HANDLE_VALUE)
154 DestroyWatch();
155 }
156
157 // static 177 // static
158 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir, 178 bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
159 HANDLE* handle) { 179 HANDLE* handle) {
160 *handle = FindFirstChangeNotification( 180 *handle = FindFirstChangeNotification(
161 dir.value().c_str(), 181 dir.value().c_str(),
162 false, // Don't watch subtrees 182 false, // Don't watch subtrees
163 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE | 183 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
164 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME | 184 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
165 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY); 185 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
166 if (*handle != INVALID_HANDLE_VALUE) { 186 if (*handle != INVALID_HANDLE_VALUE) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 watcher_.StopWatching(); 267 watcher_.StopWatching();
248 FindCloseChangeNotification(handle_); 268 FindCloseChangeNotification(handle_);
249 handle_ = INVALID_HANDLE_VALUE; 269 handle_ = INVALID_HANDLE_VALUE;
250 } 270 }
251 271
252 } // namespace 272 } // namespace
253 273
254 FilePathWatcher::FilePathWatcher() { 274 FilePathWatcher::FilePathWatcher() {
255 impl_ = new FilePathWatcherImpl(); 275 impl_ = new FilePathWatcherImpl();
256 } 276 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698