// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/dns/watching_file_reader.h" #include "base/bind.h" #include "base/location.h" #include "base/message_loop.h" #include "base/threading/worker_pool.h" namespace net { FilePathWatcherShim::FilePathWatcherShim() : watcher_(new base::files::FilePathWatcher()) {} FilePathWatcherShim::~FilePathWatcherShim() {} bool FilePathWatcherShim::Watch( const FilePath& path, base::files::FilePathWatcher::Delegate* delegate) { DCHECK(CalledOnValidThread()); return watcher_->Watch(path, delegate); } FilePathWatcherShim* FilePathWatcherFactory::CreateFilePathWatcher() { DCHECK(CalledOnValidThread()); return new FilePathWatcherShim(); } // A FilePathWatcher::Delegate that forwards calls to the WatchingFileReader. // This is separated out to keep WatchingFileReader strictly single-threaded. class WatchingFileReader::WatcherDelegate : public base::files::FilePathWatcher::Delegate { public: explicit WatcherDelegate(base::WeakPtr reader) : reader_(reader) {} void OnFilePathChanged(const FilePath& path) OVERRIDE { if (reader_) reader_->OnFilePathChanged(path); } void OnFilePathError(const FilePath& path) OVERRIDE { if (reader_) reader_->OnFilePathError(path); } private: virtual ~WatcherDelegate() {} base::WeakPtr reader_; }; WatchingFileReader::WatchingFileReader() : watcher_factory_(new FilePathWatcherFactory()) {} WatchingFileReader::~WatchingFileReader() { if (reader_) reader_->Cancel(); } void WatchingFileReader::StartWatch(const FilePath& path, SerialWorker* reader) { DCHECK(CalledOnValidThread()); DCHECK(!watcher_.get()); DCHECK(!watcher_delegate_.get()); DCHECK(path_.empty()); path_ = path; watcher_delegate_ = new WatcherDelegate(AsWeakPtr()); reader_ = reader; RestartWatch(); } void WatchingFileReader::OnFilePathChanged(const FilePath& path) { DCHECK(CalledOnValidThread()); reader_->WorkNow(); } void WatchingFileReader::OnFilePathError(const FilePath& path) { DCHECK(CalledOnValidThread()); RestartWatch(); } void WatchingFileReader::RescheduleWatch() { DCHECK(CalledOnValidThread()); MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&WatchingFileReader::RestartWatch, AsWeakPtr()), kWatchRetryDelayMs); } void WatchingFileReader::RestartWatch() { DCHECK(CalledOnValidThread()); if (reader_->IsCancelled()) return; watcher_.reset(watcher_factory_->CreateFilePathWatcher()); if (watcher_->Watch(path_, watcher_delegate_)) { reader_->WorkNow(); } else { LOG(WARNING) << "Watch on " << path_.LossyDisplayName() << " failed, scheduling restart"; RescheduleWatch(); } } } // namespace net