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.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <sys/event.h> | 8 #include <sys/event.h> |
9 #include <sys/param.h> | 9 #include <sys/param.h> |
10 | 10 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 // MessageLoopForIO::Watcher overrides. | 59 // MessageLoopForIO::Watcher overrides. |
60 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; | 60 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; |
61 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; | 61 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; |
62 | 62 |
63 // MessageLoop::DestructionObserver overrides. | 63 // MessageLoop::DestructionObserver overrides. |
64 virtual void WillDestroyCurrentMessageLoop() OVERRIDE; | 64 virtual void WillDestroyCurrentMessageLoop() OVERRIDE; |
65 | 65 |
66 // FilePathWatcher::PlatformDelegate overrides. | 66 // FilePathWatcher::PlatformDelegate overrides. |
67 virtual bool Watch(const FilePath& path, | 67 virtual bool Watch(const FilePath& path, |
68 bool recursive, | 68 bool recursive, |
69 FilePathWatcher::Delegate* delegate) OVERRIDE; | 69 const FilePathWatcher::Callback& callback) OVERRIDE; |
70 virtual void Cancel() OVERRIDE; | 70 virtual void Cancel() OVERRIDE; |
71 | 71 |
72 protected: | 72 protected: |
73 virtual ~FilePathWatcherImpl() {} | 73 virtual ~FilePathWatcherImpl() {} |
74 | 74 |
75 private: | 75 private: |
76 class EventData { | 76 class EventData { |
77 public: | 77 public: |
78 EventData(const FilePath& path, const FilePath::StringType& subdir) | 78 EventData(const FilePath& path, const FilePath::StringType& subdir) |
79 : path_(path), subdir_(subdir) { } | 79 : path_(path), subdir_(subdir) { } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 return event.ident != static_cast<uintptr_t>(-1); | 134 return event.ident != static_cast<uintptr_t>(-1); |
135 } | 135 } |
136 | 136 |
137 static EventData* EventDataForKevent(const struct kevent& event) { | 137 static EventData* EventDataForKevent(const struct kevent& event) { |
138 return reinterpret_cast<EventData*>(event.udata); | 138 return reinterpret_cast<EventData*>(event.udata); |
139 } | 139 } |
140 | 140 |
141 EventVector events_; | 141 EventVector events_; |
142 scoped_refptr<base::MessageLoopProxy> io_message_loop_; | 142 scoped_refptr<base::MessageLoopProxy> io_message_loop_; |
143 MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_; | 143 MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_; |
144 scoped_refptr<FilePathWatcher::Delegate> delegate_; | 144 FilePathWatcher::Callback callback_; |
145 FilePath target_; | 145 FilePath target_; |
146 int kqueue_; | 146 int kqueue_; |
147 | 147 |
148 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); | 148 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl); |
149 }; | 149 }; |
150 | 150 |
151 void FilePathWatcherImpl::ReleaseEvent(struct kevent& event) { | 151 void FilePathWatcherImpl::ReleaseEvent(struct kevent& event) { |
152 CloseFileDescriptor(reinterpret_cast<int*>(&event.ident)); | 152 CloseFileDescriptor(reinterpret_cast<int*>(&event.ident)); |
153 EventData* entry = EventDataForKevent(event); | 153 EventData* entry = EventDataForKevent(event); |
154 delete entry; | 154 delete entry; |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 // them in |updates|. |count| will contain the number of updates that have | 357 // them in |updates|. |count| will contain the number of updates that have |
358 // occurred. | 358 // occurred. |
359 EventVector updates(events_.size()); | 359 EventVector updates(events_.size()); |
360 struct timespec timeout = {0, 0}; | 360 struct timespec timeout = {0, 0}; |
361 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), | 361 int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(), |
362 &timeout)); | 362 &timeout)); |
363 | 363 |
364 // Error values are stored within updates, so check to make sure that no | 364 // Error values are stored within updates, so check to make sure that no |
365 // errors occurred. | 365 // errors occurred. |
366 if (!AreKeventValuesValid(&updates[0], count)) { | 366 if (!AreKeventValuesValid(&updates[0], count)) { |
367 delegate_->OnFilePathError(target_); | 367 callback_.Run(target_, true /* error */); |
368 Cancel(); | 368 Cancel(); |
369 return; | 369 return; |
370 } | 370 } |
371 | 371 |
372 bool update_watches = false; | 372 bool update_watches = false; |
373 bool send_notification = false; | 373 bool send_notification = false; |
374 | 374 |
375 // Iterate through each of the updates and react to them. | 375 // Iterate through each of the updates and react to them. |
376 for (int i = 0; i < count; ++i) { | 376 for (int i = 0; i < count; ++i) { |
377 // Find our kevent record that matches the update notification. | 377 // Find our kevent record that matches the update notification. |
(...skipping 26 matching lines...) Expand all Loading... |
404 HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches); | 404 HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches); |
405 } | 405 } |
406 if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) { | 406 if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) { |
407 HandleCreateItemChange(event, &target_file_affected, &update_watches); | 407 HandleCreateItemChange(event, &target_file_affected, &update_watches); |
408 } | 408 } |
409 send_notification |= target_file_affected; | 409 send_notification |= target_file_affected; |
410 } | 410 } |
411 | 411 |
412 if (update_watches) { | 412 if (update_watches) { |
413 if (!UpdateWatches(&send_notification)) { | 413 if (!UpdateWatches(&send_notification)) { |
414 delegate_->OnFilePathError(target_); | 414 callback_.Run(target_, true /* error */); |
415 Cancel(); | 415 Cancel(); |
416 } | 416 } |
417 } | 417 } |
418 | 418 |
419 if (send_notification) { | 419 if (send_notification) { |
420 delegate_->OnFilePathChanged(target_); | 420 callback_.Run(target_, false); |
421 } | 421 } |
422 } | 422 } |
423 | 423 |
424 void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) { | 424 void FilePathWatcherImpl::OnFileCanWriteWithoutBlocking(int fd) { |
425 NOTREACHED(); | 425 NOTREACHED(); |
426 } | 426 } |
427 | 427 |
428 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { | 428 void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() { |
429 CancelOnMessageLoopThread(); | 429 CancelOnMessageLoopThread(); |
430 } | 430 } |
431 | 431 |
432 bool FilePathWatcherImpl::Watch(const FilePath& path, | 432 bool FilePathWatcherImpl::Watch(const FilePath& path, |
433 bool recursive, | 433 bool recursive, |
434 FilePathWatcher::Delegate* delegate) { | 434 const FilePathWatcher::Callback& callback) { |
435 DCHECK(MessageLoopForIO::current()); | 435 DCHECK(MessageLoopForIO::current()); |
436 DCHECK(target_.value().empty()); // Can only watch one path. | 436 DCHECK(target_.value().empty()); // Can only watch one path. |
437 DCHECK(delegate); | 437 DCHECK(!callback.is_null()); |
438 DCHECK_EQ(kqueue_, -1); | 438 DCHECK_EQ(kqueue_, -1); |
439 | 439 |
440 if (recursive) { | 440 if (recursive) { |
441 // Recursive watch is not supported on this platform. | 441 // Recursive watch is not supported on this platform. |
442 NOTIMPLEMENTED(); | 442 NOTIMPLEMENTED(); |
443 return false; | 443 return false; |
444 } | 444 } |
445 | 445 |
446 delegate_ = delegate; | 446 callback_ = callback; |
447 target_ = path; | 447 target_ = path; |
448 | 448 |
449 MessageLoop::current()->AddDestructionObserver(this); | 449 MessageLoop::current()->AddDestructionObserver(this); |
450 io_message_loop_ = base::MessageLoopProxy::current(); | 450 io_message_loop_ = base::MessageLoopProxy::current(); |
451 | 451 |
452 kqueue_ = kqueue(); | 452 kqueue_ = kqueue(); |
453 if (kqueue_ == -1) { | 453 if (kqueue_ == -1) { |
454 DPLOG(ERROR) << "kqueue"; | 454 DPLOG(ERROR) << "kqueue"; |
455 return false; | 455 return false; |
456 } | 456 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 void FilePathWatcherImpl::CancelOnMessageLoopThread() { | 492 void FilePathWatcherImpl::CancelOnMessageLoopThread() { |
493 DCHECK(MessageLoopForIO::current()); | 493 DCHECK(MessageLoopForIO::current()); |
494 if (!is_cancelled()) { | 494 if (!is_cancelled()) { |
495 set_cancelled(); | 495 set_cancelled(); |
496 kqueue_watcher_.StopWatchingFileDescriptor(); | 496 kqueue_watcher_.StopWatchingFileDescriptor(); |
497 CloseFileDescriptor(&kqueue_); | 497 CloseFileDescriptor(&kqueue_); |
498 std::for_each(events_.begin(), events_.end(), ReleaseEvent); | 498 std::for_each(events_.begin(), events_.end(), ReleaseEvent); |
499 events_.clear(); | 499 events_.clear(); |
500 io_message_loop_ = NULL; | 500 io_message_loop_ = NULL; |
501 MessageLoop::current()->RemoveDestructionObserver(this); | 501 MessageLoop::current()->RemoveDestructionObserver(this); |
502 delegate_ = NULL; | 502 callback_.Reset(); |
503 } | 503 } |
504 } | 504 } |
505 | 505 |
506 } // namespace | 506 } // namespace |
507 | 507 |
508 FilePathWatcher::FilePathWatcher() { | 508 FilePathWatcher::FilePathWatcher() { |
509 impl_ = new FilePathWatcherImpl(); | 509 impl_ = new FilePathWatcherImpl(); |
510 } | 510 } |
511 | 511 |
512 } // namespace files | 512 } // namespace files |
513 } // namespace base | 513 } // namespace base |
OLD | NEW |