// Copyright (c) 2012 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 "webkit/common/blob/shareable_file_reference.h" #include <map> #include "base/lazy_instance.h" #include "base/message_loop/message_loop_proxy.h" #include "base/task_runner.h" #include "base/threading/non_thread_safe.h" namespace webkit_blob { namespace { // A shareable file map with enforcement of thread checker. class ShareableFileMap : public base::NonThreadSafe { public: typedef std::map<base::FilePath, ShareableFileReference*> FileMap; typedef FileMap::iterator iterator; typedef FileMap::key_type key_type; typedef FileMap::value_type value_type; ShareableFileMap() {} ~ShareableFileMap() { DetachFromThread(); } iterator Find(key_type key) { DCHECK(CalledOnValidThread()); return file_map_.find(key); } iterator End() { DCHECK(CalledOnValidThread()); return file_map_.end(); } std::pair<iterator, bool> Insert(value_type value) { DCHECK(CalledOnValidThread()); return file_map_.insert(value); } void Erase(key_type key) { DCHECK(CalledOnValidThread()); file_map_.erase(key); } private: FileMap file_map_; DISALLOW_COPY_AND_ASSIGN(ShareableFileMap); }; base::LazyInstance<ShareableFileMap> g_file_map = LAZY_INSTANCE_INITIALIZER; } // namespace // static scoped_refptr<ShareableFileReference> ShareableFileReference::Get( const base::FilePath& path) { ShareableFileMap::iterator found = g_file_map.Get().Find(path); ShareableFileReference* reference = (found == g_file_map.Get().End()) ? NULL : found->second; return scoped_refptr<ShareableFileReference>(reference); } // static scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( const base::FilePath& path, FinalReleasePolicy policy, base::TaskRunner* file_task_runner) { return GetOrCreate( ScopedFile(path, static_cast<ScopedFile::ScopeOutPolicy>(policy), file_task_runner)); } // static scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( ScopedFile scoped_file) { if (scoped_file.path().empty()) return scoped_refptr<ShareableFileReference>(); typedef std::pair<ShareableFileMap::iterator, bool> InsertResult; // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair webkit_blob::ShareableFileReference* null_reference = NULL; InsertResult result = g_file_map.Get().Insert( ShareableFileMap::value_type(scoped_file.path(), null_reference)); if (result.second == false) { scoped_file.Release(); return scoped_refptr<ShareableFileReference>(result.first->second); } // Wasn't in the map, create a new reference and store the pointer. scoped_refptr<ShareableFileReference> reference( new ShareableFileReference(scoped_file.Pass())); result.first->second = reference.get(); return reference; } void ShareableFileReference::AddFinalReleaseCallback( const FinalReleaseCallback& callback) { DCHECK(g_file_map.Get().CalledOnValidThread()); scoped_file_.AddScopeOutCallback(callback, NULL); } ShareableFileReference::ShareableFileReference(ScopedFile scoped_file) : scoped_file_(scoped_file.Pass()) { DCHECK(g_file_map.Get().Find(path())->second == NULL); } ShareableFileReference::~ShareableFileReference() { DCHECK(g_file_map.Get().Find(path())->second == this); g_file_map.Get().Erase(path()); } } // namespace webkit_blob