/** * @file _httpoperation.h * @brief Internal declarations for HttpOperation and sub-classes * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012-2013, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef _LLCORE_HTTP_OPERATION_H_ #define _LLCORE_HTTP_OPERATION_H_ #include "httpcommon.h" #include "httprequest.h" #include "_mutex.h" namespace LLCore { class HttpReplyQueue; class HttpHandler; class HttpService; /// HttpOperation is the base class for all request/reply /// pairs. /// /// Operations are expected to be of two types: immediate /// and queued. Immediate requests go to the singleton /// request queue and when picked up by the worker thread /// are executed immediately and there results placed on /// the supplied reply queue. Queued requests (namely for /// HTTP operations), go to the request queue, are picked /// up and moved to a ready queue where they're ordered by /// priority and managed by the policy component, are /// then activated issuing HTTP requests and moved to an /// active list managed by the transport (libcurl) component /// and eventually finalized when a response is available /// and status and data return via reply queue. /// /// To manage these transitions, derived classes implement /// three methods: stageFromRequest, stageFromReady and /// stageFromActive. Immediate requests will only override /// stageFromRequest which will perform the operation and /// return the result by invoking addAsReply() to put the /// request on a reply queue. Queued requests will involve /// all three stage methods. /// /// Threading: not thread-safe. Base and derived classes /// provide no locking. Instances move across threads /// via queue-like interfaces that are thread compatible /// and those interfaces establish the access rules. class HttpOperation : private boost::noncopyable, public std::enable_shared_from_this { public: typedef std::shared_ptr ptr_t; typedef std::weak_ptr wptr_t; typedef std::shared_ptr HttpReplyQueuePtr_t; /// Threading: called by consumer thread. HttpOperation(); /// Threading: called by any thread. virtual ~HttpOperation(); // Use release() public: /// Register a reply queue and a handler for completion notifications. /// /// Invokers of operations that want to receive notification that an /// operation has been completed do so by binding a reply queue and /// a handler object to the request. /// /// @param reply_queue Pointer to the reply queue where completion /// notifications are to be queued (typically /// by addAsReply()). This will typically be /// the reply queue referenced by the request /// object. This method will increment the /// refcount on the queue holding the queue /// until delivery is complete. Using a reply_queue /// even if the handler is NULL has some benefits /// for memory deallocation by keeping it in the /// originating thread. /// /// @param handler Possibly NULL pointer to a non-refcounted //// handler object to be invoked (onCompleted) /// when the operation is finished. Note that /// the handler object is never dereferenced /// by the worker thread. This is passible data /// until notification is performed. /// /// Threading: called by consumer thread. /// void setReplyPath(HttpReplyQueuePtr_t reply_queue, HttpHandler::ptr_t handler); /// The three possible staging steps in an operation's lifecycle. /// Asynchronous requests like HTTP operations move from the /// request queue to the ready queue via stageFromRequest. Then /// from the ready queue to the active queue by stageFromReady. And /// when complete, to the reply queue via stageFromActive and the /// addAsReply utility. /// /// Immediate mode operations (everything else) move from the /// request queue to the reply queue directly via stageFromRequest /// and addAsReply with no existence on the ready or active queues. /// /// These methods will take out a reference count on the request, /// caller only needs to dispose of its reference when done with /// the request. /// /// Threading: called by worker thread. /// virtual void stageFromRequest(HttpService *); virtual void stageFromReady(HttpService *); virtual void stageFromActive(HttpService *); /// Delivers a notification to a handler object on completion. /// /// Once a request is complete and it has been removed from its /// reply queue, a handler notification may be delivered by a /// call to HttpRequest::update(). This method does the necessary /// dispatching. /// /// Threading: called by consumer thread. /// virtual void visitNotifier(HttpRequest *); /// Cancels the operation whether queued or active. /// Final status of the request becomes canceled (an error) and /// that will be delivered to caller via notification scheme. /// /// Threading: called by worker thread. /// virtual HttpStatus cancel(); /// Retrieves a unique handle for this operation. HttpHandle getHandle(); template< class OPT > static std::shared_ptr< OPT > fromHandle(HttpHandle handle) { ptr_t ptr = findByHandle(handle); if (!ptr) return std::shared_ptr< OPT >(); return std::dynamic_pointer_cast< OPT >(ptr); } protected: /// Delivers request to reply queue on completion. After this /// call, worker thread no longer accesses the object and it /// is owned by the reply queue. /// /// Threading: called by worker thread. /// void addAsReply(); protected: HttpReplyQueuePtr_t mReplyQueue; HttpHandler::ptr_t mUserHandler; public: // Request Data HttpRequest::policy_t mReqPolicy; // Reply Data HttpStatus mStatus; // Tracing, debug and metrics HttpTime mMetricCreated; int mTracing; private: typedef std::map handleMap_t; HttpHandle createHandle(); void destroyHandle(); HttpHandle mMyHandle; static handleMap_t mHandleMap; static LLCoreInt::HttpMutex mOpMutex; protected: static ptr_t findByHandle(HttpHandle handle); }; // end class HttpOperation /// HttpOpStop requests the servicing thread to shutdown /// operations, cease pulling requests from the request /// queue and release shared resources (particularly /// those shared via reference count). The servicing /// thread will then exit. The underlying thread object /// remains so that another thread can join on the /// servicing thread prior to final cleanup. The /// request *does* generate a reply on the response /// queue, if requested. class HttpOpStop : public HttpOperation { public: HttpOpStop(); virtual ~HttpOpStop(); private: HttpOpStop(const HttpOpStop &); // Not defined void operator=(const HttpOpStop &); // Not defined public: virtual void stageFromRequest(HttpService *); }; // end class HttpOpStop /// HttpOpNull is a do-nothing operation used for testing via /// a basic loopback pattern. It's executed immediately by /// the servicing thread which bounces a reply back to the /// caller without any further delay. class HttpOpNull : public HttpOperation { public: HttpOpNull(); virtual ~HttpOpNull(); private: HttpOpNull(const HttpOpNull &); // Not defined void operator=(const HttpOpNull &); // Not defined public: virtual void stageFromRequest(HttpService *); }; // end class HttpOpNull /// HttpOpSpin is a test-only request that puts the worker /// thread into a cpu spin. Used for unit tests and cleanup /// evaluation. You do not want to use this in production. class HttpOpSpin : public HttpOperation { public: // 0 does a hard spin in the operation // 1 does a soft spin continuously requeuing itself HttpOpSpin(int mode); virtual ~HttpOpSpin(); private: HttpOpSpin(const HttpOpSpin &); // Not defined void operator=(const HttpOpSpin &); // Not defined public: virtual void stageFromRequest(HttpService *); protected: int mMode; }; // end class HttpOpSpin } // end namespace LLCore #endif // _LLCORE_HTTP_OPERATION_H_