(index<- ) ./libstd/rt/context.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::*;
12 use super::stack::StackSegment;
13 use libc::c_void;
14 use cast::{transmute, transmute_mut_unsafe,
15 transmute_region, transmute_mut_region};
16
17 // FIXME #7761: Registers is boxed so that it is 16-byte aligned, for storing
18 // SSE regs. It would be marginally better not to do this. In C++ we
19 // use an attribute on a struct.
20 // FIXME #7761: It would be nice to define regs as `~Option<Registers>` since
21 // the registers are sometimes empty, but the discriminant would
22 // then misalign the regs again.
23 pub struct Context {
24 /// The context entry point, saved here for later destruction
25 start: Option<~~fn()>,
26 /// Hold the registers while the task or scheduler is suspended
27 regs: ~Registers
28 }
29
30 impl Context {
31 pub fn empty() -> Context {
32 Context {
33 start: None,
34 regs: new_regs()
35 }
36 }
37
38 /// Create a new context that will resume execution by running ~fn()
39 pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
40 // FIXME #7767: Putting main into a ~ so it's a thin pointer and can
41 // be passed to the spawn function. Another unfortunate
42 // allocation
43 let start = ~start;
44
45 // The C-ABI function that is the task entry point
46 extern fn task_start_wrapper(f: &~fn()) { (*f)() }
47
48 let fp: *c_void = task_start_wrapper as *c_void;
49 let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) };
50 let stack_base: *uint = stack.start();
51 let sp: *uint = stack.end();
52 let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) };
53 // Save and then immediately load the current context,
54 // which we will then modify to call the given function when restored
55 let mut regs = new_regs();
56 unsafe {
57 swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs));
58 };
59
60 initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
61
62 return Context {
63 start: Some(start),
64 regs: regs
65 }
66 }
67
68 /* Switch contexts
69
70 Suspend the current execution context and resume another by
71 saving the registers values of the executing thread to a Context
72 then loading the registers from a previously saved Context.
73 */
74 pub fn swap(out_context: &mut Context, in_context: &Context) {
75 rtdebug!("swapping contexts");
76 let out_regs: &mut Registers = match out_context {
77 &Context { regs: ~ref mut r, _ } => r
78 };
79 let in_regs: &Registers = match in_context {
80 &Context { regs: ~ref r, _ } => r
81 };
82 rtdebug!("doing raw swap");
83 unsafe { swap_registers(out_regs, in_regs) };
84 }
85 }
86
87 extern {
88 #[rust_stack]
89 fn swap_registers(out_regs: *mut Registers, in_regs: *Registers);
90 }
91
92 #[cfg(target_arch = "x86")]
93 struct Registers {
94 eax: u32, ebx: u32, ecx: u32, edx: u32,
95 ebp: u32, esi: u32, edi: u32, esp: u32,
96 cs: u16, ds: u16, ss: u16, es: u16, fs: u16, gs: u16,
97 eflags: u32, eip: u32
98 }
99
100 #[cfg(target_arch = "x86")]
101 fn new_regs() -> ~Registers {
102 ~Registers {
103 eax: 0, ebx: 0, ecx: 0, edx: 0,
104 ebp: 0, esi: 0, edi: 0, esp: 0,
105 cs: 0, ds: 0, ss: 0, es: 0, fs: 0, gs: 0,
106 eflags: 0, eip: 0
107 }
108 }
109
110 #[cfg(target_arch = "x86")]
111 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
112 sp: *mut uint, _stack_base: *uint) {
113
114 let sp = align_down(sp);
115 let sp = mut_offset(sp, -4);
116
117 unsafe { *sp = arg as uint };
118 let sp = mut_offset(sp, -1);
119 unsafe { *sp = 0 }; // The final return address
120
121 regs.esp = sp as u32;
122 regs.eip = fptr as u32;
123
124 // Last base pointer on the stack is 0
125 regs.ebp = 0;
126 }
127
128 #[cfg(windows, target_arch = "x86_64")]
129 type Registers = [uint, ..34];
130 #[cfg(not(windows), target_arch = "x86_64")]
131 type Registers = [uint, ..22];
132
133 #[cfg(windows, target_arch = "x86_64")]
134 fn new_regs() -> ~Registers { ~([0, .. 34]) }
135 #[cfg(not(windows), target_arch = "x86_64")]
136 fn new_regs() -> ~Registers { ~([0, .. 22]) }
137
138 #[cfg(target_arch = "x86_64")]
139 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
140 sp: *mut uint, stack_base: *uint) {
141
142 // Redefinitions from regs.h
143 static RUSTRT_ARG0: uint = 3;
144 static RUSTRT_RSP: uint = 1;
145 static RUSTRT_IP: uint = 8;
146 static RUSTRT_RBP: uint = 2;
147
148 #[cfg(windows)]
149 fn initialize_tib(regs: &mut Registers, sp: *mut uint, stack_base: *uint) {
150 // Redefinitions from regs.h
151 static RUSTRT_ST1: uint = 11; // stack bottom
152 static RUSTRT_ST2: uint = 12; // stack top
153 regs[RUSTRT_ST1] = sp as uint;
154 regs[RUSTRT_ST2] = stack_base as uint;
155 }
156 #[cfg(not(windows))]
157 fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
158 }
159
160 // Win64 manages stack range at TIB: %gs:0x08 (top) and %gs:0x10 (bottom)
161 initialize_tib(regs, sp, stack_base);
162
163 let sp = align_down(sp);
164 let sp = mut_offset(sp, -1);
165
166 // The final return address. 0 indicates the bottom of the stack
167 unsafe { *sp = 0; }
168
169 rtdebug!("creating call frame");
170 rtdebug!("fptr {}", fptr as uint);
171 rtdebug!("arg {}", arg as uint);
172 rtdebug!("sp {}", sp as uint);
173
174 regs[RUSTRT_ARG0] = arg as uint;
175 regs[RUSTRT_RSP] = sp as uint;
176 regs[RUSTRT_IP] = fptr as uint;
177
178 // Last base pointer on the stack should be 0
179 regs[RUSTRT_RBP] = 0;
180 }
181
182 #[cfg(target_arch = "arm")]
183 type Registers = [uint, ..32];
184
185 #[cfg(target_arch = "arm")]
186 fn new_regs() -> ~Registers { ~([0, .. 32]) }
187
188 #[cfg(target_arch = "arm")]
189 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
190 sp: *mut uint, _stack_base: *uint) {
191 let sp = align_down(sp);
192 // sp of arm eabi is 8-byte aligned
193 let sp = mut_offset(sp, -2);
194
195 // The final return address. 0 indicates the bottom of the stack
196 unsafe { *sp = 0; }
197
198 regs[0] = arg as uint; // r0
199 regs[13] = sp as uint; // #53 sp, r13
200 regs[14] = fptr as uint; // #60 pc, r15 --> lr
201 }
202
203 #[cfg(target_arch = "mips")]
204 type Registers = [uint, ..32];
205
206 #[cfg(target_arch = "mips")]
207 fn new_regs() -> ~Registers { ~([0, .. 32]) }
208
209 #[cfg(target_arch = "mips")]
210 fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
211 sp: *mut uint, _stack_base: *uint) {
212 let sp = align_down(sp);
213 // sp of mips o32 is 8-byte aligned
214 let sp = mut_offset(sp, -2);
215
216 // The final return address. 0 indicates the bottom of the stack
217 unsafe { *sp = 0; }
218
219 regs[4] = arg as uint;
220 regs[29] = sp as uint;
221 regs[25] = fptr as uint;
222 regs[31] = fptr as uint;
223 }
224
225 fn align_down(sp: *mut uint) -> *mut uint {
226 unsafe {
227 let sp: uint = transmute(sp);
228 let sp = sp & !(16 - 1);
229 transmute::<uint, *mut uint>(sp)
230 }
231 }
232
233 // ptr::mut_offset is positive ints only
234 #[inline]
235 pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
236 use std::sys::size_of;
237 (ptr as int + count * (size_of::<T>() as int)) as *mut T
238 }
libstd/rt/context.rs:46:8-46:8 -fn- definition:
extern fn task_start_wrapper(f: &~fn()) { (*f)() }
references:-48: let fp: *c_void = task_start_wrapper as *c_void;
libstd/rt/context.rs:234:10-234:10 -fn- definition:
#[inline]
pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
references:-164: let sp = mut_offset(sp, -1);
libstd/rt/context.rs:22:33-22:33 -struct- definition:
// then misalign the regs again.
pub struct Context {
references:-80: &Context { regs: ~ref r, _ } => r
31: pub fn empty() -> Context {
39: pub fn new(start: ~fn(), stack: &mut StackSegment) -> Context {
62: return Context {
30: impl Context {
74: pub fn swap(out_context: &mut Context, in_context: &Context) {
77: &Context { regs: ~ref mut r, _ } => r
74: pub fn swap(out_context: &mut Context, in_context: &Context) {
32: Context {
libstd/rt/task.rs:
73: saved_context: Context
libstd/rt/sched.rs:
637: (&'a mut Context, &'a mut Context) {
637: (&'a mut Context, &'a mut Context) {
libstd/rt/context.rs:135:45-135:45 -fn- definition:
#[cfg(not(windows), target_arch = "x86_64")]
fn new_regs() -> ~Registers { ~([0, .. 22]) }
references:-55: let mut regs = new_regs();
34: regs: new_regs()
libstd/rt/context.rs:138:31-138:31 -fn- definition:
#[cfg(target_arch = "x86_64")]
fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
references:-60: initialize_call_frame(&mut *regs, fp, argp, sp, stack_base);
libstd/rt/context.rs:157:4-157:4 -fn- definition:
fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
}
references:-161: initialize_tib(regs, sp, stack_base);
libstd/rt/context.rs:224:1-224:1 -fn- definition:
fn align_down(sp: *mut uint) -> *mut uint {
references:-163: let sp = align_down(sp);
libstd/rt/context.rs:130:45-130:45 -ty- definition:
#[cfg(not(windows), target_arch = "x86_64")]
type Registers = [uint, ..22];
references:-157: fn initialize_tib(_: &mut Registers, _: *mut uint, _: *uint) {
76: let out_regs: &mut Registers = match out_context {
136: fn new_regs() -> ~Registers { ~([0, .. 22]) }
139: fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void,
79: let in_regs: &Registers = match in_context {
89: fn swap_registers(out_regs: *mut Registers, in_regs: *Registers);
27: regs: ~Registers
89: fn swap_registers(out_regs: *mut Registers, in_regs: *Registers);