1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
import cast = unsafe::reinterpret_cast;
import comm;
import option::{some, none};
import option = option::t;
import ptr;
export task;
export joinable_task;
export sleep;
export yield;
export task_notification;
export join;
export unsupervise;
export pin;
export unpin;
export set_min_stack;
export task_result;
export tr_success;
export tr_failure;
export get_task_id;
export spawn;
export spawn_notify;
export spawn_joinable;
native "rust" mod rustrt {
fn task_sleep(time_in_us: uint);
fn task_yield();
fn task_join(t: task_id) -> int;
fn unsupervise();
fn pin_task();
fn unpin_task();
fn get_task_id() -> task_id;
type rust_chan;
fn set_min_stack(stack_size: uint);
fn new_task() -> task_id;
fn drop_task(task: *rust_task);
fn get_task_pointer(id: task_id) -> *rust_task;
fn migrate_alloc(alloc: *u8, target: task_id);
fn start_task(id: task_id, closure: *u8);
}
type rust_task =
{id: task,
mutable notify_enabled: u32,
mutable notify_chan: comm::chan<task_notification>,
mutable stack_ptr: *u8};
resource rust_task_ptr(task: *rust_task) { rustrt::drop_task(task); }
type task = int;
type task_id = task;
type joinable_task = (task_id, comm::port<task_notification>);
fn get_task_id() -> task_id { rustrt::get_task_id() }
/**
* Hints the scheduler to yield this task for a specified ammount of time.
*
* arg: time_in_us maximum number of microseconds to yield control for
*/
fn sleep(time_in_us: uint) { ret rustrt::task_sleep(time_in_us); }
fn yield() { ret rustrt::task_yield(); }
tag task_result { tr_success; tr_failure; }
tag task_notification { exit(task, task_result); }
fn join(task_port: (task_id, comm::port<task_notification>)) -> task_result {
let (id, port) = task_port;
alt comm::recv::<task_notification>(port) {
exit(_id, res) {
if _id == id {
ret res
} else { fail #fmt["join received id %d, expected %d", _id, id] }
}
}
}
fn join_id(t: task_id) -> task_result {
alt rustrt::task_join(t) { 0 { tr_success } _ { tr_failure } }
}
fn unsupervise() { ret rustrt::unsupervise(); }
fn pin() { rustrt::pin_task(); }
fn unpin() { rustrt::unpin_task(); }
fn set_min_stack(stack_size: uint) { rustrt::set_min_stack(stack_size); }
fn spawn<~T>(-data: T, f: fn(T)) -> task {
spawn_inner2(data, f, none)
}
fn spawn_notify<~T>(-data: T, f: fn(T),
notify: comm::chan<task_notification>) -> task {
spawn_inner2(data, f, some(notify))
}
fn spawn_joinable<~T>(-data: T, f: fn(T)) -> joinable_task {
let p = comm::port::<task_notification>();
let id = spawn_notify(data, f, comm::chan::<task_notification>(p));
ret (id, p);
}
// FIXME: To transition from the unsafe spawn that spawns a shared closure to
// the safe spawn that spawns a bare function we're going to write
// barefunc-spawn on top of unsafe-spawn. Sadly, bind does not work reliably
// enough to suite our needs (#1034, probably others yet to be discovered), so
// we're going to copy the bootstrap data into a unique pointer, cast it to an
// unsafe pointer then wrap up the bare function and the unsafe pointer in a
// shared closure to spawn.
//
// After the transition this should all be rewritten.
fn spawn_inner2<~T>(-data: T, f: fn(T),
notify: option<comm::chan<task_notification>>)
-> task_id {
fn wrapper<~T>(-data: *u8, f: fn(T)) {
let data: ~T = unsafe::reinterpret_cast(data);
f(*data);
}
let data = ~data;
let dataptr: *u8 = unsafe::reinterpret_cast(data);
unsafe::leak(data);
let wrapped = bind wrapper(dataptr, f);
ret unsafe_spawn_inner(wrapped, notify);
}
// FIXME: This is the old spawn function that spawns a shared closure.
// It is a hack and needs to be rewritten.
fn unsafe_spawn_inner(-thunk: fn@(),
notify: option<comm::chan<task_notification>>) ->
task_id unsafe {
let id = rustrt::new_task();
let raw_thunk: {code: u32, env: u32} = cast(thunk);
// set up the task pointer
let task_ptr <- rust_task_ptr(rustrt::get_task_pointer(id));
assert (ptr::null() != (**task_ptr).stack_ptr);
// copy the thunk from our stack to the new stack
let sp: uint = cast((**task_ptr).stack_ptr);
let ptrsize = sys::size_of::<*u8>();
let thunkfn: *mutable uint = cast(sp - ptrsize * 2u);
let thunkenv: *mutable uint = cast(sp - ptrsize);
*thunkfn = cast(raw_thunk.code);;
*thunkenv = cast(raw_thunk.env);;
// align the stack to 16 bytes
(**task_ptr).stack_ptr = cast(sp - ptrsize * 4u);
// set up notifications if they are enabled.
alt notify {
some(c) {
(**task_ptr).notify_enabled = 1u32;;
(**task_ptr).notify_chan = c;
}
none { }
}
// give the thunk environment's allocation to the new task
rustrt::migrate_alloc(cast(raw_thunk.env), id);
rustrt::start_task(id, cast(thunkfn));
// don't cleanup the thunk in this task
unsafe::leak(thunk);
ret id;
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
|