Project: OSMain
/* Tasks are ordered in a queue based
on window front-to-back order with the
window manager as the head, which
paints the wallpaper.The scheduler
goes in a circle, checking if a task is
ready and swapping-it-in if so.
Swapping just involves storing and
restoring registers -- no disk I/O for
virtual memory and no address map
changes.Tasks can be switched in half
a microsecond.

The scheduler checks if a task is
waiting for a certain time or waiting
on a message and skips it if it's not
ready.A task runs until it
voluntarily yields control with a call
to TaskNext or gets preempted by the
timer interrupt.See IRQ20.The timer
freqency is JIFFY_FREQ.Tasks can ask
not to be preempted with Preempt(ON/OFF).
Tasks waiting on I/O often loop,
checking for a status and swapping-out.
This does not really degrade
performance, though it pegs the CPU
Load.

The scheduler checks for a few critical
key-strokes such as CTRL-ALT-X, which
kills a task; CTRL-ALT-D, which reboots;
CTRL-ALT-T, which changes focus and CTRL-ALT-C,
which breaks execution of a program.

Each core has it's own circular task
queue.For AP processors, they have a
"Seth" task which stays in a loop
waiting for jobs or requests to spawn
tasks.See MPWaitForTask().

All cores have an idle task.If the
scheduler determined all tasks were
waiting on a message or a time, it would
loop for a long time without swapping
in a task, with interrupts off.To avoid
locking-out interrupts when no task is
ready, the scheduler swaps in the idle
task(enabling IRQs).It turns-out that
core #0, indeed, swaps in the idle task,
but the other cores do not because their
Seth tasks are always checking for a
command, so there is never a case when
no task is ready.


*/

asm {
USE64
// ************************************
IDLE_START::
SAVE_CONTEXT::
//OUT:  RSI=FS
        PUSH    RSI
        PUSHFD
        XOR     RSI,RSI
        MOV     RSI,FS:TASK_ADDRESS[RSI]
        POP     U8 TASK_RFLAGS[RSI]
        POP     U8 TASK_RSI[RSI]
        MOV     U8 TASK_RAX[RSI],RAX

/*
We divert the stack to the TaskStruct memory
and push onto it and divert it back.
It's a little faster.
*/
        MOV     RAX,RSP
        LEA     RSP,U8 TASK_R15+8[RSI]
        PUSH    R15
        PUSH    R14
        PUSH    R13
        PUSH    R12
        PUSH    R11
        PUSH    R10
        PUSH    R9
        PUSH    R8
        PUSH    RDI
        PUSH    RBP
        PUSH    RBX
        PUSH    RDX
        PUSH    RCX
        MOV     RSP,RAX

        RDTSC
        SHL     RDX,32
        ADD     RAX,RDX
        SUB     RAX,U8 TASK_TIME_SLICE_START[RSI]
        ADD     U8 TASK_TOTAL_TIME[RSI],RAX

        MOV     RAX,U8 TASK_FPU_MMX[RSI]
        FXSAVE  U8 [RAX]

        MOV     RDX,U8 TASK_BPT_LIST[RSI]
@@3:    OR      RDX,RDX
        JZ      @@4
        MOV     RDI,U8 BPT_ADDRESS[RDX]
        MOV     AL,U1 BPT_U1[RDX]
        MOV     U1 [RDI],AL
        MOV     RDX,U8 BPT_NEXT[RDX]
        JMP     @@3
@@4:    LOCK
        BTR     U8 TASK_TASK_FLAGS[RSI],TASKf_CURRENTLY_RUNNING
        LOCK
        BTS     U8 TASK_TASK_FLAGS[RSI],TASKf_HAS_BEEN_SWAPPED
        RET
// ************************************
RESTORE_CONTEXT::
        XOR     RAX,RAX
        INC     U8 GS:CPU_SWAP_CNTER[RAX]
        XOR     RAX,RAX
        MOV     RSI,FS:TASK_ADDRESS[RAX]
        LOCK
        BTS     U8 TASK_TASK_FLAGS[RSI],TASKf_CURRENTLY_RUNNING
        BT      U8 TASK_TASK_FLAGS[RSI],TASKf_DISABLE_BPTS
        JC      @@4
        MOV     RDX,U8 TASK_BPT_LIST[RSI]
@@3:    OR      RDX,RDX
        JZ      @@4
        MOV     RDI,U8 BPT_ADDRESS[RDX]
        MOV     U1 [RDI],OC_BPT
        MOV     RDX,U8 BPT_NEXT[RDX]
        JMP     @@3

@@4:    INC     U8 TASK_SWAP_CNTER[RSI]

        MOV     RAX,U8 TASK_FPU_MMX[RSI]
        FXRSTOR U8 [RAX]

        RDTSC
        SHL     RDX,32
        ADD     RAX,RDX
        MOV     U8 TASK_TIME_SLICE_START[RSI],RAX

        MOV     RAX,RSP
        LEA     RSP,U8 TASK_RCX[RSI]
        POP     RCX
        POP     RDX
        POP     RBX
        POP     RBP
        POP     RDI
        POP     R8
        POP     R9
        POP     R10
        POP     R11
        POP     R12
        POP     R13
        POP     R14
        POP     R15
        MOV     RSP,RAX

        MOV     RAX,U8 TASK_RAX[RSI]
        PUSH    ZERO_DS_SEL
        PUSH    U8 TASK_RSP[RSI]
        PUSH    U8 TASK_RFLAGS[RSI]
        PUSH    SYS_CS64_SEL
        PUSH    U8 TASK_RIP[RSI]
        MOV     RSI,U8 TASK_RSI[RSI]
        IRET
// ************************************
END_RSI_TASK:
        MOV     RAX,RSI
        CALL    SET_FS_BASE
TASK_END_NOW::
        CALL    _TASK_END
        MOV     RSI,RAX
        CALL    SET_FS_BASE
        JMP     I4 RESTORE_RSI_TASK_WITH_KEY_CHECK

RESTORE_RSI_NO_PREEMPT_TASK:
        BT      U8 [SYS_CTRL_ALT_FLAGS],SYSf_CTRL_ALT_DEL
        JC      I4 HANDLE_SWAP_KEY_EVENT
        XOR     RAX,RAX
        CMP     U8 GS:CPU_IDLE_TASK[RAX],RSI
        JE      I4 RESTORE_IDLE_TASK
        JMP     RESTORE_RSI_TASK_NO_KEY_CHECK

SAVE_CONTEXT_SWAP_IN_NEXT::
        PUSHFD
        PUSH    RAX
        MOV     RAX,SYS_SEMAS
        BT      U4 SYS_SEMA_SINGLE_USER*SEMA_STRUCT_SIZE[RAX],0
        JC      @@4
        POP     RAX

        CLI
        PUSH    RSI
        XOR     RSI,RSI
        MOV     RSI,FS:TASK_ADDRESS[RSI]
        CMP     U8 TASK_NEXT_TASK[RSI],RSI
        JNE     @@0

        PUSH    RAX
        PUSH    RDX
        RDTSC
        SHL     RDX,32
        ADD     RAX,RDX
        CMP     U8 TASK_WAKE_TIME[RSI],RAX
        JA      @@0A

        POP     RDX
        POP     RAX
        POP     RSI
        POPFD
        RET

@@4:    POP     RAX
        POPFD
        RET

@@0A:   POP     RDX
        POP     RAX
@@0:    POP     RSI
        CALL    SAVE_CONTEXT

        MOV     RBX,U4 IDLE_POINT
        MOV     U8 TASK_RIP[RSI],RBX
        POP     U8 TASK_RFLAGS[RSI]
        MOV     U8 TASK_RSP[RSI],RSP

RESTORE_NEXT_RSI_TASK:
        MOV     RSI,U8 TASK_NEXT_TASK[RSI]

RESTORE_RSI_TASK_WITH_KEY_CHECK:
        TEST    U4 [SYS_CTRL_ALT_FLAGS],1<<SYSf_CTRL_ALT_DEL|
1<<SYSf_CTRL_ALT_TAB|1<<SYSf_CTRL_ALT_X|1<<SYSf_CTRL_ALT_C
        JNZ     I4 HANDLE_SWAP_KEY_EVENT

RESTORE_RSI_TASK_NO_KEY_CHECK:
        XOR     RAX,RAX
        MOV     U8 GS:CPU_SWAP_LOOP_TASK[RAX],RSI

@@1:    BT      U8 TASK_TASK_FLAGS[RSI],TASKf_KILL_TASK
        JC      I4 END_RSI_TASK
        TEST    U8 TASK_TASK_FLAGS[RSI],1<<TASKf_AWAITING_MSG|1<<TASKf_SUSPENDED|1<<TASKf_PAUSED
        JNZ     @@2

        RDTSC
        SHL     RDX,32
        ADD     RAX,RDX
        CMP     U8 TASK_WAKE_TIME[RSI],RAX
        JA      @@2

        CMP     U4 TASK_IN_QUEUE_SIGNATURE[RSI],TASK_IN_QUEUE_SIGNATURE_VAL
        JNE     SWAP_IN_SETH_TASK
        MOV     RAX,RSI
        CALL    SET_FS_BASE
        JMP     I4 RESTORE_CONTEXT

@@2:    MOV     RSI,U8 TASK_NEXT_TASK[RSI]
        XOR     RAX,RAX
        CMP     U8 GS:CPU_SWAP_LOOP_TASK[RAX],RSI
        JNE     @@1
        MOV     RAX,U8 GS:CPU_IDLE_TASK[RAX]
        MOV     RSP,U8 TASK_STACK_BASE[RAX]
        ADD     RSP,IDLE_STACK  //Reset to top
        CALL    SET_FS_BASE
        STI
        CALL    LOW_POWER_START
        OR      RAX,RAX
        JZ      RESTORE_IDLE_TASK
        HLT
RESTORE_IDLE_TASK:
        CALL    LOW_POWER_END
        CLI
        JMP     I4 RESTORE_RSI_TASK_WITH_KEY_CHECK

SWAP_IN_SETH_TASK:
        XOR     RAX,RAX
        MOV     RSI,GS:CPU_SETH_TASK[RAX]
        JMP     I4 RESTORE_RSI_TASK_WITH_KEY_CHECK

IDLE_POINT::
        RET

LOW_POWER_START::
        XOR     RAX,RAX
        MOV     U8 GS:CPU_LOW_POWER_START[RAX],RAX

        MOV     RBX,SYS_SEMAS
        BT      U4 SYS_SEMA_LOW_POWER*SEMA_STRUCT_SIZE[RBX],0
        JNC     @@100
        RDTSC
        SHL     RDX,32
        ADD     RDX,RAX
        XOR     RAX,RAX
        MOV     U8 GS:CPU_LOW_POWER_START[RAX],RDX
        INC     RAX
@@100:  RET

LOW_POWER_END::
        MOV     RBX,SYS_SEMAS
        BT      U4 SYS_SEMA_LOW_POWER*SEMA_STRUCT_SIZE[RBX],0
        JNC     @@100

        RDTSC
        SHL     RDX,32
        ADD     RDX,RAX
        XOR     RAX,RAX
        MOV     RBX,U8 GS:CPU_LOW_POWER_START[RAX]
        OR      RBX,RBX
        JZ      @@100
        SUB     RDX,RBX
        LOCK
        ADD     U8 GS:CPU_LOW_POWER_CYCLES[RAX],RDX
        MOV     U8 GS:CPU_LOW_POWER_START[RAX],RAX
@@100:  RET

IDLE_END::

HANDLE_SWAP_KEY_EVENT:
        MOV     RAX,RSI
        CALL    SET_FS_BASE
        XOR     RAX,RAX
        MOV     RAX,GS:CPU_NUM[RAX]
        OR      RAX,RAX
        JNZ     I4 RESTORE_RSI_TASK_NO_KEY_CHECK

        MOV     RAX,U4 SYS_CTRL_ALT_FLAGS
        LOCK
        BTR     U4 [RAX],SYSf_CTRL_ALT_DEL
        JC      I4 _REBOOT

@@2:    LOCK
        BTR     U4 [RAX],SYSf_CTRL_ALT_TAB
        JNC     @@3
        PUSH    RSI
        MOV     RSI,U8 [SYS_CUR_FOCUS_TASK]
        MOV     U8 [SYS_CUR_FOCUS_TASK],0
        CALL    FOCUS_RSI_NEXT_USER
        POP     RSI
        JMP     I4 RESTORE_FS_TASK_WITH_KEY_CHECK

@@3:    LOCK
        BTR     U4 [RAX],SYSf_CTRL_ALT_X
        JC      END_FOCUS_USER
        LOCK
        BTR     U4 [RAX],SYSf_CTRL_ALT_C
        JNC     I4 RESTORE_RSI_TASK_WITH_KEY_CHECK

BREAK_FOCUS_USER:
        MOV     RSI,U8 [SYS_CUR_FOCUS_TASK]
        OR      RSI,RSI
        JZ      I4 SWAP_IN_SETH_TASK
        BT      U8 TASK_TASK_FLAGS[RSI],TASKf_LOCAL_USER
        JNC     I4 RESTORE_RSI_TASK_NO_KEY_CHECK
        LOCK
        BTR     U8 TASK_TASK_FLAGS[RSI],TASKf_BREAK_LOCKED
        JNC     @@1
        LOCK
        BTS     U8 TASK_TASK_FLAGS[RSI],TASKf_PENDING_BREAK
        JMP     I4 RESTORE_RSI_TASK_NO_KEY_CHECK

@@1:    MOV     RAX,_BREAK
        MOV     U8 TASK_RIP[RSI],RAX
        BT      U8 TASK_TASK_FLAGS[RSI],TASKf_BREAK_TO_CTRLQ
        JC      @@4

//We do these two now, in case interrupt happens
        MOV     U8 TASK_WAKE_TIME[RSI],0
        LOCK
        BTR     U8 TASK_TASK_FLAGS[RSI],TASKf_AWAITING_MSG

@@4:    JMP     I4 RESTORE_RSI_TASK_NO_KEY_CHECK

END_FOCUS_USER:
        MOV     RSI,U8 [SYS_CUR_FOCUS_TASK]
        MOV     U8 [SYS_CUR_FOCUS_TASK],0
        PUSH    RSI
        CALL    FOCUS_RSI_NEXT_USER
        POP     RSI
        OR      RSI,RSI
        JZ      I4 SWAP_IN_SETH_TASK
        MOV     RAX,RSI
        CALL    SET_FS_BASE
        BT      U8 TASK_TASK_FLAGS[RSI],TASKf_LOCAL_USER
        JNC     I4 RESTORE_RSI_TASK_WITH_KEY_CHECK
        LOCK
        BTS     U8 TASK_TASK_FLAGS[RSI],TASKf_KILL_TASK
        JMP     I4 END_RSI_TASK

RESTORE_FS_TASK_WITH_KEY_CHECK:
        XOR     RSI,RSI
        MOV     RSI,FS:TASK_ADDRESS[RSI]
        JMP     I4 RESTORE_RSI_TASK_WITH_KEY_CHECK

FOCUS_RSI_NEXT_USER:
        OR      RSI,RSI
        JNZ     @@11
        MOV     RSI,U4 SYS_ADAM_TASK
@@11:   MOV     RDI,RSI
        MOV     RSI,U8 TASK_NEXT_TASK[RSI]
@@14:   BT      U8 TASK_TASK_FLAGS[ESI],TASKf_LOCAL_USER
        JNC     @@19
        CMP     U8 [SYS_CUR_FOCUS_TASK],RSI
        JE      @@19
        MOV     U8 [SYS_CUR_FOCUS_TASK],RSI
        MOV     RAX,U8 [SYS_EXTERN_TABLE]
        MOV     RAX,U8 EXT_WIN_TO_TOP*8[RAX]
        OR      RAX,RAX
        JZ      @@19B
        PUSH    RSI
        CALL    RAX
        ADD     RSP,8
        JMP     @@19B
@@19:   MOV     RSI,U8 TASK_NEXT_TASK[RSI]
        CMP     RSI,RDI
        JNE     @@14
        MOV     U8 [SYS_CUR_FOCUS_TASK],0
@@19B:  RET

}

LTextern LOW_POWER_START BoolI8 LowPowerStart();
LTextern LOW_POWER_END   U0 LowPowerEnd();
LTextern RESTORE_CONTEXT U0 RestoreContext();
LTextern SAVE_CONTEXT_SWAP_IN_NEXT U0 TaskNext();
LTextern IDLE_START U1 sys_idle_start;
LTextern IDLE_END   U1 sys_idle_end;
LTextern TASK_END_NOW U0 TaskEndNow();

U0 TaskQueueAdd(TaskStruct *task,TaskStruct *pred=NULL)
{
  TaskStruct *last;
  PushFD;
  Cli;
  if (!pred) pred=Fs;
  last=pred->last_task;
  last->next_task=pred->last_task=task;
  task ->last_task=last;
  task ->next_task=pred;
  task->task_in_queue_signature=TASK_IN_QUEUE_SIGNATURE_VAL;
  PopFD;
}

U0 TaskChildAdd(TaskStruct *task)
{
  TaskStruct *last,*pred;
  PushFD;
  Cli;
  pred=task->parent_task->last_child_task;
  last=pred->last_sibling_task;
  last->next_sibling_task=pred->last_sibling_task=task;
  task ->last_sibling_task=last;
  task ->next_sibling_task=pred;
  PopFD;
}

Historical capture: 2010-01-29. Home | Power on LoseThos | Sources and changes