source: nrEngine/include/ITask.h @ 35

Revision 35, 12.1 KB checked in by art, 13 years ago (diff)

Big changes in resource managment system. Interface functions were renamed.
Resource loading is now done throughthe resource and not through the loader.

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.c_str(); }
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                std::string     _taskName;
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.