ZealOS/src/Kernel/Job.CC

604 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 20:01:48 +00:00
}
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;
QueueRemove(tmpc);
JobDel(tmpc);
tmpc = tmpc1;
}
2020-02-15 20:01:48 +00:00
}
U0 JobCtrlInit(CJobCtrl *ctrl)
{
QueueInit(&ctrl->next_waiting);
QueueInit(&ctrl->next_done);
ctrl->flags = 0;
2020-02-15 20:01:48 +00:00
}
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.
if (!task)
task = Fs;
PUSHFD
CLI
do
{
if (TaskValidate(task))
LBtr(&task->task_flags, TASKf_AWAITING_MESSAGE);
else
break;
}
while (task = task->popup_task);
POPFD
2020-02-15 20:01:48 +00:00
}
CJob *TaskExe(CTask *server, CTask *master, U8 *data, I64 flags)
2020-02-15 22:53:02 +00:00
{//Queueues a request to compile and execute src code text.
CJob *res;
if (!data || !TaskValidate(server) || master && !TaskValidate(master) ||
server->popup_task && !Bt(&server->task_flags, TASKf_FILTER_INPUT))
return NULL;
res = ZCAlloc(sizeof(CJob));
res->master_task = master;
res->job_code = JOBT_EXE_STR;
res->flags = flags;
res->aux_str = ZStrNew(data);
res->ctrl = &server->server_ctrl;
2020-02-15 20:01:48 +00:00
PUSHFD
CLI
while (LBts(&server->server_ctrl.flags, JOBCf_LOCKED))
PAUSE
if (!TaskValidate(server))
{
LBtr(&server->server_ctrl.flags, JOBCf_LOCKED);
POPFD
JobDel(res);
return NULL;
}
else
{
LBtr(&server->task_flags, TASKf_IDLE);
TaskResetAwaitingMessage(server);
QueueInsert(res, server->server_ctrl.last_waiting);
LBtr(&server->server_ctrl.flags, JOBCf_LOCKED);
if (Bt(&flags, JOBf_WAKE_MASTER))
{
Suspend(master);
Yield;
}
}
POPFD
return res;
2020-02-15 20:01:48 +00:00
}
CJob *TaskText(CTask *server, CTask *master, U8 *data, I64 flags)
2020-02-15 20:01:48 +00:00
{//Post StdIn text to servant task. Tell who the master task is.
CJob *res;
CTask *task;
if (!data || !TaskValidate(server) || master && !TaskValidate(master) ||
server->popup_task && !Bt(&server->task_flags, TASKf_FILTER_INPUT))
return NULL;
res = ZCAlloc(sizeof(CJob));
res->master_task = master; //in case somebody cares
res->job_code = JOBT_TEXT_INPUT;
res->flags = flags;
res->aux_str = ZStrNew(data);
2020-02-15 20:01:48 +00:00
PUSHFD
task = server->last_input_filter_task;
if (Bt(&flags, JOBf_HIGHEST_PRIORITY) || task == server)
{
if (task != server)
TaskWait(server);
task = Spawn(&InputFilterTask, NULL, "Input Filter",, server);
CLI
task->next_input_filter_task = server->next_input_filter_task;
task->last_input_filter_task = server;
server->next_input_filter_task = task;
task->next_input_filter_task->last_input_filter_task = task;
}
else
{
CLI
task = server->next_input_filter_task;
}
res->ctrl = &task->server_ctrl;
while (LBts(&task->server_ctrl.flags, JOBCf_LOCKED))
PAUSE
if (!TaskValidate(task))
{
JobDel(res);
res = NULL;
}
else
{
LBtr(&task->task_flags, TASKf_IDLE);
TaskResetAwaitingMessage(task);
QueueInsert(res, task->server_ctrl.last_waiting);
LBtr(&task->server_ctrl.flags, JOBCf_LOCKED);
}
POPFD
return res;
2020-02-15 20:01:48 +00:00
}
CJob *TaskMessage(CTask *_server, CTask *master, I64 message_code, I64 arg1, I64 arg2, I64 flags)
{//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"$.
CJob *tmpc1, *tmpc;
CTask *server = _server;
if (!TaskValidate(server) || master && !TaskValidate(master)||
server->popup_task && !Bt(&server->task_flags, TASKf_FILTER_INPUT))
return NULL;
tmpc = ZCAlloc(sizeof(CJob));
tmpc->master_task = master;
tmpc->job_code = JOBT_MESSAGE;
tmpc->message_code = AbsI64(message_code); //negative means do a down and up
tmpc->aux1 = arg1;
tmpc->aux2 = arg2;
tmpc->flags = flags;
PUSHFD
if (Bt(&sys_semas[SEMA_RECORD_MACRO], 0) && server != sys_macro_task && message_code == MESSAGE_KEY_DOWN)
{
tmpc1 = ZMAllocIdent(tmpc);
CLI
QueueInsert(tmpc1, sys_macro_head.last);
}
CLI
while (Bt(&server->task_flags, TASKf_FILTER_INPUT) && !Bt(&flags, JOBf_DONT_FILTER))
server = server->next_input_filter_task;
tmpc->ctrl = &server->server_ctrl;
while (LBts(&server->server_ctrl.flags, JOBCf_LOCKED))
PAUSE
if (!TaskValidate(server))
{
JobDel(tmpc);
tmpc = NULL;
}
else
{
LBtr(&server->task_flags, TASKf_IDLE);
TaskResetAwaitingMessage(server);
QueueInsert(tmpc, server->server_ctrl.last_waiting);
LBtr(&server->server_ctrl.flags, JOBCf_LOCKED);
}
POPFD
if (message_code < 0) //Down-Up
TaskMessage(_server, master, -message_code + 1, arg1, arg2, flags);
return tmpc;
2020-02-15 20:01:48 +00:00
}
Bool JobResScan(CJob *request=NULL, I64 *_res=NULL)
2020-02-16 03:41:28 +00:00
{//Check request complete, return with or without.
CJobCtrl *ctrl;
CJob *tmpc, *tmpc1;
if (!request || Bt(&request->flags, JOBf_DONE))
{
if (!request || request->master_task)
ctrl = &Fs->server_ctrl;
else
ctrl = request->ctrl;
PUSHFD
CLI
while (LBts(&ctrl->flags, JOBCf_LOCKED))
PAUSE
tmpc1 = &ctrl->next_done;
tmpc = tmpc1->next;
while (tmpc != tmpc1)
{
if (!request || request == tmpc)
{
QueueRemove(tmpc);
LBtr(&ctrl->flags, JOBCf_LOCKED);
POPFD
if (_res)
*_res = tmpc->res;
JobDel(tmpc);
return TRUE;
}
tmpc = tmpc->next;
}
LBtr(&ctrl->flags, JOBCf_LOCKED);
POPFD
}
2020-02-15 20:01:48 +00:00
if (_res)
*_res = 0;
return FALSE;
2020-02-15 20:01:48 +00:00
}
2020-02-16 03:41:28 +00:00
I64 JobResGet(CJob *request=NULL)
2020-02-16 04:57:03 +00:00
{//See $LK,"::/Demo/MultiCore/Lock.CC"$
I64 res;
CJob *tmpc1;
if (!request)
{
tmpc1 = &Fs->server_ctrl.next_done;
while (tmpc1 == tmpc1->next)
{
LBts(&Fs->task_flags, TASKf_IDLE);
Yield;
}
}
else
{
while (!Bt(&request->flags, JOBf_DONE)) {
LBts(&Fs->task_flags, TASKf_IDLE);
Yield;
}
}
LBtr(&Fs->task_flags, TASKf_IDLE);
2020-02-15 20:01:48 +00:00
//Could get taken by someone else.
JobResScan(request, &res);
return res;
2020-02-15 20:01:48 +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->server_ctrl.next_waiting;
if (task1 == Fs || !TaskValidate(task1) ||
tmpc1 == tmpc1->next && Bt(&task1->task_flags, TASKf_IDLE) &&
(!cmd_line_prompt || Bt(&task1->task_flags, TASKf_CMD_LINE_PROMPT)))
break;
Yield;
}
POPFD
}
2020-02-15 20:01:48 +00:00
}
U0 MessagePost(CTask *task, I64 message_code, I64 arg1, I64 arg2, I64 flags=0)
2020-02-15 23:56:05 +00:00
{//Post message to a task and return immediately. See $LK,"message_code",A="MN:MESSAGE_CMD"$.
if (TaskValidate(task))
{
if (Bt(&task->task_flags, TASKf_INPUT_FILTER_TASK))
TaskMessage(task->last_input_filter_task, NULL, message_code, arg1, arg2, flags | 1 << JOBf_DONT_FILTER);
else
TaskMessage(task, NULL, message_code, arg1, arg2, flags);
}
2020-02-15 20:01:48 +00:00
}
U0 MessagePostWait(CTask *task, I64 message_code, I64 arg1, I64 arg2, I64 flags=0)
2020-02-15 23:56:05 +00:00
{//Post message to a task and wait until task is idle.See $LK,"message_code",A="MN:MESSAGE_CMD"$.
MessagePost(task, message_code, arg1, arg2, flags);
TaskWait(task);
2020-02-15 20:01:48 +00:00
}
U0 Message(I64 message_code, I64 arg1, I64 arg2, I64 flags=0)
{//Post message to current task and return immediately. See $LK,"message_code",A="MN:MESSAGE_CMD"$.
MessagePost(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
2020-02-15 20:01:48 +00:00
I64 JobRunOne(I64 run_flags, CJobCtrl *ctrl)
2020-02-15 20:01:48 +00:00
{//Called with ctrl->flags,JOBCf_LOCKED.
CJob *tmpc = ctrl->next_waiting;
CTask *master;
I64 res, flags = tmpc->flags, old_flags = RFlagsGet;
if (Bt(&flags, JOBf_EXIT_ON_COMPLETE))
res = JOB_EXIT;
else
res = JOB_CONT;
switch (tmpc->job_code)
{
case JOBT_SPAWN_TASK:
QueueRemove(tmpc);
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:
QueueRemove(tmpc);
LBts(&tmpc->flags, JOBf_DISPATCHED);
LBtr(&ctrl->flags, JOBCf_LOCKED);
RFlagsSet(run_flags);
LBtr(&Fs->task_flags, TASKf_IDLE);
try
tmpc->res = (*tmpc->addr)(tmpc->fun_arg);
catch
Fs->catch_except = TRUE;
RFlagsSet(old_flags);
break;
case JOBT_EXE_STR:
QueueRemove(tmpc);
LBts(&tmpc->flags, JOBf_DISPATCHED);
LBtr(&ctrl->flags, JOBCf_LOCKED);
RFlagsSet(run_flags);
LBtr(&Fs->task_flags, TASKf_IDLE);
try
tmpc->res = ExePrint("%s", tmpc->aux_str);
catch
Fs->catch_except = TRUE;
RFlagsSet(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->server_ctrl.flags, JOBCf_LOCKED))
PAUSE
QueueInsert(tmpc, master->server_ctrl.last_done);
LBts(&tmpc->flags, JOBf_DONE);
LBtr(&master->server_ctrl.flags, JOBCf_LOCKED);
RFlagsSet(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;
QueueInsert(tmpc, ctrl->last_done);
LBts(&tmpc->flags, JOBf_DONE);
LBtr(&ctrl->flags, JOBCf_LOCKED);
RFlagsSet(old_flags);
}
}
return res;
2020-02-15 20:01:48 +00:00
}
I64 JobsHandler(I64 run_flags, CTask *task=NULL)
2020-02-15 20:01:48 +00:00
{//Handle all waiting cmds and return.
I64 count = 0, old_flags = RFlagsGet;
if (!task)
task = Fs;
while (TRUE)
{
CLI
while (LBts(&task->server_ctrl.flags, JOBCf_LOCKED))
PAUSE
if (task->server_ctrl.next_waiting != &task->server_ctrl)
switch (JobRunOne(run_flags, &task->server_ctrl))
{
case JOB_CONT:
count++;
break;
case JOB_EXIT:
Exit;
case JOB_DONE:
goto jh_done;
}
else
goto jh_done;
}
2020-02-15 20:01:48 +00:00
jh_done:
LBtr(&task->server_ctrl.flags, JOBCf_LOCKED);
RFlagsSet(old_flags);
return count;
2020-02-15 20:01:48 +00:00
}
I64 PopUp(U8 *buf, CTask *parent=NULL, CTask **_pu_task=NULL)
2020-02-15 20:01:48 +00:00
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
I64 res;
CJob *tmpc;
CTask *task = Spawn(&ServerCmdLine, NULL, "Server",, 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;
}
2020-02-15 20:01:48 +00:00
}
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);
I64 res;
res = PopUp(buf, Fs);
Free(buf);
return res;
2020-02-15 20:01:48 +00:00
}
2021-07-02 00:53:42 +01:00
I64 Sys(U8 *format, ...)
{//Make sys_task execute code.
I64 res;
U8 *buf = StrPrintJoin(NULL, format, argc, argv);
CJob *tmpc;
2021-07-02 00:53:42 +01:00
if (Fs == sys_task)
{
2021-07-02 00:53:42 +01:00
tmpc = TaskExe(sys_task, Fs, buf, 0);
JobsHandler(RFlagsGet);
}
else
{
2021-07-02 00:53:42 +01:00
TaskWait(sys_task);
tmpc = TaskExe(sys_task, Fs, buf, 1 << JOBf_WAKE_MASTER);
}
JobResScan(tmpc, &res);
Free(buf);
return res;
2020-02-15 20:01:48 +00:00
}
2021-07-02 00:53:42 +01:00
U0 SysLog(U8 *format, ...)
{//Display text in sys_task.
U8 *buf = StrPrintJoin(NULL, format, argc, argv);
2021-07-02 00:53:42 +01:00
if (Fs == sys_task)
"%s", buf;
else if (!IsSingleUser)
2021-07-02 00:53:42 +01:00
Sys("\"%%s\",%d;", buf);
Free(buf);
2020-02-15 20:01:48 +00:00
}
2021-07-02 00:53:42 +01:00
U0 SysWarn(U8 *format, ...)
{//Display pink blinking Warn text in sys_task.
U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = MStrPrint(ST_WARN_ST "%s", buf);
2021-07-02 00:53:42 +01:00
if (Fs == sys_task)
"%s", st;
else if (!IsSingleUser)
2021-07-02 00:53:42 +01:00
Sys("\"%%s\",%d;", st);
Free(st);
Free(buf);
}
2021-07-02 00:53:42 +01:00
U0 SysErr(U8 *format, ...)
{//Display red blinking Err text in sys_task.
U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = MStrPrint(ST_ERR_ST "%s", buf);
2021-07-02 00:53:42 +01:00
if (Fs == sys_task)
"%s", st;
else if (!IsSingleUser)
2021-07-02 00:53:42 +01:00
Sys("\"%%s\",%d;", st);
Free(st);
Free(buf);
2020-02-15 20:01:48 +00:00
}
U0 XTalk(CTask *task, U8 *format, ...)
2020-02-16 04:57:03 +00:00
{//Sends text to other task. See $LK,"::/Misc/OSTestSuite.CC"$.
U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = ZStrNew(buf), *st2 = MStrPrint("\"%%s\",%d;Free(%d);", st, st);
TaskText(task, NULL, st2, 0);
Free(st2);
Free(buf);
2020-02-15 20:01:48 +00:00
}
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), *st2 = MStrPrint("\"%%s\",%d;Free(%d);", st, st);
TaskText(task, NULL, st2, 0);
Free(st2);
Free(buf);
TaskWait(task);
2020-02-15 20:01:48 +00:00
}
U0 InStr(U8 *format, ...)
2020-02-15 20:01:48 +00:00
{//Send InFile code to self.
U8 *buf = StrPrintJoin(NULL, format, argc, argv);
if (Bt(&Fs->task_flags, TASKf_INPUT_FILTER_TASK))
ExePrint("%s", buf);
else
TaskText(Fs, NULL, buf, 1 << JOBf_HIGHEST_PRIORITY);
Free(buf);
2020-02-15 20:01:48 +00:00
}
U0 InFile(U8 *filename)
{//Send InFile code file to self.
U8 *name = ExtDefault(filename, "IN");
InStr("Cd(\"%C:%s\");;#include \"%s\"", Drive2Letter(Fs->cur_dv), Fs->cur_dir, name);
Free(name);
2020-02-15 20:01:48 +00:00
}
U0 In(U8 *format, ...)
2020-02-16 04:57:03 +00:00
{//Send text to own input buffer. See $LK,"::/Demo/AcctExample/TOS/TOSDistro.CC"$.
U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = ZStrNew(buf);
InStr("\"%%s\",%d;Free(%d);", st, st);
Free(buf);
2020-02-15 20:01:48 +00:00
}
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);
TaskText(task, NULL, buf, 0);
Free(buf);
2020-02-15 20:01:48 +00:00
}
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);
TaskText(task, NULL, buf, 0);
Free(buf);
TaskWait(task);
2020-02-15 20:01:48 +00:00
}