/** * @file llqueuedthread.h * @brief * * Copyright (c) 2004-$CurrentYear$, Linden Research, Inc. * $License$ */ #ifndef LL_LLQUEUEDTHREAD_H #define LL_LLQUEUEDTHREAD_H #include #include #include #include #include "llapr.h" #include "llthread.h" #include "llsimplehash.h" //============================================================================ // Note: ~LLQueuedThread is O(N) N=# of queued threads, assumed to be small // It is assumed that LLQueuedThreads are rarely created/destroyed. class LLQueuedThread : public LLThread { //------------------------------------------------------------------------ public: enum priority_t { PRIORITY_IMMEDIATE = 0x7FFFFFFF, PRIORITY_URGENT = 0x40000000, PRIORITY_HIGH = 0x30000000, PRIORITY_NORMAL = 0x20000000, PRIORITY_LOW = 0x10000000, PRIORITY_LOWBITS = 0x0FFFFFFF }; enum status_t { STATUS_EXPIRED = -1, STATUS_UNKNOWN = 0, STATUS_QUEUED = 1, STATUS_INPROGRESS = 2, STATUS_COMPLETE = 3, STATUS_ABORT = 4, STATUS_ABORTED = 5, STATUS_DELETE = 6 }; enum flags_t { AUTO_COMPLETE = 1, AUTO_DELETE = 2 // child-class dependent }; typedef U32 handle_t; //------------------------------------------------------------------------ public: class QueuedRequest : public LLSimpleHashEntry { friend class LLQueuedThread; protected: ~QueuedRequest(); // use deleteRequest() public: QueuedRequest(handle_t handle, U32 priority, U32 flags = 0); status_t getStatus() { return mStatus; } U32 getPriority() const { return mPriority; } U32 getFlags() const { return mFlags; } bool higherPriority(const QueuedRequest& second) const { if ( mPriority == second.mPriority) return mHashKey < second.mHashKey; else return mPriority > second.mPriority; } protected: status_t setStatus(status_t newstatus) { status_t oldstatus = mStatus; mStatus = newstatus; return oldstatus; } status_t abortRequest(U32 flags) { // NOTE: flags are |'d if (mStatus == STATUS_QUEUED) { setStatus(STATUS_ABORT); } mFlags |= flags; status_t status = mStatus; return status; } status_t setFlags(U32 flags) { // NOTE: flags are |'d mFlags |= flags; status_t status = mStatus; return status; } virtual void finishRequest(); // Always called when after has been processed virtual void deleteRequest(); // Only method to delete a request void setPriority(U32 pri) { // Only do this on a request that is not in a queued list! mPriority = pri; }; protected: LLAtomic32 mStatus; U32 mPriority; U32 mFlags; }; protected: struct queued_request_less { bool operator()(const QueuedRequest* lhs, const QueuedRequest* rhs) const { return lhs->higherPriority(*rhs); // higher priority in front of queue (set) } }; //------------------------------------------------------------------------ public: static handle_t nullHandle() { return handle_t(0); } public: LLQueuedThread(const std::string& name, bool threaded = TRUE, bool runalways = TRUE); virtual ~LLQueuedThread(); private: // No copy constructor or copy assignment LLQueuedThread(const LLQueuedThread&); LLQueuedThread& operator=(const LLQueuedThread&); virtual bool runCondition(void); virtual void run(void); protected: handle_t generateHandle(); bool addRequest(QueuedRequest* req); int processNextRequest(void); virtual bool processRequest(QueuedRequest* req) = 0; public: bool waitForResult(handle_t handle, bool auto_complete = true); void update(U32 ms_elapsed); void updateQueue(S32 inc); void waitOnPending(); void printQueueStats(); S32 getPending(bool child_thread = false); bool getThreaded() { return mThreaded ? true : false; } bool getRunAlways() { return mRunAlways ? true : false; } // Request accessors status_t getRequestStatus(handle_t handle); status_t abortRequest(handle_t handle, U32 flags = 0); status_t setFlags(handle_t handle, U32 flags); void setPriority(handle_t handle, U32 priority); bool completeRequest(handle_t handle); // This is public for support classes like LLWorkerThread, // but generally the methods above should be used. QueuedRequest* getRequest(handle_t handle); // debug (see source) bool check(); protected: BOOL mThreaded; // if false, run on main thread and do updates during update() BOOL mRunAlways; // if false, only wake the threads when updateClass() is called LLAtomic32 mIdleThread; // request queue is empty (or we are quitting) and the thread is idle typedef std::set request_queue_t; request_queue_t mRequestQueue; enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2 typedef LLSimpleHash request_hash_t; request_hash_t mRequestHash; handle_t mNextHandle; }; #endif // LL_LLQUEUEDTHREAD_H