templeos-info/public/Wb/Kernel/KTask.HC

546 lines
13 KiB
HolyC
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

U0 Exit()
{//Terminate own task.
if (Fs==sys_focus_task && IsDbgMode) {
LBts(&Fs->task_flags,TASKf_KILL_AFTER_DBG);
G;
} else {
if (sys_staff_mode_flag)
AdamLog("%p:%p:%p:%p:%p:%p\n",Caller(0),Caller(1),Caller(2),Caller(3),
Caller(4),Caller(5),Caller(6),Caller(7));
if (!Gs->num && !IsDbgMode)
SingleUser(OFF);
Fs->rflags=GetRFlags;
Fs->rsp=GetRSP;
Fs->rbp=GetRBP;
Fs->rip=$$;
CLI
LBts(&Fs->task_flags,TASKf_KILL_TASK);
TaskEndNow;
}
}
Bool TaskValidate(CTask *task)
{//return TRUE if task looks valid.
if (!(0<task<=I32_MAX) || task->addr!=task ||
task->task_signature!=TASK_SIGNATURE_VAL)
return FALSE;
else
return TRUE;
}
I64 BirthWait(CTask **_task,I64 task_num=-1)
{//Wait for task valid and not task_num.
while (!TaskValidate(*_task)||(*_task)->task_num==task_num)
Yield;
return (*_task)->task_num;
}
U0 DeathWait(CTask **_task,Bool send_exit=FALSE)
{//Wait for task death.
if (send_exit && TaskValidate(*_task)) {
TaskWait(*_task,TRUE);
XTalk(*_task,"Exit;\n");
}
while (TaskValidate(*_task))
Yield;
}
Bool Kill(CTask *task,Bool wait=TRUE,Bool just_break=FALSE)
{//Terminate other task.
I64 i;
if (TaskValidate(task)) {
if (just_break) {
if (task!=Fs)
Break;
else {//TODO wait
sys_focus_task=task;
LBts(sys_ctrl_alt_flags,CTRL_ALT_C);
return TRUE;
}
} else {
if (task!=sys_winmgr_task) {
for (i=0;i<mp_cnt;i++)
if (task==cpu_structs[i].seth_task)
return FALSE;
LBts(&task->task_flags,TASKf_KILL_TASK);
if (wait) {
do Yield;
while (TaskValidate(task) && Bt(&task->task_flags,TASKf_KILL_TASK));
}
return TRUE;
}
}
}
return FALSE;
}
Bool Suspend(CTask *task=NULL,Bool state=TRUE)
{//Tell scheduler to skip task.
Bool res;
if (!task) task=Fs;
PUSHFD
CLI
if (TaskValidate(task))
res=LBEqu(&task->task_flags,TASKf_SUSPENDED,state);
else
res=FALSE;
POPFD
return res;
}
Bool IsSuspended(CTask *task=NULL)
{//You might use this in a DrawIt() or Animatetask().
if (!task) task=Fs;
if (TaskValidate(task))
return Bt(&task->task_flags,TASKf_SUSPENDED);
else
return FALSE;
}
CTaskStk *TaskStkNew(I64 stk_size,CTask *task)
{
CTaskStk *tmps=MAlloc(stk_size+offset(CTaskStk.stk_base),task);
tmps->next_stk=NULL;
tmps->stk_ptr=NULL;
tmps->stk_size=MSize(tmps)-offset(CTaskStk.stk_base);
return tmps;
}
#exe {Option(OPTf_NO_REG_VAR,ON);};
argpop I64 CallStkGrow(I64 stk_size_threshold,I64 stk_size,
/*argpop*/I64 (*fp_addr)(...),...)
{//Grow stk in call with any fixed num of args.
//See $LK,"::/Demo/StkGrow.HC"$.
CTaskStk *tmps,*tmps2,**_stk;
I64 res,*rsp,*rsp2,*old_stk;
if (UnusedStk>=stk_size_threshold) {
asm {
LEAVE
POP RAX //return addr
ADD RSP,16 //pop threshold,stk_size
POP RBX // *f
ADD RSP,8 //pop ARGC
PUSH RAX
JMP RBX //CALL fp_addr()
};
} else {
tmps2=TaskStkNew(stk_size,Fs);
tmps2->next_stk=tmps=Fs->stk;
rsp2=(&tmps2->stk_base)(U8 *)+tmps2->stk_size;
old_stk=rsp=&argv[argc];
while (argc-->0)
*--rsp2=*--rsp;
_stk=&Fs->stk;
tmps->stk_ptr=rsp=GetRSP;
asm {
IMPORT _FREE; //We are in a function, not at glbl scope.
//The compiler treats these in isolation.
PUSHFD
POP RDX //flags
CLI
MOV RBX,U64 &tmps2[RBP]
MOV RAX,&_stk[RBP]
MOV U64 [RAX],RBX //Fs->stk=tmps2
MOV RSP,U64 &rsp2[RBP]
PUSH RDX
POPFD
CALL U64 &fp_addr[RBP]
MOV U64 &res[RBP],RAX
PUSHFD
POP RDX //flags
CLI
MOV RBX,U64 &tmps[RBP]
MOV RAX,&_stk[RBP]
MOV U64 [RAX],RBX //Fs->stk=tmps
MOV RSP,U64 &rsp[RBP]
PUSH RDX
POPFD
PUSH U64 &tmps2[RBP]
CALL _FREE
MOV RDX,U64 &old_stk[RBP]
MOV RBX,U64 8[RBP]
MOV RAX,U64 &res[RBP]
MOV RBP,U64 [RBP]
MOV RSP,RDX
JMP RBX //return
};
}
return 0; //dummy to get rid of warning
}
;
#exe {Option(OPTf_NO_REG_VAR,OFF);};
I64 TaskInit(CTask *task,I64 stk_size)
{//Returns Fs of task
CTaskStk *tmps;
QueInit(&task->code_heap->next_mem_blk);
task->code_heap->last_mergable=NULL;
if (task->code_heap!=task->data_heap) {
QueInit(&task->data_heap->next_mem_blk);
task->data_heap->last_mergable=NULL;
}
task->addr=task->next_task=task->last_task=
task->next_input_filter_task=task->last_input_filter_task=
task;
task->task_num=sys_num_spawned_tasks++;
task->rflags=RFLAGG_NORMAL;
task->win_inhibit=WIG_TASK_DFT;
task->next_child_task=task->last_child_task=
(&task->next_child_task)(U8 *)-offset(CTask.next_sibling_task);
JobCtrlInit(&task->srv_ctrl);
QueInit(&task->next_cc);
QueInit(&task->next_except);
QueInit(&task->next_ctrl);
QueInit(&task->next_ode);
task->fpu_mmx=MAllocAligned(sizeof(CFPU),0x10,task);
MemCpy(task->fpu_mmx,
SYS_FIXED_AREA+offset(CSysFixedArea.init_fpu_mmx),sizeof(CFPU));
task->hash_table=HashTableNew(TASK_HASH_TABLE_SIZE,task);
if (!stk_size)
stk_size=MEM_DFT_STK;
task->stk=tmps=TaskStkNew(stk_size,task);
task->rsp=(&tmps->stk_base)(U8 *)+tmps->stk_size;
task->text_attr =WHITE<<4+BLUE;
task->border_src =BDS_CONST;
task->border_attr =DrvTextAttrGet(':');
task->title_src =TTS_CONST;
task->win_left =1;
task->win_right =text.cols-2;
task->win_top =13;
task->win_bottom =text.rows-2;
if (blkdev.home_dir) {//Beware Adam $LK,"TaskInit",A="FF:::/Kernel/KStart64.HC,TaskInit"$. I guess ok until $LK,"DskChg",A="FF:::/Kernel/KMain.HC,DskChg"$().
task->cur_dv=blkdev.let_to_drv[*blkdev.home_dir-'A'];
task->cur_dir=StrNew(blkdev.home_dir+2,task);
} else
task->cur_dir=StrNew("/Home",task);
Seed(,task);
return task;
}
CTask *Spawn(U0 (*fp_start_addr)(U8 *data),U8 *data=NULL,U8 *task_name=NULL,
I64 target_cpu=-1, //-1 for current CPU. See $LK,"multi-core",A="FI:::/Demo/MultiCore/LoadTest.HC"$.
CTask *parent=NULL, //NULL means adam
I64 stk_size=0, //0=default
I64 flags=1<<JOBf_ADD_TO_QUE)
{//Create task on core running at address.
//Alloc $LK,"CTask",A="MN:CTask"$ structure from code heap so addr will be short.
//Could be alloced off of data heap.
CTask *task;
if (target_cpu>=0)
return SpawnQue(fp_start_addr,data,task_name,target_cpu,
parent,stk_size,flags);
task=CAlloc(sizeof(CTask),adam_task->code_heap);
task->task_signature=TASK_SIGNATURE_VAL;
if (!task_name) task_name="Unnamed Task";
if (!parent) parent=Gs->seth_task;
task->parent_task=parent;
task->gs=parent->gs;
if (sys_code_bp)
task->code_heap=HeapCtrlInit(,task,sys_code_bp);
if (sys_data_bp)
task->data_heap=HeapCtrlInit(,task,sys_data_bp);
else
task->data_heap=task->code_heap;
TaskInit(task,stk_size);
task->rip=fp_start_addr;
task->rsp(U8 *)-=8;
*task->rsp=data;
task->rsp(U8 *)-=8;
*task->rsp=&Exit;
task->hash_table->next=parent->hash_table;
MemCpy(task->task_name,task_name,TASK_NAME_LEN);
StrCpy(task->task_title,task->task_name);
task->title_src=TTS_TASK_NAME;
PUSHFD
CLI
if (Bt(&flags,JOBf_ADD_TO_QUE)) {
TaskQueInsChild(task);
TaskQueIns(task);
}
POPFD
return task;
}
U0 TaskDerivedValsUpdate(CTask *task=NULL,Bool update_z_buf=TRUE)
{//Those things calculated from other variables.
if (!task) task=Fs;
PUSHFD
CLI
while (LBts(&task->task_flags,TASKf_TASK_LOCK))
PAUSE
WinDerivedValsUpdate(task);
if (fp_update_ctrls)
(*fp_update_ctrls)(task);
if (update_z_buf && Bt(&task->display_flags,DISPLAYf_SHOW))
LBts(&sys_semas[SEMA_UPDATE_WIN_Z_BUF],0);
LBtr(&task->task_flags,TASKf_TASK_LOCK);
POPFD
}
I64 ExeCmdLine(CCmpCtrl *cc)
{//Terminal JIT-compile-and-execute loop for CCmpCtrl.
I64 res=0,type,old_title_src=Fs->title_src;
U8 *ptr,*ptr2,*ptr3,*machine_code,*old_task_title=StrNew(Fs->task_title);
F64 t0;
CDocEntry *doc_e;
CDoc *doc;
if (Fs->title_src!=TTS_LOCKED_CONST)
Fs->title_src=TTS_CUR_LEX;
while (cc->token &&
(cc->token!='}' || !(cc->flags & CCF_EXE_BLK)) ) {
if (Fs->title_src==TTS_CUR_LEX) {
ptr2=&Fs->task_title;
ptr3=ptr2+STR_LEN-1;
if (cc->lex_include_stk->flags & LFSF_DOC) {
doc_e=cc->lex_include_stk->cur_entry;
doc=cc->lex_include_stk->doc;
while (doc_e!=doc && ptr2<ptr3) {
switch (doc_e->type_u8) {
case DOCT_TEXT:
ptr=doc_e->tag;
while (*ptr && ptr2<ptr3)
*ptr2++=*ptr++;
break;
case DOCT_TAB:
case DOCT_NEW_LINE:
*ptr2++='.';
break;
}
doc_e=doc_e->next;
}
if (ptr2<ptr3) *ptr2=0;
} else
if ((ptr=cc->lex_include_stk->line_start) && *ptr)
MemCpy(ptr2,ptr,STR_LEN-1);
}
cc->flags&=~CCF_HAS_MISC_DATA;
machine_code=LexStmt2Bin(cc,&type);
if (machine_code!=INVALID_PTR) {
if (!(cc->flags&CCF_JUST_LOAD)) {
t0=tS;
res=Call(machine_code);
Fs->answer=res;
Fs->answer_type=type;
Fs->answer_time=tS-t0;
Fs->new_answer=TRUE;
cc->pmt_line=0;
}
if (!(cc->flags&CCF_HAS_MISC_DATA))
Free(machine_code);
}
}
if (Fs->title_src!=TTS_LOCKED_CONST) {
Fs->title_src=old_title_src;
StrCpy(Fs->task_title,old_task_title);
}
Free(old_task_title);
if (cc->flags&CCF_JUST_LOAD) {
if (cc->error_cnt)
return FALSE;
else
return TRUE;
} else
return res;
}
U0 SrvTaskCont()
{//Act as server task in a loop handling commands.
I64 old_flags=GetRFlags;
FlushMsgs;
while (TRUE) {
CLI
if (JobsHndlr(old_flags) && Fs->title_src==TTS_TASK_NAME)
MemCpy(Fs->task_title,Fs->task_name,TASK_NAME_LEN);
FlushMsgs;
LBts(&Fs->task_flags,TASKf_IDLE);
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
Yield;
SetRFlags(old_flags);
}
}
U0 UserTaskCont()
{//Terminal key-input-execute loop.
CCmpCtrl *cc;
CDoc *doc;
Bool cont=TRUE;
do {
cc=CmpCtrlNew(,CCF_CMD_LINE|CCF_PMT|CCF_QUESTION_HELP);
QueIns(cc,Fs->last_cc);
try {
Lex(cc);
ExeCmdLine(cc);
cont=Bt(&cc->flags,CCf_PMT);
QueRem(cc);
CmpCtrlDel(cc);
} catch {
if ((doc=Fs->put_doc) && doc->doc_signature==DOC_SIGNATURE_VAL)
DocUnlock(doc);
PutExcept;
}
} while (cont);
}
U0 SrvCmdLine(I64 dummy=0)
{
no_warn dummy;
Fs->win_inhibit=WIG_USER_TASK_DFT;
CallExtStr("SrvStartUp");
SrvTaskCont;
}
U0 UserCmdLine(I64 dummy=0)
{//A user task ends-up calling this.
no_warn dummy;
Fs->win_inhibit=WIG_USER_TASK_DFT;
CallExtStr("UserStartUp");
if (!LBts(&Fs->display_flags,DISPLAYf_SHOW))
Dbg;
UserTaskCont;
}
CTask *User(U8 *fmt=NULL,...)
{//Create user term task.
U8 *st;
CTask *task=Spawn(&UserCmdLine);
TaskWait(task);
if (fmt) {
st=StrPrintJoin(NULL,fmt,argc,argv);
XTalk(task,st);
Free(st);
}
return task;
}
U0 TaskDel(CTask *task)
{//We delay freeing in case lingering ptr to reincarnated.
HeapCtrlDel(task->code_heap);
if (task->data_heap!=task->code_heap)
HeapCtrlDel(task->data_heap);
Free(task);
}
I64 TaskEnd()
{//Called with irq's off.
CTask *task=Fs,*tmpt,*tmpt1;
if (task==sys_task_being_scrn_updated) {
LBts(&task->task_flags,TASKf_KILL_TASK);
return task->next_task;
}
if (task->task_end_cb) {
task->wake_jiffy=0;
LBtr(&task->task_flags,TASKf_KILL_TASK);
TaskRstAwaitingMsg(task);
Suspend(task,FALSE);
task->rip=task->task_end_cb;
task->task_end_cb=NULL;
return task;
}
if (task->parent_task && task->parent_task->popup_task==task) {
task->parent_task->popup_task=NULL;
Kill(task->parent_task,FALSE);
return task->parent_task;
}
DrvsRelease;
BlkDevsRelease;
tmpt1=(&task->next_child_task)(U8 *)-offset(CTask.next_sibling_task);
tmpt=tmpt1->next_sibling_task;
if (tmpt!=tmpt1) {
do {
LBts(&tmpt->task_flags,TASKf_KILL_TASK);
tmpt=tmpt->next_sibling_task;
} while (tmpt!=tmpt1);
return task->next_task;
}
if (LBtr(&task->display_flags,DISPLAYf_SHOW))
LBts(&sys_semas[SEMA_UPDATE_WIN_Z_BUF],0);
while (LBts(&task->task_flags,TASKf_TASK_LOCK))
PAUSE
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
JobQueDel(&task->srv_ctrl.next_waiting);
JobQueDel(&task->srv_ctrl.next_done);
if (IsRaw)
VGAFlush;
if (sys_focus_task==task) {
if (!Gs->num)
SingleUser(OFF);
sys_focus_task=NULL;
if (fp_set_std_palette)
(*fp_set_std_palette)();
}
//QueRem
task->task_signature(I64)=0;
tmpt =task->next_input_filter_task;
tmpt1=task->last_input_filter_task;
tmpt1->next_input_filter_task=tmpt;
tmpt ->last_input_filter_task=tmpt1;
tmpt =task->next_sibling_task;
tmpt1=task->last_sibling_task;
tmpt1->next_sibling_task=tmpt;
tmpt ->last_sibling_task=tmpt1;
tmpt =task->next_task; //save to return
TaskQueRem(task);
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
LBtr(&task->task_flags,TASKf_TASK_LOCK);
task->wake_jiffy=cnts.jiffies+DYING_JIFFIES;
while (LBts(&Gs->cpu_flags,CPUf_DYING_TASK_QUE))
PAUSE
QueIns(task,Gs->last_dying);
LBtr(&Gs->cpu_flags,CPUf_DYING_TASK_QUE);
return tmpt;
}
U0 TaskKillDying()
{//Delay freeing to prevent asking for trouble with quick reincarnations.
//What if the user is doing this: $LK,"DoTreeCheckers",A="FF:::/Misc/OSTestSuite.HC,DoTreeCheckers"$.
CTaskDying *task,*task1;
if (Gs->kill_jiffy<cnts.jiffies) {//Avoid doing as many lock operations.
while (LBts(&Gs->cpu_flags,CPUf_DYING_TASK_QUE))
PAUSE
task=Gs->next_dying;
while (task!=&Gs->next_dying && task->wake_jiffy<cnts.jiffies) {
task1=task->next;
QueRem(task);
TaskDel(task);
task=task1;
}
LBtr(&Gs->cpu_flags,CPUf_DYING_TASK_QUE);
Gs->kill_jiffy=cnts.jiffies+DYING_JIFFIES;
}
}