Coverage Report

Created: 2025-07-18 07:08

/src/ogre/OgreMain/include/OgreWorkQueue.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
(Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
#ifndef __OgreWorkQueue_H__
29
#define __OgreWorkQueue_H__
30
31
#include "OgrePrerequisites.h"
32
#include "OgreAny.h"
33
#include "OgreSharedPtr.h"
34
#include "OgreCommon.h"
35
#include "Threading/OgreThreadHeaders.h"
36
#include "OgreHeaderPrefix.h"
37
38
#include <deque>
39
#include <functional>
40
41
namespace Ogre
42
{
43
    /** \addtogroup Core
44
    *  @{
45
    */
46
    /** \addtogroup General
47
    *  @{
48
    */
49
50
    /** Interface to a general purpose task-basedbackground work queue.
51
52
        A work queue is a simple structure, where tasks of work are placed
53
        onto the queue, then removed by a worker for processing.
54
        The typical use for this is in a threaded environment,
55
        although any kind of deferred processing could use this approach to 
56
        decouple and distribute work over a period of time even 
57
        if it was single threaded.
58
59
        WorkQueues also incorporate thread pools. One or more background worker threads
60
        can wait on the queue and be notified when a request is waiting to be
61
        processed. For maximal thread usage, a WorkQueue instance should be shared
62
        among many sources of work, rather than many work queues being created.
63
        This way, you can share a small number of hardware threads among a large 
64
        number of background tasks. This doesn't mean you have to implement all the
65
        request processing in one class, you can plug in many handlers in order to
66
        process the tasks.
67
68
        This is an abstract interface definition; users can subclass this and 
69
        provide their own implementation if required to centralise task management
70
        in their own subsystems. We also provide a default implementation in the
71
        form of DefaultWorkQueue.
72
    */
73
    class _OgreExport WorkQueue : public UtilityAlloc
74
    {
75
    public:
76
        /// Numeric identifier for a request
77
        typedef unsigned long long int RequestID;
78
79
        /** General purpose request structure. 
80
        */
81
        class _OgreExport Request : public UtilityAlloc
82
        {
83
            friend class WorkQueue;
84
        protected:
85
            /// The request channel, as an integer 
86
            uint16 mChannel;
87
            /// The request type, as an integer within the channel (user can define enumerations on this)
88
            uint16 mType;
89
            /// The details of the request (user defined)
90
            Any mData;
91
            /// Retry count - set this to non-zero to have the request try again on failure
92
            uint8 mRetryCount;
93
            /// Identifier (assigned by the system)
94
            RequestID mID;
95
            /// Abort Flag
96
            mutable bool mAborted;
97
98
        public:
99
            /// Constructor 
100
            Request(uint16 channel, uint16 rtype, const Any& rData, uint8 retry, RequestID rid);
101
            ~Request();
102
            /// Get the request channel (top level categorisation)
103
0
            uint16 getChannel() const { return mChannel; }
104
            /// Get the type of this request within the given channel
105
0
            uint16 getType() const { return mType; }
106
            /// Get the user details of this request
107
0
            const Any& getData() const { return mData; }
108
            /// Get the remaining retry count
109
0
            uint8 getRetryCount() const { return mRetryCount; }
110
            /// Get the identifier of this request
111
0
            RequestID getID() const { return mID; }
112
        };
113
114
        /** General purpose response structure. 
115
        */
116
        struct _OgreExport Response : public UtilityAlloc
117
        {
118
            /// Pointer to the request that this response is in relation to
119
            const Request* mRequest;
120
            /// Whether the work item succeeded or not
121
            bool mSuccess;
122
            /// Any diagnostic messages
123
            String mMessages;
124
            /// Data associated with the result of the process
125
            Any mData;
126
127
        public:
128
            Response(const Request* rq, bool success, const Any& data, const String& msg = BLANKSTRING);
129
            ~Response();
130
            /// Get the request that this is a response to (NB destruction destroys this)
131
0
            const Request* getRequest() const { return mRequest; }
132
            /// Return whether this is a successful response
133
0
            bool succeeded() const { return mSuccess; }
134
            /// Get any diagnostic messages about the process
135
0
            const String& getMessages() const { return mMessages; }
136
            /// Return the response data (user defined, only valid on success)
137
0
            const Any& getData() const { return mData; }
138
        };
139
        WorkQueue() {}
140
        virtual ~WorkQueue() {}
141
142
        /** Get the number of worker threads that this queue will start when
143
            startup() is called.
144
        */
145
0
        virtual size_t getWorkerThreadCount() const { return 1; }
146
147
        /** Set the number of worker threads that this queue will start
148
            when startup() is called (default 1).
149
            Calling this will have no effect unless the queue is shut down and
150
            restarted.
151
        */
152
0
        virtual void setWorkerThreadCount(size_t c) {}
153
154
        /** Start up the queue with the options that have been set.
155
        @param forceRestart If the queue is already running, whether to shut it
156
            down and restart.
157
        */
158
        virtual void startup(bool forceRestart = true) = 0;
159
160
        /** Add a new task to the queue */
161
        virtual void addTask(std::function<void()> task) = 0;
162
        
163
        /** Set whether to pause further processing of any requests. 
164
        If true, any further requests will simply be queued and not processed until
165
        setPaused(false) is called. Any requests which are in the process of being
166
        worked on already will still continue. 
167
        */
168
        virtual void setPaused(bool pause) = 0;
169
        /// Return whether the queue is paused ie not sending more work to workers
170
        virtual bool isPaused() const = 0;
171
172
        /** Set whether to accept new requests or not. 
173
        If true, requests are added to the queue as usual. If false, requests
174
        are silently ignored until setRequestsAccepted(true) is called. 
175
        */
176
        virtual void setRequestsAccepted(bool accept) = 0;
177
        /// Returns whether requests are being accepted right now
178
        virtual bool getRequestsAccepted() const = 0;
179
180
        /** Process the tasks in the main-thread queue.
181
182
            This method must be called from the main render
183
            thread to 'pump' tasks through the system. The method will usually
184
            try to clear all tasks before returning; however, you can specify
185
            a time limit on the tasks processing to limit the impact of
186
            spikes in demand by calling @ref setMainThreadProcessingTimeLimit.
187
        */
188
        virtual void processMainThreadTasks();
189
190
        /// @deprecated use @ref processMainThreadTasks
191
0
        OGRE_DEPRECATED virtual void processResponses() { }
192
193
        /** Get the time limit imposed on the processing of tasks in a
194
            single frame, in milliseconds (0 indicates no limit).
195
        */
196
0
        uint64 getMainThreadProcessingTimeLimit() const { return getResponseProcessingTimeLimit(); }
197
198
        /// @deprecated use @ref getMainThreadProcessingTimeLimit()
199
        virtual unsigned long getResponseProcessingTimeLimit() const = 0;
200
201
        /** Set the time limit imposed on the processing of tasks in a
202
            single frame, in milliseconds (0 indicates no limit).
203
            This sets the maximum time that will be spent in @ref processMainThreadTasks() in
204
            a single frame. The default is 10ms.
205
        */
206
0
        void setMainThreadProcessingTimeLimit(uint64 ms) { setResponseProcessingTimeLimit(ms); }
207
208
        /// @deprecated use @ref setMainThreadProcessingTimeLimit
209
        virtual void setResponseProcessingTimeLimit(unsigned long ms) = 0;
210
211
        /** Add a deferred task that will be processed on the main render thread */
212
        virtual void addMainThreadTask(std::function<void()> task) = 0;
213
214
        /** Shut down the queue.
215
        */
216
        virtual void shutdown() = 0;
217
    };
218
219
    /** Base for a general purpose task-based background work queue.
220
    */
221
    class _OgreExport DefaultWorkQueueBase : public WorkQueue
222
    {
223
    public:
224
225
        /** Constructor.
226
            Call startup() to initialise.
227
        @param name Optional name, just helps to identify logging output
228
        */
229
        DefaultWorkQueueBase(const String& name = BLANKSTRING);
230
        virtual ~DefaultWorkQueueBase();
231
        /// Get the name of the work queue
232
        const String& getName() const;
233
234
        /** Get whether worker threads will be allowed to access render system
235
            resources. 
236
            Accessing render system resources from a separate thread can require that
237
            a context is maintained for that thread. Also, it requires that the
238
            render system is running in threadsafe mode, which only happens
239
            when OGRE_THREAD_SUPPORT=1. This option defaults to false, which means
240
            that threads can not use GPU resources, and the render system can 
241
            work in non-threadsafe mode, which is more efficient.
242
        */
243
        virtual bool getWorkersCanAccessRenderSystem() const;
244
245
246
        /** Set whether worker threads will be allowed to access render system
247
            resources. 
248
            Accessing render system resources from a separate thread can require that
249
            a context is maintained for that thread. Also, it requires that the
250
            render system is running in threadsafe mode, which only happens
251
            when OGRE_THREAD_SUPPORT=1. This option defaults to false, which means
252
            that threads can not use GPU resources, and the render system can 
253
            work in non-threadsafe mode, which is more efficient.
254
            Calling this will have no effect unless the queue is shut down and
255
            restarted.
256
        */
257
        virtual void setWorkersCanAccessRenderSystem(bool access);
258
259
        /** Process the next request on the queue. 
260
261
            This method is public, but only intended for advanced users to call. 
262
            The only reason you would call this, is if you were using your 
263
            own thread to drive the worker processing. The thread calling this
264
            method will be the thread used to call the RequestHandler.
265
        */
266
        virtual void _processNextRequest();
267
268
        /// Main function for each thread spawned.
269
        virtual void _threadMain() = 0;
270
271
        /** Returns whether the queue is trying to shut down. */
272
0
        virtual bool isShuttingDown() const { return mShuttingDown; }
273
274
        /// @copydoc WorkQueue::setPaused
275
        void setPaused(bool pause) override;
276
        /// @copydoc WorkQueue::isPaused
277
        bool isPaused() const override;
278
        /// @copydoc WorkQueue::setRequestsAccepted
279
        void setRequestsAccepted(bool accept) override;
280
        /// @copydoc WorkQueue::getRequestsAccepted
281
        virtual bool getRequestsAccepted() const override;
282
        void processMainThreadTasks() override;
283
        /// @copydoc WorkQueue::getResponseProcessingTimeLimit
284
0
        unsigned long getResponseProcessingTimeLimit() const override { return mResposeTimeLimitMS; }
285
        /// @copydoc WorkQueue::setResponseProcessingTimeLimit
286
0
        void setResponseProcessingTimeLimit(unsigned long ms) override { mResposeTimeLimitMS = ms; }
287
0
        size_t getWorkerThreadCount() const override { return mWorkerThreadCount; }
288
        void setWorkerThreadCount(size_t c) override { mWorkerThreadCount = c; }
289
        void addMainThreadTask(std::function<void()> task) override;
290
        void addTask(std::function<void()> task) override;
291
    protected:
292
        String mName;
293
        size_t mWorkerThreadCount;
294
        bool mWorkerRenderSystemAccess;
295
        bool mIsRunning;
296
        unsigned long mResposeTimeLimitMS;
297
298
        std::deque<std::function<void()>> mTasks;
299
        std::deque<std::function<void()>> mMainThreadTasks;
300
301
        bool mPaused;
302
        bool mAcceptRequests;
303
        bool mShuttingDown;
304
305
        OGRE_WQ_MUTEX(mRequestMutex);
306
        OGRE_WQ_MUTEX(mResponseMutex);
307
308
        /// Notify workers about a new request. 
309
        virtual void notifyWorkers() = 0;
310
    };
311
312
313
314
315
316
    /** @} */
317
    /** @} */
318
319
}
320
321
#include "OgreHeaderSuffix.h"
322
323
#endif
324