source: nrEngine/include/ITask.h @ 17

Revision 17, 12.1 KB checked in by art, 12 years ago (diff)
Line 
1/***************************************************************************
2 *                                                                         *
3 *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
4 *       mailto: <tevs@mpi-sb.mpg.de>                                      *
5 *                                                                         *
6 *   This program is free software; you can redistribute it and/or modify  *
7 *   it under the terms of the GNU General Public License as published by  *
8 *   the Free Software Foundation; either version 2 of the License, or     *
9 *   (at your option) any later version.                                   *
10 *                                                                         *
11 ***************************************************************************/
12
13
14#ifndef _NR_I_TASK_H_
15#define _NR_I_TASK_H_
16
17//----------------------------------------------------------------------------------
18// Includes
19//----------------------------------------------------------------------------------
20#include "Prerequisities.h"
21#include "Priority.h"
22#include "IThread.h"
23
24namespace nrEngine{
25
26        /**
27        * Each task is defined through it's unique ID-number. The numbers are used
28        * to access task through the kernel.<br>
29        * There is no tasks with ID 0, because this number is reserved as for no id.
30        * \ingroup kernel
31        **/
32        typedef uint32 TaskId;
33
34
35        /**
36        * Each task can be in one of this states. It can be either stopped, running or paused (sleeping)
37        * \ingroup kernel
38        **/
39        typedef enum {
40                //! Task is currently stopped. So it was either started nor paused
41                TASK_STOPPED = 0,
42
43                //! Task is currently running, so updates of the task are done
44                TASK_RUNNING = 1,
45
46                //! Task is sleeping. No updates but waiting on resume signal.
47                TASK_PAUSED = 2,
48
49        } TaskState;
50
51        /**
52         * Task can have on of the property defined.
53         * \ingroup kernel
54         **/
55        typedef enum {
56
57                //! Nothing specialy
58                TASK_NONE       = 0,
59               
60                //! Does this task run in parallel, so it is a thread
61                TASK_IS_THREAD = 1 << 1,
62
63                //! Should this task be executed only once or it is repeating
64                TASK_RUN_ONCE = 1 << 2
65                               
66        } TaskProperty;
67
68        /**
69         *Engine does support two types of task: system task and user tasks. System tasks
70         * are task essential for engine working. They can not be handled by the user
71         * application. User tasks are task handled by the application itself.
72         * \ingroup kernel
73        **/
74        typedef enum {
75                //! Root tasks could not be stopped by user, only engine can do this
76                TASK_SYSTEM,
77
78                //! User tasks are task defined by the user
79                TASK_USER
80
81        } TaskType;
82
83
84        /**
85        * Each task is in the kernel in specified order. This enum describes all order/queue
86        * positions of any task in the kernel system
87        * \ingroup kernel
88        **/
89        typedef enum {
90                //! This number defines the a gap between two adjacent order numbers
91                ORDER_STEP                      = 32768,
92
93                /**
94                * This is a order position reserved for system tasks, that should realy run as first.
95                * You can not add any user task on this order position.
96                **/
97                ORDER_SYS_ROOT          = 0,
98
99                //! First task
100                ORDER_SYS_FIRST         = 1 * ORDER_STEP,
101
102                //! Next after first
103                ORDER_SYS_SECOND        = 2 * ORDER_STEP,
104
105                //! Next after first
106                ORDER_SYS_THIRD         = 3 * ORDER_STEP,
107
108                //! Next after first
109                ORDER_SYS_FOURTH        = 4 * ORDER_STEP,
110
111                //! Next after first
112                ORDER_SYS_FIVETH        = 5 * ORDER_STEP,
113
114                //! Greatest order border for system task (only ordering)
115                ORDER_SYS_LAST          = 6 * ORDER_STEP,
116
117                //! Task will be updated as first
118                ORDER_FIRST                     = 7 * ORDER_STEP,
119
120                //! Next after the first
121                ORDER_ULTRA_HIGH        = 8 * ORDER_STEP,
122
123                //! Next smaller order number to the ultra high value
124                ORDER_VERY_HIGH         = 9 * ORDER_STEP,
125
126                //! Next after very high
127                ORDER_HIGH                      = 10 * ORDER_STEP,
128
129                //! Default order number (Center point)
130                ORDER_NORMAL            = 11 * ORDER_STEP,
131
132                //! Later update as of the normal position
133                ORDER_LOW                       = 12 * ORDER_STEP,
134
135                //! Updating next after low
136                ORDER_VERY_LOW          = 13 * ORDER_STEP,
137
138                //! Ultra low order by comparison to the normal value
139                ORDER_ULTRA_LOW         = 14 * ORDER_STEP,
140
141                //! Task having this order will be updated as last
142                ORDER_LAST                      = 15 * ORDER_STEP
143
144        } TaskOrder;
145
146        //! Each component of the engine/application does run as tasks in the Kernel
147        /**
148        * \par
149        *       ITask - is an interface for tasks of our kernel system. Kernel runs all
150        *       specified and added task in their queue order (think on OS). So ITask
151        *       Interface defines functions to be implemented by each task.
152        *
153        * \par
154        *       There is a rule to understanding order numbers:
155        *               - Each order-number is a number
156        *               - Bigger number - task will be executed later
157        *               - Between each defined default order-numbers there is ORDER_STEP numbers available
158        *               - There is no guarantee that two or more tasks with same order would be
159        *                       executed in next cycle in same order
160        *               - you can increase/decrease the order by substracting/adding of any number to any
161        *                       predefined order state
162        *               - Task names must be unique
163        *
164        * \par
165        *       Sometimes tasks depends on each other. So for example on task should be
166        *       executed before another one. One way to solve this problem is to set the
167        *       order number of each task manually. Other way is to use the dependencies
168        *       infrastructure provided by task interface. You can setup task through it's
169        *       ids to define tasks on which this one depends. Kernel will try to solve all
170        *       dependencies and will bring all dependeable tasks in the right order according
171        *       to their order numbers. If there is circular dependencies, so both tasks will not
172        *       be added to the kernel's task list and an error code according to that problem will
173        *       be given back.<br>
174        *               - if task A depends on task B, so task A will be updated after the task B.
175        *               - if task A depends on task B and order number of task A is greater than B,
176        *                       so B will be updated before A, but the ordering number will not be changed.
177        *
178        * \par
179        *       Each task should support error handling routines. Tasks are running in the try-catch
180        *       block. If kernel will catch any error by updating the task, the \a ITask::taskHandleError()
181        *       function will be called. You have either to handle the error there or to pass the
182        *       error back. Kernel will then send up the error along the function stack.<br>
183        *       If the task couldn't handle the error it will be stopped and will be removed from
184        *       the kernel task list. So each task object should be able to release all used memory
185        *       also if there was an error before in the task update function.<br>
186        *       This infrastructure allows us to catch up and to handle errors produced by the tasks.
187        *       We can also remove tasks which couldn't handle their own errors. If you implement
188        *       the task in the right way, then we can guarantee that no tasks would crash the kernel.
189        *
190        * \ingroup kernel
191        **/
192        class _NRExport ITask : public IThread{
193        public:
194
195                /**
196                * Virtual destructor to allow to derive new classes from this one
197                **/
198                virtual ~ITask();
199
200                /**
201                * One task is smaller than another one if it's order number is smaller
202                **/
203                bool operator <  (const ITask &t);
204
205                /**
206                 * Two tasks are the same if their order number are equal or they are the same objects
207                 **/
208                bool operator == (const ITask &t);
209
210                bool operator <= (const ITask &t);
211                bool operator >  (const ITask &t);
212                bool operator >= (const ITask &t);
213                bool operator != (const ITask &t);
214
215
216                /**
217                * In each cycle of our game loop this method will be called if task was added to our kernel.
218                **/
219                virtual Result updateTask() = 0;
220
221                /**
222                 * Stop the task before task will be killed. Each derived object should
223                 * release used memory here or in the destructor.
224                **/
225                virtual Result stopTask() { return OK; }
226
227                /**
228                 * This method will be called by the kernel as soon as the task is prepared
229                 * to run. So it will be started and in the next cycle it will be updated.
230                 **/
231                virtual Result onStartTask() { return OK; }
232               
233                /**
234                 * This method will be called by kernel when the kernel will try to add
235                 * this task into the kernel's pipeline. If this method return other value
236                 * then OK, so the task will not be added into pipeline.
237                 **/
238                virtual Result onAddTask() { return OK; }
239
240                /**
241                * Will be executed on waiking up the task from sleeping.
242                **/
243                virtual Result onResumeTask() { return OK; }
244
245                /**
246                * Kernel will call this method if task will be aked to go for sleeping.
247                **/
248                virtual Result onSuspendTask() { return OK; }
249
250                /**
251                * Task should return his name. Name must not be unique. We will need this to read
252                * Log-Files in simple way.
253                **/
254                const char* getTaskName(){ return _taskName; }
255
256                /**
257                * Get order number of this task
258                **/
259                NR_FORCEINLINE TaskOrder getTaskOrder() const { return _taskOrder; }
260
261                /**
262                * Get id number of the task
263                **/
264                NR_FORCEINLINE TaskId getTaskID() const { return _taskID; }
265
266                /**
267                * Get the type of the task.
268                **/
269                NR_FORCEINLINE TaskType getTaskType() const { return _taskType; }
270
271                /**
272                * Get the state in which the task is
273                **/
274                NR_FORCEINLINE TaskState getTaskState() const { return _taskState; }
275
276                /**
277                 * Get task property
278                 **/
279                NR_FORCEINLINE TaskProperty getTaskProperty() const { return _taskProperty; }
280               
281                #if 0
282                /**
283                * Add a new task id of a task on which one this task depends.
284                *
285                * @param id Unique ID of a task on which one this depends
286                * @return either OK or:
287                *               -
288                **/
289                Result addTaskDependency(TaskId id);
290
291                /**
292                * Overloaded function that allows to add a dependency from the task itself
293                **/
294                Result addTaskDependency(const ITask& task);
295
296                /**
297                * Overloded function that allows to add a dependency from the pointer on a task
298                **/
299                Result addTaskDependency(const ITask* pTask);
300                #endif
301               
302                /**
303                * Add a new task on which one this task depends.
304                *
305                * @param task Smart poitner to the task
306                * @return either OK or:
307                **/
308                Result addTaskDependency(SharedPtr<ITask> task);
309       
310        protected:
311
312                //! Setup the name of the task
313                void setTaskName(const ::std::string& name);
314
315                /**
316                 * Define default variables. Set also default task order to ORDER_NORMAL
317                 * and define the current state of the task to TASK_STOPPED.
318                 **/
319                ITask();
320
321                /**
322                 * You are allowed to specify the task name as a parameter for the task.
323                 * Because no one can create directly the ITask instance, so only derived
324                 * classes can setup their names.
325                 **/
326                ITask(const ::std::string& name);
327
328        private:
329
330                //! Kernel should have the full access to the task data. So kernel is our friend
331                friend class Kernel;
332
333                //! Engine should also get full access to running tasks, to allow setting up system tasks
334                friend class Engine;
335
336                bool            _taskCanKill;           // we can kill this task in next system cycle
337                TaskState       _taskState;
338                TaskId          _taskID;                        // from kernel given task ID (unique)
339                TaskOrder       _taskOrder;                     // order number of our tasks
340                TaskType        _taskType;                      // type of the task
341                TaskProperty _taskProperty;             // task property
342                //uint32                _updateCounter;         // how often was this task updated
343               
344                bool            _orderChanged;
345                char            _taskName[64];
346
347                //! Used by the kernel
348                int32   _taskGraphColor;
349
350                //! This list does store all tasks on which one this depends
351                std::list< SharedPtr<ITask> >   _taskDependencies;
352
353                //! Set the task type. This method is private, so only friends can set the type
354                void setTaskType(TaskType type);
355
356                //! Only friends are allowed to set the id of the task
357                void setTaskID(TaskId id);
358
359                //! Friends are also allowed to set the task state
360                void setTaskState(TaskState state);
361
362                //! Set new order number for this task
363                void setTaskOrder(TaskOrder order);
364
365                //! Set property of the task
366                void setTaskProperty(TaskProperty property);
367
368                void init();
369                void _noticeSuspend();
370                void _noticeResume();
371                void _noticeUpdate();
372                void _noticeStop();
373
374        };
375
376        //! Empty task does not affect anything. It can helps to group tasks by making htem depends on this task
377        /**
378        * This class representing a simple task which does not do anything.
379        * This is an empty task wich can be used as placeholder or root task containing
380        * only children (task on which one it depends).<br>
381        * This technique can help us to combine tasks in groups by using of this
382        * empty tasks.
383        * \ingroup kernel
384        **/
385        class _NRExport EmptyTask : public ITask{
386        public:
387                EmptyTask() : ITask() {}
388                virtual ~EmptyTask() {}
389
390                //! Do nothing just return OK
391                virtual Result updateTask() { return OK; }
392
393        };
394
395}; // end namespace
396#endif  //_NR...
Note: See TracBrowser for help on using the repository browser.