Skip to content

Commit c5e893b

Browse files
committed
---
yaml --- r: 77613 b: refs/heads/master c: c643f1d h: refs/heads/master i: 77611: 1e05725 v: v3
1 parent 2b81749 commit c5e893b

File tree

7 files changed

+223
-75
lines changed

7 files changed

+223
-75
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: cfd0bfbd1165294fd33b1ac24e6696d4c6ceb0ca
2+
refs/heads/master: c643f1d39c4c878fdb9fa25fb01c513d53afaa11
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 60fba4d7d677ec098e6a43014132fe99f7547363
55
refs/heads/try: ebfe63cd1c0b5d23f7ea60c69b4fde2e30cfd42a

trunk/doc/tutorial.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1864,7 +1864,7 @@ so you could not apply `head` to a type
18641864
that does not implement `Clone`.
18651865

18661866
While most traits can be defined and implemented by user code,
1867-
two traits are automatically derived and implemented
1867+
three traits are automatically derived and implemented
18681868
for all applicable types by the compiler,
18691869
and may not be overridden:
18701870

@@ -1877,6 +1877,12 @@ These are types that do not contain anything intrinsically mutable.
18771877
Intrinsically mutable values include `@mut`
18781878
and `Cell` in the standard library.
18791879

1880+
* `'static` - Non-borrowed types.
1881+
These are types that do not contain any data whose lifetime is bound to
1882+
a particular stack frame. These are types that do not contain any
1883+
borrowed pointers, or types where the only contained borrowed pointers
1884+
have the `'static` lifetime.
1885+
18801886
> ***Note:*** These two traits were referred to as 'kinds' in earlier
18811887
> iterations of the language, and often still are.
18821888
@@ -2135,6 +2141,30 @@ select the method to call at runtime.
21352141

21362142
This usage of traits is similar to Java interfaces.
21372143

2144+
By default, each of the three storage classes for traits enforce a
2145+
particular set of built-in kinds that their contents must fulfill in
2146+
order to be packaged up in a trait object of that storage class.
2147+
2148+
* The contents of owned traits (`~Trait`) must fulfill the `Send` bound.
2149+
* The contents of managed traits (`@Trait`) must fulfill the `'static` bound.
2150+
* The contents of borrowed traits (`&Trait`) are not constrained by any bound.
2151+
2152+
Consequently, the trait objects themselves automatically fulfill their
2153+
respective kind bounds. However, this default behavior can be overridden by
2154+
specifying a list of bounds on the trait type, for example, by writing `~Trait:`
2155+
(which indicates that the contents of the owned trait need not fulfill any
2156+
bounds), or by writing `~Trait:Send+Freeze`, which indicates that in addition
2157+
to fulfilling `Send`, contents must also fulfill `Freeze`, and as a consequence,
2158+
the trait itself fulfills `Freeze`.
2159+
2160+
* `~Trait:Send` is equivalent to `~Trait`.
2161+
* `@Trait:'static` is equivalent to `@Trait`.
2162+
* `&Trait:` is equivalent to `&Trait`.
2163+
2164+
Builtin kind bounds can also be specified on closure types in the same way (for
2165+
example, by writing `fn:Freeze()`), and the default behaviours are the same as
2166+
for traits of the same storage class.
2167+
21382168
## Trait inheritance
21392169

21402170
We can write a trait declaration that _inherits_ from other traits, called _supertraits_.

trunk/src/libextra/json.rs

Lines changed: 60 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -459,26 +459,24 @@ impl<E: serialize::Encoder> serialize::Encodable<E> for Json {
459459
}
460460
}
461461

462-
/// Encodes a json value into a io::writer
463-
pub fn to_writer(wr: @io::Writer, json: &Json) {
464-
let mut encoder = Encoder(wr);
465-
json.encode(&mut encoder)
466-
}
467-
468-
/// Encodes a json value into a string
469-
pub fn to_str(json: &Json) -> ~str {
470-
io::with_str_writer(|wr| to_writer(wr, json))
471-
}
462+
impl Json{
463+
/// Encodes a json value into a io::writer. Uses a single line.
464+
pub fn to_writer(&self, wr: @io::Writer) {
465+
let mut encoder = Encoder(wr);
466+
self.encode(&mut encoder)
467+
}
472468

473-
/// Encodes a json value into a io::writer
474-
pub fn to_pretty_writer(wr: @io::Writer, json: &Json) {
475-
let mut encoder = PrettyEncoder(wr);
476-
json.encode(&mut encoder)
477-
}
469+
/// Encodes a json value into a io::writer.
470+
/// Pretty-prints in a more readable format.
471+
pub fn to_pretty_writer(&self, wr: @io::Writer) {
472+
let mut encoder = PrettyEncoder(wr);
473+
self.encode(&mut encoder)
474+
}
478475

479-
/// Encodes a json value into a string
480-
pub fn to_pretty_str(json: &Json) -> ~str {
481-
io::with_str_writer(|wr| to_pretty_writer(wr, json))
476+
/// Encodes a json value into a string
477+
pub fn to_pretty_str(&self) -> ~str {
478+
io::with_str_writer(|wr| self.to_pretty_writer(wr))
479+
}
482480
}
483481

484482
pub struct Parser<T> {
@@ -1307,7 +1305,10 @@ impl<A:ToJson> ToJson for Option<A> {
13071305
}
13081306

13091307
impl to_str::ToStr for Json {
1310-
fn to_str(&self) -> ~str { to_str(self) }
1308+
/// Encodes a json value into a string
1309+
fn to_str(&self) -> ~str {
1310+
io::with_str_writer(|wr| self.to_writer(wr))
1311+
}
13111312
}
13121313

13131314
impl to_str::ToStr for Error {
@@ -1358,69 +1359,67 @@ mod tests {
13581359

13591360
#[test]
13601361
fn test_write_null() {
1361-
assert_eq!(to_str(&Null), ~"null");
1362-
assert_eq!(to_pretty_str(&Null), ~"null");
1362+
assert_eq!(Null.to_str(), ~"null");
1363+
assert_eq!(Null.to_pretty_str(), ~"null");
13631364
}
13641365
13651366
13661367
#[test]
13671368
fn test_write_number() {
1368-
assert_eq!(to_str(&Number(3f)), ~"3");
1369-
assert_eq!(to_pretty_str(&Number(3f)), ~"3");
1369+
assert_eq!(Number(3f).to_str(), ~"3");
1370+
assert_eq!(Number(3f).to_pretty_str(), ~"3");
13701371
1371-
assert_eq!(to_str(&Number(3.1f)), ~"3.1");
1372-
assert_eq!(to_pretty_str(&Number(3.1f)), ~"3.1");
1372+
assert_eq!(Number(3.1f).to_str(), ~"3.1");
1373+
assert_eq!(Number(3.1f).to_pretty_str(), ~"3.1");
13731374
1374-
assert_eq!(to_str(&Number(-1.5f)), ~"-1.5");
1375-
assert_eq!(to_pretty_str(&Number(-1.5f)), ~"-1.5");
1375+
assert_eq!(Number(-1.5f).to_str(), ~"-1.5");
1376+
assert_eq!(Number(-1.5f).to_pretty_str(), ~"-1.5");
13761377
1377-
assert_eq!(to_str(&Number(0.5f)), ~"0.5");
1378-
assert_eq!(to_pretty_str(&Number(0.5f)), ~"0.5");
1378+
assert_eq!(Number(0.5f).to_str(), ~"0.5");
1379+
assert_eq!(Number(0.5f).to_pretty_str(), ~"0.5");
13791380
}
13801381
13811382
#[test]
13821383
fn test_write_str() {
1383-
assert_eq!(to_str(&String(~"")), ~"\"\"");
1384-
assert_eq!(to_pretty_str(&String(~"")), ~"\"\"");
1384+
assert_eq!(String(~"").to_str(), ~"\"\"");
1385+
assert_eq!(String(~"").to_pretty_str(), ~"\"\"");
13851386

1386-
assert_eq!(to_str(&String(~"foo")), ~"\"foo\"");
1387-
assert_eq!(to_pretty_str(&String(~"foo")), ~"\"foo\"");
1387+
assert_eq!(String(~"foo").to_str(), ~"\"foo\"");
1388+
assert_eq!(String(~"foo").to_pretty_str(), ~"\"foo\"");
13881389
}
13891390

13901391
#[test]
13911392
fn test_write_bool() {
1392-
assert_eq!(to_str(&Boolean(true)), ~"true");
1393-
assert_eq!(to_pretty_str(&Boolean(true)), ~"true");
1393+
assert_eq!(Boolean(true).to_str(), ~"true");
1394+
assert_eq!(Boolean(true).to_pretty_str(), ~"true");
13941395
1395-
assert_eq!(to_str(&Boolean(false)), ~"false");
1396-
assert_eq!(to_pretty_str(&Boolean(false)), ~"false");
1396+
assert_eq!(Boolean(false).to_str(), ~"false");
1397+
assert_eq!(Boolean(false).to_pretty_str(), ~"false");
13971398
}
13981399
13991400
#[test]
14001401
fn test_write_list() {
1401-
assert_eq!(to_str(&List(~[])), ~"[]");
1402-
assert_eq!(to_pretty_str(&List(~[])), ~"[]");
1402+
assert_eq!(List(~[]).to_str(), ~"[]");
1403+
assert_eq!(List(~[]).to_pretty_str(), ~"[]");
14031404
1404-
assert_eq!(to_str(&List(~[Boolean(true)])), ~"[true]");
1405+
assert_eq!(List(~[Boolean(true)]).to_str(), ~"[true]");
14051406
assert_eq!(
1406-
to_pretty_str(&List(~[Boolean(true)])),
1407+
List(~[Boolean(true)]).to_pretty_str(),
14071408
~"\
14081409
[\n \
14091410
true\n\
14101411
]"
14111412
);
14121413

1413-
assert_eq!(to_str(&List(~[
1414+
let longTestList = List(~[
14141415
Boolean(false),
14151416
Null,
1416-
List(~[String(~"foo\nbar"), Number(3.5f)])
1417-
])), ~"[false,null,[\"foo\\nbar\",3.5]]");
1417+
List(~[String(~"foo\nbar"), Number(3.5f)])]);
1418+
1419+
assert_eq!(longTestList.to_str(),
1420+
~"[false,null,[\"foo\\nbar\",3.5]]");
14181421
assert_eq!(
1419-
to_pretty_str(&List(~[
1420-
Boolean(false),
1421-
Null,
1422-
List(~[String(~"foo\nbar"), Number(3.5f)])
1423-
])),
1422+
longTestList.to_pretty_str(),
14241423
~"\
14251424
[\n \
14261425
false,\n \
@@ -1435,28 +1434,30 @@ mod tests {
14351434

14361435
#[test]
14371436
fn test_write_object() {
1438-
assert_eq!(to_str(&mk_object([])), ~"{}");
1439-
assert_eq!(to_pretty_str(&mk_object([])), ~"{}");
1437+
assert_eq!(mk_object([]).to_str(), ~"{}");
1438+
assert_eq!(mk_object([]).to_pretty_str(), ~"{}");
14401439
14411440
assert_eq!(
1442-
to_str(&mk_object([(~"a", Boolean(true))])),
1441+
mk_object([(~"a", Boolean(true))]).to_str(),
14431442
~"{\"a\":true}"
14441443
);
14451444
assert_eq!(
1446-
to_pretty_str(&mk_object([(~"a", Boolean(true))])),
1445+
mk_object([(~"a", Boolean(true))]).to_pretty_str(),
14471446
~"\
14481447
{\n \
14491448
\"a\": true\n\
14501449
}"
14511450
);
14521451

1453-
assert_eq!(
1454-
to_str(&mk_object([
1452+
let complexObj = mk_object([
14551453
(~"b", List(~[
14561454
mk_object([(~"c", String(~"\x0c\r"))]),
14571455
mk_object([(~"d", String(~""))])
14581456
]))
1459-
])),
1457+
]);
1458+
1459+
assert_eq!(
1460+
complexObj.to_str(),
14601461
~"{\
14611462
\"b\":[\
14621463
{\"c\":\"\\f\\r\"},\
@@ -1465,12 +1466,7 @@ mod tests {
14651466
}"
14661467
);
14671468
assert_eq!(
1468-
to_pretty_str(&mk_object([
1469-
(~"b", List(~[
1470-
mk_object([(~"c", String(~"\x0c\r"))]),
1471-
mk_object([(~"d", String(~""))])
1472-
]))
1473-
])),
1469+
complexObj.to_pretty_str(),
14741470
~"\
14751471
{\n \
14761472
\"b\": [\n \
@@ -1494,8 +1490,8 @@ mod tests {
14941490
14951491
// We can't compare the strings directly because the object fields be
14961492
// printed in a different order.
1497-
assert_eq!(a.clone(), from_str(to_str(&a)).unwrap());
1498-
assert_eq!(a.clone(), from_str(to_pretty_str(&a)).unwrap());
1493+
assert_eq!(a.clone(), from_str(a.to_str()).unwrap());
1494+
assert_eq!(a.clone(), from_str(a.to_pretty_str()).unwrap());
14991495
}
15001496
15011497
#[test]

trunk/src/libextra/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -907,7 +907,7 @@ impl MetricMap {
907907
/// Write MetricDiff to a file.
908908
pub fn save(&self, p: &Path) {
909909
let f = io::file_writer(p, [io::Create, io::Truncate]).unwrap();
910-
json::to_pretty_writer(f, &self.to_json());
910+
self.to_json().to_pretty_writer(f);
911911
}
912912

913913
/// Compare against another MetricMap. Optionally compare all

trunk/src/libstd/rt/kill.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ observed by the parent of a task::try task that itself spawns child tasks
2020
(such as any #[test] function). In both cases the data structures live in
2121
KillHandle.
2222
23+
2324
I. Task killing.
2425
2526
The model for killing involves two atomic flags, the "kill flag" and the
@@ -60,9 +61,92 @@ killer does perform both writes, it means it saw a KILL_RUNNING in the
6061
unkillable flag, which means an unkillable task will see KILL_KILLED and fail
6162
immediately (rendering the subsequent write to the kill flag unnecessary).
6263
64+
6365
II. Exit code propagation.
6466
65-
FIXME(#7544): Decide on the ultimate model for this and document it.
67+
The basic model for exit code propagation, which is used with the "watched"
68+
spawn mode (on by default for linked spawns, off for supervised and unlinked
69+
spawns), is that a parent will wait for all its watched children to exit
70+
before reporting whether it succeeded or failed. A watching parent will only
71+
report success if it succeeded and all its children also reported success;
72+
otherwise, it will report failure. This is most useful for writing test cases:
73+
74+
~~~
75+
#[test]
76+
fn test_something_in_another_task {
77+
do spawn {
78+
assert!(collatz_conjecture_is_false());
79+
}
80+
}
81+
~~~
82+
83+
Here, as the child task will certainly outlive the parent task, we might miss
84+
the failure of the child when deciding whether or not the test case passed.
85+
The watched spawn mode avoids this problem.
86+
87+
In order to propagate exit codes from children to their parents, any
88+
'watching' parent must wait for all of its children to exit before it can
89+
report its final exit status. We achieve this by using an UnsafeArc, using the
90+
reference counting to track how many children are still alive, and using the
91+
unwrap() operation in the parent's exit path to wait for all children to exit.
92+
The UnsafeArc referred to here is actually the KillHandle itself.
93+
94+
This also works transitively, as if a "middle" watched child task is itself
95+
watching a grandchild task, the "middle" task will do unwrap() on its own
96+
KillHandle (thereby waiting for the grandchild to exit) before dropping its
97+
reference to its watching parent (which will alert the parent).
98+
99+
While UnsafeArc::unwrap() accomplishes the synchronization, there remains the
100+
matter of reporting the exit codes themselves. This is easiest when an exiting
101+
watched task has no watched children of its own:
102+
103+
- If the task with no watched children exits successfully, it need do nothing.
104+
- If the task with no watched children has failed, it sets a flag in the
105+
parent's KillHandle ("any_child_failed") to false. It then stays false forever.
106+
107+
However, if a "middle" watched task with watched children of its own exits
108+
before its child exits, we need to ensure that the grandparent task may still
109+
see a failure from the grandchild task. While we could achieve this by having
110+
each intermediate task block on its handle, this keeps around the other resources
111+
the task was using. To be more efficient, this is accomplished via "tombstones".
112+
113+
A tombstone is a closure, ~fn() -> bool, which will perform any waiting necessary
114+
to collect the exit code of descendant tasks. In its environment is captured
115+
the KillHandle of whichever task created the tombstone, and perhaps also any
116+
tombstones that that task itself had, and finally also another tombstone,
117+
effectively creating a lazy-list of heap closures.
118+
119+
When a child wishes to exit early and leave tombstones behind for its parent,
120+
it must use a LittleLock (pthread mutex) to synchronize with any possible
121+
sibling tasks which are trying to do the same thing with the same parent.
122+
However, on the other side, when the parent is ready to pull on the tombstones,
123+
it need not use this lock, because the unwrap() serves as a barrier that ensures
124+
no children will remain with references to the handle.
125+
126+
The main logic for creating and assigning tombstones can be found in the
127+
function reparent_children_to() in the impl for KillHandle.
128+
129+
130+
IIA. Issues with exit code propagation.
131+
132+
There are two known issues with the current scheme for exit code propagation.
133+
134+
- As documented in issue #8136, the structure mandates the possibility for stack
135+
overflow when collecting tombstones that are very deeply nested. This cannot
136+
be avoided with the closure representation, as tombstones end up structured in
137+
a sort of tree. However, notably, the tombstones do not actually need to be
138+
collected in any particular order, and so a doubly-linked list may be used.
139+
However we do not do this yet because DList is in libextra.
140+
141+
- A discussion with Graydon made me realize that if we decoupled the exit code
142+
propagation from the parents-waiting action, this could result in a simpler
143+
implementation as the exit codes themselves would not have to be propagated,
144+
and could instead be propagated implicitly through the taskgroup mechanism
145+
that we already have. The tombstoning scheme would still be required. I have
146+
not implemented this because currently we can't receive a linked failure kill
147+
signal during the task cleanup activity, as that is currently "unkillable",
148+
and occurs outside the task's unwinder's "try" block, so would require some
149+
restructuring.
66150
67151
*/
68152

0 commit comments

Comments
 (0)