Skip to content

Commit 0ee3b66

Browse files
committed
---
yaml --- r: 11654 b: refs/heads/master c: 1347d04 h: refs/heads/master v: v3
1 parent 7678d47 commit 0ee3b66

File tree

6 files changed

+68
-13
lines changed

6 files changed

+68
-13
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 4c4a2320eb9620dbc68a264ce64ee1f233dd977d
2+
refs/heads/master: 1347d04bb086f6d76dd7287762d34ef4c57dbc00
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 4a81779abd786ff22d71434c6d9a5917ea4cdfff
55
refs/heads/try: 2898dcc5d97da9427ac367542382b6239d9c0bbf

trunk/src/libcore/comm.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ native mod rustrt {
4242

4343
fn new_port(unit_sz: ctypes::size_t) -> *rust_port;
4444
fn del_port(po: *rust_port);
45-
fn rust_port_detach(po: *rust_port);
45+
fn rust_port_begin_detach(po: *rust_port,
46+
yield: *ctypes::uintptr_t);
47+
fn rust_port_end_detach(po: *rust_port);
4648
fn get_port_id(po: *rust_port) -> port_id;
4749
fn rust_port_size(po: *rust_port) -> ctypes::size_t;
4850
fn port_recv(dptr: *uint, po: *rust_port,
@@ -82,7 +84,17 @@ enum chan<T: send> {
8284
resource port_ptr<T: send>(po: *rust_port) {
8385
// Once the port is detached it's guaranteed not to receive further
8486
// messages
85-
rustrt::rust_port_detach(po);
87+
let yield = 0u;
88+
let yieldp = ptr::addr_of(yield);
89+
rustrt::rust_port_begin_detach(po, yieldp);
90+
if yield != 0u {
91+
// Need to wait for the port to be detached
92+
// FIXME: If this fails then we're going to leave our port
93+
// in a bogus state.
94+
task::yield();
95+
}
96+
rustrt::rust_port_end_detach(po);
97+
8698
// Drain the port so that all the still-enqueued items get dropped
8799
while rustrt::rust_port_size(po) > 0u {
88100
// FIXME: For some reason if we don't assign to something here

trunk/src/rt/rust_builtin.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,18 +482,23 @@ new_port(size_t unit_sz) {
482482
}
483483

484484
extern "C" CDECL void
485-
rust_port_detach(rust_port *port) {
485+
rust_port_begin_detach(rust_port *port, uintptr_t *yield) {
486486
rust_task *task = rust_task_thread::get_task();
487487
LOG(task, comm, "rust_port_detach(0x%" PRIxPTR ")", (uintptr_t) port);
488-
port->detach();
488+
port->begin_detach(yield);
489+
}
490+
491+
extern "C" CDECL void
492+
rust_port_end_detach(rust_port *port) {
493+
port->end_detach();
489494
}
490495

491496
extern "C" CDECL void
492497
del_port(rust_port *port) {
493498
rust_task *task = rust_task_thread::get_task();
494499
LOG(task, comm, "del_port(0x%" PRIxPTR ")", (uintptr_t) port);
495-
A(task->thread, port->get_ref_count() == 1, "Expected port ref_count == 1");
496-
port->deref();
500+
A(task->thread, port->get_ref_count() == 0, "Expected port ref_count == 0");
501+
delete port;
497502
}
498503

499504
extern "C" CDECL size_t

trunk/src/rt/rust_port.cpp

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,40 @@ rust_port::~rust_port() {
2020
task->deref();
2121
}
2222

23-
void rust_port::detach() {
23+
void rust_port::delete_this() {
24+
scoped_lock with(detach_lock);
25+
26+
if (task->blocked_on(&detach_cond)) {
27+
// The port owner is waiting for the port to be detached
28+
task->wakeup(&detach_cond);
29+
}
30+
}
31+
32+
void rust_port::begin_detach(uintptr_t *yield) {
33+
*yield = false;
34+
2435
task->release_port(id);
25-
// FIXME: Busy waiting until we're the only ref
36+
37+
deref();
38+
39+
scoped_lock with(detach_lock);
40+
if (get_ref_count() != 0) {
41+
task->block(&detach_cond, "waiting for port detach");
42+
*yield = true;
43+
}
44+
}
45+
46+
void rust_port::end_detach() {
47+
// FIXME: For some reason, on rare occasion we can get here without
48+
// actually having the ref count go to 0. Possibly related to #1923
2649
bool done = false;
2750
while (!done) {
28-
done = get_ref_count() == 1;
51+
done = get_ref_count() == 0;
2952
}
53+
54+
// Just take the lock to make sure that the thread that signaled
55+
// the detach_cond isn't still holding it
56+
scoped_lock with(detach_lock);
3057
}
3158

3259
void rust_port::send(void *sptr) {

trunk/src/rt/rust_port.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "rust_internal.h"
55

6+
class port_detach_cond : public rust_cond { };
7+
68
class rust_port : public kernel_owned<rust_port>, public rust_cond {
79
public:
810
RUST_ATOMIC_REFCOUNT();
@@ -16,15 +18,23 @@ class rust_port : public kernel_owned<rust_port>, public rust_cond {
1618

1719
lock_and_signal lock;
1820

21+
private:
22+
// Protects blocking and signaling on detach_cond
23+
lock_and_signal detach_lock;
24+
port_detach_cond detach_cond;
25+
26+
public:
1927
rust_port(rust_task *task, size_t unit_sz);
2028
~rust_port();
21-
void delete_this() { delete this; }
29+
void delete_this();
2230

2331
void log_state();
2432
void send(void *sptr);
2533
void receive(void *dptr, uintptr_t *yield);
2634
size_t size();
27-
void detach();
35+
36+
void begin_detach(uintptr_t *yield);
37+
void end_detach();
2838
};
2939

3040
//

trunk/src/rt/rustrt.def.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ rust_str_push
3434
rust_list_files
3535
rust_log_console_on
3636
rust_log_console_off
37-
rust_port_detach
37+
rust_port_begin_detach
38+
rust_port_end_detach
3839
rust_port_size
3940
rust_process_wait
4041
rust_ptr_eq

0 commit comments

Comments
 (0)