OLD | NEW |
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_kqueue.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <sys/event.h> | |
9 #include <sys/param.h> | 8 #include <sys/param.h> |
10 | 9 |
11 #include <vector> | |
12 | |
13 #include "base/bind.h" | 10 #include "base/bind.h" |
14 #include "base/file_util.h" | 11 #include "base/file_util.h" |
15 #include "base/logging.h" | 12 #include "base/logging.h" |
16 #include "base/message_loop/message_loop.h" | |
17 #include "base/message_loop/message_loop_proxy.h" | |
18 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
19 | 14 |
20 // On some platforms these are not defined. | 15 // On some platforms these are not defined. |
21 #if !defined(EV_RECEIPT) | 16 #if !defined(EV_RECEIPT) |
22 #define EV_RECEIPT 0 | 17 #define EV_RECEIPT 0 |
23 #endif | 18 #endif |
24 #if !defined(O_EVTONLY) | 19 #if !defined(O_EVTONLY) |
25 #define O_EVTONLY O_RDONLY | 20 #define O_EVTONLY O_RDONLY |
26 #endif | 21 #endif |
27 | 22 |
28 namespace base { | 23 namespace base { |
29 | 24 |
30 namespace { | 25 FilePathWatcherKQueue::FilePathWatcherKQueue() : kqueue_(-1) {} |
31 | 26 |
32 // Mac-specific file watcher implementation based on kqueue. | 27 FilePathWatcherKQueue::~FilePathWatcherKQueue() {} |
33 // Originally it was based on FSEvents so that the semantics were equivalent | |
34 // on Linux, OSX and Windows where it was able to detect: | |
35 // - file creation/deletion/modification in a watched directory | |
36 // - file creation/deletion/modification for a watched file | |
37 // - modifications to the paths to a watched object that would affect the | |
38 // object such as renaming/attibute changes etc. | |
39 // The FSEvents version did all of the above except handling attribute changes | |
40 // to path components. Unfortunately FSEvents appears to have an issue where the | |
41 // current implementation (Mac OS X 10.6.7) sometimes drops events and doesn't | |
42 // send notifications. See | |
43 // http://code.google.com/p/chromium/issues/detail?id=54822#c31 for source that | |
44 // will reproduce the problem. FSEvents also required having a CFRunLoop | |
45 // backing the thread that it was running on, that caused added complexity | |
46 // in the interfaces. | |
47 // The kqueue implementation will handle all of the items in the list above | |
48 // except for detecting modifications to files in a watched directory. It will | |
49 // detect the creation and deletion of files, just not the modification of | |
50 // files. It does however detect the attribute changes that the FSEvents impl | |
51 // would miss. | |
52 class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate, | |
53 public MessageLoopForIO::Watcher, | |
54 public MessageLoop::DestructionObserver { | |
55 public: | |
56 FilePathWatcherImpl() : kqueue_(-1) {} | |
57 | 28 |
58 // MessageLoopForIO::Watcher overrides. | 29 void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) { |
59 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; | |
60 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; | |
61 | |
62 // MessageLoop::DestructionObserver overrides. | |
63 virtual void WillDestroyCurrentMessageLoop() OVERRIDE; | |
64 | |
65 // FilePathWatcher::PlatformDelegate overrides. | |
66 virtual bool Watch(const FilePath& path, | |
67 bool recursive, | |
68 const FilePathWatcher::Callback& callback) OVERRIDE; | |
69 virtual void Cancel() OVERRIDE; | |
70 | |
71 protected: | |
72 virtual ~FilePathWatcherImpl() {} | |
73 | |
74 private: | |
75 class EventData { | |
76 public: | |
77 EventData(const FilePath& path, const FilePath::StringType& subdir) | |
78 : path_(path), subdir_(subdir) { } | |
79 FilePath path_; // Full path to this item. | |
80 FilePath::StringType subdir_; // Path to any sub item. | |
81 }; | |
82 typedef std::vector<struct kevent> EventVector; | |
83 | |
84 // Can only be called on |io_message_loop_|'s thread. | |
85 virtual void CancelOnMessageLoopThread() OVERRIDE; | |
86 | |
87 // Returns true if the kevent values are error free. | |
88 bool AreKeventValuesValid(struct kevent* kevents, int count); | |
89 | |
90 // Respond to a change of attributes of the path component represented by | |
91 // |event|. Sets |target_file_affected| to true if |target_| is affected. | |
92 // Sets |update_watches| to true if |events_| need to be updated. | |
93 void HandleAttributesChange(const EventVector::iterator& event, | |
94 bool* target_file_affected, | |
95 bool* update_watches); | |
96 | |
97 // Respond to a move or deletion of the path component represented by | |
98 // |event|. Sets |target_file_affected| to true if |target_| is affected. | |
99 // Sets |update_watches| to true if |events_| need to be updated. | |
100 void HandleDeleteOrMoveChange(const EventVector::iterator& event, | |
101 bool* target_file_affected, | |
102 bool* update_watches); | |
103 | |
104 // Respond to a creation of an item in the path component represented by | |
105 // |event|. Sets |target_file_affected| to true if |target_| is affected. | |
106 // Sets |update_watches| to true if |events_| need to be updated. | |
107 void HandleCreateItemChange(const EventVector::iterator& event, | |
108 bool* target_file_affected, | |
109 bool* update_watches); | |
110 | |
111 // Update |events_| with the current status of the system. | |
112 // Sets |target_file_affected| to true if |target_| is affected. | |
113 // Returns false if an error occurs. | |
114 bool UpdateWatches(bool* target_file_affected); | |
115 | |
116 // Fills |events| with one kevent per component in |path|. | |
117 // Returns the number of valid events created where a valid event is | |
118 // defined as one that has a ident (file descriptor) field != -1. | |
119 static int EventsForPath(FilePath path, EventVector *events); | |
120 | |
121 // Release a kevent generated by EventsForPath. | |
122 static void ReleaseEvent(struct kevent& event); | |
123 | |
124 // Returns a file descriptor that will not block the system from deleting | |
125 // the file it references. | |
126 static uintptr_t FileDescriptorForPath(const FilePath& path); | |
127 | |
128 static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1); | |
129 | |
130 // Closes |*fd| and sets |*fd| to -1. | |
131 static void CloseFileDescriptor(uintptr_t* fd); | |
132 | |
133 // Returns true if kevent has open file descriptor. | |
134 static bool IsKeventFileDescriptorOpen(const struct kevent& event) { | |
135 return event.ident != kNoFileDescriptor; | |
136 } | |
137 | |
138 static EventData* EventDataForKevent(const struct kevent& event) { | |
139 return reinterpret_cast<EventData*>(event.udata); | |
140 } | |
141 | |
142 EventVector events_; | |
143 scoped_refptr<base::MessageLoopProxy> io_message_loop_; | |
144 MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_; | |
145 FilePathWatcher::Callback callback_; | |
146 FilePath target_; | |
147 int kqueue_; | |
148 | |
149 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); | |
150 }; | |
151 | |
152 void FilePathWatcherImpl::ReleaseEvent(struct kevent& event) { | |
153 CloseFileDescriptor(&event.ident); | 30 CloseFileDescriptor(&event.ident); |
154 EventData* entry = EventDataForKevent(event); | 31 EventData* entry = EventDataForKevent(event); |
155 delete entry; | 32 delete entry; |
156 event.udata = NULL; | 33 event.udata = NULL; |
157 } | 34 } |
158 | 35 |
159 int FilePathWatcherImpl::EventsForPath(FilePath path, EventVector* events) { | 36 int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) { |
160 DCHECK(MessageLoopForIO::current()); | 37 DCHECK(MessageLoopForIO::current()); |
161 // Make sure that we are working with a clean slate. | 38 // Make sure that we are working with a clean slate. |
162 DCHECK(events->empty()); | 39 DCHECK(events->empty()); |
163 | 40 |
164 std::vector<FilePath::StringType> components; | 41 std::vector<FilePath::StringType> components; |
165 path.GetComponents(&components); | 42 path.GetComponents(&components); |
166 | 43 |
167 if (components.size() < 1) { | 44 if (components.size() < 1) { |
168 return -1; | 45 return -1; |
169 } | 46 } |
(...skipping 21 matching lines...) Expand all Loading... |
191 EventData* data = new EventData(built_path, subdir); | 68 EventData* data = new EventData(built_path, subdir); |
192 struct kevent event; | 69 struct kevent event; |
193 EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT), | 70 EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT), |
194 (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB | | 71 (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB | |
195 NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data); | 72 NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data); |
196 events->push_back(event); | 73 events->push_back(event); |
197 } | 74 } |
198 return last_existing_entry; | 75 return last_existing_entry; |
199 } | 76 } |
200 | 77 |
201 uintptr_t FilePathWatcherImpl::FileDescriptorForPath(const FilePath& path) { | 78 uintptr_t FilePathWatcherKQueue::FileDescriptorForPath(const FilePath& path) { |
202 int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY)); | 79 int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY)); |
203 if (fd == -1) | 80 if (fd == -1) |
204 return kNoFileDescriptor; | 81 return kNoFileDescriptor; |
205 return fd; | 82 return fd; |
206 } | 83 } |
207 | 84 |
208 void FilePathWatcherImpl::CloseFileDescriptor(uintptr_t* fd) { | 85 void FilePathWatcherKQueue::CloseFileDescriptor(uintptr_t* fd) { |
209 if (*fd == kNoFileDescriptor) { | 86 if (*fd == kNoFileDescriptor) { |
210 return; | 87 return; |
211 } | 88 } |
212 | 89 |
213 if (IGNORE_EINTR(close(*fd)) != 0) { | 90 if (IGNORE_EINTR(close(*fd)) != 0) { |
214 DPLOG(ERROR) << "close"; | 91 DPLOG(ERROR) << "close"; |
215 } | 92 } |
216 *fd = kNoFileDescriptor; | 93 *fd = kNoFileDescriptor; |
217 } | 94 } |
218 | 95 |
219 bool FilePathWatcherImpl::AreKeventValuesValid(struct kevent* kevents, | 96 bool FilePathWatcherKQueue::AreKeventValuesValid(struct kevent* kevents, |
220 int count) { | 97 int count) { |
221 if (count < 0) { | 98 if (count < 0) { |
222 DPLOG(ERROR) << "kevent"; | 99 DPLOG(ERROR) << "kevent"; |
223 return false; | 100 return false; |
224 } | 101 } |
225 bool valid = true; | 102 bool valid = true; |
226 for (int i = 0; i < count; ++i) { | 103 for (int i = 0; i < count; ++i) { |
227 if (kevents[i].flags & EV_ERROR && kevents[i].data) { | 104 if (kevents[i].flags & EV_ERROR && kevents[i].data) { |
228 // Find the kevent in |events_| that matches the kevent with the error. | 105 // Find the kevent in |events_| that matches the kevent with the error. |
229 EventVector::iterator event = events_.begin(); | 106 EventVector::iterator event = events_.begin(); |
(...skipping 13 matching lines...) Expand all Loading... |
243 path_name = base::StringPrintf( | 120 path_name = base::StringPrintf( |
244 "fd %ld", reinterpret_cast<long>(&kevents[i].ident)); | 121 "fd %ld", reinterpret_cast<long>(&kevents[i].ident)); |
245 } | 122 } |
246 DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name; | 123 DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name; |
247 valid = false; | 124 valid = false; |
248 } | 125 } |
249 } | 126 } |
250 return valid; | 127 return valid; |
251 } | 128 } |
252 | 129 |
253 void FilePathWatcherImpl::HandleAttributesChange( | 130 void FilePathWatcherKQueue::HandleAttributesChange( |
254 const EventVector::iterator& event, | 131 const EventVector::iterator& event, |
255 bool* target_file_affected, | 132 bool* target_file_affected, |
256 bool* update_watches) { | 133 bool* update_watches) { |
257 EventVector::iterator next_event = event + 1; | 134 EventVector::iterator next_event = event + 1; |
258 EventData* next_event_data = EventDataForKevent(*next_event); | 135 EventData* next_event_data = EventDataForKevent(*next_event); |
259 // Check to see if the next item in path is still accessible. | 136 // Check to see if the next item in path is still accessible. |
260 uintptr_t have_access = FileDescriptorForPath(next_event_data->path_); | 137 uintptr_t have_access = FileDescriptorForPath(next_event_data->path_); |
261 if (have_access == kNoFileDescriptor) { | 138 if (have_access == kNoFileDescriptor) { |
262 *target_file_affected = true; | 139 *target_file_affected = true; |
263 *update_watches = true; | 140 *update_watches = true; |
264 EventVector::iterator local_event(event); | 141 EventVector::iterator local_event(event); |
265 for (; local_event != events_.end(); ++local_event) { | 142 for (; local_event != events_.end(); ++local_event) { |
266 // Close all nodes from the event down. This has the side effect of | 143 // Close all nodes from the event down. This has the side effect of |
267 // potentially rendering other events in |updates| invalid. | 144 // potentially rendering other events in |updates| invalid. |
268 // There is no need to remove the events from |kqueue_| because this | 145 // There is no need to remove the events from |kqueue_| because this |
269 // happens as a side effect of closing the file descriptor. | 146 // happens as a side effect of closing the file descriptor. |
270 CloseFileDescriptor(&local_event->ident); | 147 CloseFileDescriptor(&local_event->ident); |
271 } | 148 } |
272 } else { | 149 } else { |
273 CloseFileDescriptor(&have_access); | 150 CloseFileDescriptor(&have_access); |
274 } | 151 } |
275 } | 152 } |
276 | 153 |
277 void FilePathWatcherImpl::HandleDeleteOrMoveChange( | 154 void FilePathWatcherKQueue::HandleDeleteOrMoveChange( |
278 const EventVector::iterator& event, | 155 const EventVector::iterator& event, |
279 bool* target_file_affected, | 156 bool* target_file_affected, |
280 bool* update_watches) { | 157 bool* update_watches) { |
281 *target_file_affected = true; | 158 *target_file_affected = true; |
282 *update_watches = true; | 159 *update_watches = true; |
283 EventVector::iterator local_event(event); | 160 EventVector::iterator local_event(event); |
284 for (; local_event != events_.end(); ++local_event) { | 161 for (; local_event != events_.end(); ++local_event) { |
285 // Close all nodes from the event down. This has the side effect of | 162 // Close all nodes from the event down. This has the side effect of |
286 // potentially rendering other events in |updates| invalid. | 163 // potentially rendering other events in |updates| invalid. |
287 // There is no need to remove the events from |kqueue_| because this | 164 // There is no need to remove the events from |kqueue_| because this |
288 // happens as a side effect of closing the file descriptor. | 165 // happens as a side effect of closing the file descriptor. |
289 CloseFileDescriptor(&local_event->ident); | 166 CloseFileDescriptor(&local_event->ident); |
290 } | 167 } |
291 } | 168 } |
292 | 169 |
293 void FilePathWatcherImpl::HandleCreateItemChange( | 170 void FilePathWatcherKQueue::HandleCreateItemChange( |
294 const EventVector::iterator& event, | 171 const EventVector::iterator& event, |
295 bool* target_file_affected, | 172 bool* target_file_affected, |
296 bool* update_watches) { | 173 bool* update_watches) { |
297 // Get the next item in the path. | 174 // Get the next item in the path. |
298 EventVector::iterator next_event = event + 1; | 175 EventVector::iterator next_event = event + 1; |
299 // Check to see if it already has a valid file descriptor. | 176 // Check to see if it already has a valid file descriptor. |
300 if (!IsKeventFileDescriptorOpen(*next_event)) { | 177 if (!IsKeventFileDescriptorOpen(*next_event)) { |
301 EventData* next_event_data = EventDataForKevent(*next_event); | 178 EventData* next_event_data = EventDataForKevent(*next_event); |
302 // If not, attempt to open a file descriptor for it. | 179 // If not, attempt to open a file descriptor for it. |
303 next_event->ident = FileDescriptorForPath(next_event_data->path_); | 180 next_event->ident = FileDescriptorForPath(next_event_data->path_); |
304 if (IsKeventFileDescriptorOpen(*next_event)) { | 181 if (IsKeventFileDescriptorOpen(*next_event)) { |
305 *update_watches = true; | 182 *update_watches = true; |
306 if (next_event_data->subdir_.empty()) { | 183 if (next_event_data->subdir_.empty()) { |
307 *target_file_affected = true; | 184 *target_file_affected = true; |
308 } | 185 } |
309 } | 186 } |
310 } | 187 } |
311 } | 188 } |
312 | 189 |
313 bool FilePathWatcherImpl::UpdateWatches(bool* target_file_affected) { | 190 bool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) { |
314 // Iterate over events adding kevents for items that exist to the kqueue. | 191 // Iterate over events adding kevents for items that exist to the kqueue. |
315 // Then check to see if new components in the path have been created. | 192 // Then check to see if new components in the path have been created. |
316 // Repeat until no new components in the path are detected. | 193 // Repeat until no new components in the path are detected. |
317 // This is to get around races in directory creation in a watched path. | 194 // This is to get around races in directory creation in a watched path. |
318 bool update_watches = true; | 195 bool update_watches = true; |
319 while (update_watches) { | 196 while (update_watches) { |
320 size_t valid; | 197 size_t valid; |
321 for (valid = 0; valid < events_.size(); ++valid) { | 198 for (valid = 0; valid < events_.size(); ++valid) { |
322 if (!IsKeventFileDescriptorOpen(events_[valid])) { | 199 if (!IsKeventFileDescriptorOpen(events_[valid])) { |
323 break; | 200 break; |
(...skipping 20 matching lines...) Expand all Loading... |
344 *target_file_affected = true; | 221 *target_file_affected = true; |
345 } | 222 } |
346 } else { | 223 } else { |
347 break; | 224 break; |
348 } | 225 } |
349 } | 226 } |
350 } | 227 } |
351 return true; | 228 return true; |
352 } | 229 } |
353 | 230 |
354 void FilePathWatcherImpl::OnFileCanReadWithoutBlocking(int fd) { | 231 void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) { |
355 DCHECK(MessageLoopForIO::current()); | 232 DCHECK(MessageLoopForIO::current()); |
356 DCHECK_EQ(fd, kqueue_); | 233 DCHECK_EQ(fd, kqueue_); |
357 DCHECK(events_.size()); | 234 DCHECK(events_.size()); |
358 | 235 |
359 // Request the file system update notifications that have occurred and return | 236 // Request the file system update notifications that have occurred and return |
360 // them in |updates|. |count| will contain the number of updates that have | 237 // them in |updates|. |count| will contain the number of updates that have |
361 // occurred. | 238 // occurred. |
362 EventVector updates(events_.size()); | 239 EventVector updates(events_.size()); |
363 struct timespec timeout = {0, 0}; | 240 struct timespec timeout = {0, 0}; |
364 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), | 241 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 callback_.Run(target_, true /* error */); | 294 callback_.Run(target_, true /* error */); |
418 Cancel(); | 295 Cancel(); |
419 } | 296 } |
420 } | 297 } |
421 | 298 |
422 if (send_notification) { | 299 if (send_notification) { |
423 callback_.Run(target_, false); | 300 callback_.Run(target_, false); |
424 } | 301 } |
425 } | 302 } |
426 | 303 |
427 void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) { | 304 void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) { |
428 NOTREACHED(); | 305 NOTREACHED(); |
429 } | 306 } |
430 | 307 |
431 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { | 308 void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() { |
432 CancelOnMessageLoopThread(); | 309 CancelOnMessageLoopThread(); |
433 } | 310 } |
434 | 311 |
435 bool FilePathWatcherImpl::Watch(const FilePath& path, | 312 bool FilePathWatcherKQueue::Watch(const FilePath& path, |
436 bool recursive, | 313 bool recursive, |
437 const FilePathWatcher::Callback& callback) { | 314 const FilePathWatcher::Callback& callback) { |
438 DCHECK(MessageLoopForIO::current()); | 315 DCHECK(MessageLoopForIO::current()); |
439 DCHECK(target_.value().empty()); // Can only watch one path. | 316 DCHECK(target_.value().empty()); // Can only watch one path. |
440 DCHECK(!callback.is_null()); | 317 DCHECK(!callback.is_null()); |
441 DCHECK_EQ(kqueue_, -1); | 318 DCHECK_EQ(kqueue_, -1); |
442 | 319 |
443 if (recursive) { | 320 if (recursive) { |
444 // Recursive watch is not supported on this platform. | 321 // Recursive watch is not supported using kqueue. |
445 NOTIMPLEMENTED(); | 322 NOTIMPLEMENTED(); |
446 return false; | 323 return false; |
447 } | 324 } |
448 | 325 |
449 callback_ = callback; | 326 callback_ = callback; |
450 target_ = path; | 327 target_ = path; |
451 | 328 |
452 MessageLoop::current()->AddDestructionObserver(this); | 329 MessageLoop::current()->AddDestructionObserver(this); |
453 io_message_loop_ = base::MessageLoopProxy::current(); | 330 io_message_loop_ = base::MessageLoopProxy::current(); |
454 | 331 |
(...skipping 16 matching lines...) Expand all Loading... |
471 // be long lived, and if an error has occurred, there is no reason to waste | 348 // be long lived, and if an error has occurred, there is no reason to waste |
472 // the file descriptors. | 349 // the file descriptors. |
473 Cancel(); | 350 Cancel(); |
474 return false; | 351 return false; |
475 } | 352 } |
476 | 353 |
477 return MessageLoopForIO::current()->WatchFileDescriptor( | 354 return MessageLoopForIO::current()->WatchFileDescriptor( |
478 kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this); | 355 kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this); |
479 } | 356 } |
480 | 357 |
481 void FilePathWatcherImpl::Cancel() { | 358 void FilePathWatcherKQueue::Cancel() { |
482 base::MessageLoopProxy* proxy = io_message_loop_.get(); | 359 base::MessageLoopProxy* proxy = io_message_loop_.get(); |
483 if (!proxy) { | 360 if (!proxy) { |
484 set_cancelled(); | 361 set_cancelled(); |
485 return; | 362 return; |
486 } | 363 } |
487 if (!proxy->BelongsToCurrentThread()) { | 364 if (!proxy->BelongsToCurrentThread()) { |
488 proxy->PostTask(FROM_HERE, | 365 proxy->PostTask(FROM_HERE, |
489 base::Bind(&FilePathWatcherImpl::Cancel, this)); | 366 base::Bind(&FilePathWatcherKQueue::Cancel, this)); |
490 return; | 367 return; |
491 } | 368 } |
492 CancelOnMessageLoopThread(); | 369 CancelOnMessageLoopThread(); |
493 } | 370 } |
494 | 371 |
495 void FilePathWatcherImpl::CancelOnMessageLoopThread() { | 372 void FilePathWatcherKQueue::CancelOnMessageLoopThread() { |
496 DCHECK(MessageLoopForIO::current()); | 373 DCHECK(MessageLoopForIO::current()); |
497 if (!is_cancelled()) { | 374 if (!is_cancelled()) { |
498 set_cancelled(); | 375 set_cancelled(); |
499 kqueue_watcher_.StopWatchingFileDescriptor(); | 376 kqueue_watcher_.StopWatchingFileDescriptor(); |
500 if (IGNORE_EINTR(close(kqueue_)) != 0) { | 377 if (IGNORE_EINTR(close(kqueue_)) != 0) { |
501 DPLOG(ERROR) << "close kqueue"; | 378 DPLOG(ERROR) << "close kqueue"; |
502 } | 379 } |
503 kqueue_ = -1; | 380 kqueue_ = -1; |
504 std::for_each(events_.begin(), events_.end(), ReleaseEvent); | 381 std::for_each(events_.begin(), events_.end(), ReleaseEvent); |
505 events_.clear(); | 382 events_.clear(); |
506 io_message_loop_ = NULL; | 383 io_message_loop_ = NULL; |
507 MessageLoop::current()->RemoveDestructionObserver(this); | 384 MessageLoop::current()->RemoveDestructionObserver(this); |
508 callback_.Reset(); | 385 callback_.Reset(); |
509 } | 386 } |
510 } | 387 } |
511 | 388 |
512 } // namespace | |
513 | |
514 FilePathWatcher::FilePathWatcher() { | |
515 impl_ = new FilePathWatcherImpl(); | |
516 } | |
517 | |
518 } // namespace base | 389 } // namespace base |
OLD | NEW |