Skip to content

Commit b2dad8a

Browse files
author
Eric Holk
committed
Added a library version of spawn. Before long, we can remove the old version.
1 parent 871d131 commit b2dad8a

File tree

8 files changed

+161
-30
lines changed

8 files changed

+161
-30
lines changed

src/lib/task.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import cast = unsafe::reinterpret_cast;
2+
13
native "rust" mod rustrt {
24
fn task_sleep(time_in_us: uint);
35
fn task_yield();
@@ -9,8 +11,15 @@ native "rust" mod rustrt {
911
fn clone_chan(c: *rust_chan) -> *rust_chan;
1012

1113
type rust_chan;
14+
type rust_task;
1215

1316
fn set_min_stack(stack_size: uint);
17+
18+
fn new_task() -> task_id;
19+
fn get_task_pointer(id : task_id) -> *rust_task;
20+
fn get_task_context(id : task_id) -> *x86_registers;
21+
fn start_task(id : task_id);
22+
fn get_task_trampoline() -> u32;
1423
}
1524

1625
type task_id = int;
@@ -54,6 +63,76 @@ fn set_min_stack(stack_size : uint) {
5463
rustrt::set_min_stack(stack_size);
5564
}
5665

66+
// FIXME: make this a fn~ once those are supported.
67+
fn _spawn(thunk : -fn() -> ()) -> task_id {
68+
let id = rustrt::new_task();
69+
70+
// the order of arguments are outptr, taskptr, envptr.
71+
72+
// In LLVM fastcall puts the first two in ecx, edx, and the rest on the
73+
// stack.
74+
let regs = rustrt::get_task_context(id);
75+
76+
// set up the task pointer
77+
let task_ptr : u32 = cast(rustrt::get_task_pointer(id));
78+
(*regs).edx = task_ptr;
79+
80+
let raw_thunk : { code: u32, env: u32 } = cast(thunk);
81+
(*regs).eip = raw_thunk.code;
82+
83+
log_err #fmt("{ %u, %u }", raw_thunk.code as uint, raw_thunk.env as uint);
84+
85+
// okay, now we align the stack and add the environment pointer and a fake
86+
// return address.
87+
88+
// -12 for the taskm output location, the env pointer
89+
// -4 for the return address.
90+
(*regs).esp = align_down((*regs).esp - 12u32) - 4u32;
91+
92+
let ra : *mutable u32 = cast((*regs).esp);
93+
let env : *mutable u32 = cast((*regs).esp+4u32);
94+
let tptr : *mutable u32 = cast((*regs).esp+12u32);
95+
96+
// put the return pointer in ecx.
97+
(*regs).ecx = (*regs).esp + 8u32;
98+
99+
*tptr = task_ptr;
100+
*env = raw_thunk.env;
101+
*ra = rustrt::get_task_trampoline();
102+
103+
rustrt::start_task(id);
104+
105+
ret id;
106+
}
107+
108+
// Who says we can't write an operating system in Rust?
109+
type x86_registers = {
110+
// This needs to match the structure in context.h
111+
mutable eax : u32,
112+
mutable ebx : u32,
113+
mutable ecx : u32,
114+
mutable edx : u32,
115+
mutable ebp : u32,
116+
mutable esi : u32,
117+
mutable edi : u32,
118+
mutable esp : u32,
119+
120+
mutable cs : u16,
121+
mutable ds : u16,
122+
mutable ss : u16,
123+
mutable es : u16,
124+
mutable fs : u16,
125+
mutable gs : u16,
126+
127+
mutable eflags : u32,
128+
mutable eip : u32
129+
};
130+
131+
fn align_down(x : u32) -> u32 {
132+
// Aligns x down to 16 bytes
133+
x & !(15u32)
134+
}
135+
57136
// Local Variables:
58137
// mode: rust;
59138
// fill-column: 78;

src/rt/arch/i386/_context.s

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,17 @@ swap_registers:
2222
movl 4(%esp), %eax
2323
//movl %eax, 0(%eax)
2424
movl %ebx, 4(%eax)
25-
//movl %ecx, 8(%eax)
26-
//movl %edx, 12(%eax)
25+
movl %ecx, 8(%eax)
26+
movl %edx, 12(%eax)
2727
movl %ebp, 16(%eax)
2828
movl %esi, 20(%eax)
2929
movl %edi, 24(%eax)
30-
movw %cs, 32(%eax)
31-
movw %ds, 34(%eax)
32-
movw %ss, 36(%eax)
33-
movw %es, 38(%eax)
34-
movw %fs, 40(%eax)
35-
movw %gs, 42(%eax)
30+
//movl %cs, 32(%eax)
31+
//movl %ds, 34(%eax)
32+
//movl %ss, 36(%eax)
33+
//movl %es, 38(%eax)
34+
//movl %fs, 40(%eax)
35+
//movl %gs, 42(%eax)
3636

3737
// save the flags
3838
pushf
@@ -50,23 +50,32 @@ swap_registers:
5050

5151
movl 4(%eax), %ebx
5252
// save ecx for later...
53-
//movl 12(%eax), %edx
53+
movl 12(%eax), %edx
5454
movl 16(%eax), %ebp
5555
movl 20(%eax), %esi
5656
movl 24(%eax), %edi
5757
movl 28(%eax), %esp
5858
// We can't actually change this...
5959
//movl 32(%eax), %cs
60-
movw 34(%eax), %ds
61-
movw 36(%eax), %ss
62-
movw 38(%eax), %es
63-
movw 40(%eax), %fs
64-
movw 42(%eax), %gs
60+
//movl 34(%eax), %ds
61+
//movl 36(%eax), %ss
62+
//movl 38(%eax), %es
63+
//movl 40(%eax), %fs
64+
//movl 42(%eax), %gs
6565

6666
// restore the flags
6767
movl 44(%eax), %ecx
6868
push %ecx
6969
popf
7070

71+
// ok, now we can restore ecx
72+
movl 8(%eax), %ecx
73+
7174
// Return!
7275
jmp *48(%eax)
76+
77+
78+
.globl task_trampoline
79+
task_trampoline:
80+
// This gets set up by std::task::_spawn.
81+
call _task_exit

src/rt/arch/i386/context.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ struct registers_t {
1818
};
1919

2020
class context {
21+
public:
2122
registers_t regs;
2223

23-
public:
2424
context();
2525

2626
context *next;

src/rt/rust_builtin.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,37 @@ get_task_id(rust_task *task) {
707707
return task->id;
708708
}
709709

710+
extern "C" CDECL rust_task_id
711+
new_task(rust_task *task) {
712+
return task->kernel->create_task(task, NULL);
713+
}
714+
715+
extern "C" CDECL registers_t *
716+
get_task_context(rust_task *task, rust_task_id id) {
717+
registers_t *regs = &task->kernel->get_task_by_id(id)->ctx.regs;
718+
// This next line is a little dangerous.. It means we can only safely call
719+
// this when starting a task.
720+
regs->esp = task->rust_sp;
721+
return regs;
722+
}
723+
724+
extern "C" CDECL rust_task *
725+
get_task_pointer(rust_task *task, rust_task_id id) {
726+
return task->kernel->get_task_by_id(id);
727+
}
728+
729+
extern "C" CDECL void
730+
start_task(rust_task *task, rust_task_id id) {
731+
task->kernel->get_task_by_id(id)->start();
732+
}
733+
734+
extern "C" void *task_trampoline asm("task_trampoline");
735+
736+
extern "C" CDECL void **
737+
get_task_trampoline(rust_task *task) {
738+
return &task_trampoline;
739+
}
740+
710741
extern "C" CDECL rust_chan *
711742
clone_chan(rust_task *task, rust_chan *chan) {
712743
return chan->clone(task);

src/rt/rust_task.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,6 @@ del_stk(rust_task *task, stk_seg *stk)
5252
}
5353

5454
// Tasks
55-
56-
// FIXME (issue #31): ifdef by platform. This is getting absurdly
57-
// x86-specific.
58-
59-
size_t const n_callee_saves = 4;
60-
size_t const callee_save_fp = 0;
61-
6255
rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
6356
rust_task *spawner, const char *name) :
6457
ref_count(1),
@@ -115,15 +108,8 @@ struct spawn_args {
115108
};
116109

117110
extern "C" CDECL
118-
void task_start_wrapper(spawn_args *a)
119-
{
120-
rust_task *task = a->task;
121-
int rval = 42;
122-
123-
a->f(&rval, task, a->a3, a->a4);
124-
111+
void task_exit(void *env, int rval, rust_task *task) {
125112
LOG(task, task, "task exited with value %d", rval);
126-
127113
task->die();
128114
task->lock.lock();
129115
task->notify_tasks_waiting_to_join();
@@ -132,6 +118,16 @@ void task_start_wrapper(spawn_args *a)
132118
task->yield(1);
133119
}
134120

121+
extern "C" CDECL
122+
void task_start_wrapper(spawn_args *a)
123+
{
124+
rust_task *task = a->task;
125+
int rval = 42;
126+
127+
a->f(&rval, task, a->a3, a->a4);
128+
task_exit(NULL, rval, task);
129+
}
130+
135131
void
136132
rust_task::start(uintptr_t spawnee_fn,
137133
uintptr_t args)
@@ -154,6 +150,11 @@ rust_task::start(uintptr_t spawnee_fn,
154150

155151
ctx.call((void *)task_start_wrapper, a, sp);
156152

153+
this->start();
154+
}
155+
156+
void rust_task::start()
157+
{
157158
yield_timer.reset_us(0);
158159
transition(&sched->newborn_tasks, &sched->running_tasks);
159160
sched->lock.signal();

src/rt/rust_task.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ rust_task : public kernel_owned<rust_task>, rust_cond
109109

110110
void start(uintptr_t spawnee_fn,
111111
uintptr_t args);
112+
void start();
112113
void grow(size_t n_frame_bytes);
113114
bool running();
114115
bool blocked();

src/rt/rustrt.def.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ do_gc
2727
drop_chan
2828
drop_port
2929
get_port_id
30+
get_task_context
3031
get_task_id
32+
get_task_pointer
33+
get_task_trampoline
3134
get_time
3235
hack_allow_leaks
3336
ivec_copy_from_buf
@@ -40,6 +43,7 @@ last_os_error
4043
nano_time
4144
new_chan
4245
new_port
46+
new_task
4347
pin_task
4448
port_recv
4549
unpin_task
@@ -61,6 +65,7 @@ set_min_stack
6165
sched_threads
6266
size_of
6367
squareroot
68+
start_task
6469
str_alloc
6570
str_buf
6671
str_byte_len

src/test/stdtest/task.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,8 @@ fn test_send_recv() {
3333
assert (task::recv(p) == 10);
3434
}
3535

36+
#[test]
37+
fn test_lib_spawn() {
38+
fn foo() { log_err "Hello, World!"; }
39+
task::_spawn(foo);
40+
}

0 commit comments

Comments
 (0)