Practical Session 7
Co-RoutinesCo-Routines
• co-routines are assembly implementation of threads
• each co-routine decides to which co-routine to pass a control - unlike “usual” threads
Co-routine stateCo-routine state• co-routine is denoted by Coi, where i is ID of the co-
routine• scheduler is also a co-routine • co-routine suspends itself after some “time slice”• co-routine resumes a scheduler
• co-routine should save its current state before it suspends itself, in order to continue its execution later
• a state of co-routine includes:• stack state• registers• flags• stack pointer (ESP)• instructions pointer (EIP)
Co-routine structureCo-routine structure
STKSIZE equ 16*1024 ;(16 Kb)STK1: resb STKSIZE
CO1: dd Function1 ; pointer to co-routine codeFlags: dd 0 ; 0 if co-routine is not initialized, 1 otherwiseSP1: dd STK1 + STKSIZE ; pointer to co-routine stack
Co-routine structureCo-routine structure
Variable DeclarationVariable DeclarationSTKSZ equ 16*1024CODEP equ 0FLAGSP equ 4SPP equ 8
section .rodataalign 16global numco
numco: dd 3CORS: dd CO1
dd CO2dd CO3
section .dataalign 16
CO1: dd Function1 ; Structure for first co-routineFlags1: dd 0SP1: dd STK1+STKSZCO2: dd Function1 ; Structure for second co-routineFlags2: dd 0SP2: dd STK2+STKSZCO3: dd Function2 ; Structure for third co-routineFlags3: dd 0SP3: dd STK3+STKSZ
section .bssalign 16
CURR: resd 1SPT: resd 1SPMAIN: resd 1STK1: resb STKSZSTK2: resb STKSZSTK3: resb STKSZ
Co-routine initializationCo-routine initialization
Co-routine initialization:Co-routine initialization:save initial co-routine statesave initial co-routine state
‘bts’ instruction tests one bit of its first operand, whose index is given by the second operand, and stores the value of that bit in the carry flag (CF). In addition, ‘bts’ sets the bit to be 1.
Co-routine initializationCo-routine initializationinit_co_from_c : initialize a co-routine, which number is given as an argument from Csection .text
align 16extern printfglobal init_co_from_cglobal start_co_from_cglobal end_co
init_co_from_c:push EBPmov EBP, ESPpush EBXmov EBX, [EBP+8] ; EBX contains a number of the co-routine to be initializedmov EBX, [EBX*4+CORS] ; EBX contains a pointer to co-routine structure to be initializedcall co_initpop EBXpop EBPret
co_init:pushabts dword [EBX+FLAGSP],0 ; test if already initializedjc init_donemov EAX,[EBX+CODEP] ; get initial PCmov [SPT], ESP ; save original SPmov ESP,[EBX+SPP] ; get initial SPmov EBP, ESP ; also use as EBPpush EAX ; push initial "return" address (initial PC)pushf ; push flagspusha ; push all other registersmov [EBX+SPP],ESP ; save new SP in structuremov ESP, [SPT] ; restore original SP
init_done:poparet
Co-routine code (function)Co-routine code (function)
Scheduler co-routine functionScheduler co-routine functionScheduler function is started by main.
scheduler_Function:
pick up some thread ID imov EBX, [CORS + i*4] ; resumes Coicall resume
pick up some other thread ID jmov EBX, [CORS + j*4] ; resumes Cojcall resume…jmp end_co ; resume main
Co-routine resumeCo-routine resume• What should resume do?
• save a state of the current co-routine• resume a state of the next co-routine (EBX should contain a
pointer to it)
• Let’s look closer at the resume function:• after ‘call resume’ , returned address (i.e. EIP) is pushed • automatically into (co-routine) stack• we just have to save EFLAGS, ESP, and registers
resume:pushfpushamov EDX, [CURR]mov [EDX+SPP], ESP
Co-routine resumeCo-routine resume
Co-routine resumeCo-routine resume
EBX is pointer to co-init structure of co-routine to be resumedCURR holds a pointer to co-init structure of the current co-routine
resume:pushf ; save state of callerpushamov EDX, [CURR]mov [EDX+SPP],ESP ; save current SP
do_resume:mov ESP, [EBX+SPP] ; load SP for resumed co-routinemov [CURR], EBXpopa ; restore resumed co-routine statepopfret ; "return" to resumed co-routine!
Function1Function1
This function used as code for co-routines 0 and 1FMT1: db "Function1, co %lx, called by %lx, pass %ld", 10, 0
Function1:push dword 1push dword [CORS+8]push dword [CURR]push dword FMT1call printfadd ESP, 20mov EBX, [CORS+8] ; resume a schedulercall dword resume
push 2push dword [CORS+8]push dword [CURR]push dword FMT1call printfadd ESP, 20mov EBX, [CORS+8] ; resume a schedulercall dword resume
Function2Function2This function used as code for co-routine 2FMT2: db "Function2, co %lx, called by %lx, pass %ld", 10, 0
Function2:push dword 1push dword [CORS]push dword [CURR]push dword FMT2call printfadd ESP, 16mov EBX, [CORS] ; resume CO1call dword resume
push dword 2push dword [CORS+4]push dword [CURR]push dword FMT2call printfadd ESP, 20
mov EBX, [CORS+4] ; resume CO2call dword resumepush dword 3push dword [CORS]push dword [CURR]push dword FMT2call printfadd ESP, 16mov EBX, [CORS] ; resume CO1call dword resumepush dword 4push dword [CORS+4]push dword [CURR]push dword FMT2call printfadd ESP, 16mov EBX, [CORS+4] ; resume CO2call dword resumejmp end_co ; resume main
Start co-routine schedulerStart co-routine scheduler
• We start scheduling by suspending main function and starting (resuming) a first co-routine (scheduler)
• In our implementation, we call (from c) to start_co_from_c(2)
start_co_from_c:pushamov [SPMAIN], ESP ; save stack pointer of the main codemov EBX, [EBP+8] ; gets ID number of a scheduler structuremov EBX, [EBX*4 + CORS] ; gets a pointer to a scheduler structurejmp do_resume ; resume a scheduler co-routine
co-routine start and endco-routine start and endC-callable start of the first co-routine
start_co_from_c:push EBPmov EBP, ESPpushamov [SPMAIN], ESP ; save SP of main codemov EBX, [EBP+8] ; get number of co-routinemov EBX, [EBX*4+CORS] ; and pointer to co-routine structurejmp do_resume
End co-routine mechanism, back to c main
end_co:mov ESP, [SPMAIN] ; restore state of main codepopapop EBPret
Main.c#include <stdio.h>extern long numco;extern void end_co();extern void start_co_from_c(int num);extern void init_co_from_c(int num);extern void resume_from_c(int num);
main() {long i;for(i = 0; i < numco; i++)
init_co_from_c(i); // initialize co-routinesprintf("After init\n");start_co_from_c(2); // start a scheduler co-routineprintf("All co-routines done\n");
}
Run example – data declarationRun example – data declaration
CURR
SPT
SPMAIN
STK1
STK2
STK3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
0 Flags1
SP1
Function1 CO2
0 Flags2
SP2
Function2 CO3
0 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .data
AfterAfter co-routine initializationco-routine initialization
CURR
SPT
SPMAIN
STK1
Registers
Flags
Function1
STK2
Registers
Flags
Function1
STK3
Registers
Flags
Function2
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .data
Resuming - right beforeResuming - right before
CO2 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
STK2
ESP ……….
……….
STK3
Registers
Flags
Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
resume:pushf
pushamov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
.bss .data
Resuming – resume is calledResuming – resume is called
CO2 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
STK2
ESP Addr2
……….
……….
STK3
Registers
Flags
Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
Resuming – backup registersResuming – backup registers
CO2 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
ESP Registers STK2
Flags
Addr2
……….
……….
STK3
Registers
Flags
Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
Resuming – backup stack pointer Resuming – backup stack pointer
CO2 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
ESP Registers STK2
Flags
Addr2
……….
……….
STK3
Registers
Flags
Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
Resuming Resuming - - load stack pointer of resume co-routineload stack pointer of resume co-routine
CO2 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
Registers STK2
Flags
Addr2
……….
……….
STK3
ESP Registers
Flags
Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP,
[EBX+SPP] mov [CURR], EBXpopapopfret
Resuming – Resuming – set current co-routine variableset current co-routine variable
CO3 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
Registers STK2
Flags
Addr2
……….
……….
STK3
ESP Registers
Flags
Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
Resuming – Resuming – restore a state of loaded co-routinerestore a state of loaded co-routine
CO3 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
Registers STK2
Flags
Addr2
……….
……….
STK3
ESP Addr3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
Resuming – Resuming – go to execute the loaded co-routinego to execute the loaded co-routine
CO3 CURR
SPT
SPMAIN
STK1
Registers
Flags
Addr1
Registers STK2
Flags
Addr2
……….
……….
STK3
3 numco
CO1 CORS
CO2
CO3
Function1 CO1
1 Flags1
SP1
Function1 CO2
1 Flags2
SP2
Function2 CO3
1 Flags3
SP3
0 COUNTER
3 MAX_ITER
.bss .dataresume:
pushfpusha
mov EDX, [CURR]mov [EDX+SPP],ESP
do_resume:mov ESP, [EBX+SPP] mov [CURR], EBXpopapopfret
Top Related