(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 spuint = 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, countint) -> *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);