]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/local.rs
std: Allow spawners to specify stack size
[rust.git] / src / libstd / rt / local.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use option::{Option, Some, None};
12 use rt::sched::Scheduler;
13 use rt::task::Task;
14 use rt::local_ptr;
15 use rt::rtio::{EventLoop, IoFactoryObject};
16 //use borrow::to_uint;
17 use cell::Cell;
18
19 pub trait Local {
20     fn put(value: ~Self);
21     fn take() -> ~Self;
22     fn exists() -> bool;
23     fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
24     unsafe fn unsafe_borrow() -> *mut Self;
25     unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
26 }
27
28 impl Local for Task {
29     fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
30     fn take() -> ~Task { unsafe { local_ptr::take() } }
31     fn exists() -> bool { local_ptr::exists() }
32     fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
33         let mut res: Option<T> = None;
34         let res_ptr: *mut Option<T> = &mut res;
35         unsafe {
36             do local_ptr::borrow |task| {
37                 let result = f(task);
38                 *res_ptr = Some(result);
39             }
40         }
41         match res {
42             Some(r) => { r }
43             None => { rtabort!("function failed in local_borrow") }
44         }
45     }
46     unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
47     unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
48         if Local::exists::<Task>() {
49             Some(Local::unsafe_borrow())
50         } else {
51             None
52         }
53     }
54 }
55
56 impl Local for Scheduler {
57     fn put(value: ~Scheduler) {
58         let value = Cell::new(value);
59         do Local::borrow::<Task,()> |task| {
60             let task = task;
61             task.sched = Some(value.take());
62         };
63     }
64     fn take() -> ~Scheduler {
65         do Local::borrow::<Task,~Scheduler> |task| {
66             let sched = task.sched.take_unwrap();
67             let task = task;
68             task.sched = None;
69             sched
70         }
71     }
72     fn exists() -> bool {
73         do Local::borrow::<Task,bool> |task| {
74             match task.sched {
75                 Some(ref _task) => true,
76                 None => false
77             }
78         }
79     }
80     fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
81         do Local::borrow::<Task, T> |task| {
82             match task.sched {
83                 Some(~ref mut task) => {
84                     f(task)
85                 }
86                 None => {
87                     rtabort!("no scheduler")
88                 }
89             }
90         }
91     }
92     unsafe fn unsafe_borrow() -> *mut Scheduler {
93         match (*Local::unsafe_borrow::<Task>()).sched {
94             Some(~ref mut sched) => {
95                 let s: *mut Scheduler = &mut *sched;
96                 return s;
97             }
98             None => {
99                 rtabort!("no scheduler")
100             }
101         }
102     }
103     unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
104         if Local::exists::<Scheduler>() {
105             Some(Local::unsafe_borrow())
106         } else {
107             None
108         }
109     }
110 }
111
112 // XXX: This formulation won't work once ~IoFactoryObject is a real trait pointer
113 impl Local for IoFactoryObject {
114     fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") }
115     fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
116     fn exists() -> bool { rtabort!("unimpl") }
117     fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
118     unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
119         let sched = Local::unsafe_borrow::<Scheduler>();
120         let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();
121         return io;
122     }
123     unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") }
124 }
125
126
127 #[cfg(test)]
128 mod test {
129     use option::None;
130     use unstable::run_in_bare_thread;
131     use rt::test::*;
132     use super::*;
133     use rt::task::Task;
134     use rt::local_ptr;
135
136     #[test]
137     fn thread_local_task_smoke_test() {
138         do run_in_bare_thread {
139             local_ptr::init_tls_key();
140             let mut sched = ~new_test_uv_sched();
141             let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
142             Local::put(task);
143             let task: ~Task = Local::take();
144             cleanup_task(task);
145         }
146     }
147
148     #[test]
149     fn thread_local_task_two_instances() {
150         do run_in_bare_thread {
151             local_ptr::init_tls_key();
152             let mut sched = ~new_test_uv_sched();
153             let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
154             Local::put(task);
155             let task: ~Task = Local::take();
156             cleanup_task(task);
157             let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
158             Local::put(task);
159             let task: ~Task = Local::take();
160             cleanup_task(task);
161         }
162
163     }
164
165     #[test]
166     fn borrow_smoke_test() {
167         do run_in_bare_thread {
168             local_ptr::init_tls_key();
169             let mut sched = ~new_test_uv_sched();
170             let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
171             Local::put(task);
172
173             unsafe {
174                 let _task: *mut Task = Local::unsafe_borrow();
175             }
176             let task: ~Task = Local::take();
177             cleanup_task(task);
178         }
179     }
180
181     #[test]
182     fn borrow_with_return() {
183         do run_in_bare_thread {
184             local_ptr::init_tls_key();
185             let mut sched = ~new_test_uv_sched();
186             let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
187             Local::put(task);
188
189             let res = do Local::borrow::<Task,bool> |_task| {
190                 true
191             };
192             assert!(res)
193                 let task: ~Task = Local::take();
194             cleanup_task(task);
195         }
196     }
197
198 }
199