Added a library version of spawn. Before long, we can remove the old version.
This commit is contained in:
parent
871d1317e5
commit
b2dad8af31
src
lib
rt
test/stdtest
@ -1,3 +1,5 @@
|
||||
import cast = unsafe::reinterpret_cast;
|
||||
|
||||
native "rust" mod rustrt {
|
||||
fn task_sleep(time_in_us: uint);
|
||||
fn task_yield();
|
||||
@ -9,8 +11,15 @@ native "rust" mod rustrt {
|
||||
fn clone_chan(c: *rust_chan) -> *rust_chan;
|
||||
|
||||
type rust_chan;
|
||||
type rust_task;
|
||||
|
||||
fn set_min_stack(stack_size: uint);
|
||||
|
||||
fn new_task() -> task_id;
|
||||
fn get_task_pointer(id : task_id) -> *rust_task;
|
||||
fn get_task_context(id : task_id) -> *x86_registers;
|
||||
fn start_task(id : task_id);
|
||||
fn get_task_trampoline() -> u32;
|
||||
}
|
||||
|
||||
type task_id = int;
|
||||
@ -54,6 +63,76 @@ fn set_min_stack(stack_size : uint) {
|
||||
rustrt::set_min_stack(stack_size);
|
||||
}
|
||||
|
||||
// FIXME: make this a fn~ once those are supported.
|
||||
fn _spawn(thunk : -fn() -> ()) -> task_id {
|
||||
let id = rustrt::new_task();
|
||||
|
||||
// the order of arguments are outptr, taskptr, envptr.
|
||||
|
||||
// In LLVM fastcall puts the first two in ecx, edx, and the rest on the
|
||||
// stack.
|
||||
let regs = rustrt::get_task_context(id);
|
||||
|
||||
// set up the task pointer
|
||||
let task_ptr : u32 = cast(rustrt::get_task_pointer(id));
|
||||
(*regs).edx = task_ptr;
|
||||
|
||||
let raw_thunk : { code: u32, env: u32 } = cast(thunk);
|
||||
(*regs).eip = raw_thunk.code;
|
||||
|
||||
log_err #fmt("{ %u, %u }", raw_thunk.code as uint, raw_thunk.env as uint);
|
||||
|
||||
// okay, now we align the stack and add the environment pointer and a fake
|
||||
// return address.
|
||||
|
||||
// -12 for the taskm output location, the env pointer
|
||||
// -4 for the return address.
|
||||
(*regs).esp = align_down((*regs).esp - 12u32) - 4u32;
|
||||
|
||||
let ra : *mutable u32 = cast((*regs).esp);
|
||||
let env : *mutable u32 = cast((*regs).esp+4u32);
|
||||
let tptr : *mutable u32 = cast((*regs).esp+12u32);
|
||||
|
||||
// put the return pointer in ecx.
|
||||
(*regs).ecx = (*regs).esp + 8u32;
|
||||
|
||||
*tptr = task_ptr;
|
||||
*env = raw_thunk.env;
|
||||
*ra = rustrt::get_task_trampoline();
|
||||
|
||||
rustrt::start_task(id);
|
||||
|
||||
ret id;
|
||||
}
|
||||
|
||||
// Who says we can't write an operating system in Rust?
|
||||
type x86_registers = {
|
||||
// This needs to match the structure in context.h
|
||||
mutable eax : u32,
|
||||
mutable ebx : u32,
|
||||
mutable ecx : u32,
|
||||
mutable edx : u32,
|
||||
mutable ebp : u32,
|
||||
mutable esi : u32,
|
||||
mutable edi : u32,
|
||||
mutable esp : u32,
|
||||
|
||||
mutable cs : u16,
|
||||
mutable ds : u16,
|
||||
mutable ss : u16,
|
||||
mutable es : u16,
|
||||
mutable fs : u16,
|
||||
mutable gs : u16,
|
||||
|
||||
mutable eflags : u32,
|
||||
mutable eip : u32
|
||||
};
|
||||
|
||||
fn align_down(x : u32) -> u32 {
|
||||
// Aligns x down to 16 bytes
|
||||
x & !(15u32)
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
|
@ -22,17 +22,17 @@ swap_registers:
|
||||
movl 4(%esp), %eax
|
||||
//movl %eax, 0(%eax)
|
||||
movl %ebx, 4(%eax)
|
||||
//movl %ecx, 8(%eax)
|
||||
//movl %edx, 12(%eax)
|
||||
movl %ecx, 8(%eax)
|
||||
movl %edx, 12(%eax)
|
||||
movl %ebp, 16(%eax)
|
||||
movl %esi, 20(%eax)
|
||||
movl %edi, 24(%eax)
|
||||
movw %cs, 32(%eax)
|
||||
movw %ds, 34(%eax)
|
||||
movw %ss, 36(%eax)
|
||||
movw %es, 38(%eax)
|
||||
movw %fs, 40(%eax)
|
||||
movw %gs, 42(%eax)
|
||||
//movl %cs, 32(%eax)
|
||||
//movl %ds, 34(%eax)
|
||||
//movl %ss, 36(%eax)
|
||||
//movl %es, 38(%eax)
|
||||
//movl %fs, 40(%eax)
|
||||
//movl %gs, 42(%eax)
|
||||
|
||||
// save the flags
|
||||
pushf
|
||||
@ -50,23 +50,32 @@ swap_registers:
|
||||
|
||||
movl 4(%eax), %ebx
|
||||
// save ecx for later...
|
||||
//movl 12(%eax), %edx
|
||||
movl 12(%eax), %edx
|
||||
movl 16(%eax), %ebp
|
||||
movl 20(%eax), %esi
|
||||
movl 24(%eax), %edi
|
||||
movl 28(%eax), %esp
|
||||
// We can't actually change this...
|
||||
//movl 32(%eax), %cs
|
||||
movw 34(%eax), %ds
|
||||
movw 36(%eax), %ss
|
||||
movw 38(%eax), %es
|
||||
movw 40(%eax), %fs
|
||||
movw 42(%eax), %gs
|
||||
//movl 34(%eax), %ds
|
||||
//movl 36(%eax), %ss
|
||||
//movl 38(%eax), %es
|
||||
//movl 40(%eax), %fs
|
||||
//movl 42(%eax), %gs
|
||||
|
||||
// restore the flags
|
||||
movl 44(%eax), %ecx
|
||||
push %ecx
|
||||
popf
|
||||
|
||||
// ok, now we can restore ecx
|
||||
movl 8(%eax), %ecx
|
||||
|
||||
// Return!
|
||||
jmp *48(%eax)
|
||||
|
||||
|
||||
.globl task_trampoline
|
||||
task_trampoline:
|
||||
// This gets set up by std::task::_spawn.
|
||||
call _task_exit
|
||||
|
@ -18,9 +18,9 @@ struct registers_t {
|
||||
};
|
||||
|
||||
class context {
|
||||
public:
|
||||
registers_t regs;
|
||||
|
||||
public:
|
||||
context();
|
||||
|
||||
context *next;
|
||||
|
@ -707,6 +707,37 @@ get_task_id(rust_task *task) {
|
||||
return task->id;
|
||||
}
|
||||
|
||||
extern "C" CDECL rust_task_id
|
||||
new_task(rust_task *task) {
|
||||
return task->kernel->create_task(task, NULL);
|
||||
}
|
||||
|
||||
extern "C" CDECL registers_t *
|
||||
get_task_context(rust_task *task, rust_task_id id) {
|
||||
registers_t *regs = &task->kernel->get_task_by_id(id)->ctx.regs;
|
||||
// This next line is a little dangerous.. It means we can only safely call
|
||||
// this when starting a task.
|
||||
regs->esp = task->rust_sp;
|
||||
return regs;
|
||||
}
|
||||
|
||||
extern "C" CDECL rust_task *
|
||||
get_task_pointer(rust_task *task, rust_task_id id) {
|
||||
return task->kernel->get_task_by_id(id);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
start_task(rust_task *task, rust_task_id id) {
|
||||
task->kernel->get_task_by_id(id)->start();
|
||||
}
|
||||
|
||||
extern "C" void *task_trampoline asm("task_trampoline");
|
||||
|
||||
extern "C" CDECL void **
|
||||
get_task_trampoline(rust_task *task) {
|
||||
return &task_trampoline;
|
||||
}
|
||||
|
||||
extern "C" CDECL rust_chan *
|
||||
clone_chan(rust_task *task, rust_chan *chan) {
|
||||
return chan->clone(task);
|
||||
|
@ -52,13 +52,6 @@ del_stk(rust_task *task, stk_seg *stk)
|
||||
}
|
||||
|
||||
// Tasks
|
||||
|
||||
// FIXME (issue #31): ifdef by platform. This is getting absurdly
|
||||
// x86-specific.
|
||||
|
||||
size_t const n_callee_saves = 4;
|
||||
size_t const callee_save_fp = 0;
|
||||
|
||||
rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
|
||||
rust_task *spawner, const char *name) :
|
||||
ref_count(1),
|
||||
@ -115,15 +108,8 @@ struct spawn_args {
|
||||
};
|
||||
|
||||
extern "C" CDECL
|
||||
void task_start_wrapper(spawn_args *a)
|
||||
{
|
||||
rust_task *task = a->task;
|
||||
int rval = 42;
|
||||
|
||||
a->f(&rval, task, a->a3, a->a4);
|
||||
|
||||
void task_exit(void *env, int rval, rust_task *task) {
|
||||
LOG(task, task, "task exited with value %d", rval);
|
||||
|
||||
task->die();
|
||||
task->lock.lock();
|
||||
task->notify_tasks_waiting_to_join();
|
||||
@ -132,6 +118,16 @@ void task_start_wrapper(spawn_args *a)
|
||||
task->yield(1);
|
||||
}
|
||||
|
||||
extern "C" CDECL
|
||||
void task_start_wrapper(spawn_args *a)
|
||||
{
|
||||
rust_task *task = a->task;
|
||||
int rval = 42;
|
||||
|
||||
a->f(&rval, task, a->a3, a->a4);
|
||||
task_exit(NULL, rval, task);
|
||||
}
|
||||
|
||||
void
|
||||
rust_task::start(uintptr_t spawnee_fn,
|
||||
uintptr_t args)
|
||||
@ -154,6 +150,11 @@ rust_task::start(uintptr_t spawnee_fn,
|
||||
|
||||
ctx.call((void *)task_start_wrapper, a, sp);
|
||||
|
||||
this->start();
|
||||
}
|
||||
|
||||
void rust_task::start()
|
||||
{
|
||||
yield_timer.reset_us(0);
|
||||
transition(&sched->newborn_tasks, &sched->running_tasks);
|
||||
sched->lock.signal();
|
||||
|
@ -109,6 +109,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
|
||||
|
||||
void start(uintptr_t spawnee_fn,
|
||||
uintptr_t args);
|
||||
void start();
|
||||
void grow(size_t n_frame_bytes);
|
||||
bool running();
|
||||
bool blocked();
|
||||
|
@ -27,7 +27,10 @@ do_gc
|
||||
drop_chan
|
||||
drop_port
|
||||
get_port_id
|
||||
get_task_context
|
||||
get_task_id
|
||||
get_task_pointer
|
||||
get_task_trampoline
|
||||
get_time
|
||||
hack_allow_leaks
|
||||
ivec_copy_from_buf
|
||||
@ -40,6 +43,7 @@ last_os_error
|
||||
nano_time
|
||||
new_chan
|
||||
new_port
|
||||
new_task
|
||||
pin_task
|
||||
port_recv
|
||||
unpin_task
|
||||
@ -61,6 +65,7 @@ set_min_stack
|
||||
sched_threads
|
||||
size_of
|
||||
squareroot
|
||||
start_task
|
||||
str_alloc
|
||||
str_buf
|
||||
str_byte_len
|
||||
|
@ -33,3 +33,8 @@ fn test_send_recv() {
|
||||
assert (task::recv(p) == 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lib_spawn() {
|
||||
fn foo() { log_err "Hello, World!"; }
|
||||
task::_spawn(foo);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user