2009-02-09 21:15:56 +00:00
|
|
|
//[module] THREADMAN
|
|
|
|
//[processor] IOP
|
|
|
|
//[type] ELF-IRX
|
|
|
|
//[name] Multi_Thread_Manager
|
|
|
|
//[version] 0x101
|
|
|
|
//[memory map] 0xBF802070
|
|
|
|
//[handlers] -
|
|
|
|
//[entry point] start, thbase_stub, thevent_stub, thsemap_stub,
|
|
|
|
// thmsgbx_stub, thfpool_stub, thvpool_stub, thrdman_stub
|
|
|
|
//[made by] [RO]man (roman_ps2dev@hotmail.com) november 2002 - january 2003
|
|
|
|
|
|
|
|
#include "err.h"
|
|
|
|
#include "ksysmem.h"
|
|
|
|
#include "kloadcore.h"
|
|
|
|
#include "kintrman.h"
|
|
|
|
#include "kstdio.h"
|
|
|
|
#include "ksysclib.h"
|
|
|
|
#include "ktimrman.h"
|
|
|
|
#include "kheaplib.h"
|
|
|
|
#include "iopdebug.h"
|
|
|
|
#include "kthbase.h"
|
|
|
|
|
|
|
|
int debug=1;
|
|
|
|
|
|
|
|
#define _dprintf(fmt, args...) \
|
|
|
|
if (debug > 0) __printf("threadman:" fmt, ## args)
|
|
|
|
|
|
|
|
int _start();
|
|
|
|
|
|
|
|
|
|
|
|
void _retonly() {}
|
|
|
|
|
|
|
|
struct export thbase_stub={
|
|
|
|
0x41C00000,
|
|
|
|
0,
|
|
|
|
VER(1, 1), // 1.1 => 0x101
|
|
|
|
0,
|
|
|
|
"thbase",
|
|
|
|
(func)_start, // entrypoint
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x08
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x10
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x18
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x20
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x28
|
|
|
|
(func)_retonly,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
struct export thevent_stub={
|
|
|
|
0x41C00000,
|
|
|
|
0,
|
|
|
|
VER(1, 1), // 1.1 => 0x101
|
|
|
|
0,
|
|
|
|
"thevent",
|
|
|
|
(func)_start, // entrypoint
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x08
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
struct export thsemap_stub={
|
|
|
|
0x41C00000,
|
|
|
|
0,
|
|
|
|
VER(1, 1), // 1.1 => 0x101
|
|
|
|
0,
|
|
|
|
"thsemap",
|
|
|
|
(func)_start, // entrypoint
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly, // 0x08
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
(func)_retonly,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
int _start() {
|
|
|
|
int x;
|
|
|
|
|
|
|
|
_dprintf("_start\n");
|
|
|
|
|
|
|
|
// if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1;
|
|
|
|
if (RegisterLibraryEntries(&thbase_stub)) return 1;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
|
|
|
|
RegisterLibraryEntries(&thevent_stub);
|
|
|
|
RegisterLibraryEntries(&thsemap_stub);
|
|
|
|
// RegisterLibraryEntries(&thmsgbx_stub);
|
|
|
|
// RegisterLibraryEntries(&thfpool_stub);
|
|
|
|
// RegisterLibraryEntries(&thvpool_stub);
|
|
|
|
|
|
|
|
CpuEnableIntr();
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
unsigned int ready;
|
|
|
|
unsigned int _263;
|
|
|
|
unsigned int _14;
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
unsigned int *threadman_callx(){
|
|
|
|
return &ready;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int thbase_start(int argc, char* argv[]){
|
|
|
|
int x;
|
|
|
|
|
|
|
|
if (RegisterNonAutoLinkEntries(&thrdman_stub)) return 1;
|
|
|
|
if (RegisterLibraryEntries(&thbase_stub)) return 1;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
|
|
|
|
RegisterLibraryEntries(&thevent_stub);
|
|
|
|
RegisterLibraryEntries(&thsemap_stub);
|
|
|
|
RegisterLibraryEntries(&thmsgbx_stub);
|
|
|
|
RegisterLibraryEntries(&thfpool_stub);
|
|
|
|
RegisterLibraryEntries(&thvpool_stub);
|
|
|
|
|
|
|
|
memset(&ready, 0, 1220); //305 x 4 => zero all bss
|
|
|
|
|
|
|
|
_unk3=8;
|
|
|
|
_2=NULL;
|
|
|
|
LL_reset(&a);
|
|
|
|
LL_reset(&b);
|
|
|
|
LL_reset(&c);
|
|
|
|
LL_reset(&d);
|
|
|
|
LL_reset(&e);
|
|
|
|
LL_reset(&f);
|
|
|
|
LL_reset(&g);
|
|
|
|
LL_reset(&h);
|
|
|
|
LL_reset(&i);
|
|
|
|
LL_reset(&threads_list);
|
|
|
|
|
|
|
|
for (j=0; j<128; j++)
|
|
|
|
LL_reset(&prio_lists[j]);
|
|
|
|
hp=CreateHeap(0x800, 1); //s3=&hp
|
|
|
|
th=allocheap(0x7F01, sizeof(struct TCB));
|
|
|
|
th->id=++ids;//short
|
|
|
|
th->thp_stackSize=512;
|
|
|
|
th->stack=AllocSysMemory(ALLOC_LAST, 512, 0);
|
|
|
|
th->prio=th->thp_priority=127;//LOWEST_PRIORITY+1
|
|
|
|
th->thp_attr=TH_C;
|
|
|
|
th->status=THS_READY;
|
|
|
|
th->gp=gp;
|
|
|
|
th->thp_entry=infinite_call;
|
|
|
|
th->area=th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8;
|
|
|
|
memset(th->area, 0, 0xB8);
|
|
|
|
th->area->field_00=0xFFFFFFFE;
|
|
|
|
th->area->H78=th->area->H74==&th->area->regs;
|
|
|
|
th->area->ExitThread=ExitThread;
|
|
|
|
th->area->gp=th->gp;
|
|
|
|
th->area->attr=(th->attr & TH_COP) | 0x404;
|
|
|
|
th->area->attr|=th->attr & TH_UMODE;
|
|
|
|
th->area->entry=th->thp_entry;
|
|
|
|
th->area->ei=1;
|
|
|
|
_2.next=th;
|
|
|
|
_2.prev=th;
|
|
|
|
enqueue(th);
|
|
|
|
|
|
|
|
th=allocheap(0x7F01, sizeof(struct TCB));
|
|
|
|
th->id=++ids;//short
|
|
|
|
th->thp_stackSize=QueryBlockSize(&j);
|
|
|
|
th->stack=QueryBlockTopAddress(&j);
|
|
|
|
th->thp_priority=8; //MODULE_INIT_PRIORITY
|
|
|
|
th->prio=1; //HIGHEST_PRIORITY
|
|
|
|
th->thp_attr=0x2000000;
|
|
|
|
th->status=THS_RUN;
|
|
|
|
th->gp=gp;
|
|
|
|
th->next_2=_2.next;
|
|
|
|
_2.next=th;
|
|
|
|
ready.prev=ready.next=th;
|
|
|
|
th->next=NULL;
|
|
|
|
th->prev=NULL;
|
|
|
|
SetCtxSwitchHandler(handler1_switchcontexts);
|
|
|
|
SetCtxSwitchReqHandler(handler2_morethan1ready);
|
|
|
|
sub_50A0();
|
|
|
|
|
|
|
|
efp.attr=2;
|
|
|
|
efp.initPattern=0;
|
|
|
|
efp.option=0;
|
|
|
|
systemStatusFlag=CreateEventFlag(&efp);
|
|
|
|
|
|
|
|
if (v0=QueryBootMode(4))
|
|
|
|
SetEventFlag(systemStatusFlag, 1<<(v0->H0 & 3));//H0 short
|
|
|
|
|
|
|
|
loadcore_call20_registerFunc(&lc20_2, 2, 0);
|
|
|
|
loadcore_call20_registerFunc(&lc20_3, 3, 0);
|
|
|
|
CpuEnableIntr();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int lc20_2(){
|
|
|
|
CpuEnableIntr();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int lc20_3(int a){
|
|
|
|
_dprintf("%s\n", __FUNCTION__);
|
|
|
|
CpuEnableIntr();
|
|
|
|
|
|
|
|
ChangeThreadPriority(0, 126);//LOWEST_PRIORIT
|
|
|
|
if (a->H0 == 0) {
|
|
|
|
for (;;) {
|
|
|
|
DelayThread(1000000); //never exit
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void infinite_call(){
|
|
|
|
infinite_call();
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void syscall_32(){
|
|
|
|
li $v0, 0x20
|
|
|
|
syscall #0
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void enqueue(struct TCB *th){
|
|
|
|
flags[th->prio>>5] |= 1 << (th->prio & 0x1F);
|
|
|
|
LL_add_before(&prio_lists[th->prio], th);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////clone?
|
|
|
|
void enqueue2(struct TCB *th){
|
|
|
|
flags[th->prio>>5] |= 1 << (th->prio & 0x1F);
|
|
|
|
LL_add_before(&prio_lists[th->prio], th);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void unqueue(ll, prio){
|
|
|
|
if (LL_0_1_elements(ll)
|
|
|
|
flags[prio>>5] &= ~(1 << (prio & 0x1F))
|
|
|
|
LL_remove(ll);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int run(struct TCB *th, int x){
|
|
|
|
if (th->prio >= ready.next->prio){
|
|
|
|
th->status=THS_READY;
|
|
|
|
enqueue(th);
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_OK;
|
|
|
|
}else{
|
|
|
|
ready.next->status=THS_READY;
|
|
|
|
enqueue2(ready.next);
|
|
|
|
th->status=THS_RUN;
|
|
|
|
ready->prev=th;
|
|
|
|
return syscall_32(0, 0, x, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int getHighestUsed(){
|
|
|
|
int i;
|
|
|
|
for (i=0; i<4; i++)
|
|
|
|
if (flags[i])
|
|
|
|
return (i<<5)+getHighestUsed_32(flags[i]);
|
|
|
|
return 128; //LOWEST_PRIORITY+2
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void switch(){
|
|
|
|
int hp;
|
|
|
|
|
|
|
|
ready.prev=ready.next;
|
|
|
|
if (ready.next->status != THS_RUN){
|
|
|
|
if (unk3 & 4)
|
|
|
|
Kprintf(" not THS_RUN ");
|
|
|
|
hp=getHighestUsed();
|
|
|
|
if (hp<128){
|
|
|
|
if (unk3 & 4)
|
|
|
|
Kprintf(" readyq = %x, newrun = %x:%d, prio = %d",
|
|
|
|
&prio_lists[hp], prio_lists[hp].next, prio_lists[hp].next->id, hp);
|
|
|
|
unqueue(prio_lists[hp].next, hp);
|
|
|
|
prio_lists[hp].next->status=THS_RUN;
|
|
|
|
ready.prev=prio_lists[hp].next;
|
|
|
|
}else
|
|
|
|
Kprintf("Panic: not found executable Thread\n");
|
|
|
|
}else
|
|
|
|
if ((hp=getHighestUsed())<128){
|
|
|
|
if (unk3 & 4)
|
|
|
|
Kprintf(" THS_RUN cp=%d : hp=%d ", ready.next->prio, hp);
|
|
|
|
if (hp<ready.next->prio){
|
|
|
|
if (unk3 & 4)
|
|
|
|
Kprintf(" readyq = %x, newrun = %x:%d, prio = %d",
|
|
|
|
&prio_list[hp], prio_list[hp].next, prio_list[hp].next->id, hp);
|
|
|
|
unqueue(prio_list[hp].next, hp);
|
|
|
|
prio_list[hp].next->status=ready.next->status;
|
|
|
|
ready.prev=prio_lists[hp].next;
|
|
|
|
ready.next->status=THS_READY;
|
|
|
|
enqueue2(ready.next);
|
|
|
|
}
|
|
|
|
}else
|
|
|
|
Kprintf("Panic: not found ready Thread\n");
|
|
|
|
if (unk3 & 4)
|
|
|
|
Kprintf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void stack_overflow(struct TCB *th){
|
|
|
|
register ImageInfo ii;
|
|
|
|
register char *name;
|
|
|
|
Kprintf("\nThread (thid=%x, #%d) stack overflow\n Stack = %x, Stack size = %x, SP=%x\n",
|
|
|
|
(th<<5) | ((th->id & 0x3F) << 1) | 1, th->id & 0xFFFF, th->stack, th->thp_stackSize, th->area);
|
|
|
|
if ((ii=loadcore_call24_findImageInfo(th->thp_entry)) &&
|
|
|
|
(name=ii->H04))
|
|
|
|
Kprintf(" Module Name = %s\n", name);
|
|
|
|
__asm break #0x400
|
|
|
|
);
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
struct TCB *handler1_switchcontexts(struct AREA *area){
|
|
|
|
s0=&unk4;
|
|
|
|
unk4++;
|
|
|
|
if (unk3 & 3){
|
|
|
|
if (1==unk3 & 3)
|
|
|
|
Kprintf("[%3d->", ready.next->id);
|
|
|
|
if (2==unk3 & 3)
|
|
|
|
Kprintf("switch_context(%x:%x,pc=%x,ei=%x =>%x:%d)\n",
|
|
|
|
area, area->field_00, area->entry, area->ei, ready.next, ready.next->id);
|
|
|
|
}
|
|
|
|
ready.next->area=area;
|
|
|
|
if (area < ready.next->stack)
|
|
|
|
stack_overflow(ready.next);
|
|
|
|
if (ready.prev->next==NULL)
|
|
|
|
switch();
|
|
|
|
if (ready.prev != ready.next){
|
|
|
|
s0=GetTimerCounter(timid);
|
|
|
|
ready.next->field_30=moveregs(0, s0-www.prev, ready.next->field_30);
|
|
|
|
www.prev=s0;
|
|
|
|
}
|
|
|
|
if (unk3 & 3){
|
|
|
|
if (unk3 & 3 == 1)
|
|
|
|
Kprintf("%3d]", ready.prev->id);
|
|
|
|
if (unk3 & 3 == 2)
|
|
|
|
Kprintf(" switch_context --> %x:%x,pc=%x,ei=%x =>%x:%d\n"
|
|
|
|
ready.prev->area, ready.prev->area->field_00, ready.prev->area->entry,
|
|
|
|
ready.prev->area->ei, ready.prev, ready.prev->id);
|
|
|
|
}
|
|
|
|
if (unk3 & 0x20){
|
|
|
|
0xBF802070=~(1 << ((ready.prev->id-1) & 7));
|
|
|
|
}
|
|
|
|
return ready.prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int handler2_morethan1ready(){
|
|
|
|
return (0 < (ready.prev^ready.next));
|
|
|
|
//return (ready.prev!=ready.next);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void queue_on_prio(struct TCB *th, void *fld, int prio){
|
|
|
|
register struct TCB *p;
|
|
|
|
|
|
|
|
LL_remove(th);
|
|
|
|
for (p=fld->H14; p !=&fld->H14 && prio>=p->prio; p=p->next);
|
|
|
|
LL_add_before(p, th);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[04]
|
|
|
|
int CreateThread(struct ThreadParam *param){
|
|
|
|
int x;
|
|
|
|
register struct TCB *th;
|
|
|
|
|
|
|
|
if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT;
|
|
|
|
if (param->attr & 0x1CFFFFF7) return KE_ILLEGAL_ATTR;
|
|
|
|
if (param->initPriority-1>=126) return KE_ILLEGAL_PRIORITY;
|
|
|
|
if (param->entry & 3) return KE_ILLEGAL_ENTRY;
|
|
|
|
if (param->stackSize<0x130) return KE_ILLEGAL_STACK_SIZE;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
if (th=allocheap(0x7F01, sizeof(struct TCB))){ //0x50
|
|
|
|
param->stackSize = (param->stackSize+0xFF) & 0xFFFFFF00;
|
|
|
|
stack=AllocSysMemory(ALLOC_LAST, param->stackSize, NULL);
|
|
|
|
if (!stack)
|
|
|
|
freeheap(th);
|
|
|
|
}
|
|
|
|
if (!th || !stack){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_NO_MEMORY;
|
|
|
|
}
|
|
|
|
th->id=++ids;
|
|
|
|
th->thp_entry=param->entry;
|
|
|
|
th->stack=stack;
|
|
|
|
th->thp_stackSize;
|
|
|
|
th->thp_priority=param->initPriority;
|
|
|
|
th->thp_attr=attr;
|
|
|
|
th->status=THS_DORMANT;
|
|
|
|
th->thp_option=param->option;
|
|
|
|
th->gp=$gp;
|
|
|
|
th->next_2=&_2;
|
|
|
|
_2.next=th;
|
|
|
|
LL_add_before(threads_list, th);
|
|
|
|
if (!(th->thp_attr & TH_NO_FILLSTACK))
|
|
|
|
memset(th->stack, 0xFF, th->thp_stackSize-48);
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return ((int)th<<5) | ((th->id & 0x3F) << 1) | 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[05]
|
|
|
|
int DeleteThread(int thid){
|
|
|
|
int x;
|
|
|
|
register struct TCB *th, *p;
|
|
|
|
|
|
|
|
if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT;
|
|
|
|
if (thid==0) return KE_ILLEGAL_THID;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
th=(struct TCB *)(thid>>7<<2);
|
|
|
|
if ((th->_7F01 != 0x7F01) ||
|
|
|
|
(((thid>>1) & 0x3F) != (th->id & 0x3F)) ||
|
|
|
|
(_2.prev == th)){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_UNKNOWN_THID;
|
|
|
|
}
|
|
|
|
if (th->status != THS_DORMANT){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_NOT_DORMANT;
|
|
|
|
}
|
|
|
|
FreeSysMemory(th->stack);
|
|
|
|
LL_remove(th);
|
|
|
|
|
|
|
|
if (_2.next==th)
|
|
|
|
_2.next=th->next_2;
|
|
|
|
else
|
|
|
|
for (p=_2.next; p->next_2; p=p->next_2)
|
|
|
|
if (p->next_2==th){
|
|
|
|
p->next_2=th->next_2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
freeheap(th);
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int startThread(struct TCB *th,int x){
|
|
|
|
th->field_1C=0;
|
|
|
|
th->field_20=0;
|
|
|
|
th->field_1E=0;
|
|
|
|
th->prio=thp_priority;
|
|
|
|
th->area->field_00=0xFFFFFFFE;
|
|
|
|
th->area->field_78=th->area->field_74=&th->area->regs;
|
|
|
|
th->area->ExitThread=ExitThread;
|
|
|
|
th->area->gp=th->gp;
|
|
|
|
th->area->attr=(th->attr & TH_COP) | 0x404;
|
|
|
|
th->area->attr|=th->attr & TH_UMODE;
|
|
|
|
th->area->entry->th->thp_entry;
|
|
|
|
th->ei=1;
|
|
|
|
LL_remove(th);
|
|
|
|
return run(th, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[06]
|
|
|
|
int StartThread(int thid,u_long arg){
|
|
|
|
int x;
|
|
|
|
register struct TCB *th, *p;
|
|
|
|
|
|
|
|
if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT;
|
|
|
|
if (thid==0) return KE_ILLEGAL_THID;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
th=(struct TCB *)(thid>>7<<2);
|
|
|
|
if ((th->_7F01 != 0x7F01) ||
|
|
|
|
(((thid>>1) & 0x3F) != (th->id & 0x3F))){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_UNKNOWN_THID;
|
|
|
|
}
|
|
|
|
if (th->status != THS_DORMANT){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_NOT_DORMANT;
|
|
|
|
}
|
|
|
|
th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8;
|
|
|
|
memset(th->area, 0, 0xB8);
|
|
|
|
th->area->arg=arg;
|
|
|
|
return startThread(th, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[07]
|
|
|
|
int StartThreadArgs(int thid,int args,void *argp){
|
|
|
|
int x;
|
|
|
|
register struct TCB *th, *p;
|
|
|
|
register void *_argp;
|
|
|
|
|
|
|
|
if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT;
|
|
|
|
if (thid==0) return KE_ILLEGAL_THID;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
th=(struct TCB *)(thid>>7<<2);
|
|
|
|
if ((th->_7F01 != 0x7F01) ||
|
|
|
|
(((thid>>1) & 0x3F) != (th->id & 0x3F))){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_UNKNOWN_THID;
|
|
|
|
}
|
|
|
|
if (th->status != THS_DORMANT){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_NOT_DORMANT;
|
|
|
|
}
|
|
|
|
|
|
|
|
_argp=th->stack + ((th->thp_stackSize >> 2) - ((args+3) >> 2)) << 2
|
|
|
|
if (args>0 && argp)
|
|
|
|
memcpy(_argp, argp, args);
|
|
|
|
|
|
|
|
memset(th->area, 0, 0xB8); //BUG: these instructions should be switched!
|
|
|
|
th->area = th->stack + ((th->thp_stackSize >> 2) << 2) - 0xB8;
|
|
|
|
|
|
|
|
th->area->arg =args;
|
|
|
|
th->area->argp=_argp;
|
|
|
|
return startThread(th, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[08]
|
|
|
|
int ExitThread(){
|
|
|
|
th=ready->next;
|
|
|
|
if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
th->status=THS_DORMANT;
|
|
|
|
LL_add_before(&threads_list, th);
|
|
|
|
a0=0;
|
|
|
|
do{
|
|
|
|
ready.prev=0;
|
|
|
|
syscall_32(0, 0, x, 0);
|
|
|
|
Kprintf("panic ! Thread DORMANT !\n");
|
|
|
|
__asm break #0x400
|
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[09]
|
|
|
|
int ExitDeleteThread(){
|
|
|
|
return KE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////[10]
|
|
|
|
int TerminateThread(int thid){
|
|
|
|
int x;
|
|
|
|
register struct TCB *th, *p;
|
|
|
|
|
|
|
|
if (QueryIntrContext()) return KE_ILLEGAL_CONTEXT;
|
|
|
|
if (thid==0) return KE_ILLEGAL_THID;
|
|
|
|
|
|
|
|
CpuSuspendIntr(&x);
|
|
|
|
th=(struct TCB *)(thid>>7<<2);
|
|
|
|
if (ready.next==th){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_ILLEGAL_THID;
|
|
|
|
}
|
|
|
|
if ((th->_7F01 != 0x7F01) ||
|
|
|
|
(((thid>>1) & 0x3F) != (th->id & 0x3F))){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_UNKNOWN_THID;
|
|
|
|
}
|
|
|
|
if (th->status == THS_DORMANT){
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_DORMANT;
|
|
|
|
}
|
|
|
|
LL_remove(th);
|
|
|
|
if (th->status==THS_WAIT)
|
|
|
|
if (th->field_1C==2)
|
|
|
|
CancelAlarm(alarmhandler, th);
|
|
|
|
else
|
|
|
|
if (th->field_1C>=2) && (th->field_1C<8)
|
|
|
|
th->field_20->H10--;
|
|
|
|
th->status=THS_DORMANT;
|
|
|
|
LL_add_before(&threads_list, th);
|
|
|
|
|
|
|
|
CpuResumeIntr(x);
|
|
|
|
return KE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void LL_add_before(struct ll *list, struct ll *new){
|
|
|
|
new->next=list;
|
|
|
|
new->prev=list->prev;
|
|
|
|
list->prev=new;
|
|
|
|
new->prev->next=new;
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////:)
|
|
|
|
int getHighestUsed_32(int flags_32){
|
|
|
|
v=-4;
|
|
|
|
do{
|
|
|
|
i=flags_32<<28;
|
|
|
|
flags_32>>=4;
|
|
|
|
v+=4;
|
|
|
|
}while(i==0);
|
|
|
|
return v + ((0x1020103 >> ((i>>26) & 0x1C)) & 0xF);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|