To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

thread.rs 6.54 KB
Newer Older
qinsoon's avatar
qinsoon committed
1
#![allow(dead_code)]
qinsoon's avatar
qinsoon committed
2
3

use ast::ir::*;
qinsoon's avatar
qinsoon committed
4
5
6
use ast::ptr::*;
use ast::types::*;
use vm::VM;
7
use runtime::ValueLocation;
8
use runtime::mm;
qinsoon's avatar
qinsoon committed
9

qinsoon's avatar
qinsoon committed
10
use utils::ByteSize;
qinsoon's avatar
qinsoon committed
11
12
13
14
15
16
use utils::Address;
use utils::mem::memmap;
use utils::mem::memsec;

use std::thread;
use std::thread::JoinHandle;
qinsoon's avatar
qinsoon committed
17
18
19
20
21
22

pub const STACK_SIZE : ByteSize = (4 << 20); // 4mb

#[cfg(target_arch = "x86_64")]
pub const PAGE_SIZE  : ByteSize = (4 << 10); // 4kb

qinsoon's avatar
qinsoon committed
23
24
25
impl_mu_entity!(MuThread);
impl_mu_entity!(MuStack);

qinsoon's avatar
qinsoon committed
26
pub struct MuStack {
qinsoon's avatar
qinsoon committed
27
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
28
    
29
30
    func_addr: ValueLocation,
    func_id: MuID, 
qinsoon's avatar
qinsoon committed
31
    
qinsoon's avatar
qinsoon committed
32
    size: ByteSize,
qinsoon's avatar
qinsoon committed
33
34
35
36
37
38
39
40
41
42
    //    lo addr                                                    hi addr
    //     | overflow guard page | actual stack ..................... | underflow guard page|
    //     |                     |                                    |                     |
    // overflowGuard           lowerBound                           upperBound
    //                                                              underflowGuard    
    overflow_guard : Address,
    lower_bound    : Address,
    upper_bound    : Address,
    underflow_guard: Address,
    
qinsoon's avatar
qinsoon committed
43
44
45
46
47
    // this frame pointers should only be used when stack is not active
    sp : Address,
    bp : Address,
    ip : Address,
    
qinsoon's avatar
qinsoon committed
48
49
    exception_obj  : Option<Address>,
    
50
    state: MuStackState,
qinsoon's avatar
qinsoon committed
51
52
53
54
55
    #[allow(dead_code)]
    mmap           : memmap::Mmap
}

impl MuStack {
56
    pub fn new(id: MuID, func_addr: ValueLocation, func: &MuFunction) -> MuStack {
qinsoon's avatar
qinsoon committed
57
58
59
60
61
62
63
        let total_size = PAGE_SIZE * 2 + STACK_SIZE;
        
        let anon_mmap = match memmap::Mmap::anonymous(total_size, memmap::Protection::ReadWrite) {
            Ok(m) => m,
            Err(_) => panic!("failed to mmap for a stack"),
        };
        
qinsoon's avatar
qinsoon committed
64
65
66
67
68
69
70
71
72
73
74
75
        let mmap_start = Address::from_ptr(anon_mmap.ptr());
        debug_assert!(mmap_start.is_aligned_to(PAGE_SIZE));
        
        let overflow_guard = mmap_start;
        let lower_bound = mmap_start.plus(PAGE_SIZE);
        let upper_bound = lower_bound.plus(STACK_SIZE);
        let underflow_guard = upper_bound;
        
        unsafe {
            memsec::mprotect(overflow_guard.to_ptr_mut::<u8>(),  PAGE_SIZE, memsec::Prot::NoAccess);
            memsec::mprotect(underflow_guard.to_ptr_mut::<u8>(), PAGE_SIZE, memsec::Prot::NoAccess);
        }
qinsoon's avatar
qinsoon committed
76
        
qinsoon's avatar
qinsoon committed
77
78
79
80
81
82
83
84
        debug!("creating stack {} with entry func {:?}", id, func);
        debug!("overflow_guard : {}", overflow_guard);
        debug!("lower_bound    : {}", lower_bound);
        debug!("upper_bound    : {}", upper_bound);
        debug!("underflow_guard: {}", underflow_guard);
        
        MuStack {
            hdr: MuEntityHeader::unnamed(id),
85
            func_addr: func_addr,
qinsoon's avatar
qinsoon committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
            func_id: func.id(),
            
            state: MuStackState::Ready(func.sig.arg_tys.clone()),
            
            size: STACK_SIZE,
            overflow_guard: overflow_guard,
            lower_bound: lower_bound,
            upper_bound: upper_bound,
            underflow_guard: upper_bound,
            
            sp: upper_bound,
            bp: upper_bound,
            ip: unsafe {Address::zero()},
            
            exception_obj: None,
            
            mmap: anon_mmap
        }
qinsoon's avatar
qinsoon committed
104
    }
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    
    #[cfg(target_arch = "x86_64")]
    pub fn runtime_load_args(&mut self, vals: Vec<ValueLocation>) {
        use compiler::backend::Word;
        use compiler::backend::WORD_SIZE;
        use compiler::backend::RegGroup;
        use compiler::backend::x86_64;
        
        let mut gpr_used = vec![];
        let mut fpr_used = vec![];
        
        for i in 0..vals.len() {
            let ref val = vals[i];
            let (reg_group, word) = val.load_value();
            
            match reg_group {
                RegGroup::GPR => gpr_used.push(word),
                RegGroup::FPR => fpr_used.push(word),
            }
        }
        
        let mut stack_ptr = self.sp;
        for i in 0..x86_64::ARGUMENT_FPRs.len() {
            stack_ptr = stack_ptr.sub(WORD_SIZE);
            let val = {
                if i < fpr_used.len() {
                    fpr_used[i]
                } else {
                    0 as Word
                }
            };
            
            debug!("store {} to {}", val, stack_ptr);
            unsafe {stack_ptr.store(val);}
        }
        
        for i in 0..x86_64::ARGUMENT_GPRs.len() {
            stack_ptr = stack_ptr.sub(WORD_SIZE);
            let val = {
                if i < gpr_used.len() {
                    gpr_used[i]
                } else {
                    0 as Word
                }
            };
            
            debug!("store {} to {}", val, stack_ptr);
            unsafe {stack_ptr.store(val);}
        }
        
        // should have put 6 + 6 words on the stack
        debug_assert!(self.sp.diff(stack_ptr) == 12 * WORD_SIZE);
        // save it back
        self.sp = stack_ptr;
    }
qinsoon's avatar
qinsoon committed
160
161
}

qinsoon's avatar
qinsoon committed
162
163
164
165
166
167
pub enum MuStackState {
    Ready(Vec<P<MuType>>), // ready to resume when values of given types are supplied (can be empty)
    Active,
    Dead
}

qinsoon's avatar
qinsoon committed
168
pub struct MuThread {
qinsoon's avatar
qinsoon committed
169
    pub hdr: MuEntityHeader,
170
    allocator: Box<mm::Mutator>,
qinsoon's avatar
qinsoon committed
171
172
173
174
175
    stack: Option<Box<MuStack>>,
    
    user_tls: Option<Address>
}

176
177
178
179
180
181
182
#[cfg(target_arch = "x86_64")]
#[cfg(target_os = "macos")]
#[link(name = "runtime")]
extern "C" {
    fn init_thread_local(thread: &Box<MuThread>) -> Address;
}

qinsoon's avatar
qinsoon committed
183
impl MuThread {
184
    pub fn new(id: MuID, allocator: Box<mm::Mutator>, stack: Box<MuStack>, user_tls: Option<Address>) -> MuThread {
qinsoon's avatar
qinsoon committed
185
186
187
188
189
190
191
        MuThread {
            hdr: MuEntityHeader::unnamed(id),
            allocator: allocator,
            stack: Some(stack),
            user_tls: user_tls
        }
    }
qinsoon's avatar
qinsoon committed
192
    
193
    #[no_mangle]
qinsoon's avatar
qinsoon committed
194
    #[allow(unused_variables)]
195
    pub extern fn mu_thread_launch(id: MuID, stack: Box<MuStack>, user_tls: Option<Address>, vm: &VM) -> JoinHandle<()> {
qinsoon's avatar
qinsoon committed
196
        match thread::Builder::new().name(format!("Mu Thread #{}", id)).spawn(move || {
197
            let muthread = Box::new(MuThread::new(id, mm::new_mutator(), stack, user_tls));
198
199
200
201
202
            
            // set thread local
            let addr = unsafe {init_thread_local(&muthread)};
            
            MuThread::thread_entry(muthread);
qinsoon's avatar
qinsoon committed
203
204
205
206
207
208
209
        }) {
            Ok(handle) => handle,
            Err(_) => panic!("failed to create a thread")
        }
    }
    
    /// entry function for launching a mu thread
qinsoon's avatar
qinsoon committed
210
    #[allow(unused_variables)]
211
212
    pub fn thread_entry(mu_thread: Box<MuThread>) -> ! {
        unimplemented!()
qinsoon's avatar
qinsoon committed
213
    }
214
215
}

qinsoon's avatar
qinsoon committed
216
#[derive(Debug, RustcEncodable, RustcDecodable)]
217
218
219
pub struct MuPrimordialThread {
    pub func_id: MuID,
    pub args: Vec<Constant>
qinsoon's avatar
qinsoon committed
220
}