ZealOS/src/Kernel/Job.HC

503 lines
13 KiB
HolyC
Raw Normal View History

2020-02-15 20:01:48 +00:00
U0 JobDel(CJob *tmpc)
{//Free one cmd node.
Free(tmpc->aux_str);
Free(tmpc);
}
2020-02-15 22:53:02 +00:00
U0 JobQueueDel(CJob *head)
2020-02-15 20:01:48 +00:00
{
CJob *tmpc=head->next,*tmpc1;
while (tmpc!=head) {
tmpc1=tmpc->next;
2020-02-15 23:13:27 +00:00
QueueRemove(tmpc);
2020-02-15 20:01:48 +00:00
JobDel(tmpc);
tmpc=tmpc1;
}
}
U0 JobCtrlInit(CJobCtrl *ctrl)
{
2020-02-15 22:53:02 +00:00
QueueInit(&ctrl->next_waiting);
QueueInit(&ctrl->next_done);
2020-02-15 20:01:48 +00:00
ctrl->flags=0;
}
2020-02-16 00:54:39 +00:00
U0 TaskResetAwaitingMessage(CTask *task=NULL)
2020-02-15 23:56:05 +00:00
{//Pop-ups get parent messages so wake-up our pop-ups if we got a message.
2020-02-15 20:01:48 +00:00
if (!task) task=Fs;
PUSHFD
CLI
do {
if (TaskValidate(task))
2020-02-15 23:56:05 +00:00
LBtr(&task->task_flags,TASKf_AWAITING_MESSAGE);
2020-02-15 20:01:48 +00:00
else
break;
} while (task=task->popup_task);
POPFD
}
CJob *TaskExe(CTask *srv,CTask *master,U8 *data,I64 flags)
2020-02-15 22:53:02 +00:00
{//Queueues a request to compile and execute src code text.
2020-02-15 20:01:48 +00:00
CJob *res;
if (!data || !TaskValidate(srv) || master && !TaskValidate(master) ||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
return NULL;
2020-02-16 02:38:13 +00:00
res=ZCAlloc(sizeof(CJob));
2020-02-15 20:01:48 +00:00
res->master_task=master;
res->job_code=JOBT_EXE_STR;
res->flags=flags;
2020-02-16 02:38:13 +00:00
res->aux_str=ZStrNew(data);
2020-02-15 20:01:48 +00:00
res->ctrl=&srv->srv_ctrl;
PUSHFD
CLI
while (LBts(&srv->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (!TaskValidate(srv)) {
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
POPFD
JobDel(res);
return NULL;
} else {
LBtr(&srv->task_flags,TASKf_IDLE);
2020-02-16 00:54:39 +00:00
TaskResetAwaitingMessage(srv);
2020-02-15 22:53:02 +00:00
QueueInsert(res,srv->srv_ctrl.last_waiting);
2020-02-15 20:01:48 +00:00
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
if (Bt(&flags,JOBf_WAKE_MASTER)) {
Suspend(master);
Yield;
}
}
POPFD
return res;
}
CJob *TaskText(CTask *srv,CTask *master,U8 *data,I64 flags)
{//Post StdIn text to servant task. Tell who the master task is.
CJob *res;
CTask *task;
if (!data || !TaskValidate(srv) || master && !TaskValidate(master) ||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
return NULL;
2020-02-16 02:38:13 +00:00
res=ZCAlloc(sizeof(CJob));
2020-02-15 20:01:48 +00:00
res->master_task=master; //in case somebody cares
res->job_code=JOBT_TEXT_INPUT;
res->flags=flags;
2020-02-16 02:38:13 +00:00
res->aux_str=ZStrNew(data);
2020-02-15 20:01:48 +00:00
PUSHFD
task=srv->last_input_filter_task;
if (Bt(&flags,JOBf_HIGHEST_PRIORITY) || task==srv) {
if (task!=srv)
TaskWait(srv);
task=Spawn(&InputFilterTask,NULL,"Input Filter",,srv);
CLI
task->next_input_filter_task=srv->next_input_filter_task;
task->last_input_filter_task=srv;
srv->next_input_filter_task=task;
task->next_input_filter_task->last_input_filter_task=task;
} else {
CLI
task=srv->next_input_filter_task;
}
res->ctrl=&task->srv_ctrl;
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (!TaskValidate(task)) {
JobDel(res);
res=NULL;
} else {
LBtr(&task->task_flags,TASKf_IDLE);
2020-02-16 00:54:39 +00:00
TaskResetAwaitingMessage(task);
2020-02-15 22:53:02 +00:00
QueueInsert(res,task->srv_ctrl.last_waiting);
2020-02-15 20:01:48 +00:00
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
}
POPFD
return res;
}
2020-02-15 23:56:05 +00:00
CJob *TaskMessage(CTask *_srv,CTask *master,
I64 message_code,I64 arg1,I64 arg2,I64 flags)
2020-02-15 20:01:48 +00:00
{//Post message to servant task. Tell who the master task is.
2020-02-15 23:56:05 +00:00
//See $LK,"flags",A="MN:JOBf_WAKE_MASTER"$ and $LK,"message_code",A="MN:MESSAGE_CMD"$.
2020-02-15 20:01:48 +00:00
CJob *tmpc1,*tmpc;
CTask *srv=_srv;
if (!TaskValidate(srv) || master && !TaskValidate(master)||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
return NULL;
2020-02-16 02:38:13 +00:00
tmpc=ZCAlloc(sizeof(CJob));
2020-02-15 20:01:48 +00:00
tmpc->master_task=master;
2020-02-15 23:56:05 +00:00
tmpc->job_code=JOBT_MESSAGE;
tmpc->message_code=AbsI64(message_code); //negative means do a down and up
2020-02-15 20:01:48 +00:00
tmpc->aux1=arg1;
tmpc->aux2=arg2;
tmpc->flags=flags;
PUSHFD
if (Bt(&sys_semas[SEMA_RECORD_MACRO],0) &&
2020-02-15 23:56:05 +00:00
srv!=sys_macro_task && message_code==MESSAGE_KEY_DOWN) {
2020-02-16 02:38:13 +00:00
tmpc1=ZMAllocIdent(tmpc);
2020-02-15 20:01:48 +00:00
CLI
2020-02-15 22:53:02 +00:00
QueueInsert(tmpc1,sys_macro_head.last);
2020-02-15 20:01:48 +00:00
}
CLI
while (Bt(&srv->task_flags,TASKf_FILTER_INPUT) &&
!Bt(&flags,JOBf_DONT_FILTER))
srv=srv->next_input_filter_task;
tmpc->ctrl=&srv->srv_ctrl;
while (LBts(&srv->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (!TaskValidate(srv)) {
JobDel(tmpc);
tmpc=NULL;
} else {
LBtr(&srv->task_flags,TASKf_IDLE);
2020-02-16 00:54:39 +00:00
TaskResetAwaitingMessage(srv);
2020-02-15 22:53:02 +00:00
QueueInsert(tmpc,srv->srv_ctrl.last_waiting);
2020-02-15 20:01:48 +00:00
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
}
POPFD
2020-02-15 23:56:05 +00:00
if (message_code<0) //Down-Up
TaskMessage(_srv,master,-message_code+1,arg1,arg2,flags);
2020-02-15 20:01:48 +00:00
return tmpc;
}
2020-02-16 03:41:28 +00:00
Bool JobResScan(CJob *request=NULL,I64 *_res=NULL)
{//Check request complete, return with or without.
2020-02-15 20:01:48 +00:00
CJobCtrl *ctrl;
CJob *tmpc,*tmpc1;
2020-02-16 03:41:28 +00:00
if (!request || Bt(&request->flags,JOBf_DONE)) {
if (!request || request->master_task)
2020-02-15 20:01:48 +00:00
ctrl=&Fs->srv_ctrl;
else
2020-02-16 03:41:28 +00:00
ctrl=request->ctrl;
2020-02-15 20:01:48 +00:00
PUSHFD
CLI
while (LBts(&ctrl->flags,JOBCf_LOCKED))
PAUSE
tmpc1=&ctrl->next_done;
tmpc=tmpc1->next;
while (tmpc!=tmpc1) {
2020-02-16 03:41:28 +00:00
if (!request || request==tmpc) {
2020-02-15 23:13:27 +00:00
QueueRemove(tmpc);
2020-02-15 20:01:48 +00:00
LBtr(&ctrl->flags,JOBCf_LOCKED);
POPFD
if (_res)
*_res=tmpc->res;
JobDel(tmpc);
return TRUE;
}
tmpc=tmpc->next;
}
LBtr(&ctrl->flags,JOBCf_LOCKED);
POPFD
}
if (_res)
*_res=0;
return FALSE;
}
2020-02-16 03:41:28 +00:00
I64 JobResGet(CJob *request=NULL)
2020-02-15 20:01:48 +00:00
{//See $LK,"::/Demo/MultiCore/Lock.HC"$
I64 res;
CJob *tmpc1;
2020-02-16 03:41:28 +00:00
if (!request) {
2020-02-15 20:01:48 +00:00
tmpc1=&Fs->srv_ctrl.next_done;
while (tmpc1==tmpc1->next) {
LBts(&Fs->task_flags,TASKf_IDLE);
Yield;
}
} else {
2020-02-16 03:41:28 +00:00
while (!Bt(&request->flags,JOBf_DONE)) {
2020-02-15 20:01:48 +00:00
LBts(&Fs->task_flags,TASKf_IDLE);
Yield;
}
}
LBtr(&Fs->task_flags,TASKf_IDLE);
//Could get taken by someone else.
2020-02-16 03:41:28 +00:00
JobResScan(request,&res);
2020-02-15 20:01:48 +00:00
return res;
}
2020-02-16 01:19:05 +00:00
U0 TaskWait(CTask *task=NULL,Bool cmd_line_prompt=FALSE)
2020-02-15 20:01:48 +00:00
{//Wait for idle.
CTask *task1;
CJob *tmpc1;
if (!task) task=Fs;
if (TaskValidate(task)) {
PUSHFD
CLI
while (TRUE) {
task1=task->last_input_filter_task;
tmpc1=&task1->srv_ctrl.next_waiting;
if (task1==Fs || !TaskValidate(task1) ||
tmpc1==tmpc1->next && Bt(&task1->task_flags,TASKf_IDLE) &&
2020-02-16 01:19:05 +00:00
(!cmd_line_prompt || Bt(&task1->task_flags,TASKf_CMD_LINE_PROMPT)))
2020-02-15 20:01:48 +00:00
break;
Yield;
}
POPFD
}
}
2020-02-15 23:56:05 +00:00
U0 PostMessage(CTask *task,I64 message_code,I64 arg1,I64 arg2,I64 flags=0)
{//Post message to a task and return immediately. See $LK,"message_code",A="MN:MESSAGE_CMD"$.
2020-02-15 20:01:48 +00:00
if (TaskValidate(task)) {
if (Bt(&task->task_flags,TASKf_INPUT_FILTER_TASK))
2020-02-15 23:56:05 +00:00
TaskMessage(task->last_input_filter_task,NULL,message_code,arg1,arg2,
2020-02-15 20:01:48 +00:00
flags|1<<JOBf_DONT_FILTER);
else
2020-02-15 23:56:05 +00:00
TaskMessage(task,NULL,message_code,arg1,arg2,flags);
2020-02-15 20:01:48 +00:00
}
}
2020-02-15 23:56:05 +00:00
U0 PostMessageWait(CTask *task,I64 message_code,I64 arg1,I64 arg2,I64 flags=0)
{//Post message to a task and wait until task is idle.See $LK,"message_code",A="MN:MESSAGE_CMD"$.
PostMessage(task,message_code,arg1,arg2,flags);
2020-02-15 20:01:48 +00:00
TaskWait(task);
}
2020-02-15 23:56:05 +00:00
U0 Message(I64 message_code,I64 arg1,I64 arg2,I64 flags=0)
2020-02-15 20:01:48 +00:00
{//Post message to current task and return immediately.
2020-02-15 23:56:05 +00:00
//See $LK,"message_code",A="MN:MESSAGE_CMD"$.
PostMessage(Fs,message_code,arg1,arg2,flags);
2020-02-15 20:01:48 +00:00
}
#define JOB_DONE 0
#define JOB_CONT 1
#define JOB_EXIT 2
I64 JobRunOne(I64 run_flags,CJobCtrl *ctrl)
{//Called with ctrl->flags,JOBCf_LOCKED.
CJob *tmpc=ctrl->next_waiting;
CTask *master;
I64 res,flags=tmpc->flags,old_flags=GetRFlags;
if (Bt(&flags,JOBf_EXIT_ON_COMPLETE))
res=JOB_EXIT;
else
res=JOB_CONT;
switch (tmpc->job_code) {
case JOBT_SPAWN_TASK:
2020-02-15 23:13:27 +00:00
QueueRemove(tmpc);
2020-02-15 20:01:48 +00:00
LBts(&tmpc->flags,JOBf_DISPATCHED);
LBtr(&ctrl->flags,JOBCf_LOCKED);
if (tmpc->aux_str)
tmpc->spawned_task=Spawn(tmpc->addr,tmpc->fun_arg,
tmpc->aux_str,,tmpc->aux1,tmpc->aux2,tmpc->flags);
else
tmpc->spawned_task=Spawn(tmpc->addr,tmpc->fun_arg,
"Unnamed",,tmpc->aux1,tmpc->aux2,tmpc->flags);
break;
case JOBT_CALL:
2020-02-15 23:13:27 +00:00
QueueRemove(tmpc);
2020-02-15 20:01:48 +00:00
LBts(&tmpc->flags,JOBf_DISPATCHED);
LBtr(&ctrl->flags,JOBCf_LOCKED);
SetRFlags(run_flags);
LBtr(&Fs->task_flags,TASKf_IDLE);
try
tmpc->res=(*tmpc->addr)(tmpc->fun_arg);
catch
Fs->catch_except=TRUE;
SetRFlags(old_flags);
break;
case JOBT_EXE_STR:
2020-02-15 23:13:27 +00:00
QueueRemove(tmpc);
2020-02-15 20:01:48 +00:00
LBts(&tmpc->flags,JOBf_DISPATCHED);
LBtr(&ctrl->flags,JOBCf_LOCKED);
SetRFlags(run_flags);
LBtr(&Fs->task_flags,TASKf_IDLE);
try
tmpc->res=ExePrint("%s",tmpc->aux_str);
catch
Fs->catch_except=TRUE;
SetRFlags(old_flags);
break;
default:
res=JOB_DONE;
}
if (res) {
if (master=tmpc->master_task) {
if (!Bt(&flags,JOBf_FREE_ON_COMPLETE)) {
CLI
while (LBts(&master->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
2020-02-15 22:53:02 +00:00
QueueInsert(tmpc,master->srv_ctrl.last_done);
2020-02-15 20:01:48 +00:00
LBts(&tmpc->flags,JOBf_DONE);
LBtr(&master->srv_ctrl.flags,JOBCf_LOCKED);
SetRFlags(old_flags);
}
if (Bt(&flags,JOBf_FOCUS_MASTER) &&
!Bt(&master->win_inhibit,WIf_SELF_FOCUS))
sys_focus_task=master;
if (Bt(&flags,JOBf_WAKE_MASTER))
Suspend(master,FALSE);
}
if (Bt(&flags,JOBf_FREE_ON_COMPLETE))
JobDel(tmpc);
else if (!master) {
CLI
while (LBts(&ctrl->flags,JOBCf_LOCKED))
Yield;
2020-02-15 22:53:02 +00:00
QueueInsert(tmpc,ctrl->last_done);
2020-02-15 20:01:48 +00:00
LBts(&tmpc->flags,JOBf_DONE);
LBtr(&ctrl->flags,JOBCf_LOCKED);
SetRFlags(old_flags);
}
}
return res;
}
2020-02-15 23:09:55 +00:00
I64 JobsHandler(I64 run_flags,CTask *task=NULL)
2020-02-15 20:01:48 +00:00
{//Handle all waiting cmds and return.
2020-02-16 00:20:04 +00:00
I64 count=0,old_flags=GetRFlags;
2020-02-15 20:01:48 +00:00
if (!task) task=Fs;
while (TRUE) {
CLI
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
PAUSE
if (task->srv_ctrl.next_waiting!=&task->srv_ctrl)
switch (JobRunOne(run_flags,&task->srv_ctrl)) {
case JOB_CONT:
2020-02-16 00:20:04 +00:00
count++;
2020-02-15 20:01:48 +00:00
break;
case JOB_EXIT:
Exit;
case JOB_DONE:
goto jh_done;
}
else
goto jh_done;
}
jh_done:
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
SetRFlags(old_flags);
2020-02-16 00:20:04 +00:00
return count;
2020-02-15 20:01:48 +00:00
}
I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL)
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
I64 res;
CJob *tmpc;
CTask *task=Spawn(&SrvCmdLine,NULL,"Servant",,parent);
if (!parent) {
TaskExe(task,parent,buf,1<<JOBf_EXIT_ON_COMPLETE|1<<JOBf_FREE_ON_COMPLETE);
if (_pu_task) *_pu_task=task;
return 0;
} else {
Fs->popup_task=task;
tmpc=TaskExe(task,parent,buf,1<<JOBf_WAKE_MASTER|1<<JOBf_FOCUS_MASTER);
if (_pu_task) *_pu_task=task;
JobResScan(tmpc,&res);
Fs->popup_task=NULL;
Kill(task);
if (_pu_task) *_pu_task=NULL;
return res;
}
}
I64 PopUpPrint(U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
2020-02-15 20:01:48 +00:00
I64 res;
res=PopUp(buf,Fs);
Free(buf);
return res;
}
I64 Zenith(U8 *format,...)
2020-02-15 22:25:33 +00:00
{//Make zenith_task execute code.
2020-02-15 20:01:48 +00:00
I64 res;
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
2020-02-15 20:01:48 +00:00
CJob *tmpc;
2020-02-15 22:25:33 +00:00
if (Fs==zenith_task) {
tmpc=TaskExe(zenith_task,Fs,buf,0);
2020-02-15 23:09:55 +00:00
JobsHandler(GetRFlags);
2020-02-15 20:01:48 +00:00
} else {
2020-02-15 22:25:33 +00:00
TaskWait(zenith_task);
tmpc=TaskExe(zenith_task,Fs,buf,1<<JOBf_WAKE_MASTER);
2020-02-15 20:01:48 +00:00
}
JobResScan(tmpc,&res);
Free(buf);
return res;
}
U0 ZenithLog(U8 *format,...)
2020-02-15 22:25:33 +00:00
{//Display text in zenith_task.
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
2020-02-15 22:25:33 +00:00
if (Fs==zenith_task)
2020-02-15 20:01:48 +00:00
"%s",buf;
else if (!IsSingleUser)
2020-02-15 22:25:33 +00:00
Zenith("\"%%s\",%d;",buf);
2020-02-15 20:01:48 +00:00
Free(buf);
}
U0 ZenithErr(U8 *format,...)
2020-02-15 22:25:33 +00:00
{//Display red blinking Err text in zenith_task.
U8 *buf=StrPrintJoin(NULL,format,argc,argv),
2020-02-15 20:01:48 +00:00
*st=MStrPrint(ST_ERR_ST "%s",buf);
2020-02-15 22:25:33 +00:00
if (Fs==zenith_task)
2020-02-15 20:01:48 +00:00
"%s",st;
else if (!IsSingleUser)
2020-02-15 22:25:33 +00:00
Zenith("\"%%s\",%d;",st);
2020-02-15 20:01:48 +00:00
Free(st);
Free(buf);
}
U0 XTalk(CTask *task,U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Sends text to other task. See $LK,"::/Misc/OSTestSuite.HC"$.
U8 *buf=StrPrintJoin(NULL,format,argc,argv),*st=ZStrNew(buf),
2020-02-15 20:01:48 +00:00
*st2=MStrPrint("\"%%s\",%d;Free(%d);",st,st);
TaskText(task,NULL,st2,0);
Free(st2);
Free(buf);
}
U0 XTalkWait(CTask *task,U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Send text to other task and wait for it to idle.
U8 *buf=StrPrintJoin(NULL,format,argc,argv),*st=ZStrNew(buf),
2020-02-15 20:01:48 +00:00
*st2=MStrPrint("\"%%s\",%d;Free(%d);",st,st);
TaskText(task,NULL,st2,0);
Free(st2);
Free(buf);
TaskWait(task);
}
U0 InStr(U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Send InFile code to self.
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
2020-02-15 20:01:48 +00:00
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK))
ExePrint("%s",buf);
else
TaskText(Fs,NULL,buf,1<<JOBf_HIGHEST_PRIORITY);
Free(buf);
}
U0 InFile(U8 *filename)
{//Send InFile code file to self.
2020-02-16 00:45:35 +00:00
U8 *name=ExtDefault(filename,"IN");
2020-02-15 20:01:48 +00:00
InStr("Cd(\"%C:%s\");;#include \"%s\"",
2020-02-15 22:53:02 +00:00
Drive2Letter(Fs->cur_dv),Fs->cur_dir,name);
2020-02-15 20:01:48 +00:00
Free(name);
}
U0 In(U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Send text to own input buffer. See $LK,"::/Demo/AcctExample/TOS/TOSDistro.HC"$.
U8 *buf=StrPrintJoin(NULL,format,argc,argv),*st=ZStrNew(buf);
2020-02-15 20:01:48 +00:00
InStr("\"%%s\",%d;Free(%d);",st,st);
Free(buf);
}
U0 XTalkStr(CTask *task,U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Send InFile code to other task.
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
2020-02-15 20:01:48 +00:00
TaskText(task,NULL,buf,0);
Free(buf);
}
U0 XTalkStrWait(CTask *task,U8 *format,...)
2020-02-15 20:01:48 +00:00
{//Send InFile code to other task and wait for it to idle.
U8 *buf=StrPrintJoin(NULL,format,argc,argv);
2020-02-15 20:01:48 +00:00
TaskText(task,NULL,buf,0);
Free(buf);
TaskWait(task);
}