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

Side by Side Diff: trunk/src/base/files/file_path_watcher_kqueue.cc

Issue 316853003: Revert 274735 "Use FSEvents for recursive file watch on Mac" (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 years, 6 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) 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_kqueue.h" 5 #include "base/files/file_path_watcher.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <sys/event.h>
8 #include <sys/param.h> 9 #include <sys/param.h>
9 10
11 #include <vector>
12
10 #include "base/bind.h" 13 #include "base/bind.h"
11 #include "base/file_util.h" 14 #include "base/file_util.h"
12 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
14 19
15 // On some platforms these are not defined. 20 // On some platforms these are not defined.
16 #if !defined(EV_RECEIPT) 21 #if !defined(EV_RECEIPT)
17 #define EV_RECEIPT 0 22 #define EV_RECEIPT 0
18 #endif 23 #endif
19 #if !defined(O_EVTONLY) 24 #if !defined(O_EVTONLY)
20 #define O_EVTONLY O_RDONLY 25 #define O_EVTONLY O_RDONLY
21 #endif 26 #endif
22 27
23 namespace base { 28 namespace base {
24 29
25 FilePathWatcherKQueue::FilePathWatcherKQueue() : kqueue_(-1) {} 30 namespace {
26 31
27 FilePathWatcherKQueue::~FilePathWatcherKQueue() {} 32 // Mac-specific file watcher implementation based on kqueue.
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) {}
28 57
29 void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) { 58 // MessageLoopForIO::Watcher overrides.
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) {
30 CloseFileDescriptor(&event.ident); 153 CloseFileDescriptor(&event.ident);
31 EventData* entry = EventDataForKevent(event); 154 EventData* entry = EventDataForKevent(event);
32 delete entry; 155 delete entry;
33 event.udata = NULL; 156 event.udata = NULL;
34 } 157 }
35 158
36 int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) { 159 int FilePathWatcherImpl::EventsForPath(FilePath path, EventVector* events) {
37 DCHECK(MessageLoopForIO::current()); 160 DCHECK(MessageLoopForIO::current());
38 // Make sure that we are working with a clean slate. 161 // Make sure that we are working with a clean slate.
39 DCHECK(events->empty()); 162 DCHECK(events->empty());
40 163
41 std::vector<FilePath::StringType> components; 164 std::vector<FilePath::StringType> components;
42 path.GetComponents(&components); 165 path.GetComponents(&components);
43 166
44 if (components.size() < 1) { 167 if (components.size() < 1) {
45 return -1; 168 return -1;
46 } 169 }
(...skipping 21 matching lines...) Expand all
68 EventData* data = new EventData(built_path, subdir); 191 EventData* data = new EventData(built_path, subdir);
69 struct kevent event; 192 struct kevent event;
70 EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT), 193 EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT),
71 (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB | 194 (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB |
72 NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data); 195 NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data);
73 events->push_back(event); 196 events->push_back(event);
74 } 197 }
75 return last_existing_entry; 198 return last_existing_entry;
76 } 199 }
77 200
78 uintptr_t FilePathWatcherKQueue::FileDescriptorForPath(const FilePath& path) { 201 uintptr_t FilePathWatcherImpl::FileDescriptorForPath(const FilePath& path) {
79 int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY)); 202 int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY));
80 if (fd == -1) 203 if (fd == -1)
81 return kNoFileDescriptor; 204 return kNoFileDescriptor;
82 return fd; 205 return fd;
83 } 206 }
84 207
85 void FilePathWatcherKQueue::CloseFileDescriptor(uintptr_t* fd) { 208 void FilePathWatcherImpl::CloseFileDescriptor(uintptr_t* fd) {
86 if (*fd == kNoFileDescriptor) { 209 if (*fd == kNoFileDescriptor) {
87 return; 210 return;
88 } 211 }
89 212
90 if (IGNORE_EINTR(close(*fd)) != 0) { 213 if (IGNORE_EINTR(close(*fd)) != 0) {
91 DPLOG(ERROR) << "close"; 214 DPLOG(ERROR) << "close";
92 } 215 }
93 *fd = kNoFileDescriptor; 216 *fd = kNoFileDescriptor;
94 } 217 }
95 218
96 bool FilePathWatcherKQueue::AreKeventValuesValid(struct kevent* kevents, 219 bool FilePathWatcherImpl::AreKeventValuesValid(struct kevent* kevents,
97 int count) { 220 int count) {
98 if (count < 0) { 221 if (count < 0) {
99 DPLOG(ERROR) << "kevent"; 222 DPLOG(ERROR) << "kevent";
100 return false; 223 return false;
101 } 224 }
102 bool valid = true; 225 bool valid = true;
103 for (int i = 0; i < count; ++i) { 226 for (int i = 0; i < count; ++i) {
104 if (kevents[i].flags & EV_ERROR && kevents[i].data) { 227 if (kevents[i].flags & EV_ERROR && kevents[i].data) {
105 // Find the kevent in |events_| that matches the kevent with the error. 228 // Find the kevent in |events_| that matches the kevent with the error.
106 EventVector::iterator event = events_.begin(); 229 EventVector::iterator event = events_.begin();
(...skipping 13 matching lines...) Expand all
120 path_name = base::StringPrintf( 243 path_name = base::StringPrintf(
121 "fd %ld", reinterpret_cast<long>(&kevents[i].ident)); 244 "fd %ld", reinterpret_cast<long>(&kevents[i].ident));
122 } 245 }
123 DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name; 246 DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name;
124 valid = false; 247 valid = false;
125 } 248 }
126 } 249 }
127 return valid; 250 return valid;
128 } 251 }
129 252
130 void FilePathWatcherKQueue::HandleAttributesChange( 253 void FilePathWatcherImpl::HandleAttributesChange(
131 const EventVector::iterator& event, 254 const EventVector::iterator& event,
132 bool* target_file_affected, 255 bool* target_file_affected,
133 bool* update_watches) { 256 bool* update_watches) {
134 EventVector::iterator next_event = event + 1; 257 EventVector::iterator next_event = event + 1;
135 EventData* next_event_data = EventDataForKevent(*next_event); 258 EventData* next_event_data = EventDataForKevent(*next_event);
136 // Check to see if the next item in path is still accessible. 259 // Check to see if the next item in path is still accessible.
137 uintptr_t have_access = FileDescriptorForPath(next_event_data->path_); 260 uintptr_t have_access = FileDescriptorForPath(next_event_data->path_);
138 if (have_access == kNoFileDescriptor) { 261 if (have_access == kNoFileDescriptor) {
139 *target_file_affected = true; 262 *target_file_affected = true;
140 *update_watches = true; 263 *update_watches = true;
141 EventVector::iterator local_event(event); 264 EventVector::iterator local_event(event);
142 for (; local_event != events_.end(); ++local_event) { 265 for (; local_event != events_.end(); ++local_event) {
143 // Close all nodes from the event down. This has the side effect of 266 // Close all nodes from the event down. This has the side effect of
144 // potentially rendering other events in |updates| invalid. 267 // potentially rendering other events in |updates| invalid.
145 // There is no need to remove the events from |kqueue_| because this 268 // There is no need to remove the events from |kqueue_| because this
146 // happens as a side effect of closing the file descriptor. 269 // happens as a side effect of closing the file descriptor.
147 CloseFileDescriptor(&local_event->ident); 270 CloseFileDescriptor(&local_event->ident);
148 } 271 }
149 } else { 272 } else {
150 CloseFileDescriptor(&have_access); 273 CloseFileDescriptor(&have_access);
151 } 274 }
152 } 275 }
153 276
154 void FilePathWatcherKQueue::HandleDeleteOrMoveChange( 277 void FilePathWatcherImpl::HandleDeleteOrMoveChange(
155 const EventVector::iterator& event, 278 const EventVector::iterator& event,
156 bool* target_file_affected, 279 bool* target_file_affected,
157 bool* update_watches) { 280 bool* update_watches) {
158 *target_file_affected = true; 281 *target_file_affected = true;
159 *update_watches = true; 282 *update_watches = true;
160 EventVector::iterator local_event(event); 283 EventVector::iterator local_event(event);
161 for (; local_event != events_.end(); ++local_event) { 284 for (; local_event != events_.end(); ++local_event) {
162 // Close all nodes from the event down. This has the side effect of 285 // Close all nodes from the event down. This has the side effect of
163 // potentially rendering other events in |updates| invalid. 286 // potentially rendering other events in |updates| invalid.
164 // There is no need to remove the events from |kqueue_| because this 287 // There is no need to remove the events from |kqueue_| because this
165 // happens as a side effect of closing the file descriptor. 288 // happens as a side effect of closing the file descriptor.
166 CloseFileDescriptor(&local_event->ident); 289 CloseFileDescriptor(&local_event->ident);
167 } 290 }
168 } 291 }
169 292
170 void FilePathWatcherKQueue::HandleCreateItemChange( 293 void FilePathWatcherImpl::HandleCreateItemChange(
171 const EventVector::iterator& event, 294 const EventVector::iterator& event,
172 bool* target_file_affected, 295 bool* target_file_affected,
173 bool* update_watches) { 296 bool* update_watches) {
174 // Get the next item in the path. 297 // Get the next item in the path.
175 EventVector::iterator next_event = event + 1; 298 EventVector::iterator next_event = event + 1;
176 // Check to see if it already has a valid file descriptor. 299 // Check to see if it already has a valid file descriptor.
177 if (!IsKeventFileDescriptorOpen(*next_event)) { 300 if (!IsKeventFileDescriptorOpen(*next_event)) {
178 EventData* next_event_data = EventDataForKevent(*next_event); 301 EventData* next_event_data = EventDataForKevent(*next_event);
179 // If not, attempt to open a file descriptor for it. 302 // If not, attempt to open a file descriptor for it.
180 next_event->ident = FileDescriptorForPath(next_event_data->path_); 303 next_event->ident = FileDescriptorForPath(next_event_data->path_);
181 if (IsKeventFileDescriptorOpen(*next_event)) { 304 if (IsKeventFileDescriptorOpen(*next_event)) {
182 *update_watches = true; 305 *update_watches = true;
183 if (next_event_data->subdir_.empty()) { 306 if (next_event_data->subdir_.empty()) {
184 *target_file_affected = true; 307 *target_file_affected = true;
185 } 308 }
186 } 309 }
187 } 310 }
188 } 311 }
189 312
190 bool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) { 313 bool FilePathWatcherImpl::UpdateWatches(bool* target_file_affected) {
191 // Iterate over events adding kevents for items that exist to the kqueue. 314 // Iterate over events adding kevents for items that exist to the kqueue.
192 // Then check to see if new components in the path have been created. 315 // Then check to see if new components in the path have been created.
193 // Repeat until no new components in the path are detected. 316 // Repeat until no new components in the path are detected.
194 // This is to get around races in directory creation in a watched path. 317 // This is to get around races in directory creation in a watched path.
195 bool update_watches = true; 318 bool update_watches = true;
196 while (update_watches) { 319 while (update_watches) {
197 size_t valid; 320 size_t valid;
198 for (valid = 0; valid < events_.size(); ++valid) { 321 for (valid = 0; valid < events_.size(); ++valid) {
199 if (!IsKeventFileDescriptorOpen(events_[valid])) { 322 if (!IsKeventFileDescriptorOpen(events_[valid])) {
200 break; 323 break;
(...skipping 20 matching lines...) Expand all
221 *target_file_affected = true; 344 *target_file_affected = true;
222 } 345 }
223 } else { 346 } else {
224 break; 347 break;
225 } 348 }
226 } 349 }
227 } 350 }
228 return true; 351 return true;
229 } 352 }
230 353
231 void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) { 354 void FilePathWatcherImpl::OnFileCanReadWithoutBlocking(int fd) {
232 DCHECK(MessageLoopForIO::current()); 355 DCHECK(MessageLoopForIO::current());
233 DCHECK_EQ(fd, kqueue_); 356 DCHECK_EQ(fd, kqueue_);
234 DCHECK(events_.size()); 357 DCHECK(events_.size());
235 358
236 // Request the file system update notifications that have occurred and return 359 // Request the file system update notifications that have occurred and return
237 // them in |updates|. |count| will contain the number of updates that have 360 // them in |updates|. |count| will contain the number of updates that have
238 // occurred. 361 // occurred.
239 EventVector updates(events_.size()); 362 EventVector updates(events_.size());
240 struct timespec timeout = {0, 0}; 363 struct timespec timeout = {0, 0};
241 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), 364 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(),
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 callback_.Run(target_, true /* error */); 417 callback_.Run(target_, true /* error */);
295 Cancel(); 418 Cancel();
296 } 419 }
297 } 420 }
298 421
299 if (send_notification) { 422 if (send_notification) {
300 callback_.Run(target_, false); 423 callback_.Run(target_, false);
301 } 424 }
302 } 425 }
303 426
304 void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) { 427 void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) {
305 NOTREACHED(); 428 NOTREACHED();
306 } 429 }
307 430
308 void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() { 431 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
309 CancelOnMessageLoopThread(); 432 CancelOnMessageLoopThread();
310 } 433 }
311 434
312 bool FilePathWatcherKQueue::Watch(const FilePath& path, 435 bool FilePathWatcherImpl::Watch(const FilePath& path,
313 bool recursive, 436 bool recursive,
314 const FilePathWatcher::Callback& callback) { 437 const FilePathWatcher::Callback& callback) {
315 DCHECK(MessageLoopForIO::current()); 438 DCHECK(MessageLoopForIO::current());
316 DCHECK(target_.value().empty()); // Can only watch one path. 439 DCHECK(target_.value().empty()); // Can only watch one path.
317 DCHECK(!callback.is_null()); 440 DCHECK(!callback.is_null());
318 DCHECK_EQ(kqueue_, -1); 441 DCHECK_EQ(kqueue_, -1);
319 442
320 if (recursive) { 443 if (recursive) {
321 // Recursive watch is not supported using kqueue. 444 // Recursive watch is not supported on this platform.
322 NOTIMPLEMENTED(); 445 NOTIMPLEMENTED();
323 return false; 446 return false;
324 } 447 }
325 448
326 callback_ = callback; 449 callback_ = callback;
327 target_ = path; 450 target_ = path;
328 451
329 MessageLoop::current()->AddDestructionObserver(this); 452 MessageLoop::current()->AddDestructionObserver(this);
330 io_message_loop_ = base::MessageLoopProxy::current(); 453 io_message_loop_ = base::MessageLoopProxy::current();
331 454
(...skipping 16 matching lines...) Expand all
348 // be long lived, and if an error has occurred, there is no reason to waste 471 // be long lived, and if an error has occurred, there is no reason to waste
349 // the file descriptors. 472 // the file descriptors.
350 Cancel(); 473 Cancel();
351 return false; 474 return false;
352 } 475 }
353 476
354 return MessageLoopForIO::current()->WatchFileDescriptor( 477 return MessageLoopForIO::current()->WatchFileDescriptor(
355 kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this); 478 kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
356 } 479 }
357 480
358 void FilePathWatcherKQueue::Cancel() { 481 void FilePathWatcherImpl::Cancel() {
359 base::MessageLoopProxy* proxy = io_message_loop_.get(); 482 base::MessageLoopProxy* proxy = io_message_loop_.get();
360 if (!proxy) { 483 if (!proxy) {
361 set_cancelled(); 484 set_cancelled();
362 return; 485 return;
363 } 486 }
364 if (!proxy->BelongsToCurrentThread()) { 487 if (!proxy->BelongsToCurrentThread()) {
365 proxy->PostTask(FROM_HERE, 488 proxy->PostTask(FROM_HERE,
366 base::Bind(&FilePathWatcherKQueue::Cancel, this)); 489 base::Bind(&FilePathWatcherImpl::Cancel, this));
367 return; 490 return;
368 } 491 }
369 CancelOnMessageLoopThread(); 492 CancelOnMessageLoopThread();
370 } 493 }
371 494
372 void FilePathWatcherKQueue::CancelOnMessageLoopThread() { 495 void FilePathWatcherImpl::CancelOnMessageLoopThread() {
373 DCHECK(MessageLoopForIO::current()); 496 DCHECK(MessageLoopForIO::current());
374 if (!is_cancelled()) { 497 if (!is_cancelled()) {
375 set_cancelled(); 498 set_cancelled();
376 kqueue_watcher_.StopWatchingFileDescriptor(); 499 kqueue_watcher_.StopWatchingFileDescriptor();
377 if (IGNORE_EINTR(close(kqueue_)) != 0) { 500 if (IGNORE_EINTR(close(kqueue_)) != 0) {
378 DPLOG(ERROR) << "close kqueue"; 501 DPLOG(ERROR) << "close kqueue";
379 } 502 }
380 kqueue_ = -1; 503 kqueue_ = -1;
381 std::for_each(events_.begin(), events_.end(), ReleaseEvent); 504 std::for_each(events_.begin(), events_.end(), ReleaseEvent);
382 events_.clear(); 505 events_.clear();
383 io_message_loop_ = NULL; 506 io_message_loop_ = NULL;
384 MessageLoop::current()->RemoveDestructionObserver(this); 507 MessageLoop::current()->RemoveDestructionObserver(this);
385 callback_.Reset(); 508 callback_.Reset();
386 } 509 }
387 } 510 }
388 511
512 } // namespace
513
514 FilePathWatcher::FilePathWatcher() {
515 impl_ = new FilePathWatcherImpl();
516 }
517
389 } // namespace base 518 } // namespace base
OLDNEW
« no previous file with comments | « trunk/src/base/files/file_path_watcher_kqueue.h ('k') | trunk/src/base/files/file_path_watcher_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698