General Info | |
Interface: TaskManager Files: taskmanager.h Last change: 15/06/2005 Author: Luiz Henrique Shigunov |
Description
Structures |
System Functions | |
xxxx - AtomicAdd - Atomically add xxxx - AtomicDec - Atomically decrement xxxx - AtomicInc - Atomically increment xxxx - AtomicSub - Atomically subtract 0x00 - CancelWait - Cancel a task wait 0x01 - CreateTask - Create a task 0x02 - CreateThread - Create a thread 0x03 - DelTaskInfo - Remove data stored in task structure 0x04 - DelThreadInfo - Remove data stored in thread structure 0x2d - Destroyable - Set task destroyable 0x30 - DestroyableThread - Set thread destroyable 0x05 - DestroyTask - Destroy a task 0x06 - DestroyThread - Destroy a thread 0x18 - GetLastError - Get information about the last error 0x07 - GetMsCounter - Get the ms counter 0x26 - GetParentTaskHandle - Get parent task handle 0x27 - GetTaskHandleID - Get task handle 0x08 - GetTaskHandle - Get task handle 0x28 - GetTaskID - Get task ID 0x09 - GetTaskInfo - Get data stored in task structure 0x1d - GetTaskMMap - Get task's memory mapping 0x29 - GetThreadHandleID - Get thread handle 0x0a - GetThreadHandle - Get thread handle |
0x2a - GetThreadID - Get thread ID 0x0b - GetThreadInfo - Get data stored in thread structure 0x0c - GetThreadStatus - Get thread state 0x0d - LockRead - Get read access in a R/W synchronizer 0x0e - LockWrite - Get write access in a R/W synchronizer 0x0f - P - Get a semaphore 0x10 - Resume - Resume a thread 0x11 - Schedule - Switch of tasks, but don't save registers 0x2e - SetLastError - Set the last error 0x12 - SetTaskInfo - Store data in task structure 0x13 - SetThreadInfo - Store data in thread structure 0x14 - SpinLock - Get a spinlock 0x15 - SpinUnlock - Free a spinlock 0x16 - Suspend - Suspend a thread 0x17 - ToUserLevel - Go to user space 0x2f - Undestroyable - Set task undestroyable 0x19 - UnlockRW - Free a R/W synchronizer 0x1a - V - Free a semaphore 0x1b - Wait - Suspend a thread for some time 0x1e - WaitQueueAdd - Add a thread in a wait queue 0x1f - WaitQueueWakeup - Wake up all threads in a wait queue 0x1c - Yield - Switch of tasks saving registers |
User Functions | |
0x20 - UCreateThread - Create a thread 0x21 - UDestroyThread - Destroy a thread 0x31 - UGetLastError - Get information about the last error 0x2b - UGetParentTaskID - Get parent task ID 0x2c - UGetTaskID - Get task ID |
0x22 - UGetThreadID - Get thread ID 0x23 - UP - Get a semaphore 0x32 - USetLastError - Set the last error 0x24 - UTryP - Try to get a semaphore 0x25 - UV - Free a semaphore |
This page describes the TaskManager interface which provides functions to manage tasks, threads and everything related to them, including synchronization and events.
Every task created with this interface has:
A task can be a system task and in this case it doesn't has its own memory mapping, but use the current mapping. So, a thread from a system task can't access user memory space.
Each thread created with this interface has:
It's a thread that executes code. A task has one or more threads, each one has the same time and frequency of execution in the task.
ModulOS uses the same concept of task/process tree as Unix does, that is, a task that creates one task is the mother (father, in case of process) of the created task and the created task is the child. So, there's a tree of tasks.
For a system module to create a task that runs in user mode, it must do: call CreateTask to create a task and a thread, the thread created must load code in user memory space and then call ToUserLevel to start executing in user mode.
Every time a thread that runs code in user mode starts to run system code, it must be set undestroyable and when it returns to user mode it must be set destroyable again. This is done because system modules assume that the thread that is executing system code won't be destroyed. If it can be destroyed, semaphores, data structures, etc can stay in an undefined state.
Because undestroyable threads can't be destroyed, special attention must be taken with threads that wait for synchronizers. To prevent that a thread stay undestroyable for ever, threads that can stay suspended waiting for a synchronizer must be set interruptible.
When an interruptible thread locks a synchronizer, the function that locks the synchronizer can return a return code saying that the synchronizer was not lock because the task is been destroyed.
There's many types of synchronizers available, such as semaphores, spin locks, read/write.
Synchronizers must be used with care. They must be used only to protect module's own data to avoid deadlocks.
Many modules need to store informations about a task/thread. One way would be each module keep a structure to link the task/thread with the data. But this has some problems, such as more memory usage (besides the data itself we need a data structure); bigger access time (must search the data structure) and synchronization problems.
To solve this, it's possible to store informations in the task/thread structure. There's many functions to insert, remove, update and get these informations stored in the task/thread structure.
A module that implements this interface must generate events defined in TaskManagerE interface.
typedef struct { void *data[4]; } TaskManager_RWSync;
This is a R/W synchronizer structure, where many threads can read but only one thread can write.
It isn't a recursive synchronizer. So, if the same thread calls LockWrite twice it will block.
This structure must be initialized with zeros.
typedef struct { int count; void *data; } TaskManager_Semaphore;
This is a semaphore synchronizer structure.
It isn't a recursive synchronizer.
count must be initialized with the initial semaphore count and data with NULL. If count is less than or equal to zero, P function blocks.
typedef struct { void *data; } TaskManager_WaitQueue;
This is a wait queue structure, where many threads wait an event and are all removed when the event happens.
data must be initialized with NULL.
This structures are defined here to permit a static created synchronizer. This is important for some modules.
These functions are exclusive for system modules.
void TaskManager_AtomicAdd(unsigned int *var, unsigned int value);
This function is an inline function, that is, is like a macro and so doesn't need to appear in the usedfunctions session of the module's .spec file.
It adds atomically value on var.
void TaskManager_AtomicDec(unsigned int *var);
This function is an inline function, that is, is like a macro and so doesn't need to appear in the usedfunctions session of the module's .spec file.
It decrements atomically var.
void TaskManager_AtomicInc(unsigned int *var);
This function is an inline function, that is, is like a macro and so doesn't need to appear in the usedfunctions session of the module's .spec file.
It increments atomically var.
void TaskManager_AtomicSub(unsigned int *var, unsigned int value);
This function is an inline function, that is, is like a macro and so doesn't need to appear in the usedfunctions session of the module's .spec file.
It subtracts atomically value from var.
int TaskManager_CancelWait(TaskManager_Thread *thread, int prop);
This function cancels thread wait.
thread must be undestroyable.
prop must be 0 or the sum of:
int TaskManager_CreateTask(void *startCode, void *arg, int prop, TaskManager_Task **task, TaskManager_Thread **thread);
This function creates a task and a thread.
The thread will start executing in startCode, which must be inside system memory area, and will have arg as parameter. If thread returns it will be terminated.
prop has this format:
Bit | Description |
---|---|
0 | 1 - TaskManager_CREATE_SUS - thread created suspended |
1 | 1 - TaskManager_CREATE_SYSTEM - system task |
24-31 | task priority |
Task priority goes from 0 to 100, which 0 been an idle task, that is, only executes if there aren't other tasks that aren't idle tasks.
Tasks with priority bigger or equal to 60 must be used by system only.
The created thread will be undestroyable and is the caller responsability to set it destroyable.
In case of success, task and thread will have the task and thread handle.
int TaskManager_CreateThread(TaskManager_Task *task, void *startCode, void *arg, int prop, TaskManager_Thread **thread);
This function creates a thread for task that will start executing in startCode and will have arg as parameter. If thread returns it will be terminated.
If task is NULL, the thread will be created in the caller task.
In case task is different than NULL, task must be undestroyable.
startCode must be inside system memory area.
prop must be 0 or:
The created thread will be undestroyable and is the caller responsability to set it destroyable.
In case of success, thread will have the thread handle.
void *TaskManager_DelTaskInfo(TaskManager_Task *task, SysModManager_Module *module);
This function removes module data from task structure.
If task is NULL, caller task is used.
In case task is different than NULL, task must be undestroyable.
Use the macros IS_PTR_ERROR and PTR_TO_ERROR to know whether an error occurred and to get the error.
void *TaskManager_DelThreadInfo(TaskManager_Thread *thread, SysModManager_Module *module);
This function removes module data from thread structure.
If thread is NULL, caller thread is used.
In case thread is different than NULL, thread must be undestroyable.
Use the macros IS_PTR_ERROR and PTR_TO_ERROR to know whether an error occurred and to get the error.
void TaskManager_Destroyable(TaskManager_Task *task);
This function sets task destroyable and must be called the same number of times the task was set undestroyable to set the task destroyable.
If task is NULL, caller task will be used.
When a destroyable task is destroyed it will be destroyed immediatly.
If task is already been destroyed and if the caller thread belongs to task then it will be destroyed, that is, this function won't return.
void TaskManager_DestroyableThread(TaskManager_Thread *thread);
This function sets thread destroyable and must be called the same number of times that the function UndestroyableThread to set the thread destroyable.
If thread is NULL, caller thread will be used.
When a destroyable thread is destroyed it will be destroyed immediatly.
If thread is NULL and if the caller thread is already been destroyed then it will be destroyed, that is, this function won't return.
int TaskManager_DestroyTask(TaskManager_Task *task);
This function destroys task and all its threads.
If task is NULL, caller task is used.
task must be undestroyable.
Remember that a task running system code is already undestroyable. So, if task is NULL you donīt need to call UndestroyableThread and if task is not NULL it was set undestroyable or you couldnīt use task.
Before each thread is destroyed the event ThreadDestroyed is signaled and before task is destroyed the event TaskDestroyed is signaled.
To receive these events, a module must implement TaskManagerE interface.
int TaskManager_DestroyThread(TaskManager_Thread *thread);
This function destroys thread.
If thread is NULL, caller thread is used.
thread must be undestroyable.
Before thread is destroyed the event ThreadDestroyed is signaled.
To receive this event, a module must implement TaskManagerE interface.
long TaskManager_GetLastError(const char **name, int *function);
This function gets the last error code set by the function SetLastError.
name is optional and can be NULL. In case it isn't NULL, will receive a pointer to the interface name or module that generated the error.
If name has a interface name the value returned will have its higher bit set (a negative number). Otherwise, name will receive the module name.
This was done this way so interface implementations can specify their own error codes.
function is optional and can be NULL. In case it isn't NULL, will receive the number of the function that generated the error.
unsigned int TaskManager_GetMsCounter(void);
This function gets the ms counter value. This counter is incremented at each ms.
TaskManager_Task *TaskManager_GetParentTaskHandle(TaskManager_Task *task);
This function gets the parent task handle of task.
If task is NULL, gets from caller task.
In case task is different than NULL, task must be undestroyable.
In case of success, the parent task will be set undestroyable and the caller is responsable for setting it destroyable when the handle is not used anymore.
TaskManager_Task *TaskManager_GetTaskHandleID(int taskID);
This function gets the task handle of the task with ID taskID.
If taskID is zero, gets from caller task.
In case of success, the task will be set undestroyable and the caller is responsable for setting it destroyable when the handle is not used anymore.
Task handle or NULL if ID is invalid.
TaskManager_Task *TaskManager_GetTaskHandle(TaskManager_Thread *thread);
This function gets thread's task handle.
If thread is NULL, gets from caller thread.
In case thread is different than NULL, thread must be undestroyable.
In case of success, the task will be set undestroyable and the caller is responsable for setting it destroyable when the handle is not used anymore.
int TaskManager_GetTaskID(TaskManager_Task *task);
This function gets the ID of task.
If task is NULL, gets from caller task.
In case task is different than NULL, task must be undestroyable.
void *TaskManager_GetTaskInfo(TaskManager_Task *task, SysModManager_Module *module);
This function gets module data from task structure.
If task is NULL, caller task is used.
In case task is different than NULL, task must be undestroyable.
Use the macros IS_PTR_ERROR and PTR_TO_ERROR to know whether an error occurred and to get the error.
int TaskManager_GetTaskMMap(TaskManager_Task *task);
This function gets task's memory mapping.
If task is NULL, caller task is used.
In case task is different than NULL, task must be undestroyable.
TaskManager_Thread *TaskManager_GetThreadHandleID(TaskManager_Task *task, int threadID);
This function gets the thread handle of the thread with ID threadID from task.
If threadID is zero, gets from caller thread.
If task is NULL, gets from caller task.
In case task is different than NULL, task must be undestroyable.
In case of success, the thread will be set undestroyable and the caller is responsable for setting it destroyable when the handle is not used anymore.
Thread handle or NULL if ID is invalid.
TaskManager_Thread *TaskManager_GetThreadHandle(void);
This function gets the thread handle of the caller.
In case of success, the thread will be set undestroyable and the caller is responsable for setting it destroyable when the handle is not used anymore.
int TaskManager_GetThreadID(TaskManager_Thread *thread);
This function gets the thread ID of thread.
If thread is NULL, gets from caller.
In case thread is different than NULL, thread must be undestroyable.
void *TaskManager_GetThreadInfo(TaskManager_Thread *thread, SysModManager_Module *module);
This function gets module data from thread structure.
If thread is NULL, caller thread is used.
In case thread is different than NULL, thread must be undestroyable.
Use the macros IS_PTR_ERROR and PTR_TO_ERROR to know whether an error occurred and to get the error.
int TaskManager_GetThreadStatus(TaskManager_Thread *thread);
This function gets thread state.
If thread is NULL, caller thread is used.
In case thread is different than NULL, thread must be undestroyable.
int TaskManager_LockRead(TaskManager_RWSync *rw, int prop);
This function locks rw for read.
prop must be 0 or:
int TaskManager_LockWrite(TaskManager_RWSync *rw, int prop);
This function locks rw for write.
prop must be 0 or:
int TaskManager_P(TaskManager_Semaphore *semaphore, int prop, unsigned int timeout);
This function locks semaphore.
If the thread blocks it will stay blocked at most timeout miliseconds. But, if timeout is zero the thread will stay blocked till get the semaphore.
prop must be 0 or:
int TaskManager_Resume(TaskManager_Thread *thread, int prop);
This function resumes thread execution. Caller thread may lose the CPU.
thread must be undestroyable.
prop must be 0 or the sum of:
void TaskManager_Schedule(void);
This function implements the scheduler algorithm, switching tasks according. But it doesn't save CPU context and interrupts must be disabled before calling it.
long TaskManager_SetLastError(long error, const char *name, int function);
This function sets the last error which can be get using GetLastError.
error is the error code, name the interface name or module that generated the error and function the number of the function that generated the error.
name cannot be NULL and can have at most 32 chars including the terminating zero. If error has the higher bit set (if error is negative), name must be the name of the interface that generated the error. Otherwise must have the name of the module.
This was done so modules can have their own error codes.
void *TaskManager_SetTaskInfo(TaskManager_Task *task, SysModManager_Module *module, void *info, int prop);
This function stores info from module in task structure.
If task is NULL, caller task is used.
In case task is different than NULL, task must be undestroyable.
prop must be 0 or:
If module already has data, they will be overwrited if prop is 0.
Use the macros IS_PTR_ERROR and PTR_TO_ERROR to know whether an error occurred and to get the error.
void *TaskManager_SetThreadInfo(TaskManager_Thread *thread, SysModManager_Module *module, void *info, int prop);
This function stores info from module in thread structure.
If thread is NULL, caller thread is used.
In case thread is different than NULL, thread must be undestroyable.
prop must be 0 or:
If module already has data, they will be overwrited if prop is 0.
Use the macros IS_PTR_ERROR and PTR_TO_ERROR to know whether an error occurred and to get the error.
void TaskManager_SpinLock(int *lock);
This function guarantees exclusive execution after it's called, that is, it guarantees that after calling it code will be executing in only one processor.
Can only be called by code that doesn't block. Is indicated for fast operations. Interrupts can be disabled after calling this function.
lock must be initialized with zero before starting to use it.
void TaskManager_SpinUnlock(int *lock);
This function unlocks the spin.
int TaskManager_Suspend(TaskManager_Thread *thread);
This function suspends thread.
If thread is NULL, caller thread is suspended.
In case thread is different than NULL, thread must be undestroyable.
void TaskManager_ToUserLevel(TaskManager_Regs *regs);
This function returns to user mode and sets the value of the computer's registers to regs.
Each architecture defines regs in different manner. So, one must include the .h specific to that architecture to have the definition of regs.
This function is used mainly to go to user mode after creating a task.
void TaskManager_UndestroyableThread(void);
This function sets caller thread and task undestroyable.
The function DestroyableThread must be called the same number of times as this one to set the thread destroyable.
When an undestroyable thread is destroyed it will be destroyed when it becames destroyable.
If task/thread is already been destroyed then the thread will be destroyed, that is, this function won't return.
int TaskManager_UnlockRW(TaskManager_RWSync *rw, int prop);
This function unlocks rw from read or write lock.
prop must be 0 or:
int TaskManager_V(TaskManager_Semaphore *semaphore, int prop);
This function unlocks semaphore.
prop must be 0 or:
int TaskManager_Wait(TaskManager_Thread *thread, unsigned int time);
This function suspends thread for time ms.
If thread is NULL, caller thread is suspended.
In case thread is different than NULL, thread must be undestroyable.
int TaskManager_WaitQueueAdd(TaskManager_WaitQueue *waitQ, TaskManager_Semaphore *sem, int prop);
This function adds caller thread in waitQ, suspends caller thread and calls V for semaphore sem.
prop must be 0 or:
int TaskManager_WaitQueueWakeup(TaskManager_WaitQueue *waitQ);
This function wakes up all threads waiting in waitQ.
void TaskManager_Yield(void);
This function yields the CPU, that is, it says that this thread has nothing to do.
Nothing.
These functions were designed for user modules.
int TaskManager_UCreateThread(void *stack, void *startCode, int prop);
User modules
This function creates a thread for the task that calls this function.
The created thread will start to run at startCode with stack address at stack.
prop must be 0 or:
int TaskManager_UDestroyThread(int threadID, void *stack, unsigned int size);
User modules
This function destroys threadID.
Before threadID is destroyed stack with size is freed.
long TaskManager_UGetLastError(char *name, int *function);
User modules
This function gets the last error set by SetLastError or USetLastError.
name is optional and can be NULL. In case it isn't NULL, will receive the name of the interface or module that generated the error. name must be at least 32 bytes long.
If name has a interface name the value returned will have the higher bit set (a negative number). Otherwise, name will have the name of the module.
This was done so interface implementations can specify their own error codes.
function is optional and can be NULL. In case it isn't NULL, will receive the number of the function that generated the error.
int TaskManager_UGetParentTaskID(void);
User modules
This function gets the caller parent task ID.
int TaskManager_UGetTaskID(void);
User modules
This function gets caller task ID.
int TaskManager_UGetThreadID(void);
User modules
This function gets the caller thread ID.
int TaskManager_UP(TaskManager_Semaphore *semaphore);
User modules
This function locks semaphore.
long TaskManager_USetLastError(long error, const char *name, int function);
User modules
This function sets the last error which can be get using UGetLastError.
error is the error code, name the interface name or module that generated the error and function the number of the function that generated the error.
name cannot be NULL and can have at most 32 chars including the terminating zero. If error has the higher bit set (if error is negative), name must be the name of the interface that generated the error. Otherwise must have the name of the module.
This was done so modules can have their own error codes.
int TaskManager_UTryP(TaskManager_Semaphore *semaphore);
User modules
This function tries to lock semaphore, that is, only locks it if it's available.
int TaskManager_UV(TaskManager_Semaphore *semaphore);
User modules
This function unlocks semaphore. The caller can lose the CPU.