Kernel.h

00001 /***************************************************************************
00002  *                                                                         *
00003  *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
00004  *       mailto: <tevs@mpi-sb.mpg.de>                                      *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  ***************************************************************************/
00012 
00013 /*!
00014  * \defgroup kernel Kernel (Heart) of the nrEngine
00015  *
00016  * As you know each operating system has got a kernel. This kernel run tasks
00017  * (user programms) to allow to do a lot of things. So our engine is nothing
00018  * else as a little operating system. Here we implement kernel of the engine.
00019  * This kernel runs tasks in there priority order, so you can run for example
00020  * display task as last task and input as first. Kernel has also support to freeze
00021  * tasks (suspend) and resume them from sleeping. To run application written
00022  * for nrEngine it is better if you use this system. Actually kernel is nothing else
00023  * than the old style game loop. Kernel runs tasks in a one big loop until there
00024  * is no more tasks.
00025  *
00026  */
00027 
00028 #ifndef _NR_C_KERNEL_H_
00029 #define _NR_C_KERNEL_H_
00030 
00031 
00032 //----------------------------------------------------------------------------------
00033 // Includes
00034 //----------------------------------------------------------------------------------
00035 #include "Prerequisities.h"
00036 #include "ITask.h"
00037 
00038 
00039 namespace nrEngine {
00040 
00041         //! Heart of our engine system, where tasks are running
00042         /**
00043         * \par
00044         * Kernel - is the heart of our engine. Kernel is something like the oldschool
00045         * Game Loop. You can add, remove, suspend or resume tasks from kernel's pipeline
00046         * Tasks would be executed in their order - smaller order number comes before
00047         * greater order number.
00048         *
00049         * \par
00050         * What should tasks supports:
00051         *       - They should implement the \a ITask Interface
00052         *       - They should be loaded and be ready to start before adding to kernels pipeline
00053         *       - In each game cycle \a ITask::updateTask() Method will be executed
00054         *       - By suspending or resuming the Tasks \a ITask::onSuspendTask()/onResumeTask() Method will be executed
00055         *       - Before task will be removed \a ITask::stopTask() Method will executed
00056         *       - Each taskID is unique and is greater than 0
00057         *       - There is no TaskId wich will be given twice
00058         *
00059         * \par
00060         *       Tasks can depends on each other, so one task should be updated before another one.
00061         *       This can be defined through task dependencies functions. Sometimes you also
00062         *       need to execute a task more than once per one kernel tick. This also can be
00063         *       specified by executing of appropriate functions.<br>
00064         *       Sleeping tasks will not be sorted in into the kernel's pipeline if any task
00065         *       will be added, that depends on such one. If the task will be resumed than the sorting
00066         *       will be done. So be warned that it is possible to retrieve a circularity
00067         *       error code during the waking up.
00068         *
00069         * \par
00070         *       In our Engine their exisists system and user tasks. System tasks are not accessable through the
00071         *       user, because they are essential for engine's work. So to allow the engine to use
00072         *       same functions for task access, we define a boolean lock variable. If this variable
00073         *       is true, so all accesses to the kernel are done through the engine. The kernel
00074         *       can give then all tasks engine ask about. Locking of the kernel can only be done
00075         *       through the engine, so the user is not able to do the locking.<br>
00076         *       Better way to implement this is to have other programming language that allows
00077         *       "sandboxes" or similar techniques to distinguish between engine's own and user calls.
00078         *
00079         * \note: Try to optimise this kernel by implementing O(1) Scheduler or something
00080         *                else if kernel loop/pipeline need a lot of time for updating.
00081         *                Better if you implement supporting of multithreaded Kernel, so we can
00082         *                support Multiple-CPU-System to increase game speed
00083         * \ingroup kernel
00084         **/
00085         class _NRExport Kernel{
00086         public:
00087 
00088                 /**
00089                  * Define if a kernel should send special task events on the
00090                  * engines default channel. Task events are used to inform the application
00091                  * and the engine, that state of certain tasks is changed.
00092                  *
00093                  * Actually the engine does not need this events, cause engine's modules
00094                  * does not depend on each other, so they do not need this information.
00095                  * However your application could require this messages to react to
00096                  * certain conditions, i.e. clock task is sleeping
00097                  *
00098                  * @param bSend if true the events would be sent, if false so kernel is silent
00099                  **/
00100                 void sendEvents(bool bSend = true) { bSendEvents = bSend; }
00101 
00102                 /**
00103                  * If true, so the kernel is currently inform teh application about
00104                  * task state changes by sending messages over the engine's default communication
00105                  * channel.
00106                  **/
00107                 bool isSendingEvents() const { return bSendEvents; }
00108 
00109                 /**
00110                  * Executes the kernel (old school main loop :-)
00111                  * Before main loop is started all tasks will be intialized by calling task
00112                  * function \a ITask::taskStart() . If taskStart returns error, so this task will be
00113                  * excluded from execution task list.
00114                  * \return OK or error code:
00115                  *              - ERROR_UNKNOWN for unknown error
00116                  *
00117                  * \par
00118                  *              If you get an error code back, so you can probably found more useful information
00119                  *              in a log file filled out by the engine's kernel.
00120                  **/
00121                 Result Execute();
00122 
00123                 /**
00124                  * Executes all task according to their order. After that
00125                  * return back. If you call this function for the first time,
00126                  * so the task will start before updating.
00127                  * \see ITask manual to understand how tasks works
00128                  **/
00129                 Result OneTick();
00130 
00131 
00132                 /**
00133                  * Add the given task into our kernel pipeline (main loop)
00134                  * Before task will be added it's \a ITask::taskInit()) function will be executed
00135                  * The returned task id number can be used to access to the task through kernel.
00136                  *
00137                  *
00138                  * \param task - is a smart pointer to an object implementing ITask-Interface
00139                  * \param order Order number for this task (default is ORDER_NORMAL)
00140                  * \param property Specifiy the special property of the task
00141                  * \return task id of added task or 0 if task could not be added
00142                  * 
00143                  **/
00144                 TaskId AddTask (SharedPtr<ITask> task, TaskOrder order = ORDER_NORMAL, TaskProperty property = TASK_NONE);
00145 
00146                 /**
00147                  * Remove the task from our game loop (pipeline).
00148                  *
00149                  * \param id - id of a task to be removed
00150                  * \return OK or error code:
00151                  *              - ERROR_UNKNOWN for unknown error
00152                  *              - KERNEL_NO_TASK_FOUND if no such task was found
00153                  *              - KERNEL_NO_RIGHTS if you try to remove a system task
00154                  **/
00155                 Result RemoveTask       (TaskId id);
00156 
00157 
00158                 /**
00159                 * This method will start a task with given id. If task could be started,
00160                 * so it will be updated in next cycles. Otherwise task state will be set
00161                 * to stopped. If the task is already running it will be not started again.
00162                 * If task is paused, so it will be resumed through \a ResumeTask() method.
00163                 *
00164                 * @param id Unique id of the task to be started
00165                 * @return either OK or:
00166                 *               - UNKNOWN_ERROR
00167                 *               - KERNEL_NO_TASK_FOUND
00168                 *               - KERNEL_NO_RIGHTS if you try to remove a system task
00169                 **/
00170                 //Result StartTask      (TaskId id);
00171 
00172 
00173                 /**
00174                  * Suspend task to prevent it from update. Task will get to sleep.
00175                  *
00176                  * \param id - id of a task to be suspended
00177                  * \return OK or error code:
00178                  *              - ERROR_UNKNOWN for unknown error
00179                  *              - KERNEL_NO_TASK_FOUND if such a task was not found
00180                  *              - KERNEL_NO_RIGHTS if you try to remove a system task
00181                  **/
00182                 Result SuspendTask (TaskId id);
00183 
00184                 /**
00185                  * Resume task from sleeping.
00186                  *
00187                  * \param id - id of a task to waik
00188                  * \return OK or error code:
00189                  *              - ERROR_UNKNOWN for unknown error
00190                  *              - KERNEL_NO_TASK_FOUND if such a task was not found
00191                  *              - KERNEL_NO_RIGHTS if you try to remove a system task
00192                  **/
00193                 Result ResumeTask  (TaskId id);
00194 
00195 
00196                 /**
00197                  * Remove and kill all tasks from the kernel's task list. If no tasks are in the
00198                  * list, so the kernel will stop executing.
00199                  *
00200                  * \return OK or error code:
00201                  *              - ERROR_UNKNOWN for unknown error
00202                  **/
00203                 Result StopExecution();
00204 
00205 
00206                 /**
00207                  * Changes the order number of task with given id
00208                  * \param id  id of a task
00209                  * \param order  New order number for the task
00210                  * \return OK or error code:
00211                  *              - ERROR_UNKNOWN for unknown error
00212                  *              - KERNEL_NO_TASK_FOUND if such a task was not found
00213                  *              - KERNEL_NO_RIGHTS if you try to remove a system task
00214                  **/
00215                 Result ChangeTaskOrder(TaskId id, TaskOrder order = ORDER_NORMAL);
00216 
00217 
00218                 /**
00219                  * Returns smart pointer to a task with the given id.
00220                  *
00221                  * \param id ID of the task
00222                  * \return smart pointer to the task or NULL if no such task found or task is system task
00223                  **/
00224                 SharedPtr<ITask> getTaskByID(TaskId id);
00225 
00226                 /**
00227                  * Get the task wich has the same name as the given one.
00228                  *
00229                  * \param name Unique name of the task
00230                  * \return smart poitner to the task or to the NULL if no such task found or task is system task
00231                 **/
00232                 SharedPtr<ITask> getTaskByName(const std::string& name);
00233 
00234         protected:
00235 
00236                 //! Here kernel does store all currently running tasks
00237                 std::list< SharedPtr<ITask> > taskList;
00238 
00239                 //! Here kernel store all tasks that are sleeping now.
00240                 std::list< SharedPtr<ITask> > pausedTaskList;
00241 
00242                 //! Get information about lock state of the kernel
00243                 bool areSystemTasksAccessable() { return _bSystemTasksAccessable; }
00244 
00245         private:
00246                 
00247                 /**
00248                  * Define the kernel's list names containing tasks.
00249                  **/
00250                 enum {
00251                         //! Task that are currently running are stored here
00252                         TL_RUNNING = 1 << 1,
00253 
00254                         //! Tasks that are sleeping are stored in this list
00255                         TL_SLEEPING = 1 << 2
00256 
00257                 };
00258 
00259                 //! Engine is allowed to create instances of that object
00260                 friend class Engine;
00261 
00262                 /**
00263                  * Clear all lists and initialize internal variables.
00264                  **/
00265                 Kernel();
00266 
00267                 /**
00268                  * Release all used memory and remove all tasks from the kernel. Each task is
00269                  * added to the kernel's taks list through shared pointers, so by removing
00270                  * tasks of the kernel's list the pointer reference number will be decreased.
00271                  *
00272                  * The destructor is defined as virtual, so you can create your own kernel class
00273                  * if you have to.
00274                  */
00275                 ~Kernel();
00276 
00277 
00278                 typedef std::list< SharedPtr<ITask> >::iterator PipelineIterator;
00279 
00280                 /**
00281                  * Find the task by task ID.
00282                  *
00283                  * \param id is the id of task
00284                  * \param it Iterator pointing to the element
00285                  * \param useList declare in which lists should be searched for the task
00286                  * \return true if such one was found
00287                  * \note This Function runs in O(N) so optimize this if you know how
00288                 **/
00289                 bool _getTaskByID(TaskId id, PipelineIterator& it, int32 useList = TL_RUNNING);
00290 
00291                 /**
00292                  * Find the task by task's name.
00293                  *
00294                  * \param name is the name of task
00295                  * \param it Iterator pointing to the element
00296                  * \param useList declare in which lists should be searched for the task
00297                  * \return true if such one was found
00298                  * \note This Function runs in O(N) so optimize this if you know how
00299                  **/
00300                 bool _getTaskByName(const std::string& name, PipelineIterator& it, int32 useList = TL_RUNNING);
00301 
00302                 /**
00303                  * Get the list containing all smart pointers of tasks that are in kernel's
00304                  * execution list.
00305                  **/
00306                 const std::list< SharedPtr<ITask> >& getTaskList(){return taskList;}
00307 
00308 
00309                 /**
00310                  * Get list of all paused tasks that are running in the kernel. Paused tasks are tasks
00311                  * which were suspended through \a SuspendTask() method.
00312                  **/
00313                 const std::list< SharedPtr<ITask> >& getPausedTaskList(){return pausedTaskList;}
00314 
00315                 /**
00316                 * Solving of dependencies is needed to bring up the task
00317                 * list in the right order. Each task that depends on another one, should be
00318                 * later in the list, as the one on which depends.
00319                 *
00320                 * \param retTasks In this vector there will be task ids stored according to the
00321                 *                               error code given back (for OK no task ids, circularity - all task ids
00322                 *                               that builds the circle, task missing - task ids which are missing, ...)
00323                 *
00324                 * \return either OK or:
00325                 *                       - KERNEL_CIRCUIT_DEPENDENCIES
00326                 *                       - KERNEL_TASK_MISSING
00327                 *                       - BAD_PARAMETERS if the given pointer is null or the vector does contain data
00328                 **/
00329                 //Result _solveDependencies(std::vector<taskID>* retTasks);
00330 
00331                 /**
00332                 * This method will start a one cycle in the kernel loop. So it will prepare
00333                 * the variables needed by the next task function, which will return next task
00334                 * in the kernel's task pipeline
00335                 * \return error code if any occurs
00336                 **/
00337                 Result _loopStartCycle();
00338 
00339                 /**
00340                 * This method will give us the next task in the kernel's pipeline which should be updated.
00341                 * This function also solve the dependencies of the tasks by the depth first search
00342                 * algorithm. So you will get an iterator from the kernel'S task list containing the
00343                 * task to be updated as next. If iterator is equal to the end, so there is no more
00344                 * tasks in the kernel's list
00345                 * \return error code if any occurs (i.e. circularity or task missing)
00346                 **/
00347                 Result _loopGetNextTask(PipelineIterator it, PipelineIterator& result, int depth = 0);
00348 
00349                 /**
00350                 * This method should be called after the cycle is ended. This will bring the
00351                 * variables in the right state, so works can be done again later.
00352                 **/
00353                 Result _loopEndCycle();
00354 
00355                 /**
00356                  * Prepare the kernel to run tasks. This will create a root task and add
00357                  * all necessary dependencies.
00358                  **/
00359                 void prepareRootTask();
00360 
00361 
00362                 /**
00363                  * This function will start each task and set it's state to running,
00364                  * if starting was successful otherwise the task will not run.
00365                  **/
00366                 void startTasks();
00367 
00368                 //! Lock the kernel, so kernel gices us access to system tasks
00369                 void lockSystemTasks();
00370 
00371                 //! Unlock the kernel, so it close access to the system tasks
00372                 void unlockSystemTasks();
00373 
00374                 //! Try to start a given task
00375                 Result _taskStart(SharedPtr<ITask>& task);
00376 
00377                 //! Stop the given task
00378                 Result _taskStop(SharedPtr<ITask>& task);
00379 
00380                 //! Last given task id. Is used to generate new ids for newly added tasks
00381                 TaskId lastTaskID;
00382 
00383                 //! If true, so we know that all tasks are started and a list of the tasks is sorted. Only for internal use.
00384                 bool bTaskStarted;
00385 
00386                 //! Check whenever we have already added a root task
00387                 bool bInitializedRoot;
00388 
00389                 //! Root task
00390                 SharedPtr<ITask>        mRootTask;
00391                 
00392                 //! If it is true, so the kernel is locked for engine access. All next operations until unlock, can access to system tasks
00393                 bool _bSystemTasksAccessable;
00394 
00395                 //! Used by the _loop* Methods
00396                 static PipelineIterator _loopIterator;
00397 
00398                 //! Should kernel send events if states of tasks are changed
00399                 bool bSendEvents;
00400         };
00401 
00402 }; // end Namespace
00403 
00404 #endif  //_NR...

Generated on Wed Sep 12 23:19:42 2007 for nrEngine by  doxygen 1.5.1