hschumann2/TempleOS-Source-Code
0838
1 2/*On each core, tasks are linked in a3circular doubly-linked list queue with4the Seth task as the head. On Core0,5the queue order represents the front-to-back6window stack order with the window mgr7as the wallpaper.8 9The scheduler is round-robin. It checks10if a task is ready and runs it or skips it.11Swapping tasks just involves storing and12restoring regs (no disk I/O for virtual13memory and no addr map changes). It is14always fully identity-mapped on all cores.15Tasks can be switched in half a microsecond.16 17The scheduler checks if a task is18waiting for a certain time or waiting19on a message and skips if not ready.20A task runs until it voluntarily yields ctrl21with a call to Yield(). Tasks waiting on I/O22often loop, checking for a status and23Yielding. This does not really degrade24performance, but pegs the CPU Load.25 26The scheduler checks for a few keys:27 28<CTRL-ALT-x> kill a task.29<CTRL-ALT-DEL> reboots.30<CTRL-ALT-n> Next task.31<CTRL-ALT-c> breaks execution of a program.32 33Each core has its own circular task queue.34For AP processors, they have a "Seth" task35which stays in a loop waiting for jobs or36requests to spawn tasks. See CoreAPSethTask().37*/38 39U0 TaskFocusNext()40{41 CTask *task,*_task=sys_focus_task;42 sys_focus_task=NULL;43 if (!_task) _task=adam_task;44 task=_task->next_task;45 do {46 if (!Bt(&task->win_inhibit,WIf_SELF_FOCUS)) {47 sys_focus_task=task;48 CallExtNum(EXT_WIN_TO_TOP,task,TRUE);49 return;50 }51 task=task->next_task;52 } while (task!=_task);53}54 55asm {56TASK_CONTEXT_SAVE::57//OUT: RSI=FS58 PUSH RSI59 PUSHFD60 XOR RSI,RSI61 MOV RSI,FS:CTask.addr[RSI]62 POP U64 CTask.rflags[RSI]63 POP U64 CTask.rsi[RSI]64 MOV U64 CTask.rax[RSI],RAX65 66/*Divert the stk to the Task memory67and push onto it and divert it back.68It's a little faster.69*/70 MOV RAX,RSP71 LEA RSP,U64 CTask.r15+8[RSI]72 PUSH R1573 PUSH R1474 PUSH R1375 PUSH R1276 PUSH R1177 PUSH R1078 PUSH R979 PUSH R880 PUSH RDI81 PUSH RBP82 PUSH RBX83 PUSH RDX84 PUSH RCX85 MOV RSP,RAX86 87 MOV RAX,U64 CTask.fpu_mmx[RSI]88 FXSAVE U64 [RAX]89 90 MOV RDX,U64 CTask.bpt_lst[RSI]91@@05: TEST RDX,RDX92 JZ @@1093 MOV RDI,U64 CBpt.addr[RDX]94 MOV AL,U8 CBpt.val[RDX]95 MOV U8 [RDI],AL96 MOV RDX,U64 CBpt.next[RDX]97 JMP @@0598@@10: RET99//************************************100_TASK_CONTEXT_RESTORE::101 XOR RAX,RAX102 INC U64 GS:CCPU.swap_cnter[RAX]103 MOV RSI,FS:CTask.addr[RAX]104 BT U32 CTask.rflags[RSI],RFLAGf_INT105 JNC @@05106 BTS U32 GS:CCPU.cpu_flags[RAX],CPUf_RAN_A_TASK107@@05: BT U64 CTask.task_flags[RSI],TASKf_DISABLE_BPTS108 JC @@15109 MOV RDX,U64 CTask.bpt_lst[RSI]110@@10: TEST RDX,RDX111 JZ @@15112 MOV RDI,U64 CBpt.addr[RDX]113 MOV U8 [RDI],OC_BPT114 MOV RDX,U64 CBpt.next[RDX]115 JMP @@10116 117@@15: INC U64 CTask.swap_cnter[RSI]118 119 MOV RAX,U64 CTask.fpu_mmx[RSI]120 FXRSTOR U64 [RAX]121 122 MOV RAX,RSP123 LEA RSP,U64 CTask.rcx[RSI]124 POP RCX125 POP RDX126 POP RBX127 POP RBP128 POP RDI129 POP R8130 POP R9131 POP R10132 POP R11133 POP R12134 POP R13135 POP R14136 POP R15137 MOV RSP,RAX138 139 MOV RAX,U64 CTask.rax[RSI]140 PUSH CGDT.ds141 PUSH U64 CTask.rsp[RSI]142 PUSH U64 CTask.rflags[RSI]143 PUSH CGDT.cs64144 PUSH U64 CTask.rip[RSI]145 MOV RSI,U64 CTask.rsi[RSI]146 IRET147//************************************148END_RSI_TASK:149 MOV RAX,RSI150 CALL SET_FS_BASE151_TASK_END_NOW::152 CALL &TaskEnd153 MOV RSI,RAX154 CALL SET_FS_BASE155 JMP I8 RESTORE_RSI_TASK156 157_YIELD::158 PUSHFD159 TEST U8 [SYS_SEMAS+SEMA_SINGLE_USER*DFT_CACHE_LINE_WIDTH],1160 JZ @@05161 POPFD //If single user, don't change task.162 RET163 164@@05: CLI165 CALL TASK_CONTEXT_SAVE166 MOV EBX,U32 _RET167 MOV U64 CTask.rip[RSI],RBX168 POP U64 CTask.rflags[RSI]169 MOV U64 CTask.rsp[RSI],RSP170 MOV RSI,U64 CTask.next_task[RSI]171 172RESTORE_RSI_TASK:173 TEST U64 [SYS_CTRL_ALT_FLAGS],1<<CTRL_ALT_DEL|1741<<CTRL_ALT_TAB|1<<CTRL_ALT_X|1<<CTRL_ALT_C175 JNZ HANDLE_SYSF_KEY_EVENT176 177RESTORE_RSI_TASK2:178@@20: BT U64 CTask.task_flags[RSI],TASKf_KILL_TASK179 JC END_RSI_TASK180 TEST U64 CTask.task_flags[RSI],181 1<<TASKf_AWAITING_MSG|1<<TASKf_SUSPENDED182 JNZ @@25183 184 MOV RAX,U64 [&cnts.jiffies]185 CMP U64 CTask.wake_jiffy[RSI],RAX186 JG @@25 //Jmp if not ready, yet.187 188 MOV RAX,RSI189 CALL SET_FS_BASE190 JMP I32 _TASK_CONTEXT_RESTORE191 192@@25: MOV RSI,U64 CTask.next_task[RSI]193 XOR RAX,RAX194 CMP U64 GS:CCPU.seth_task[RAX],RSI195 JNE @@20 //Jmp if not Seth196 BTR U32 GS:CCPU.cpu_flags[RAX],CPUf_RAN_A_TASK197 JC @@20 //Jmp if had chance for IRQ already198 MOV RAX,U64 GS:CCPU.idle_task[RAX]199 MOV RSP,U64 CTask.stk[RAX]200 ADD RSP,MEM_DFT_STK+CTaskStk.stk_base //Rst to top201 CALL SET_FS_BASE202 STI //Restore idle task so we can unmask IRQs.203 HLT204SYS_IDLE_PT::205 CLI206 207RESTORE_SETH_TASK_IF_READY:208 XOR RAX,RAX209 MOV RSI,GS:CCPU.seth_task[RAX]210 JMP RESTORE_RSI_TASK211 212HANDLE_SYSF_KEY_EVENT:213 MOV RAX,RSI214 CALL SET_FS_BASE215 XOR RBX,RBX216 MOV RAX,GS:CCPU.num[RBX]217 TEST RAX,RAX218 JNZ I32 RESTORE_RSI_TASK2219 220 MOV EAX,U32 SYS_CTRL_ALT_FLAGS221 LOCK222 BTR U32 [RAX],CTRL_ALT_DEL223 JC I32 &Reboot224 225 CMP U64 GS:CCPU.idle_task[RBX],RSI226 JE RESTORE_SETH_TASK_IF_READY227 228 LOCK229 BTR U32 [RAX],CTRL_ALT_TAB230 JNC @@05231 CALL &TaskFocusNext232 JMP I32 RESTORE_FS_TASK233 234@@05: LOCK235 BTR U32 [RAX],CTRL_ALT_X236 JC END_FOCUS_USER237 LOCK238 BTR U32 [RAX],CTRL_ALT_C239 JNC I32 RESTORE_RSI_TASK240 241BREAK_FOCUS_USER:242 MOV RSI,U64 [SYS_FOCUS_TASK]243 TEST RSI,RSI244 JZ RESTORE_SETH_TASK_IF_READY245 BT U64 CTask.win_inhibit[RSI],WIf_SELF_FOCUS246 JC I32 RESTORE_RSI_TASK247 LOCK248 BTR U64 CTask.task_flags[RSI],TASKf_BREAK_LOCKED249 JNC @@10250 LOCK251 BTS U64 CTask.task_flags[RSI],TASKf_PENDING_BREAK252 JMP I32 RESTORE_RSI_TASK253 254@@10: MOV RAX,&Break255 MOV U64 CTask.rip[RSI],RAX256 BT U64 CTask.task_flags[RSI],TASKf_BREAK_TO_SHIFT_ESC257 JC I32 RESTORE_RSI_TASK258 259//Do these now, in case interrupt happens.260 MOV U64 CTask.wake_jiffy[RSI],0261 PUSH RSI262 CALL &TaskRstAwaitingMsg263 JMP I32 RESTORE_RSI_TASK264 265END_FOCUS_USER:266 MOV RSI,U64 [SYS_FOCUS_TASK]267 CALL &TaskFocusNext268 TEST RSI,RSI269 JZ I32 RESTORE_SETH_TASK_IF_READY270 MOV RAX,RSI271 CALL SET_FS_BASE272 BT U64 CTask.win_inhibit[RSI],WIf_SELF_FOCUS273 JC I32 RESTORE_RSI_TASK274 LOCK275 BTS U64 CTask.task_flags[RSI],TASKf_KILL_TASK276 JMP I32 END_RSI_TASK277 278RESTORE_FS_TASK:279 XOR RSI,RSI280 MOV RSI,FS:CTask.addr[RSI]281 JMP I32 RESTORE_RSI_TASK282}283 284_extern _TASK_CONTEXT_RESTORE U0 TaskContextRestore(); //Restore a task context.285_extern _YIELD U0 Yield(); //Yield cpu to next task.286_extern _TASK_END_NOW U0 TaskEndNow(); //Terminate current task.287 288U0 TaskQueIns(CTask *task,CTask *pred=NULL)289{//Insert a task in the scheduler running task queue.290//You have no business with this, probably.291 CTask *last;292 PUSHFD293 CLI294 if (!pred) pred=Fs;295 last=pred->last_task;296 last->next_task=pred->last_task=task;297 task->last_task=last;298 task->next_task=pred;299 POPFD300}301 302U0 TaskQueRem(CTask *task)303{//Remove a task from the scheduler running task queue.304//Use Suspend().305 CTask *next,*last;306 PUSHFD307 CLI308 next=task->next_task;309 last=task->last_task;310 last->next_task=next;311 next->last_task=last;312 POPFD313}314 315U0 TaskQueInsChild(CTask *task)316{317 CTask *last,*pred;318 PUSHFD319 CLI320 pred=task->parent_task->last_child_task;321 last=pred->last_sibling_task;322 last->next_sibling_task=pred->last_sibling_task=task;323 task->last_sibling_task=last;324 task->next_sibling_task=pred;325 POPFD326}327 