diff options
Diffstat (limited to 'chrome/browser/cancelable_request.h')
-rw-r--r-- | chrome/browser/cancelable_request.h | 702 |
1 files changed, 5 insertions, 697 deletions
diff --git a/chrome/browser/cancelable_request.h b/chrome/browser/cancelable_request.h index dce7a2c..cb749ee 100644 --- a/chrome/browser/cancelable_request.h +++ b/chrome/browser/cancelable_request.h @@ -2,703 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// CancelableRequestProviders and Consumers work together to make requests that -// execute on a background thread in the provider and return data to the -// consumer. These class collaborate to keep a list of open requests and to -// make sure that requests to not outlive either of the objects involved in the -// transaction. -// -// If you do not need to return data to the consumer, do not use this system, -// just use the regular Task/RunnableMethod stuff. -// -// The CancelableRequest object is used internally to each provider to track -// request data and callback information. -// -// Example consumer calling |StartRequest| on a frontend service: -// -// class MyClass { -// void MakeRequest() { -// frontend_service->StartRequest(some_input1, some_input2, -// &callback_consumer_, -// NewCallback(this, &MyClass:RequestComplete)); -// // StartRequest() returns a Handle which may be retained for use with -// // CancelRequest() if required, e.g. in MyClass's destructor. -// } -// -// void RequestComplete(int status) { -// ... -// } -// -// private: -// CancelableRequestConsumer callback_consumer_; -// }; -// -// -// Example frontend provider. It receives requests and forwards them to the -// backend on another thread: -// -// class Frontend : public CancelableRequestProvider { -// typedef Callback1<int>::Type RequestCallbackType; -// -// Handle StartRequest(int some_input1, int some_input2, -// CancelableRequestConsumerBase* consumer, -// RequestCallbackType* callback) { -// scoped_refptr<CancelableRequest<RequestCallbackType> > request( -// new CancelableRequest<RequestCallbackType>(callback)); -// AddRequest(request, consumer); -// -// // Send the parameters and the request to the backend thread. -// backend_thread_->PostTask(FROM_HERE, -// NewRunnableMethod(backend_, &Backend::DoRequest, request, -// some_input1, some_input2)); -// -// // The handle will have been set by AddRequest. -// return request->handle(); -// } -// }; -// -// -// Example backend provider that does work and dispatches the callback back -// to the original thread. Note that we need to pass it as a scoped_refptr so -// that the object will be kept alive if the request is canceled (releasing -// the provider's reference to it). -// -// class Backend { -// void DoRequest( -// scoped_refptr< CancelableRequest<Frontend::RequestCallbackType> > -// request, -// int some_input1, int some_input2) { -// if (request->canceled()) -// return; -// -// ... do your processing ... -// -// // Depending on your typedefs, one of these two forms will be more -// // convenient: -// request->ForwardResult(Tuple1<int>(return_value)); -// -// // -- or -- (inferior in this case) -// request->ForwardResult(Frontend::RequestCallbackType::TupleType( -// return_value)); -// } -// }; - -#ifndef CHROME_BROWSER_CANCELABLE_REQUEST_H__ -#define CHROME_BROWSER_CANCELABLE_REQUEST_H__ +#ifndef CHROME_BROWSER_CANCELABLE_REQUEST_H_ +#define CHROME_BROWSER_CANCELABLE_REQUEST_H_ #pragma once -#include <map> -#include <vector> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" -#include "base/synchronization/cancellation_flag.h" -#include "base/synchronization/lock.h" -#include "base/task.h" -#include "build/build_config.h" - -class CancelableRequestBase; -class CancelableRequestConsumerBase; - -// CancelableRequestProvider -------------------------------------------------- -// -// This class is threadsafe. Requests may be added or canceled from any thread, -// but a task must only be canceled from the same thread it was initially run -// on. -// -// It is intended that providers inherit from this class to provide the -// necessary functionality. - -class CancelableRequestProvider { - public: - // Identifies a specific request from this provider. - typedef int Handle; - - CancelableRequestProvider(); - virtual ~CancelableRequestProvider(); - - // Called by the enduser of the request to cancel it. This MUST be called on - // the same thread that originally issued the request (which is also the same - // thread that would have received the callback if it was not canceled). - // handle must be for a valid pending (not yet complete or cancelled) request. - void CancelRequest(Handle handle); - - protected: - // Adds a new request and initializes it. This is called by a derived class - // to add a new request. The request's Init() will be called (which is why - // the consumer is required. The handle to the new request is returned. - Handle AddRequest(CancelableRequestBase* request, - CancelableRequestConsumerBase* consumer); - - // Called by the CancelableRequest when the request has executed. It will - // be removed from the list of pending requests (as opposed to canceling, - // which will also set some state on the request). - void RequestCompleted(Handle handle); - - private: - typedef std::map<Handle, scoped_refptr<CancelableRequestBase> > - CancelableRequestMap; - - // Only call this when you already have acquired pending_request_lock_. - void CancelRequestLocked(const CancelableRequestMap::iterator& item); - - friend class CancelableRequestBase; - - base::Lock pending_request_lock_; - - // Lists all outstanding requests. Protected by the |lock_|. - CancelableRequestMap pending_requests_; - - // The next handle value we will return. Protected by the |lock_|. - int next_handle_; - - DISALLOW_COPY_AND_ASSIGN(CancelableRequestProvider); -}; - -// CancelableRequestConsumer -------------------------------------------------- -// -// Classes wishing to make requests on a provider should have an instance of -// this class. Callers will need to pass a pointer to this consumer object -// when they make the request. It will automatically track any pending -// requests, and will automatically cancel them on destruction to prevent the -// accidental calling of freed memory. -// -// It is recommended to just have this class as a member variable since there -// is nothing to be gained by inheriting from it other than polluting your -// namespace. -// -// THIS CLASS IS NOT THREADSAFE (unlike the provider). You must make requests -// and get callbacks all from the same thread. - -// Base class used to notify of new requests. -class CancelableRequestConsumerBase { - protected: - friend class CancelableRequestBase; - friend class CancelableRequestProvider; - - virtual ~CancelableRequestConsumerBase() { - } - - // Adds a new request to the list of requests that are being tracked. This - // is called by the provider when a new request is created. - virtual void OnRequestAdded(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) = 0; - - // Removes the given request from the list of pending requests. Called - // by the CancelableRequest immediately after the callback has executed for a - // given request, and by the provider when a request is canceled. - virtual void OnRequestRemoved(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) = 0; - - // Sent to provider before executing a callback. - virtual void WillExecute(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) = 0; - - // Sent after executing a callback. - virtual void DidExecute(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) = 0; -}; - -// Template for clients to use. It allows them to associate random "client -// data" with a specific request. The default value for this type is 0. -// The type T should be small and easily copyable (like a pointer -// or an integer). -template<class T> -class CancelableRequestConsumerTSimple : public CancelableRequestConsumerBase { - public: - CancelableRequestConsumerTSimple(); - - // Cancel any outstanding requests so that we do not get called back after we - // are destroyed. As these requests are removed, the providers will call us - // back on OnRequestRemoved, which will then update the list. To iterate - // successfully while the list is changing out from under us, we make a copy. - virtual ~CancelableRequestConsumerTSimple(); - - // Associates some random data with a specified request. The request MUST be - // outstanding, or it will assert. This is intended to be called immediately - // after a request is issued. - void SetClientData(CancelableRequestProvider* p, - CancelableRequestProvider::Handle h, - T client_data); - - // Retrieves previously associated data for a specified request. The request - // MUST be outstanding, or it will assert. This is intended to be called - // during processing of a callback to retrieve extra data. - T GetClientData(CancelableRequestProvider* p, - CancelableRequestProvider::Handle h); - - // Returns the data associated with the current request being processed. This - // is only valid during the time a callback is being processed. - T GetClientDataForCurrentRequest(); - - // Returns true if there are any pending requests. - bool HasPendingRequests() const; - - // Returns the number of pending requests. - size_t PendingRequestCount() const; - - // Cancels all requests outstanding. - void CancelAllRequests(); - - // Returns the handle for the first request that has the specified client data - // (in |handle|). Returns true if there is a request for the specified client - // data, false otherwise. - bool GetFirstHandleForClientData(T client_data, - CancelableRequestProvider::Handle* handle); - - // Gets the client data for all pending requests. - void GetAllClientData(std::vector<T>* data); - - protected: - struct PendingRequest { - PendingRequest(CancelableRequestProvider* p, - CancelableRequestProvider::Handle h) - : provider(p), handle(h) { - } - - PendingRequest() : provider(NULL), handle(0) {} - - // Comparison operator for stl. - bool operator<(const PendingRequest& other) const { - if (provider != other.provider) - return provider < other.provider; - return handle < other.handle; - } - - bool is_valid() const { return provider != NULL; } - - CancelableRequestProvider* provider; - CancelableRequestProvider::Handle handle; - }; - typedef std::map<PendingRequest, T> PendingRequestList; - - virtual T get_initial_t() const; - - virtual void OnRequestAdded(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle); - - virtual void OnRequestRemoved(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle); - - virtual void WillExecute(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle); - - virtual void DidExecute(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle); - - // Lists all outstanding requests. - PendingRequestList pending_requests_; - - // This is valid while processing a request and is used to identify the - // provider/handle of request. - PendingRequest current_request_; -}; - -template<class T> -CancelableRequestConsumerTSimple<T>::CancelableRequestConsumerTSimple() { -} - -template<class T> -CancelableRequestConsumerTSimple<T>::~CancelableRequestConsumerTSimple() { - CancelAllRequests(); -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::SetClientData( - CancelableRequestProvider* p, - CancelableRequestProvider::Handle h, - T client_data) { - PendingRequest request(p, h); - DCHECK(pending_requests_.find(request) != pending_requests_.end()); - pending_requests_[request] = client_data; -} - -template<class T> -T CancelableRequestConsumerTSimple<T>::GetClientData( - CancelableRequestProvider* p, - CancelableRequestProvider::Handle h) { - PendingRequest request(p, h); - DCHECK(pending_requests_.find(request) != pending_requests_.end()); - return pending_requests_[request]; -} - -template<class T> -T CancelableRequestConsumerTSimple<T>::GetClientDataForCurrentRequest() { - DCHECK(current_request_.is_valid()); - return GetClientData(current_request_.provider, current_request_.handle); -} - -template<class T> -bool CancelableRequestConsumerTSimple<T>::HasPendingRequests() const { - return !pending_requests_.empty(); -} - -template<class T> -size_t CancelableRequestConsumerTSimple<T>::PendingRequestCount() const { - return pending_requests_.size(); -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::CancelAllRequests() { - PendingRequestList copied_requests(pending_requests_); - for (typename PendingRequestList::iterator i = copied_requests.begin(); - i != copied_requests.end(); ++i) - i->first.provider->CancelRequest(i->first.handle); - copied_requests.clear(); - - // That should have cleared all the pending items. - DCHECK(pending_requests_.empty()); -} - -template<class T> -bool CancelableRequestConsumerTSimple<T>::GetFirstHandleForClientData( - T client_data, - CancelableRequestProvider::Handle* handle) { - for (typename PendingRequestList::const_iterator i = - pending_requests_.begin(); i != pending_requests_.end(); ++i) { - if (i->second == client_data) { - *handle = i->first.handle; - return true; - } - } - *handle = 0; - return false; -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::GetAllClientData( - std::vector<T>* data) { - DCHECK(data); - for (typename PendingRequestList::iterator i = pending_requests_.begin(); - i != pending_requests_.end(); ++i) - data->push_back(i->second); -} - -template<class T> -T CancelableRequestConsumerTSimple<T>::get_initial_t() const { - return 0; -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::OnRequestAdded( - CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) { - DCHECK(pending_requests_.find(PendingRequest(provider, handle)) == - pending_requests_.end()); - pending_requests_[PendingRequest(provider, handle)] = get_initial_t(); -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::OnRequestRemoved( - CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) { - typename PendingRequestList::iterator i = - pending_requests_.find(PendingRequest(provider, handle)); - if (i == pending_requests_.end()) { - NOTREACHED() << "Got a complete notification for a nonexistent request"; - return; - } - - pending_requests_.erase(i); -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::WillExecute( - CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) { - current_request_ = PendingRequest(provider, handle); -} - -template<class T> -void CancelableRequestConsumerTSimple<T>::DidExecute( - CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle) { - current_request_ = PendingRequest(); -} - -// See CancelableRequestConsumerTSimple. The default value for T -// is given in |initial_t|. -template<class T, T initial_t> -class CancelableRequestConsumerT : public CancelableRequestConsumerTSimple<T> { - public: - CancelableRequestConsumerT(); - virtual ~CancelableRequestConsumerT(); - - protected: - virtual T get_initial_t() const; -}; - -template<class T, T initial_t> -CancelableRequestConsumerT<T, initial_t>::CancelableRequestConsumerT() { -} - -template<class T, T initial_t> -CancelableRequestConsumerT<T, initial_t>::~CancelableRequestConsumerT() { -} - -template<class T, T initial_t> -T CancelableRequestConsumerT<T, initial_t>::get_initial_t() const { - return initial_t; -} - -// Some clients may not want to store data. Rather than do some complicated -// thing with virtual functions to allow some consumers to store extra data and -// some not to, we just define a default one that stores some dummy data. -typedef CancelableRequestConsumerT<int, 0> CancelableRequestConsumer; - -// MSVC doesn't like complex extern templates and DLLs. -#if !defined(COMPILER_MSVC) -// The vast majority of CancelableRequestConsumers are instantiated on <int>, -// so prevent that template from being expanded in normal code. -extern template class CancelableRequestConsumerTSimple<int>; - -// We'll also want to extern-template the most common, typedef-ed -// CancelableRequestConsumerT. -extern template class CancelableRequestConsumerT<int, 0>; -#endif - -// CancelableRequest ---------------------------------------------------------- -// -// The request object that is used by a CancelableRequestProvider to send -// results to a CancelableRequestConsumer. This request handles the returning -// of results from a thread where the request is being executed to the thread -// and callback where the results are used. IT SHOULD BE PASSED AS A -// scoped_refptr TO KEEP IT ALIVE. -// -// It does not handle input parameters to the request. The caller must either -// transfer those separately or derive from this class to add the desired -// parameters. -// -// When the processing is complete on this message, the caller MUST call -// ForwardResult() with the return arguments that will be passed to the -// callback. If the request has been canceled, Return is optional (it will not -// do anything). If you do not have to return to the caller, the cancelable -// request system should not be used! (just use regular fire-and-forget tasks). -// -// Callback parameters are passed by value. In some cases, the request will -// want to return a large amount of data (for example, an image). One good -// approach is to derive from the CancelableRequest and make the data object -// (for example, a std::vector) owned by the CancelableRequest. The pointer -// to this data would be passed for the callback parameter. Since the -// CancelableRequest outlives the callback call, the data will be valid on the -// other thread for the callback, but will still be destroyed properly. - -// Non-templatized base class that provides cancellation -class CancelableRequestBase - : public base::RefCountedThreadSafe<CancelableRequestBase> { - public: - friend class CancelableRequestProvider; - - // Initializes most things to empty, Init() must be called to complete - // initialization of the object. This will be done by the provider when - // the request is dispatched. - // - // This must be called on the same thread the callback will be executed on, - // it will save that thread for later. - // - // This two-phase init is done so that the constructor can have no - // parameters, which makes it much more convenient for derived classes, - // which can be common. The derived classes need only declare the variables - // they provide in the constructor rather than many lines of internal - // tracking data that are passed to the base class (us). - // - // In addition, not all of the information (for example, the handle) is known - // at construction time. - CancelableRequestBase(); - - CancelableRequestConsumerBase* consumer() const { - return consumer_; - } - - CancelableRequestProvider::Handle handle() const { - return handle_; - } - - // The canceled flag indicates that the request should not be executed. - // A request can never be uncanceled, so only a setter for true is provided. - // This can be called multiple times, but only from one thread. - void set_canceled() { - canceled_.Set(); - } - bool canceled() { - return canceled_.IsSet(); - } - - protected: - friend class base::RefCountedThreadSafe<CancelableRequestBase>; - virtual ~CancelableRequestBase(); - - // Initializes the object with the particulars from the provider. It may only - // be called once (it is called by the provider, which is a friend). - void Init(CancelableRequestProvider* provider, - CancelableRequestProvider::Handle handle, - CancelableRequestConsumerBase* consumer); - - // Tells the provider that the request is complete, which then tells the - // consumer. - void NotifyCompleted() const { - provider_->RequestCompleted(handle()); - consumer_->DidExecute(provider_, handle_); - } - - // Cover method for CancelableRequestConsumerBase::WillExecute. - void WillExecute() { - consumer_->WillExecute(provider_, handle_); - } - - // The message loop that this request was created on. The callback will - // happen on the same thread. - MessageLoop* callback_thread_; - - // The provider for this request. When we execute, we will notify this that - // request is complete to it can remove us from the requests it tracks. - CancelableRequestProvider* provider_; - - // Notified after we execute that the request is complete. This should only - // be accessed if !canceled_.IsSet(), otherwise the pointer is invalid. - CancelableRequestConsumerBase* consumer_; - - // The handle to this request inside the provider. This will be initialized - // to 0 when the request is created, and the provider will set it once the - // request has been dispatched. - CancelableRequestProvider::Handle handle_; - - // Set if the caller cancels this request. No callbacks should be made when - // this is set. - base::CancellationFlag canceled_; - - private: - DISALLOW_COPY_AND_ASSIGN(CancelableRequestBase); -}; - -// Templatized class. This is the one you should use directly or inherit from. -// The callback can be invoked by calling the ForwardResult() method. For this, -// you must either pack the parameters into a tuple, or use DispatchToMethod -// (in tuple.h). -// -// If you inherit to add additional input parameters or to do more complex -// memory management (see the bigger comment about this above), you can put -// those on a subclass of this. -// -// We have decided to allow users to treat derived classes of this as structs, -// so you can add members without getters and setters (which just makes the -// code harder to read). Don't use underscores after these vars. For example: -// -// typedef Callback1<int>::Type DoodieCallback; -// -// class DoodieRequest : public CancelableRequest<DoodieCallback> { -// public: -// DoodieRequest(CallbackType* callback) : CancelableRequest(callback) { -// } -// -// private: -// ~DoodieRequest() {} -// -// int input_arg1; -// std::wstring input_arg2; -// }; -template<typename CB> -class CancelableRequest : public CancelableRequestBase { - public: - typedef CB CallbackType; // CallbackRunner<...> - typedef typename CB::TupleType TupleType; // Tuple of the callback args. - - // The provider MUST call Init() (on the base class) before this is valid. - // This class will take ownership of the callback object and destroy it when - // appropriate. - explicit CancelableRequest(CallbackType* callback) - : CancelableRequestBase(), - callback_(callback) { - DCHECK(callback) << "We should always have a callback"; - } - - // Dispatches the parameters to the correct thread so the callback can be - // executed there. The caller does not need to check for cancel before - // calling this. It is optional in the cancelled case. In the non-cancelled - // case, this MUST be called. - // - // If there are any pointers in the parameters, they must live at least as - // long as the request so that it can be forwarded to the other thread. - // For complex objects, this would typically be done by having a derived - // request own the data itself. - void ForwardResult(const TupleType& param) { - DCHECK(callback_.get()); - if (!canceled()) { - if (callback_thread_ == MessageLoop::current()) { - // We can do synchronous callbacks when we're on the same thread. - ExecuteCallback(param); - } else { - callback_thread_->PostTask(FROM_HERE, NewRunnableMethod(this, - &CancelableRequest<CB>::ExecuteCallback, param)); - } - } - } - - // Like |ForwardResult| but this never does a synchronous callback. - void ForwardResultAsync(const TupleType& param) { - DCHECK(callback_.get()); - if (!canceled()) { - callback_thread_->PostTask(FROM_HERE, NewRunnableMethod(this, - &CancelableRequest<CB>::ExecuteCallback, param)); - } - } - - protected: - virtual ~CancelableRequest() {} - - private: - // Executes the callback and notifies the provider and the consumer that this - // request has been completed. This must be called on the callback_thread_. - void ExecuteCallback(const TupleType& param) { - if (!canceled_.IsSet()) { - WillExecute(); - - // Execute the callback. - callback_->RunWithParams(param); - - // Notify the provider that the request is complete. The provider will - // notify the consumer for us. - NotifyCompleted(); - } - } - - // This should only be executed if !canceled_.IsSet(), - // otherwise the pointers may be invalid. - scoped_ptr<CallbackType> callback_; -}; - -// A CancelableRequest with a single value. This is intended for use when -// the provider provides a single value. The provider fills the result into -// the value, and notifies the request with a pointer to the value. For example, -// HistoryService has many methods that callback with a vector. Use the -// following pattern for this: -// 1. Define the callback: -// typedef Callback2<Handle, std::vector<Foo>*>::Type FooCallback; -// 2. Define the CancelableRequest1 type. -// typedef CancelableRequest1<FooCallback, std::vector<Foo>> FooRequest; -// 3. The provider method should then fillin the contents of the vector, -// forwarding the result like so: -// request->ForwardResult(FooRequest::TupleType(request->handle(), -// &request->value)); -// -// Tip: for passing more than one value, use a Tuple for the value. -template<typename CB, typename Type> -class CancelableRequest1 : public CancelableRequest<CB> { - public: - explicit CancelableRequest1( - typename CancelableRequest<CB>::CallbackType* callback) - : CancelableRequest<CB>(callback) { - } - - // The value. - Type value; - - protected: - virtual ~CancelableRequest1() {} -}; +// TODO(jam): remove this file when all files have been converted. +#include "content/browser/cancelable_request.h" -#endif // CHROME_BROWSER_CANCELABLE_REQUEST_H__ +#endif // CHROME_BROWSER_CANCELABLE_REQUEST_H_ |