STKSZ equ 16*1024 CODEP equ 0 FLAGSP equ 4 SPP equ 8 BUFFCNT equ 10 section .rodata align 16 global numco numco: dd 4 CORS: dd CO1 dd CO2 dd CO3 dd CO4 section .data align 16 ; Structure for first co-routine (writer) CO1: dd Function1 Flags1: dd 0 SP1: dd STK1+STKSZ ; Structure for second co-routine (reader1) CO2: dd Function2 Flags2: dd 0 SP2: dd STK2+STKSZ ; Structure for third co-routine (reader2) CO3: dd Function3 Flags3: dd 0 SP3: dd STK3+STKSZ ; Structure for forth co-routine (scheduler) CO4: dd Function4 Flags4: dd 0 SP4: dd STK4+STKSZ SWITCH: dd 0 ; indicator - reader1/reader2 EXIT: db 0 ; indicator - becomes 1 if we should exit FINISH: db 0 ; indicator - becomes 1 if input is fully written MUX: db 1 ; indicator - which reader to choose section .bss align 16 CURR: resd 1 SPT: resd 1 SPMAIN: resd 1 STK1: resb STKSZ STK2: resb STKSZ STK3: resb STKSZ STK4: resb STKSZ BUFFER: resb 4 INPUT: resb 4 BUFF: resb 4 section .text align 16 extern printf extern gets global init_co_from_c global start_co_from_c global end_co ; Initalize a co-routine number given as an argument from C init_co_from_c: push EBP mov EBP, ESP push EBX mov EBX, [EBP+8] mov EBX, [EBX*4+CORS] call co_init pop EBX pop EBP ret ; EBX is pointer to co-routine structure to initialize co_init: pusha bts dword [EBX+FLAGSP],0 ; test if already initialized jc init_done mov EAX,[EBX+CODEP] ; Get initial PC mov [SPT], ESP mov ESP,[EBX+SPP] ; Get initial SP mov EBP, ESP ; Also use as EBP push EAX ; Push initial "return" address pushf ; and flags pusha ; and all other regs mov [EBX+SPP],ESP ; Save new SP in structure mov ESP, [SPT] ; Restore original SP init_done: popa ret ; EBX is pointer to co-init structure of co-routine to be resumed ; CURR holds a pointer to co-init structure of the curent co-routine resume: pushf ; Save state of caller pusha mov EDX, [CURR] mov [EDX+SPP],ESP ; Save current SP do_resume: mov ESP, [EBX+SPP] ; Load SP for resumed co-routine mov [CURR], EBX popa ; Restore resumed co-routine state popf ret ; "return" to resumed co-routine! ; C-callable start of the first co-routine start_co_from_c: push EBP mov EBP, ESP pusha mov [SPMAIN], ESP ; Save SP of main code mov EBX, [EBP+8] ; Get number of co-routine mov EBX, [EBX*4+CORS] ; and pointer to co-routine structure jmp do_resume ; End co-routine mechanism, back to C main end_co: mov ESP, [SPMAIN] ; Restore state of main code popa pop EBP ret ; Example functions using co-routine mechanism WRITERES: db "Writer Resumes.", 10, 0 READ1RES: db "Reader1 Resumes.", 10, 0 READ2RES: db "Reader2 Resumes.", 10, 0 SCHEDRES: db "Scheduler Resumes.", 10, 0 WRITER: db "Writer: %s", 10, 0 READ1: db "Reader1: %s", 10, 0 READ2: db "Reader2: %s", 10, 0 SCHED: db "Scheduler: %s", 10, 0 WRITEPROM: db "Writer: Hello, master. What can I write and read for you today? ", 0 WRITING: db "Writer: Writing %s.", 10, 0 WRITEFIN: db "Writer: I have finished writing your words of wisdom, sir.", 10, 0 READSORR: db "Terribly sorry, sir. The buffer is locked by the writer.", 0 READFIN1: db "Reader1: Ah, a fine read, sir. You wrote: %s.", 10, 0 READFIN2: db "Reader2: Ah, a fine read, sir. You wrote: %s.", 10, 0 GOODBYE: db "Goodbye, master.", 0 ; This function used as code for co-routines 0 and 1 Function1: push dword WRITERES ; display resume call printf add esp, 4 NeWInput: push dword WRITEPROM call printf add esp, 4 mov ecx, INPUT pusha push ecx call gets add esp, 4 popa pusha push ecx call printf add esp, 4 popa mov byte[FINISH], 0 cmp byte[ecx], 113 ; q je quit mov edx, BUFF loop_init: mov esi, 0 ; loop counter till 10 mov ebx, BUFFER func1_loop: mov al, byte[ecx] cmp al, 0 je end_string mov byte[ebx], al ;mov byte[edx], al inc ebx inc ecx ;inc edx inc esi cmp esi ,BUFFCNT jne func1_loop end_10_chars: mov byte[ebx], 0 pusha push dword BUFFER push dword WRITING call printf add esp, 8 popa mov ebx, [CORS + 12] call dword resume pusha push dword WRITERES ; display resume call printf add esp, 4 popa jmp loop_init end_string: mov byte[FINISH], 1 mov byte[ebx], 0 ;mov byte[edx], 0 pusha push dword BUFFER push dword WRITING call printf add esp, 8 popa pusha push dword WRITEFIN call printf add esp, 4 popa mov ebx, [CORS + 12] call dword resume jmp Function1 quit: mov byte[EXIT], 1 pusha push dword GOODBYE push dword WRITER call printf add esp, 8 popa mov ebx, [CORS + 12] call dword resume ; This function used as code for co-routine 2 Function2: first_reader: mov eax, READ1RES pusha push eax call printf add esp, 4 popa cmp byte[EXIT], 1 je goodbye1 cmp byte[FINISH], 1 jne sorry1 read_buffer1: pusha push dword INPUT push dword READFIN1 call printf add esp, 8 popa jmp func2_loop1 sorry1: push dword READSORR push dword READ1 call printf add esp, 8 jmp func2_loop1 goodbye1: push dword GOODBYE push dword READ1 call printf add esp, 8 func2_loop1: mov ebx, [CORS + 12] call dword resume jmp first_reader ; This function used as code for co-routine 3 Function3: second_reader: mov eax, READ2RES push eax call printf add esp, 4 cmp byte[EXIT], 1 je goodbye2 cmp byte[FINISH], 1 jne sorry2 read_buffer2: push dword INPUT push dword READFIN2 call printf add esp, 8 jmp func2_loop2 sorry2: push dword READSORR push dword READ2 call printf add esp, 8 jmp func2_loop2 goodbye2: push dword GOODBYE push dword READ2 call printf add esp, 8 func2_loop2: mov ebx, [CORS + 12] call dword resume jmp second_reader ; This function used as code for co-routine 3 Function4: Writer: push dword SCHEDRES call printf add esp, 4 mov ebx, [CORS] call dword resume push dword INPUT; call printf add esp, 4 cmp byte[EXIT], 1 je Reader1 cmp byte[MUX], 2 je Reader2 Reader1: push dword SCHEDRES call printf add esp, 4 mov ebx, [CORS + 4] call dword resume mov byte[MUX], 2 cmp byte[EXIT], 1 jne Writer Reader2: push dword SCHEDRES call printf add esp, 4 mov ebx, [CORS + 8] call dword resume mov byte[MUX], 1 cmp byte[EXIT], 1 jne Writer finish: push dword SCHEDRES call printf add esp, 4 cmp byte[EXIT], 1 jne Function3 push dword GOODBYE push dword SCHED call printf add esp, 8 jmp end_co