U0 JobDel(CJob *tmpc) {//Free one cmd node. Free(tmpc->aux_str); Free(tmpc); } U0 JobQueueDel(CJob *head) { CJob *tmpc = head->next, *tmpc1; while (tmpc != head) { tmpc1 = tmpc->next; QueueRemove(tmpc); JobDel(tmpc); tmpc = tmpc1; } } U0 JobCtrlInit(CJobCtrl *ctrl) { QueueInit(&ctrl->next_waiting); QueueInit(&ctrl->next_done); ctrl->flags = 0; } U0 TaskResetAwaitingMessage(CTask *task=NULL) {//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 } CJob *TaskExe(CTask *server, CTask *master, U8 *data, I64 flags) {//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 = SysCAlloc(sizeof(CJob)); res->master_task = master; res->job_code = JOBT_EXE_STR; res->flags = flags; res->aux_str = SysStrNew(data); res->ctrl = &server->server_ctrl; 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; } CJob *TaskText(CTask *server, 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(server) || master && !TaskValidate(master) || server->popup_task && !Bt(&server->task_flags, TASKf_FILTER_INPUT)) return NULL; res = SysCAlloc(sizeof(CJob)); res->master_task = master; //in case somebody cares res->job_code = JOBT_TEXT_INPUT; res->flags = flags; res->aux_str = SysStrNew(data); 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; } 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. //See flags and message_code. 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 = SysCAlloc(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 = SysMAllocIdent(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; } Bool JobResScan(CJob *request=NULL, I64 *_res=NULL) {//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 } if (_res) *_res = 0; return FALSE; } I64 JobResGet(CJob *request=NULL) {//See ::/Demo/MultiCore/Lock.ZC 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); //Could get taken by someone else. JobResScan(request, &res); return res; } U0 TaskWait(CTask *task=NULL, Bool cmd_line_prompt=FALSE) {//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 } } U0 MessagePost(CTask *task, I64 message_code, I64 arg1, I64 arg2, I64 flags=0) {//Post message to a task and return immediately. See message_code. 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); } } U0 MessagePostWait(CTask *task, I64 message_code, I64 arg1, I64 arg2, I64 flags=0) {//Post message to a task and wait until task is idle.See message_code. MessagePost(task, message_code, arg1, arg2, flags); TaskWait(task); } U0 Message(I64 message_code, I64 arg1, I64 arg2, I64 flags=0) {//Post message to current task and return immediately. See message_code. MessagePost(Fs, message_code, arg1, arg2, flags); } #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 = 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; } I64 JobsHandler(I64 run_flags, CTask *task=NULL) {//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; } jh_done: LBtr(&task->server_ctrl.flags, JOBCf_LOCKED); RFlagsSet(old_flags); return count; } I64 PopUp(U8 *buf, CTask *parent=NULL, CTask **_pu_task=NULL) {//Execute code in 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; } } I64 PopUpPrint(U8 *format, ...) {//Execute code in PopUp task. U8 *buf = StrPrintJoin(NULL, format, argc, argv); I64 res; res = PopUp(buf, Fs); Free(buf); return res; } I64 Sys(U8 *format, ...) {//Make sys_task execute code. I64 res; U8 *buf = StrPrintJoin(NULL, format, argc, argv); CJob *tmpc; if (Fs == sys_task) { tmpc = TaskExe(sys_task, Fs, buf, 0); JobsHandler(RFlagsGet); } else { TaskWait(sys_task); tmpc = TaskExe(sys_task, Fs, buf, 1 << JOBf_WAKE_MASTER); } JobResScan(tmpc, &res); Free(buf); return res; } U0 SysLog(U8 *format, ...) {//Display text in sys_task. U8 *buf = StrPrintJoin(NULL, format, argc, argv); if (Fs == sys_task) "%s", buf; else if (!IsSingleUser) Sys("\"%%s\",%d;", buf); Free(buf); } 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); if (Fs == sys_task) "%s", st; else if (!IsSingleUser) Sys("\"%%s\",%d;", st); Free(st); Free(buf); } 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); if (Fs == sys_task) "%s", st; else if (!IsSingleUser) Sys("\"%%s\",%d;", st); Free(st); Free(buf); } U0 XTalk(CTask *task, U8 *format, ...) {//Sends text to other task. See ::/Misc/OSTestSuite.ZC. U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = SysStrNew(buf), *st2 = MStrPrint("\"%%s\",%d;Free(%d);", st, st); TaskText(task, NULL, st2, 0); Free(st2); Free(buf); } U0 XTalkWait(CTask *task, U8 *format, ...) {//Send text to other task and wait for it to idle. U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = SysStrNew(buf), *st2 = MStrPrint("\"%%s\",%d;Free(%d);", st, st); TaskText(task, NULL, st2, 0); Free(st2); Free(buf); TaskWait(task); } U0 InStr(U8 *format, ...) {//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); } 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); } U0 In(U8 *format, ...) {//Send text to own input buffer. See ::/Demo/AcctExample/TOS/TOSDistro.ZC. U8 *buf = StrPrintJoin(NULL, format, argc, argv), *st = SysStrNew(buf); InStr("\"%%s\",%d;Free(%d);", st, st); Free(buf); } U0 XTalkStr(CTask *task, U8 *format, ...) {//Send InFile code to other task. U8 *buf = StrPrintJoin(NULL, format, argc, argv); TaskText(task, NULL, buf, 0); Free(buf); } U0 XTalkStrWait(CTask *task, U8 *format, ...) {//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); }