Index: extensions/browser/api/api_resource_manager.h |
diff --git a/extensions/browser/api/api_resource_manager.h b/extensions/browser/api/api_resource_manager.h |
index 7cff1732c1b068112c2f3bb78331a14745134f62..3f63b612f74a4ace04e0db301bff3088effd64a9 100644 |
--- a/extensions/browser/api/api_resource_manager.h |
+++ b/extensions/browser/api/api_resource_manager.h |
@@ -36,8 +36,45 @@ class TCPSocketEventDispatcher; |
class UDPSocketEventDispatcher; |
} |
+template <typename T> |
+struct NamedThreadTraits { |
+ static bool IsCalledOnValidThread() { |
+ return content::BrowserThread::CurrentlyOn(T::kThreadId); |
+ } |
+ |
+ static bool IsMessageLoopValid() { |
+ return content::BrowserThread::IsMessageLoopValid(T::kThreadId); |
+ } |
+ |
+ static scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() { |
+ return content::BrowserThread::GetMessageLoopProxyForThread(T::kThreadId); |
+ } |
+}; |
+ |
+template <typename T> |
+struct TestThreadTraits { |
+ static bool IsCalledOnValidThread() { |
+ return content::BrowserThread::CurrentlyOn(thread_id_); |
+ } |
+ |
+ static bool IsMessageLoopValid() { |
+ return content::BrowserThread::IsMessageLoopValid(thread_id_); |
+ } |
+ |
+ static scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() { |
+ return content::BrowserThread::GetMessageLoopProxyForThread(thread_id_); |
+ } |
+ |
+ static content::BrowserThread::ID thread_id_; |
+}; |
+ |
+template <typename T> |
+content::BrowserThread::ID TestThreadTraits<T>::thread_id_ = |
+ content::BrowserThread::IO; |
+ |
// An ApiResourceManager manages the lifetime of a set of resources that |
-// ApiFunctions use. Examples are sockets or USB connections. |
+// that live on named threads (i.e. BrowserThread::IO) which ApiFunctions use. |
+// Examples of such resources are sockets or USB connections. |
// |
// Users of this class should define kThreadId to be the thread that |
// ApiResourceManager to works on. The default is defined in ApiResource. |
@@ -72,13 +109,13 @@ class UDPSocketEventDispatcher; |
// ApiResourceManager<Resource>::GetFactoryInstance() { |
// return g_factory.Pointer(); |
// } |
-template <class T> |
+template <class T, typename ThreadingTraits = NamedThreadTraits<T> > |
class ApiResourceManager : public BrowserContextKeyedAPI, |
public base::NonThreadSafe, |
public content::NotificationObserver { |
public: |
explicit ApiResourceManager(content::BrowserContext* context) |
- : thread_id_(T::kThreadId), data_(new ApiResourceData(thread_id_)) { |
+ : data_(new ApiResourceData()) { |
registrar_.Add(this, |
chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, |
content::NotificationService::AllSources()); |
@@ -86,20 +123,19 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
content::NotificationService::AllSources()); |
} |
- |
// For Testing. |
- static ApiResourceManager<T>* CreateApiResourceManagerForTest( |
- content::BrowserContext* context, |
- content::BrowserThread::ID thread_id) { |
- ApiResourceManager* manager = new ApiResourceManager<T>(context); |
- manager->thread_id_ = thread_id; |
- manager->data_ = new ApiResourceData(thread_id); |
+ static ApiResourceManager<T, TestThreadTraits<T> >* |
+ CreateApiResourceManagerForTest(content::BrowserContext* context, |
+ content::BrowserThread::ID thread_id) { |
+ TestThreadTraits<T>::thread_id_ = thread_id; |
+ ApiResourceManager<T, TestThreadTraits<T> >* manager = |
+ new ApiResourceManager<T, TestThreadTraits<T> >(context); |
return manager; |
} |
virtual ~ApiResourceManager() { |
DCHECK(CalledOnValidThread()); |
- DCHECK(content::BrowserThread::IsMessageLoopValid(thread_id_)) |
+ DCHECK(ThreadingTraits::IsMessageLoopValid()) |
<< "A unit test is using an ApiResourceManager but didn't provide " |
"the thread message loop needed for that kind of resource. " |
"Please ensure that the appropriate message loop is operational."; |
@@ -107,15 +143,6 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
data_->InititateCleanup(); |
} |
- // BrowserContextKeyedAPI implementation. |
- static BrowserContextKeyedAPIFactory<ApiResourceManager<T> >* |
- GetFactoryInstance(); |
- |
- // Convenience method to get the ApiResourceManager for a profile. |
- static ApiResourceManager<T>* Get(content::BrowserContext* context) { |
- return BrowserContextKeyedAPIFactory<ApiResourceManager<T> >::Get(context); |
- } |
- |
// Takes ownership. |
int Add(T* api_resource) { return data_->Add(api_resource); } |
@@ -131,6 +158,18 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
return data_->GetResourceIds(extension_id); |
} |
+ // BrowserContextKeyedAPI implementation. |
+ static BrowserContextKeyedAPIFactory<ApiResourceManager<T> >* |
+ GetFactoryInstance(); |
+ |
+ // Convenience method to get the ApiResourceManager for a profile. |
+ static ApiResourceManager<T>* Get(content::BrowserContext* context) { |
+ return BrowserContextKeyedAPIFactory<ApiResourceManager<T> >::Get(context); |
+ } |
+ |
+ // BrowserContextKeyedAPI implementation. |
+ static const char* service_name() { return T::service_name(); } |
+ |
protected: |
// content::NotificationObserver: |
virtual void Observe(int type, |
@@ -163,9 +202,6 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
friend class core_api::UDPSocketEventDispatcher; |
friend class BrowserContextKeyedAPIFactory<ApiResourceManager<T> >; |
- // BrowserContextKeyedAPI implementation. |
- static const char* service_name() { return T::service_name(); } |
- |
static const bool kServiceHasOwnInstanceInIncognito = true; |
static const bool kServiceIsNULLWhileTesting = true; |
@@ -177,11 +213,10 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
// Lookup map from extension id's to allocated resource id's. |
typedef std::map<std::string, base::hash_set<int> > ExtensionToResourceMap; |
- explicit ApiResourceData(const content::BrowserThread::ID thread_id) |
- : next_id_(1), thread_id_(thread_id) {} |
+ ApiResourceData() : next_id_(1) {} |
int Add(T* api_resource) { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
int id = GenerateId(); |
if (id > 0) { |
linked_ptr<T> resource_ptr(api_resource); |
@@ -200,7 +235,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
} |
void Remove(const std::string& extension_id, int api_resource_id) { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
if (GetOwnedResource(extension_id, api_resource_id) != NULL) { |
DCHECK(extension_resource_map_.find(extension_id) != |
extension_resource_map_.end()); |
@@ -210,21 +245,20 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
} |
T* Get(const std::string& extension_id, int api_resource_id) { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
return GetOwnedResource(extension_id, api_resource_id); |
} |
base::hash_set<int>* GetResourceIds(const std::string& extension_id) { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
return GetOwnedResourceIds(extension_id); |
} |
void InitiateExtensionUnloadedCleanup(const std::string& extension_id) { |
- if (content::BrowserThread::CurrentlyOn(thread_id_)) { |
+ if (ThreadingTraits::IsCalledOnValidThread()) { |
CleanupResourcesFromUnloadedExtension(extension_id); |
} else { |
- content::BrowserThread::PostTask( |
- thread_id_, |
+ ThreadingTraits::GetSequencedTaskRunner()->PostTask( |
FROM_HERE, |
base::Bind(&ApiResourceData::CleanupResourcesFromUnloadedExtension, |
this, |
@@ -233,11 +267,10 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
} |
void InitiateExtensionSuspendedCleanup(const std::string& extension_id) { |
- if (content::BrowserThread::CurrentlyOn(thread_id_)) { |
+ if (ThreadingTraits::IsCalledOnValidThread()) { |
CleanupResourcesFromSuspendedExtension(extension_id); |
} else { |
- content::BrowserThread::PostTask( |
- thread_id_, |
+ ThreadingTraits::GetSequencedTaskRunner()->PostTask( |
FROM_HERE, |
base::Bind(&ApiResourceData::CleanupResourcesFromSuspendedExtension, |
this, |
@@ -246,11 +279,11 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
} |
void InititateCleanup() { |
- if (content::BrowserThread::CurrentlyOn(thread_id_)) { |
+ if (ThreadingTraits::IsCalledOnValidThread()) { |
Cleanup(); |
} else { |
- content::BrowserThread::PostTask( |
- thread_id_, FROM_HERE, base::Bind(&ApiResourceData::Cleanup, this)); |
+ ThreadingTraits::GetSequencedTaskRunner()->PostTask( |
+ FROM_HERE, base::Bind(&ApiResourceData::Cleanup, this)); |
} |
} |
@@ -268,7 +301,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
} |
base::hash_set<int>* GetOwnedResourceIds(const std::string& extension_id) { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
if (extension_resource_map_.find(extension_id) == |
extension_resource_map_.end()) |
return NULL; |
@@ -288,7 +321,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
void CleanupResourcesFromExtension(const std::string& extension_id, |
bool remove_all) { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
if (extension_resource_map_.find(extension_id) == |
extension_resource_map_.end()) { |
@@ -324,7 +357,7 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
} |
void Cleanup() { |
- DCHECK_CURRENTLY_ON(thread_id_); |
+ DCHECK(ThreadingTraits::IsCalledOnValidThread()); |
api_resource_map_.clear(); |
extension_resource_map_.clear(); |
@@ -333,16 +366,80 @@ class ApiResourceManager : public BrowserContextKeyedAPI, |
int GenerateId() { return next_id_++; } |
int next_id_; |
- const content::BrowserThread::ID thread_id_; |
ApiResourceMap api_resource_map_; |
ExtensionToResourceMap extension_resource_map_; |
}; |
- content::BrowserThread::ID thread_id_; |
content::NotificationRegistrar registrar_; |
scoped_refptr<ApiResourceData> data_; |
}; |
+// With WorkerPoolThreadTraits, ApiResourceManager can be used to manage the |
+// lifetime of a set of resources that live on sequenced task runner threads |
+// which ApiFunctions use. Examples of such resources are temporary file |
+// resources produced by certain API calls. |
+// |
+// Instead of kThreadId. classes used for tracking such resources should define |
+// kSequenceToken and kShutdownBehavior to identify sequence task runner for |
+// ApiResourceManager to work on and how pending tasks should behave on |
+// shutdown. |
+// The user must also define a static const char* service_name() that returns |
+// the name of the service, and in order for ApiWorkerPoolResourceManager to use |
+// service_name() friend this class. |
+// |
+// In the cc file the user must define a GetFactoryInstance() and manage their |
+// own instances (typically using LazyInstance or Singleton). |
+// |
+// E.g.: |
+// |
+// class PoolResource { |
+// public: |
+// static const char kSequenceToken[] = "temp_files"; |
+// static const base::SequencedWorkerPool::WorkerShutdown kShutdownBehavior = |
+// base::SequencedWorkerPool::BLOCK_SHUTDOWN; |
+// private: |
+// friend class ApiResourceManager<WorkerPoolResource, |
+// WorkerPoolThreadTraits>; |
+// static const char* service_name() { |
+// return "TempFilesResourceManager"; |
+// } |
+// }; |
+// |
+// In the cc file: |
+// |
+// static base::LazyInstance<BrowserContextKeyedAPIFactory< |
+// ApiResourceManager<Resource, WorkerPoolThreadTraits> > > |
+// g_factory = LAZY_INSTANCE_INITIALIZER; |
+// |
+// |
+// template <> |
+// BrowserContextKeyedAPIFactory<ApiResourceManager<WorkerPoolResource> >* |
+// ApiResourceManager<WorkerPoolPoolResource, |
+// WorkerPoolThreadTraits>::GetFactoryInstance() { |
+// return g_factory.Pointer(); |
+// } |
+template <typename T> |
+struct WorkerPoolThreadTraits { |
+ static bool IsCalledOnValidThread() { |
+ return content::BrowserThread::GetBlockingPool() |
+ ->IsRunningSequenceOnCurrentThread( |
+ content::BrowserThread::GetBlockingPool()->GetNamedSequenceToken( |
+ T::kSequenceToken)); |
+ } |
+ |
+ static bool IsMessageLoopValid() { |
+ return content::BrowserThread::GetBlockingPool() != NULL; |
+ } |
+ |
+ static scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() { |
+ return content::BrowserThread::GetBlockingPool() |
+ ->GetSequencedTaskRunnerWithShutdownBehavior( |
+ content::BrowserThread::GetBlockingPool()->GetNamedSequenceToken( |
+ T::kSequenceToken), |
+ T::kShutdownBehavior); |
+ } |
+}; |
+ |
} // namespace extensions |
#endif // EXTENSIONS_BROWSER_API_API_RESOURCE_MANAGER_H_ |