#include "common.h" #include "dolphin/os.h" extern int gcsetjmp(jmp_buf *jump); extern void gclongjmp(jmp_buf *jump, int status); #define EXEC_NORMAL 0 #define EXEC_SLEEP 1 #define EXEC_CHILDWATCH 2 #define EXEC_KILLED 3 static jmp_buf processjmpbuf; static Process *processtop; static Process *processcur; static u16 processcnt; u32 procfunc; void HuPrcInit(void) { processcnt = 0; processtop = NULL; } static void LinkProcess(Process** root, Process* process) { Process* src_process = *root; if (src_process && (src_process->prio >= process->prio)) { while (src_process->next && src_process->next->prio >= process->prio) { src_process = src_process->next; } process->next = src_process->next; process->prev = src_process; src_process->next = process; if (process->next) { process->next->prev = process; } } else { process->next = (*root); process->prev = NULL; *root = process; if (src_process) { src_process->prev = process; } } } static void UnlinkProcess(Process **root, Process *process) { if (process->next) { process->next->prev = process->prev; } if (process->prev) { process->prev->next = process->next; } else { *root = process->next; } } Process *HuPrcCreate(void (*func)(void), u16 prio, u32 stack_size, s32 extra_size) { Process *process; s32 alloc_size; void *heap; if(stack_size == 0) { stack_size = 2048; } alloc_size = HuMemMemoryAllocSizeGet(sizeof(Process)) +HuMemMemoryAllocSizeGet(stack_size) +HuMemMemoryAllocSizeGet(extra_size); if(!(heap = HuMemDirectMalloc(HEAP_SYSTEM, alloc_size))) { OSReport("process> malloc error size %d\n", alloc_size); return NULL; } HuMemHeapInit(heap, alloc_size); process = HuMemMemoryAlloc(heap, sizeof(Process), 0xA5A5A5A5); process->heap = heap; process->exec = EXEC_NORMAL; process->stat = 0; process->prio = prio; process->sleep_time = 0; process->base_sp = ((u32)HuMemMemoryAlloc(heap, stack_size, 0xA5A5A5A5))+stack_size-8; gcsetjmp(&process->jump); process->jump.lr = (u32)func; process->jump.sp = process->base_sp; process->dtor = NULL; process->user_data = NULL; LinkProcess(&processtop, process); process->child = NULL; process->parent = NULL; processcnt++; return process; } void HuPrcChildLink(Process *parent, Process *child) { HuPrcChildUnlink(child); if(parent->child) { parent->child->first_child = child; } child->next_child = parent->child; child->first_child = NULL; parent->child = child; child->parent = parent; } void HuPrcChildUnlink(Process *process) { if(process->parent) { if(process->next_child) { process->next_child->first_child = process->first_child; } if(process->first_child) { process->first_child->next_child = process->next_child; } else { process->parent->child = process->next_child; } process->parent = NULL; } } Process *HuPrcChildCreate(void (*func)(void), u16 prio, u32 stack_size, s32 extra_size, Process *parent) { Process *child = HuPrcCreate(func, prio, stack_size, extra_size); HuPrcChildLink(parent, child); return child; } void HuPrcChildWatch() { Process *curr = HuPrcCurrentGet(); if(curr->child) { curr->exec = EXEC_CHILDWATCH; if(!gcsetjmp(&curr->jump)) { gclongjmp(&processjmpbuf, 1); } } } Process *HuPrcCurrentGet() { return processcur; } static int SetKillStatusProcess(Process *process) { if(process->exec != EXEC_KILLED) { HuPrcWakeup(process); process->exec = EXEC_KILLED; return 0; } else { return -1; } } int HuPrcKill(Process *process) { if(process == NULL) { process = HuPrcCurrentGet(); } HuPrcChildKill(process); HuPrcChildUnlink(process); return SetKillStatusProcess(process); } void HuPrcChildKill(Process *process) { Process *child = process->child; while(child) { if(child->child) { HuPrcChildKill(child); } SetKillStatusProcess(child); child = child->next_child; } process->child = NULL; } static void gcTerminateProcess(Process *process) { if(process->dtor) { process->dtor(); } UnlinkProcess(&processtop, process); processcnt--; gclongjmp(&processjmpbuf, 2); } void HuPrcEnd() { Process *process = HuPrcCurrentGet(); HuPrcChildKill(process); HuPrcChildUnlink(process); gcTerminateProcess(process); } void HuPrcSleep(s32 time) { Process *process = HuPrcCurrentGet(); if(time != 0 && process->exec != EXEC_KILLED) { process->exec = EXEC_SLEEP; process->sleep_time = time; } if(!gcsetjmp(&process->jump)) { gclongjmp(&processjmpbuf, 1); } } void HuPrcVSleep() { Process *process = HuPrcCurrentGet(); if(!gcsetjmp(&process->jump)) { gclongjmp(&processjmpbuf, 1); } } void HuPrcWakeup(Process *process) { process->sleep_time = 0; } void HuPrcDestructorSet2(Process *process, void (*func)(void)) { process->dtor = func; } void HuPrcDestructorSet(void (*func)(void)) { Process *process = HuPrcCurrentGet(); process->dtor = func; } void HuPrcCall(int tick) { Process *process; int ret; processcur = processtop; ret = gcsetjmp(&processjmpbuf); while(1) { switch(ret) { case 2: HuMemDirectFree(processcur->heap); case 1: if(((u8 *)(processcur->heap))[4] != 165) { printf("stack overlap error.(process pointer %x)\n", processcur); while(1); } else { processcur = processcur->next; } break; } process = processcur; if(!process) { return; } procfunc = process->jump.lr; if((process->stat & 0x3) && process->exec != EXEC_KILLED) { ret = 1; continue; } switch(process->exec) { case EXEC_SLEEP: if(process->sleep_time > 0) { process->sleep_time -= tick; if(process->sleep_time <= 0) { process->sleep_time = 0; process->exec = EXEC_NORMAL; } } ret = 1; break; case EXEC_CHILDWATCH: if(process->child) { ret = 1; } else { process->exec = EXEC_NORMAL; ret = 0; } break; case EXEC_KILLED: process->jump.lr = (u32)HuPrcEnd; case EXEC_NORMAL: gclongjmp(&process->jump, 1); break; } } } void *HuPrcMemAlloc(s32 size) { Process *process = HuPrcCurrentGet(); return HuMemMemoryAlloc(process->heap, size, 0xA5A5A5A5); } void HuPrcMemFree(void *ptr) { HuMemMemoryFree(ptr, 0xA5A5A5A5); } void HuPrcSetStat(Process *process, u16 value) { process->stat |= value; } void HuPrcResetStat(Process *process, u16 value) { process->stat &= ~value; } void HuPrcAllPause(int flag) { Process *process = processtop; if(flag) { while(process != NULL) { if(!(process->stat & 0x4)) { HuPrcSetStat(process, 0x1); } process = process->next; } } else { while(process != NULL) { if(process->stat & 0x1) { HuPrcResetStat(process, 0x1); } process = process->next; } } } void HuPrcAllUPause(int flag) { Process *process = processtop; if(flag) { while(process != NULL) { if(!(process->stat & 0x8)) { HuPrcSetStat(process, 0x2); } process = process->next; } } else { while(process != NULL) { if(process->stat & 0x2) { HuPrcResetStat(process, 0x2); } process = process->next; } } }