Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coroutine context: support mingw #172

Merged
merged 2 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/demo/coroutine/process_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static tb_void_t tb_demo_coroutine_proc(tb_cpointer_t priv)
{
// init process
tb_process_attr_t attr = {0};
attr.outpipe = file[1];
attr.out.pipe = file[1];
attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE;
tb_process_ref_t process = tb_process_init(argv[1], (tb_char_t const**)(argv + 1), &attr);
if (process)
Expand Down
2 changes: 1 addition & 1 deletion src/demo/coroutine/stackless/process_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static tb_void_t tb_demo_lo_coroutine_func(tb_lo_coroutine_ref_t coroutine, tb_c
if (tb_pipe_file_init_pair(process->file, 0))
{
// init process
process->attr.outpipe = process->file[1];
process->attr.out.pipe = process->file[1];
process->attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE;
process->proc = tb_process_init(process->argv[1], (tb_char_t const**)(process->argv + 1), &process->attr);
if (process->proc)
Expand Down
160 changes: 160 additions & 0 deletions src/tbox/platform/arch/x64/context.S
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,165 @@
* implementation
*/

/**
* translated from x64/context.asm by Alvin
*
* - support mingw/cygwin on windows
*/
#ifdef _WIN32

function(tb_context_make)

// save the stack top to rax
movq %rcx, %rax
addq %rdx, %rax

// reserve space for first argument(from) and retval(from) item of context-function
subq $32, %rax

// 16-align of the stack top address
andq $-16, %rax

// reserve space for context-data on context-stack
subq $112, %rax

// context.rbx = func
movq %r8, 80(%rax)

// save bottom address of context stack as 'limit'
movq %rcx, 16(%rax)

// save address of context stack limit as 'dealloction stack'
movq %rcx, 8(%rax)

// save top address of context stack as 'base'
addq %rdx, %rcx
movq %rcx, 24(%rax)

// init fiber-storage to zero
xorq %rcx, %rcx
movq %rcx, (%rax)

// init context.retval(saved) = a writeable space (unused)
// it will write context (unused) and priv (unused) when jump to a new context function entry first
leaq 128(%rax), %rcx
movq %rcx, 96(%rax)

// context.rip = the address of label __entry
leaq __entry(%rip), %rcx
movq %rcx, 104(%rax)

// context.end = the address of label __end
leaq __end(%rip), %rcx
movq %rcx, 88(%rax)

// return pointer to context-data
ret

__entry:
// patch return address (__end) on stack
push %rbp

// jump to the context function entry(rip)
jmp *%rbx

__end:
xorq %rcx, %rcx
call _exit
hlt

endfunc


function(tb_context_jump)

// save the hidden argument: retval (from-context)
pushq %rcx

// save registers and construct the current context
pushq %rbp
pushq %rbx
pushq %rsi
pushq %rdi
pushq %r15
pushq %r14
pushq %r13
pushq %r12

// load TIB
movq %gs:(0x30), %r10

// save current stack base
movq 0x08(%r10), %rax
pushq %rax

// save current stack limit
movq 0x10(%r10), %rax
pushq %rax

// save current deallocation stack
movq 0x1478(%r10), %rax
pushq %rax

// save fiber local storage
movq 0x18(%r10), %rax
pushq %rax

// save the old context(esp) to r9
movq %rsp, %r9

// switch to the new context(esp) and stack
movq %rdx, %rsp

// load TIB
movq %gs:(0x30), %r10

// restore fiber local storage
popq %rax
movq %rax, 0x18(%r10)

// restore deallocation stack
popq %rax
movq %rax, 0x1478(%r10)

// restore stack limit
popq %rax
mov %rax, 0x10(%r10)

// restore stack base
popq %rax
movq %rax, 0x08(%r10)

// restore registers of the new context
popq %r12
popq %r13
popq %r14
popq %r15
popq %rdi
popq %rsi
popq %rbx
popq %rbp

// restore retval (saved) to rax
popq %rax

// restore the return or function address(r10)
popq %r10

// return from-context(retval: [rcx](context: r9, priv: r8)) from jump
// it will write context (unused) and priv (unused) when jump to a new context function entry first
movq %r9, (%rax)
movq %r8, 8(%rax)

movq %rax, %rcx

// jump to the return or function address(rip)
jmp *%r10

endfunc

#else

/* make context (refer to boost.context)
*
* ------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -165,3 +324,4 @@ function(tb_context_jump)

endfunc

#endif
191 changes: 190 additions & 1 deletion src/tbox/platform/arch/x86/context.S
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,196 @@
* implementation
*/

#if defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)
/**
* translated from x86/context.asm by Alvin
*
* - support mingw/cygwin.. on windows
*/
#if defined(_WIN32)

function(tb_context_make)

// save the stack top to eax
movl 4(%esp), %eax
addl 8(%esp), %eax
movl %eax, %ecx

// reserve space for first argument(from) and seh item of context-function
leal -20(%eax), %eax

// 16-align of the stack top address
andl $-16, %eax

// reserve space for context-data on context-stack
leal -40(%eax), %eax

// save top address of context stack as 'base'
movl %ecx, 12(%eax)

// save bottom address of context-stack as 'limit'
movl 4(%esp), %ecx
movl %ecx, 8(%eax)

// save bottom address of context-stack as 'dealloction stack'
movl %ecx, 4(%eax)

// set fiber-storage as zero
xorl %ecx, %ecx
movl %ecx, (%eax)

// context.ebx = func
movl 12(%esp), %ecx
movl %ecx, 28(%eax)

// context.eip = __entry
movl $__entry, %ecx
movl %ecx, 36(%eax)

// context.ebp = the address of label __end
movl $__end, %ecx
movl %ecx, 32(%eax)

// load the current seh chain from TIB
//assume fs:nothing
movl %fs:(0x0), %ecx
//assume fs:error

__walkchain:

// if (sehitem.prev == 0xffffffff) (last?) goto __found
movl (%ecx), %edx
incl %edx
jz __found

// sehitem = sehitem.prev
decl %edx
xchgl %ecx, %edx
jmp __walkchain

__found:

// context.seh.handler = sehitem.handler
movl 4(%ecx), %ecx
movl %ecx, 60(%eax)

// context.seh.prev = 0xffffffff
movl $0xffffffff, %ecx
movl %ecx, 56(%eax)

// context.seh = the address of context.seh.prev
leal 56(%eax), %ecx
movl %ecx, 16(%eax)

// return pointer to context-data
ret

__entry:

// pass old-context(context: eax, priv: edx) arguments to the context function
movl %eax, (%esp)
movl %edx, 4(%esp)

// patch return address: __end
pushl %ebp

// jump to the context function entry(eip)
jmp *%ebx

__end:

// exit(0)
xorl %eax, %eax
movl %eax, (%esp)
call __exit
hlt

endfunc


function(tb_context_jump)

// save registers and construct the current context
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi

// load TIB to edx
//assume fs:nothing
movl %fs:(0x18), %edx
//assume fs:error

// load and save current seh exception list
movl (%edx), %eax
pushl %eax

// load and save current stack base
movl 0x04(%edx), %eax
pushl %eax

// load and save current stack limit
movl 0x08(%edx), %eax
pushl %eax

// load and save current deallocation stack
movl 0xe0c(%edx), %eax
pushl %eax

// load and save fiber local storage
movl 0x10(%edx), %eax
pushl %eax

// save the old context(esp) to eax
movl %esp, %eax

// switch to the new context(esp) and stack
movl 40(%esp), %ecx
movl %ecx, %esp

// load TIB to edx
//assume fs:nothing
movl %fs:(0x18), %edx
//assume fs:error

// restore fiber local storage (context.fiber)
popl %ecx
movl %ecx, 0x10(%edx)

// restore current deallocation stack (context.dealloc)
popl %ecx
movl %ecx, 0xe0c(%edx)

// restore current stack limit (context.limit)
popl %ecx
movl %ecx, 0x08(%edx)

// restore current stack base (context.base)
popl %ecx
movl %ecx, 0x04(%edx)

// restore current seh exception list (context.seh)
popl %ecx
movl %ecx, (%edx)

// restore registers of the new context
popl %edi
popl %esi
popl %ebx
popl %ebp

// restore the return or function address(ecx)
popl %ecx

// return from-context(context: eax, priv: edx) from jump
// edx = [eax + 44] = [esp_jump + 44] = jump.argument(priv)
movl 44(%eax), %edx

// jump to the return or function address(eip)
jmp *%ecx

endfunc

#elif defined(TB_CONFIG_OS_MACOSX) || defined(TB_CONFIG_OS_IOS)

/* make context
*
Expand Down
Loading