]> git.lizzy.rs Git - rust.git/blob - src/libcore/task.rs
simplify task impl
[rust.git] / src / libcore / task.rs
1 /*
2 Module: task
3
4 Task management.
5
6 An executing Rust program consists of a tree of tasks, each with their own
7 stack, and sole ownership of their allocated heap data. Tasks communicate
8 with each other using ports and channels.
9
10 When a task fails, that failure will propagate to its parent (the task
11 that spawned it) and the parent will fail as well. The reverse is not
12 true: when a parent task fails its children will continue executing. When
13 the root (main) task fails, all tasks fail, and then so does the entire
14 process.
15
16 A task may remove itself from this failure propagation mechanism by
17 calling the <unsupervise> function, after which failure will only
18 result in the termination of that task.
19
20 Tasks may execute in parallel and are scheduled automatically by the runtime.
21
22 Example:
23
24 > spawn("Hello, World", fn (&&msg: str) {
25 >   log(debug, msg);
26 > });
27
28 */
29 import cast = unsafe::reinterpret_cast;
30 import comm;
31 import option::{some, none};
32 import option = option::t;
33 import ptr;
34 import c = ctypes;
35
36 export task;
37 export joinable_task;
38 export sleep;
39 export yield;
40 export task_notification;
41 export join;
42 export unsupervise;
43 export pin;
44 export unpin;
45 export task_result;
46 export tr_success;
47 export tr_failure;
48 export get_task;
49 export spawn;
50 export spawn_joinable;
51
52 #[abi = "rust-intrinsic"]
53 native mod rusti {
54     // these must run on the Rust stack so that they can swap stacks etc:
55     fn task_sleep(task: *rust_task, time_in_us: uint, &killed: bool);
56 }
57
58 type rust_closure = {
59     fnptr: c::intptr_t, envptr: c::intptr_t
60 };
61
62 #[link_name = "rustrt"]
63 #[abi = "cdecl"]
64 native mod rustrt {
65     // these can run on the C stack:
66     fn pin_task();
67     fn unpin_task();
68     fn get_task_id() -> task_id;
69     fn rust_get_task() -> *rust_task;
70
71     fn new_task() -> task_id;
72     fn drop_task(task_id: *rust_task);
73     fn get_task_pointer(id: task_id) -> *rust_task;
74
75     fn migrate_alloc(alloc: *u8, target: task_id);
76
77     fn start_task(id: task, closure: *rust_closure);
78 }
79
80 /* Section: Types */
81
82 type rust_task =
83     {id: task,
84      mutable notify_enabled: int,
85      mutable notify_chan: comm::chan<task_notification>,
86      mutable stack_ptr: *u8};
87
88 resource rust_task_ptr(task: *rust_task) { rustrt::drop_task(task); }
89
90 type task_id = int;
91
92 /*
93 Type: task
94
95 A handle to a task
96 */
97 type task = task_id;
98
99 /*
100 Function: spawn
101
102 Creates and executes a new child task
103
104 Sets up a new task with its own call stack and schedules it to be
105 executed.  Upon execution, the closure `f()` will be invoked.
106
107 Parameters:
108
109 f - A function to execute in the new task
110
111 Returns:
112
113 A handle to the new task
114 */
115 fn spawn(-f: sendfn()) -> task unsafe {
116     let closure: *rust_closure = unsafe::reinterpret_cast(ptr::addr_of(f));
117     #debug("spawn: closure={%x,%x}", (*closure).fnptr, (*closure).envptr);
118     let id = rustrt::new_task();
119     rustrt::start_task(id, closure);
120     unsafe::leak(f);
121     ret id;
122 }
123
124 /*
125 Type: joinable_task
126
127 A task that sends notification upon termination
128 */
129 type joinable_task = (task, comm::port<task_notification>);
130
131 fn spawn_joinable(-f: sendfn()) -> joinable_task {
132     resource notify_rsrc(data: (comm::chan<task_notification>,
133                                 task,
134                                 @mutable task_result)) {
135         let (chan, task, tr) = data;
136         let msg = exit(task, *tr);
137         comm::send(chan, msg);
138     }
139
140     let notify_port = comm::port();
141     let notify_chan = comm::chan(notify_port);
142     let g = sendfn[copy notify_chan; move f]() {
143         let this_task = rustrt::get_task_id();
144         let result = @mutable tr_failure;
145         let _rsrc = notify_rsrc((notify_chan, this_task, result));
146         f();
147         *result = tr_success; // rsrc will fire msg when fn returns
148     };
149     let task = spawn(g);
150     ret (task, notify_port);
151 }
152
153 /*
154 Tag: task_result
155
156 Indicates the manner in which a task exited
157 */
158 tag task_result {
159     /* Variant: tr_success */
160     tr_success;
161     /* Variant: tr_failure */
162     tr_failure;
163 }
164
165 /*
166 Tag: task_notification
167
168 Message sent upon task exit to indicate normal or abnormal termination
169 */
170 tag task_notification {
171     /* Variant: exit */
172     exit(task, task_result);
173 }
174
175 /* Section: Operations */
176
177 /*
178 Type: get_task
179
180 Retreives a handle to the currently executing task
181 */
182 fn get_task() -> task { rustrt::get_task_id() }
183
184 /*
185 Function: sleep
186
187 Hints the scheduler to yield this task for a specified ammount of time.
188
189 Parameters:
190
191 time_in_us - maximum number of microseconds to yield control for
192 */
193 fn sleep(time_in_us: uint) {
194     let task = rustrt::rust_get_task();
195     let killed = false;
196     // FIXME: uncomment this when extfmt is moved to core
197     // in a snapshot.
198     // #debug("yielding for %u us", time_in_us);
199     rusti::task_sleep(task, time_in_us, killed);
200     if killed {
201         fail "killed";
202     }
203 }
204
205 /*
206 Function: yield
207
208 Yield control to the task scheduler
209
210 The scheduler may schedule another task to execute.
211 */
212 fn yield() { sleep(1u) }
213
214 /*
215 Function: join
216
217 Wait for a child task to exit
218
219 The child task must have been spawned with <spawn_joinable>, which
220 produces a notification port that the child uses to communicate its
221 exit status.
222
223 Returns:
224
225 A task_result indicating whether the task terminated normally or failed
226 */
227 fn join(task_port: joinable_task) -> task_result {
228     let (id, port) = task_port;
229     alt comm::recv::<task_notification>(port) {
230       exit(_id, res) {
231         if _id == id {
232             ret res
233         } else {
234             // FIXME: uncomment this when extfmt is moved to core
235             // in a snapshot.
236             // fail #fmt["join received id %d, expected %d", _id, id]
237             fail;
238         }
239       }
240     }
241 }
242
243 /*
244 Function: unsupervise
245
246 Detaches this task from its parent in the task tree
247
248 An unsupervised task will not propagate its failure up the task tree
249 */
250 fn unsupervise() { ret sys::unsupervise(); }
251
252 /*
253 Function: pin
254
255 Pins the current task and future child tasks to a single scheduler thread
256 */
257 fn pin() { rustrt::pin_task(); }
258
259 /*
260 Function: unpin
261
262 Unpin the current task and future child tasks
263 */
264 fn unpin() { rustrt::unpin_task(); }
265
266 // Local Variables:
267 // mode: rust;
268 // fill-column: 78;
269 // indent-tabs-mode: nil
270 // c-basic-offset: 4
271 // buffer-file-coding-system: utf-8-unix
272 // End: