Wrote swap_context in assembly. Closes #548. This also allows us to re-enable optimization on OSX for both gcc and clang. Also, re-enamed task-comm-1.rs, which was previously broken by optimization.
This commit is contained in:
parent
3c534b2bef
commit
98dee91f25
|
@ -48,8 +48,8 @@ ifeq ($(CFG_OSTYPE), Darwin)
|
|||
# approaches welcome!
|
||||
#
|
||||
# NB: Currently GCC's optimizer breaks rustrt (task-comm-1 hangs) on Darwin.
|
||||
CFG_GCC_CFLAGS += -m32 -O0
|
||||
CFG_CLANG_CFLAGS += -m32 -O0
|
||||
CFG_GCC_CFLAGS += -m32 -O2
|
||||
CFG_CLANG_CFLAGS += -m32 -O2
|
||||
ifeq ($(CFG_CPUTYPE), x86_64)
|
||||
CFG_GCCISH_CFLAGS += -arch i386
|
||||
CFG_GCCISH_LINK_FLAGS += -arch i386
|
||||
|
|
|
@ -25,7 +25,6 @@ get_registers:
|
|||
movl %ebp, 16(%eax)
|
||||
movl %esi, 20(%eax)
|
||||
movl %edi, 24(%eax)
|
||||
movl %esp, 28(%eax)
|
||||
movw %cs, 32(%eax)
|
||||
movw %ds, 34(%eax)
|
||||
movw %ss, 36(%eax)
|
||||
|
@ -39,12 +38,14 @@ get_registers:
|
|||
movl %ecx, 44(%eax)
|
||||
|
||||
// save the return address as the instruction pointer
|
||||
movl 0(%esp), %ecx
|
||||
// and save the stack pointer of the caller
|
||||
popl %ecx
|
||||
movl %esp, 28(%eax)
|
||||
movl %ecx, 48(%eax)
|
||||
|
||||
// return 0
|
||||
xor %eax, %eax
|
||||
ret
|
||||
jmp *%ecx
|
||||
|
||||
.globl set_registers
|
||||
set_registers:
|
||||
|
@ -70,13 +71,9 @@ set_registers:
|
|||
push %ecx
|
||||
popf
|
||||
|
||||
// get ready to return back to the old eip
|
||||
// We could write this directly to 0(%esp), but Valgrind on OS X
|
||||
// complains.
|
||||
pop %ecx
|
||||
// get ready to return.
|
||||
mov 48(%eax), %ecx
|
||||
push %ecx
|
||||
//movl %ecx, 0(%esp)
|
||||
|
||||
// okay, now we can restore ecx.
|
||||
movl 8(%eax), %ecx
|
||||
|
@ -84,3 +81,26 @@ set_registers:
|
|||
// return 1 to the saved eip
|
||||
movl $1, %eax
|
||||
ret
|
||||
|
||||
// swap_registers(registers_t *oregs, registers_t *regs)
|
||||
.globl swap_registers
|
||||
swap_registers:
|
||||
// %eax = get_registers(oregs);
|
||||
movl 4(%esp), %eax
|
||||
push %eax
|
||||
call get_registers
|
||||
|
||||
// if(!%eax) goto call_set
|
||||
test %eax, %eax
|
||||
jz call_set
|
||||
|
||||
// else
|
||||
addl $4, %esp
|
||||
ret
|
||||
|
||||
call_set:
|
||||
// set_registers(regs)
|
||||
movl 12(%esp), %eax
|
||||
movl %eax, 0(%esp)
|
||||
call set_registers
|
||||
// set_registers never returns
|
|
@ -5,32 +5,22 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" uint32_t CDECL get_registers(registers_t *regs)
|
||||
asm ("get_registers");
|
||||
extern "C" uint32_t CDECL set_registers(registers_t *regs)
|
||||
asm ("set_registers");
|
||||
//extern "C" uint32_t CDECL get_registers(registers_t *regs)
|
||||
// asm ("get_registers");
|
||||
extern "C" uint32_t CDECL swap_registers(registers_t *oregs,
|
||||
registers_t *regs)
|
||||
asm ("swap_registers");
|
||||
|
||||
context::context()
|
||||
: next(NULL)
|
||||
{
|
||||
get_registers(®s);
|
||||
}
|
||||
|
||||
void context::set()
|
||||
{
|
||||
//printf("Activating %p...\n", this);
|
||||
set_registers(®s);
|
||||
//get_registers(®s);
|
||||
swap_registers(®s, ®s);
|
||||
}
|
||||
|
||||
void context::swap(context &out)
|
||||
{
|
||||
//printf("Swapping to %p and saving in %p\n", this, &out);
|
||||
uint32_t r = get_registers(&out.regs);
|
||||
//printf("get_registers = %d, sp = 0x%x\n", r, out.regs.esp);
|
||||
if(!r) {
|
||||
set();
|
||||
}
|
||||
//printf("Resumed %p...\n", &out);
|
||||
swap_registers(&out.regs, ®s);
|
||||
}
|
||||
|
||||
void context::call(void *f, void *arg, void *stack) {
|
||||
|
@ -43,7 +33,6 @@ void context::call(void *f, void *arg, void *stack) {
|
|||
*--sp = (uint32_t)this;
|
||||
*--sp = (uint32_t)arg;
|
||||
*--sp = 0xdeadbeef;
|
||||
*--sp = 0xca11ab1e;
|
||||
|
||||
regs.esp = (uint32_t)sp;
|
||||
regs.eip = (uint32_t)f;
|
||||
|
|
|
@ -25,8 +25,6 @@ public:
|
|||
|
||||
context *next;
|
||||
|
||||
void set();
|
||||
|
||||
void swap(context &out);
|
||||
|
||||
void call(void *f, void *arg, void *sp);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// xfail-stage0
|
||||
// xfail-stage1
|
||||
// xfail-stage2
|
||||
|
||||
use std;
|
||||
|
||||
import std::task::join;
|
||||
|
||||
fn main() -> () {
|
||||
test00();
|
||||
}
|
||||
|
@ -10,7 +13,7 @@ fn start() {
|
|||
}
|
||||
|
||||
fn test00() {
|
||||
let task t = spawn thread start();
|
||||
join t;
|
||||
let task t = spawn start();
|
||||
join(t);
|
||||
log "Completing.";
|
||||
}
|
Loading…
Reference in New Issue