418 lines
15 KiB
C
418 lines
15 KiB
C
/*---------------------------------------------------------------------------
|
|
T A S K
|
|
|
|
This is a portable task switching module. Tasks are maintained in a
|
|
circular list and switched in between. Waiting for some task to end,
|
|
a yield and a primitive form of inter task communication is implemented.
|
|
|
|
Mark Koennecke, September 1997
|
|
|
|
extended to support task groups
|
|
Mark Koennecke, December 2012
|
|
|
|
copyright: see implementation file
|
|
-----------------------------------------------------------------------------*/
|
|
#ifndef TASKOMAT
|
|
#define TASKOMAT
|
|
|
|
typedef long TaskTaskID;
|
|
typedef long TaskGroupID;
|
|
extern TaskTaskID TaskUnknownTaskID, TaskBadTaskID;
|
|
extern TaskGroupID TaskUnknownGroupID, TaskBadGroupID;
|
|
/*---------------------------------------------------------------------------*/
|
|
typedef enum eTaskLogLevel {
|
|
eTaskLogNone = 0,
|
|
eTaskLogDebug = 1,
|
|
eTaskLogInfo = 2,
|
|
eTaskLogWarning = 3,
|
|
eTaskLogError = 4,
|
|
eTaskLogFatal = 5
|
|
} eTaskLogLevel;
|
|
typedef void (*TaskLogFunc) (eTaskLogLevel, const char *buf);
|
|
/*
|
|
A TaskLogFunc can be registered for logging activity within the task module.
|
|
*/
|
|
/*
|
|
* Use these values for the Task Priority
|
|
*/
|
|
#define TASK_PRIO_LOW 10
|
|
#define TASK_PRIO_MED 30
|
|
#define TASK_PRIO_HIGH 50
|
|
/*--------------------------------------------------------------------------*/
|
|
typedef struct __TaskHead *pTaskHead;
|
|
typedef struct __TaskMan *pTaskMan;
|
|
typedef struct __TaskQueue *pTaskQueue;
|
|
typedef struct __TaskMessage *pTaskMessage;
|
|
/*
|
|
two data structure used internally and defined in task.c
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
typedef int (*TaskFunc) (void *pData);
|
|
|
|
/*
|
|
a task function must be implemented by each task. This function will be
|
|
called when it is the tasks turn to execute. This function obtains a
|
|
pointer to a user defined data structure as parameter. If the task is going
|
|
to end, it has to return 0. It's data structure will be removed by a
|
|
KillFunction of the type defined below. If the task is
|
|
going to run again in its next turn the task function has to return a
|
|
1.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
typedef int (*TaskMsgFunc) (void *pData, pTaskMessage pMsg);
|
|
|
|
/*
|
|
* Like the TaskFunc but with a message extracted from the task queue
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
typedef void (*TaskKillFunc) (void *pData);
|
|
/*
|
|
Each task using private data structures must define this functions. It's
|
|
task is to clear the private data structure of the task and free all memory
|
|
associated with it. This function will be called automatically by the
|
|
Tasker when a task finishes or when the whole Tasker is shut down.
|
|
*/
|
|
/*---------------------------------------------------------------------------*/
|
|
typedef void (*SignalFunc) (void *pUser, int iSignal, void *pSigData);
|
|
|
|
/*
|
|
A SignalFunction can be implemented by each task. It is the means of
|
|
inter task communication. The first parameter is a pointer to the
|
|
tasks private datastructure. Further parameters are an integer signal ID
|
|
and a pointer to a datastructure for this signal. The meaning of signal
|
|
ID's and signal data structures is up to the client of this code.
|
|
*/
|
|
/*===========================================================================
|
|
ALL FUNTIONS RETURN 0 on FAILURE, 1 ON SUCCESS WHEN NOT MENTIONED
|
|
OTHERWISE
|
|
============================================================================*/
|
|
int TaskerInit(pTaskMan * self);
|
|
/*
|
|
Initalises a Task Manager.
|
|
*/
|
|
int TaskerDelete(pTaskMan * self);
|
|
/*
|
|
Stops all running tasks and clears all data structures associated with
|
|
tasks and the TaskManager.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
TaskTaskID TaskRegister(pTaskMan self, TaskFunc pTaskRun,
|
|
SignalFunc pSignalFunc,
|
|
TaskKillFunc pKillFunc, void *pData, int iPriority);
|
|
/*
|
|
This call enter a new task into the system. The caller has to
|
|
specify:
|
|
a TaskFunction [Required]
|
|
a SignalFunction [Optional, can be NULL]
|
|
a KillFunction for task private data.
|
|
[Optional, can be NULL]
|
|
a pointer to task private data
|
|
[Optional, can be NULL]
|
|
a priority for this task. This is currently unused.
|
|
On Success a positive value denoting the ID of the task is returned.
|
|
On error a negative value is returned.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
TaskTaskID TaskRegisterN(pTaskMan self, char *name, TaskFunc pTaskRun,
|
|
SignalFunc pSignalFunc, TaskKillFunc pKillFunc,
|
|
void *pData, int iPriority);
|
|
/*
|
|
This call enter a new task into the system. The caller has to
|
|
specify:
|
|
a TaskFunction [Required]
|
|
a SignalFunction [Optional, can be NULL]
|
|
a KillFunction for task private data.
|
|
[Optional, can be NULL]
|
|
a pointer to task private data
|
|
[Optional, can be NULL]
|
|
a priority for this task. This is currently unused.
|
|
On Success a positive value denoting the ID of the task is returned.
|
|
On error a negative value is returned.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
TaskTaskID TaskRegisterD(pTaskMan self, char *name, TaskFunc pTaskRun,
|
|
SignalFunc pSignalFunc, TaskKillFunc pKillFunc,
|
|
void *pData, int iPriority, double delay);
|
|
/*
|
|
This call enters a new task into the system.
|
|
The task will start running after the given delay in seconds.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
TaskTaskID TaskRegisterP(pTaskMan self, char *name, TaskFunc pTaskRun,
|
|
SignalFunc pSignalFunc, TaskKillFunc pKillFunc,
|
|
void *pData, int iPriority, double delay, double period);
|
|
/*
|
|
This call enters a new task into the system.
|
|
The task will run after delay seconds and then every period seconds.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
TaskTaskID TaskRegisterQ(pTaskMan self, char *name, TaskMsgFunc pTaskRun,
|
|
SignalFunc pSignalFunc, TaskKillFunc pKillFunc,
|
|
void *pData, int iPriority);
|
|
/*
|
|
This call enters a new task with queue into the system.
|
|
As for TaskRegisterN except the task function signature has
|
|
a message pointer.
|
|
*/
|
|
/*-------------------------------------------------------------------------*/
|
|
int TaskSchedule(pTaskMan self);
|
|
/*
|
|
Starts task switching.
|
|
*/
|
|
/*-----------------------------------------------------------------------*/
|
|
int TaskStop(pTaskMan self);
|
|
/*
|
|
Interrupts task switching all together
|
|
*/
|
|
/*------------------------------------------------------------------------*/
|
|
int TaskContinue(pTaskMan self);
|
|
/*
|
|
Continues an task switching session interrupted by TaskStop. After this
|
|
the apopriate TaskYield, TaskSchedule or wahtever has to be called.
|
|
*/
|
|
/*-------------------------------------------------------------------------*/
|
|
int TaskWait(pTaskMan self, TaskTaskID taskID);
|
|
/*
|
|
Waits until the task specified by taskID has finished. taskID is obtained
|
|
from a call to TaskRegister.
|
|
*/
|
|
/*-------------------------------------------------------------------------*/
|
|
int TaskYield(pTaskMan self);
|
|
/*
|
|
does one cycle of the task loop and returns to the caller.This call allows
|
|
other tasks to execute while a task executes a lengthy calculation.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskSignal(pTaskMan self, int iSignal, void *pSigData);
|
|
/*
|
|
Invokes each Task's signal function with parameters iSignal and
|
|
pSigData.
|
|
*/
|
|
/*-------------------------------------------------------------------------*/
|
|
void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData);
|
|
/*
|
|
remove the task with the given task function and the given data pointer
|
|
*/
|
|
/*-------------------------------------------------------------------------*/
|
|
int StopTask(pTaskMan self, char *name);
|
|
/*
|
|
stop the task with the given name. Returns 0 on failure, 1 on success
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int isTaskRunning(pTaskMan self, char *name);
|
|
/*
|
|
returns 1 when task name is running, 0 else
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int isTaskIDRunning(pTaskMan self, TaskTaskID taskID);
|
|
/*
|
|
returns 1 when task name is running, 0 else
|
|
*/
|
|
/*===========================================================================
|
|
Iterating the task list. This works like:
|
|
|
|
pTaskHead it;
|
|
char *des;
|
|
|
|
for(it = TaskIteratorStart(self); it != NULL; it = TaskIteratorNext(it)){
|
|
des = TaskDescription(it);
|
|
}
|
|
|
|
There are two limitations of the implementation here:
|
|
|
|
- Never, ever delete the Iterator it
|
|
- Do your iteration in one go or abandon it mid iteration. If another task
|
|
gets in between and registers new tasks or removes one, then the whole
|
|
iterator may be messed up.
|
|
=============================================================================*/
|
|
|
|
pTaskHead TaskIteratorStart(pTaskMan self);
|
|
/*
|
|
starts iterating on the TaskList. Do NOT delete the returned pointer!
|
|
*/
|
|
pTaskHead TaskIteratorNext(pTaskHead it);
|
|
/*
|
|
Steps to the next element in the task list. Returns NULL when node.
|
|
Do NOT delete the returned pointer!
|
|
*/
|
|
pTaskHead TaskIteratorCurrent(pTaskMan self);
|
|
pTaskHead TaskIteratorByName(pTaskMan self, const char* name);
|
|
pTaskHead TaskIteratorByID(pTaskMan self, TaskTaskID taskID);
|
|
/*
|
|
Gets the task iterator for either the current, named or numbered task
|
|
Do NOT delete the returned pointer!
|
|
*/
|
|
|
|
char *TaskDescription(pTaskHead it);
|
|
/*
|
|
get a description of the task at the current iterator
|
|
You are responsible for deleting the returned character array.
|
|
*/
|
|
|
|
char *TaskDetail(pTaskHead it);
|
|
/*
|
|
get a detailed description of the task at the current iterator
|
|
You are responsible for deleting the returned character array.
|
|
*/
|
|
TaskTaskID GetTaskID(pTaskHead it);
|
|
/*
|
|
get the ID of the current task
|
|
*/
|
|
TaskGroupID GetGroupID(pTaskHead it);
|
|
/*
|
|
get the group ID of the current task
|
|
*/
|
|
const char *GetTaskName(pTaskHead it);
|
|
/*
|
|
get the name of the current task. Do not delete the returned pointer.
|
|
*/
|
|
const void *GetTaskData(pTaskHead it);
|
|
/*
|
|
Get the user data for the current task. Do not free the returned pointer!
|
|
*/
|
|
/*=============================================================================
|
|
Task Groups. The implementation has the limit that any given task can
|
|
only be member of one task group
|
|
===============================================================================*/
|
|
TaskGroupID GetTaskGroupID(pTaskMan self);
|
|
/*
|
|
get the ID for a task group
|
|
*/
|
|
void AddTaskToGroup(pTaskMan self, TaskTaskID taskID, TaskGroupID groupID);
|
|
/*
|
|
Add taskID to the task group groupID
|
|
*/
|
|
int isTaskGroupRunning(pTaskMan self, TaskGroupID groupID);
|
|
/*
|
|
Returns 1 when the task group is still running, 0 else
|
|
*/
|
|
|
|
int TaskGroupTask(void *data);
|
|
/*
|
|
This is a task function which implements the common task of waiting
|
|
for a group of tasks to finish. It expects as data a TaskGroupData
|
|
structure.
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, TaskGroupID groupID);
|
|
/*
|
|
signal only tasks in the group groupID
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
void TaskSetLogFunc(TaskLogFunc);
|
|
TaskLogFunc TaskGetLogFunc(void);
|
|
eTaskLogLevel TaskSetLogLevel(eTaskLogLevel thresh);
|
|
eTaskLogLevel TaskGetLogLevel(void);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskGetStack(pTaskMan self, pTaskHead it[]);
|
|
/*
|
|
* Returns the current stack depth of tasks and, if provided, fills the array
|
|
* of iterators. The iterators start at it[0] and can be used to get
|
|
* information about each task.
|
|
*/
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
void TaskRunMeAfter(pTaskMan self, double delay);
|
|
/*
|
|
* Run this task once in <delay> seconds
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
void TaskRunMeEvery(pTaskMan self, double delay);
|
|
/*
|
|
* Run this task every <delay> seconds from now on
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
double TaskRunMyPeriod(pTaskMan self);
|
|
/*
|
|
* Return this task run period in seconds
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
pTaskQueue TaskQueueAlloc(void);
|
|
/*
|
|
* Task Queue constructor
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskQueueFree(pTaskQueue);
|
|
/*
|
|
* Task Queue destructor
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskQueueCount(pTaskQueue);
|
|
/*
|
|
* Returns the message count on the Task Queue
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskQueueSend(pTaskQueue, pTaskMessage);
|
|
/*
|
|
* Pushes a Task Message onto the tail of the Task Queue
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskQueueSendID(pTaskMan self, TaskTaskID taskID, pTaskMessage);
|
|
/*
|
|
* Pushes a Task Message onto the tail of the Task Queue
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
pTaskMessage TaskQueueRecv(pTaskQueue);
|
|
/*
|
|
* Pops a Task Message off the head of the given Task Queue
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
pTaskMessage TaskQueueRecvMine(pTaskMan self);
|
|
/*
|
|
* Pops a Task Message off the head of the owner's Task Queue
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskQueueSet(pTaskMan self, TaskTaskID taskID, pTaskQueue);
|
|
/*
|
|
* Sets the Task Queue of the task
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskQueueRem(pTaskMan self, TaskTaskID taskID);
|
|
/*
|
|
* Clears the Task Queue of the task
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
pTaskQueue TaskQueueGet(pTaskMan self, TaskTaskID taskID);
|
|
/*
|
|
* Gets the Task Queue of the specified task
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
pTaskQueue TaskQueueGetMine(pTaskMan self);
|
|
/*
|
|
* Gets the Task Queue of the current task
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
pTaskMessage TaskMessageAlloc(size_t mSize, int mType);
|
|
/*
|
|
* Constructor for a Task Message of the requested size and type
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskMessageFree(pTaskMessage);
|
|
/*
|
|
* Destructor for the Task Message
|
|
* returne 0=success, -1=fail
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
int TaskMessageGetType(pTaskMessage self);
|
|
/*
|
|
* Get the type of the Task Message
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
void TaskMessageSetType(pTaskMessage self, int mType);
|
|
/*
|
|
* Set the type of the Task Message
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
void * TaskMessageGetData(pTaskMessage self);
|
|
/*
|
|
* Get the data pointer from the message
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
void TaskMessageSetData(pTaskMessage self, void *mData);
|
|
/*
|
|
* Set the data pointer in the message
|
|
*/
|
|
/*--------------------------------------------------------------------------*/
|
|
#endif
|