Difference between revisions of "Task Queue System"
(Added task destruction sample code) |
|||
(5 intermediate revisions by 2 users not shown) | |||
Line 12: | Line 12: | ||
| 0x0D || 0x01 || uint8_t || Unknown value | | 0x0D || 0x01 || uint8_t || Unknown value | ||
|- | |- | ||
| 0x10 || 0x08 || uint64_t* || | | 0x10 || 0x08 || uint64_t* || Next task pointer | ||
|- | |- | ||
| 0x18 || 0x08 || uint64_t* || | | 0x18 || 0x08 || uint64_t* || Some task pointer | ||
|- | |- | ||
| 0x20 || 0x08 || uint64_t* || | | 0x20 || 0x08 || uint64_t* || Current task pointer (at the moment of creation) | ||
|- | |- | ||
| 0x28 || 0x08 || uint64_t* || | | 0x28 || 0x08 || uint64_t* || Some task pointer | ||
|- | |- | ||
| 0x30 || 0x08 || uint64_t* || | | 0x30 || 0x08 || uint64_t* || Some task pointer | ||
|- | |- | ||
| 0x38 || 0x08 || uint64_t* || | | 0x38 || 0x08 || uint64_t* || Some task pointer | ||
|- | |- | ||
| 0x40 || 0x08 || uint64_t* || | | 0x40 || 0x08 || uint64_t* || Some task pointer | ||
|- | |- | ||
| 0x48 || 0x08 || uint64_t* || Unknown pointer | | 0x48 || 0x08 || uint64_t* || Unknown pointer | ||
Line 47: | Line 47: | ||
=Enqueue task= | =Enqueue task= | ||
==Enqueue task without | ==Enqueue task without TASK data allocation== | ||
To enqueue an task without | To enqueue an task without TASK data allocation the subroutine 0x14049D890 (v1.07) needs to be called. | ||
<sub> | <sub> | ||
EnqueueTask(void* callbackFunction, uint8_t nextFunctionIndex, uint8_t a3, uint32_t taskToken) | EnqueueTask(void* callbackFunction, uint8_t nextFunctionIndex, uint8_t a3, uint32_t taskToken) | ||
</sub> | </sub> | ||
==Enqueue task with | ==Enqueue task with TASK data allocation== | ||
To enqueue an task with | To enqueue an task with TASK data allocation the subroutine 0x14049DA10 (v1.07) needs to be called.<br> | ||
<sub> | <sub> | ||
EnqueueTaskWithData(void* callbackFunction, uint8_t nextFunctionIndex, uint8_t a3, uint32_t dataSize, uint32_t taskToken, char* debugTaskName) | |||
</sub> | </sub> | ||
Line 67: | Line 67: | ||
The main loop iterates through the task queue and calls the callback function with the optional parameter.<br> | The main loop iterates through the task queue and calls the callback function with the optional parameter.<br> | ||
When the callback function returns the next task pointer is read from the current task and moved into the task queue address pointer. | When the callback function returns the next task pointer is read from the current task and moved into the task queue address pointer. | ||
<syntaxhighlight lang="C++" line> | |||
void Shenmue::Main(int argc, void *argv) { | |||
// initialize | |||
if ( Shenmue::Initialization(argc, argv) ) | |||
{ | |||
HLib_Task * taskPtr = nullptr; | |||
// loop all tasks | |||
for ( taskPtr = HLib::CurrentTask; ; HLib::CurrentTask = taskPtr ) | |||
{ | |||
// execute task function | |||
taskPtr->taskCallbackFnPtr(taskPtr->task_data); | |||
// select next task | |||
taskPtr = HLib::CurrentTask->next_task; | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
=Task cleanup (Destruction)= | =Task cleanup (Destruction)= | ||
A task controls how long it lives in its own callback function.<br> | A task controls how long it lives in its own callback function.<br> | ||
When a task wants to be destroyed it calls the subroutine 0x14049D660 (v1.07) during its own callback.<br> | When a task wants to be destroyed it calls the subroutine 0x14049D660 (v1.07) during its own callback.<br> | ||
Tasks can also be destroyed if a pointer can be retrieved for it, like this: | |||
<syntaxhighlight lang="C++" line> | |||
HLib_Task * TASK = HLib::EnqueueTaskWithoutParameter(HLTaskFunc_CharacterHandler_Callback, a1, 4ui64, 'RAHC'); | |||
if ( !TASK ) | |||
goto COULD_NOT_ENQUEUE_TASK; | |||
if ( TASK->task_data ) | |||
goto TASK_DATA_ALREADY_EXISTS; | |||
task_memory = HLib::AllocHeapMemBlock(272i64, 'KSAT'); | |||
if ( task_memory ) | |||
*((int *)task_memory + 0x7) |= 0x10u; | |||
TASK->task_data = task_memory; | |||
if ( !task_memory ) | |||
{ | |||
TASK_DATA_ALREADY_EXISTS: | |||
TASK->initTaskFnPtr = 0i64; | |||
TASK->taskCallbackFnPtr = HLib::DestroyCurrentTask; | |||
TASK->taskPtr08 = 0i64; | |||
COULD_NOT_ENQUEUE_TASK: | |||
TASK = 0i64; | |||
} | |||
</syntaxhighlight> | |||
=Task parameter= | =Task parameter= |
Latest revision as of 22:34, 31 December 2021
Task memory structure
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x08 | uint64_t* | Callback function pointer |
0x08 | 0x04 | char* | Task type/name token |
0x0C | 0x01 | uint8_t | Unknown value |
0x0D | 0x01 | uint8_t | Unknown value |
0x10 | 0x08 | uint64_t* | Next task pointer |
0x18 | 0x08 | uint64_t* | Some task pointer |
0x20 | 0x08 | uint64_t* | Current task pointer (at the moment of creation) |
0x28 | 0x08 | uint64_t* | Some task pointer |
0x30 | 0x08 | uint64_t* | Some task pointer |
0x38 | 0x08 | uint64_t* | Some task pointer |
0x40 | 0x08 | uint64_t* | Some task pointer |
0x48 | 0x08 | uint64_t* | Unknown pointer |
0x50 | 0x08 | uint64_t* | Unknown pointer |
0x58 | 0x08 | uint64_t* | Unknown pointer |
0x60 | 0x08 | uint64_t* | Unknown pointer |
0x68 | 0x08 | uint64_t* | Callback function parameter struct pointer |
Task queue
Task Queue Pointer Offset: 0x1481FFA50 (v1.07)
At the start an ROOT task is created.
When the ROOT task was created the Queue gets filled with NONE task's which do nothing.
At initialization each task has the next task in order as their next task specified inside 0x18.
The last task however points to 0x142A88530 (v1.07) as their next task.
The ROOT task points to the first task as it's next task.
Enqueue task
Enqueue task without TASK data allocation
To enqueue an task without TASK data allocation the subroutine 0x14049D890 (v1.07) needs to be called.
EnqueueTask(void* callbackFunction, uint8_t nextFunctionIndex, uint8_t a3, uint32_t taskToken)
Enqueue task with TASK data allocation
To enqueue an task with TASK data allocation the subroutine 0x14049DA10 (v1.07) needs to be called.
EnqueueTaskWithData(void* callbackFunction, uint8_t nextFunctionIndex, uint8_t a3, uint32_t dataSize, uint32_t taskToken, char* debugTaskName)
Task creation
During the enqueue process the task will be created with the given callback function.
The callback function parameter, which is optional, is an pointer to an struct than can have any shape or size the callback function needs.
This parameter struct will be allocated inside the USE/fREe storage.
Task execution
The main loop iterates through the task queue and calls the callback function with the optional parameter.
When the callback function returns the next task pointer is read from the current task and moved into the task queue address pointer.
void Shenmue::Main(int argc, void *argv) {
// initialize
if ( Shenmue::Initialization(argc, argv) )
{
HLib_Task * taskPtr = nullptr;
// loop all tasks
for ( taskPtr = HLib::CurrentTask; ; HLib::CurrentTask = taskPtr )
{
// execute task function
taskPtr->taskCallbackFnPtr(taskPtr->task_data);
// select next task
taskPtr = HLib::CurrentTask->next_task;
}
}
}
Task cleanup (Destruction)
A task controls how long it lives in its own callback function.
When a task wants to be destroyed it calls the subroutine 0x14049D660 (v1.07) during its own callback.
Tasks can also be destroyed if a pointer can be retrieved for it, like this:
HLib_Task * TASK = HLib::EnqueueTaskWithoutParameter(HLTaskFunc_CharacterHandler_Callback, a1, 4ui64, 'RAHC');
if ( !TASK )
goto COULD_NOT_ENQUEUE_TASK;
if ( TASK->task_data )
goto TASK_DATA_ALREADY_EXISTS;
task_memory = HLib::AllocHeapMemBlock(272i64, 'KSAT');
if ( task_memory )
*((int *)task_memory + 0x7) |= 0x10u;
TASK->task_data = task_memory;
if ( !task_memory )
{
TASK_DATA_ALREADY_EXISTS:
TASK->initTaskFnPtr = 0i64;
TASK->taskCallbackFnPtr = HLib::DestroyCurrentTask;
TASK->taskPtr08 = 0i64;
COULD_NOT_ENQUEUE_TASK:
TASK = 0i64;
}
Task parameter
When a task gets enqueued with a parameter it will need to find some "fREe" storage in the USE/fREe storage.
Storage entry
Position | Length | Type | Description |
---|---|---|---|
0x00 | 0x04 | string | Task token (TASK) |
0x10 | 0x08 | uint64_t* | Unknown pointer |
0x18 | 0x08 | uint64_t* | Unknown pointer |
0x20 | 0x04 | string | USE/fREe token |
0x40 | 0x?? | ? | Storage data |