Skip to content

Commit 5b3b229

Browse files
author
Eric Holk
committed
---
yaml --- r: 4749 b: refs/heads/master c: 8686645 h: refs/heads/master i: 4747: d214c45 v: v3
1 parent 0f5992c commit 5b3b229

File tree

7 files changed

+129
-19
lines changed

7 files changed

+129
-19
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 07225e2169d3a96bed28110ff976a6752c0ec0a8
2+
refs/heads/master: 8686645aad315467c97f457e8330696d88a4f9a0

trunk/src/lib/task.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
import cast = unsafe::reinterpret_cast;
2+
import comm;
3+
import comm::_chan;
4+
import option::some;
5+
import option::none;
6+
import option = option::t;
27

38
native "rust" mod rustrt {
49
fn task_sleep(time_in_us: uint);
@@ -10,7 +15,6 @@ native "rust" mod rustrt {
1015
fn get_task_id() -> task_id;
1116

1217
type rust_chan;
13-
type rust_task;
1418

1519
fn set_min_stack(stack_size: uint);
1620

@@ -26,7 +30,13 @@ native "rust" mod rustrt {
2630
fn leak<@T>(thing : -T);
2731
}
2832

29-
type task_id = int;
33+
type rust_task = {
34+
mutable notify_enabled : u8,
35+
mutable notify_chan : _chan[task_notification]
36+
};
37+
38+
type task = int;
39+
type task_id = task;
3040

3141
fn get_task_id() -> task_id {
3242
rustrt::get_task_id()
@@ -43,12 +53,13 @@ fn yield() { ret rustrt::task_yield(); }
4353

4454
tag task_result { tr_success; tr_failure; }
4555

46-
// FIXME: Re-enable this once the task type is removed from the compiler.
47-
/*
56+
tag task_notification {
57+
exit(task, task_result);
58+
}
59+
4860
fn join(t: task) -> task_result {
4961
join_id(cast(t))
5062
}
51-
*/
5263

5364
fn join_id(t : task_id) -> task_result {
5465
alt rustrt::task_join(t) { 0 { tr_success } _ { tr_failure } }
@@ -64,8 +75,22 @@ fn set_min_stack(stack_size : uint) {
6475
rustrt::set_min_stack(stack_size);
6576
}
6677

78+
fn _spawn(thunk : fn() -> ()) -> task {
79+
spawn(thunk)
80+
}
81+
82+
fn spawn(thunk : fn() -> ()) -> task {
83+
spawn_inner(thunk, none)
84+
}
85+
86+
fn spawn_notify(thunk : fn() -> (), notify : _chan[task_notification])
87+
-> task {
88+
spawn_inner(thunk, some(notify))
89+
}
90+
6791
// FIXME: make this a fn~ once those are supported.
68-
fn _spawn(thunk : fn() -> ()) -> task_id {
92+
fn spawn_inner(thunk : fn() -> (), notify : option[_chan[task_notification]])
93+
-> task_id {
6994
let id = rustrt::new_task();
7095

7196
// the order of arguments are outptr, taskptr, envptr.
@@ -75,12 +100,21 @@ fn _spawn(thunk : fn() -> ()) -> task_id {
75100
let regs = rustrt::get_task_context(id);
76101

77102
// set up the task pointer
78-
let task_ptr : u32 = cast(rustrt::get_task_pointer(id));
79-
(*regs).edx = task_ptr;
103+
let task_ptr = rustrt::get_task_pointer(id);
104+
(*regs).edx = cast(task_ptr);
80105

81106
let raw_thunk : { code: u32, env: u32 } = cast(thunk);
82107
(*regs).eip = raw_thunk.code;
83108

109+
// set up notifications if they are enabled.
110+
alt notify {
111+
some(c) {
112+
(*task_ptr).notify_enabled = 1u8;
113+
(*task_ptr).notify_chan = c;
114+
}
115+
none {}
116+
};
117+
84118
// okay, now we align the stack and add the environment pointer and a fake
85119
// return address.
86120

@@ -95,7 +129,7 @@ fn _spawn(thunk : fn() -> ()) -> task_id {
95129
// put the return pointer in ecx.
96130
(*regs).ecx = (*regs).esp + 8u32;
97131

98-
*tptr = task_ptr;
132+
*tptr = cast(task_ptr);
99133
*env = raw_thunk.env;
100134
*ra = rustrt::get_task_trampoline();
101135

trunk/src/rt/rust_chan.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ class rust_chan : public kernel_owned<rust_chan>,
2525
rust_chan *clone(rust_task *target);
2626
};
2727

28-
// Corresponds to the rust chan (currently _chan) type.
29-
struct chan_handle {
30-
rust_task_id task;
31-
rust_port_id port;
32-
};
33-
3428
//
3529
// Local Variables:
3630
// mode: C++

trunk/src/rt/rust_internal.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ struct rust_task;
5656
class rust_log;
5757
class rust_port;
5858
class rust_chan;
59-
struct chan_handle;
6059
struct rust_token;
6160
class rust_kernel;
6261
class rust_crate_cache;
@@ -68,6 +67,12 @@ struct frame_glue_fns;
6867
typedef intptr_t rust_task_id;
6968
typedef intptr_t rust_port_id;
7069

70+
// Corresponds to the rust chan (currently _chan) type.
71+
struct chan_handle {
72+
rust_task_id task;
73+
rust_port_id port;
74+
};
75+
7176
#ifndef __i386__
7277
#error "Target CPU not supported."
7378
#endif

trunk/src/rt/rust_task.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
8080
LOGPTR(sched, "new task", (uintptr_t)this);
8181
DLOG(sched, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);
8282

83+
assert((void*)this == (void*)&user);
84+
85+
user.notify_enabled = 0;
86+
8387
stk = new_stk(sched, this, 0);
8488
rust_sp = stk->limit;
8589
}
@@ -89,6 +93,19 @@ rust_task::~rust_task()
8993
DLOG(sched, task, "~rust_task %s @0x%" PRIxPTR ", refcnt=%d",
9094
name, (uintptr_t)this, ref_count);
9195

96+
if(user.notify_enabled) {
97+
rust_chan *target =
98+
get_chan_by_handle(&user.notify_chan);
99+
if(target) {
100+
task_notification msg;
101+
msg.id = id;
102+
msg.result = failed ? tr_failure : tr_success;
103+
104+
target->send(&msg);
105+
target->deref();
106+
}
107+
}
108+
92109
kernel->release_task_id(id);
93110

94111
/* FIXME: tighten this up, there are some more
@@ -400,15 +417,20 @@ rust_task::free(void *p, bool is_gc)
400417

401418
void
402419
rust_task::transition(rust_task_list *src, rust_task_list *dst) {
403-
I(sched, !sched->lock.lock_held_by_current_thread());
404-
scoped_lock with(sched->lock);
420+
bool unlock = false;
421+
if(!sched->lock.lock_held_by_current_thread()) {
422+
unlock = true;
423+
sched->lock.lock();
424+
}
405425
DLOG(sched, task,
406426
"task %s " PTR " state change '%s' -> '%s' while in '%s'",
407427
name, (uintptr_t)this, src->name, dst->name, state->name);
408428
I(sched, state == src);
409429
src->remove(this);
410430
dst->append(this);
411431
state = dst;
432+
if(unlock)
433+
sched->lock.unlock();
412434
}
413435

414436
void

trunk/src/rt/rust_task.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,32 @@ struct gc_alloc {
3434
}
3535
};
3636

37+
// portions of the task structure that are accessible from the standard
38+
// library. This struct must agree with the std::task::rust_task record.
39+
struct rust_task_user {
40+
uint8_t notify_enabled;
41+
chan_handle notify_chan;
42+
};
43+
44+
// std::lib::task::task_result
45+
enum task_result {
46+
tr_success = 0,
47+
tr_failure = 1
48+
};
49+
50+
// std::lib::task::task_notification
51+
//
52+
// since it's currently a unary tag, we only add the fields.
53+
struct task_notification {
54+
rust_task_id id;
55+
task_result result; // task_result
56+
};
57+
3758
struct
3859
rust_task : public kernel_owned<rust_task>, rust_cond
3960
{
61+
rust_task_user user;
62+
4063
RUST_ATOMIC_REFCOUNT();
4164

4265
// Fields known to the compiler.

trunk/src/test/stdtest/task.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std;
22
import std::task;
3+
import std::comm;
34

45
#[test]
56
fn test_sleep() { task::sleep(1000000u); }
@@ -11,6 +12,7 @@ fn test_unsupervise() {
1112
}
1213

1314
#[test]
15+
#[ignore]
1416
fn test_join() {
1517
fn winner() { }
1618

@@ -36,3 +38,33 @@ fn test_lib_spawn2() {
3638
fn foo(x : int) { assert(x == 42); }
3739
task::_spawn(bind foo(42));
3840
}
41+
42+
#[test]
43+
fn test_join_chan() {
44+
fn winner() { }
45+
46+
let p = comm::mk_port[task::task_notification]();
47+
task::spawn_notify(bind winner(), p.mk_chan());
48+
let s = p.recv();
49+
log_err "received task status message";
50+
log_err s;
51+
alt s {
52+
task::exit(_, task::tr_success.) { /* yay! */ }
53+
_ { fail "invalid task status received" }
54+
}
55+
}
56+
57+
#[test]
58+
fn test_join_chan_fail() {
59+
fn failer() { task::unsupervise(); fail }
60+
61+
let p = comm::mk_port[task::task_notification]();
62+
task::spawn_notify(bind failer(), p.mk_chan());
63+
let s = p.recv();
64+
log_err "received task status message";
65+
log_err s;
66+
alt s {
67+
task::exit(_, task::tr_failure.) { /* yay! */ }
68+
_ { fail "invalid task status received" }
69+
}
70+
}

0 commit comments

Comments
 (0)