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

thread.rs 19.8 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright 2017 The Australian National University
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

qinsoon's avatar
qinsoon committed
15
use ast::ir::*;
qinsoon's avatar
qinsoon committed
16
17
18
use ast::ptr::*;
use ast::types::*;
use vm::VM;
19
use runtime;
20
use runtime::ValueLocation;
21
use runtime::mm;
qinsoon's avatar
qinsoon committed
22

qinsoon's avatar
qinsoon committed
23
use utils::ByteSize;
qinsoon's avatar
qinsoon committed
24
use utils::Address;
qinsoon's avatar
qinsoon committed
25
use utils::Word;
qinsoon's avatar
qinsoon committed
26
27
28
use utils::mem::memmap;
use utils::mem::memsec;

qinsoon's avatar
qinsoon committed
29
use std::ptr;
qinsoon's avatar
qinsoon committed
30
31
use std::thread;
use std::thread::JoinHandle;
32
use std::sync::Arc;
33
use std::fmt;
qinsoon's avatar
qinsoon committed
34

qinsoon's avatar
qinsoon committed
35
/// a 4mb Mu stack
qinsoon's avatar
qinsoon committed
36
37
pub const STACK_SIZE : ByteSize = (4 << 20); // 4mb

qinsoon's avatar
qinsoon committed
38
39
/// operating system page size
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
qinsoon's avatar
qinsoon committed
40
41
pub const PAGE_SIZE  : ByteSize = (4 << 10); // 4kb

qinsoon's avatar
qinsoon committed
42
// MuThread and MuStack are MuEntity (has MuID and an optional MuName)
qinsoon's avatar
qinsoon committed
43
44
45
impl_mu_entity!(MuThread);
impl_mu_entity!(MuStack);

qinsoon's avatar
qinsoon committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/// MuStack represents metadata for a Mu stack.
/// A Mu stack is explicitly different from a native stack that comes with the thread from
/// OS, and is managed by the VM. A Mu stack is logically independent from a Mu thread,
/// as we allow creation of stacks to be independent of thread creation, we allow binding stack
/// to a new thread and swap stack to rebind stacks. A Mu stack is seen as a piece of memory
/// that contains function execution records.

/// Zebu stack has a layout as below:
///                              <- stack grows this way <-
///    lo addr                                                    hi addr
///     | overflow guard page | actual stack ..................... | underflow guard page|
///     |                     |                                    |                     |

/// We use guard page for overflow/underflow detection.
//  FIXME: we need to capture the signal (See Issue #50)
//  FIXME: this mechanics may ignore cases when frame size is larger than page size (Issue #49)
62
#[repr(C)]
qinsoon's avatar
qinsoon committed
63
pub struct MuStack {
qinsoon's avatar
qinsoon committed
64
    pub hdr: MuEntityHeader,
65

qinsoon's avatar
qinsoon committed
66
    /// entry function for the stack, represented as (address, func id)
67
    func: Option<(ValueLocation, MuID)>,
qinsoon's avatar
qinsoon committed
68
69

    /// stack size
qinsoon's avatar
qinsoon committed
70
    size: ByteSize,
qinsoon's avatar
qinsoon committed
71

qinsoon's avatar
qinsoon committed
72
73
74
75
    //    lo addr                                                    hi addr
    //     | overflow guard page | actual stack ..................... | underflow guard page|
    //     |                     |                                    |                     |
    // overflowGuard           lowerBound                           upperBound
qinsoon's avatar
qinsoon committed
76
77
    //                                                              underflowGuard
    /// start address of overflow guard page
qinsoon's avatar
qinsoon committed
78
    overflow_guard : Address,
qinsoon's avatar
qinsoon committed
79
    /// lower bound of the stack
qinsoon's avatar
qinsoon committed
80
    lower_bound    : Address,
qinsoon's avatar
qinsoon committed
81
    /// upper bound of the stack
qinsoon's avatar
qinsoon committed
82
    upper_bound    : Address,
qinsoon's avatar
qinsoon committed
83
    /// start address of underflow guard page
qinsoon's avatar
qinsoon committed
84
85
    underflow_guard: Address,
    
qinsoon's avatar
qinsoon committed
86
87
    // these frame/instruction pointers should only be used when the stack is not active
    /// stack pointer to the stack (before it becomes inactive)
qinsoon's avatar
qinsoon committed
88
    sp : Address,
qinsoon's avatar
qinsoon committed
89
    /// frame pointer to the stack (before it becomes inactive)
qinsoon's avatar
qinsoon committed
90
    bp : Address,
qinsoon's avatar
qinsoon committed
91
    /// instruction pointer (before the stack becomes inactive)
qinsoon's avatar
qinsoon committed
92
    ip : Address,
qinsoon's avatar
qinsoon committed
93
94
95

    /// state of this stack: ready (inactive), active, dead
    //  TODO: we are not using this for now
96
    state: MuStackState,
qinsoon's avatar
qinsoon committed
97
98

    /// the Mmap that keeps this memory alive
qinsoon's avatar
qinsoon committed
99
    #[allow(dead_code)]
100
    mmap           : Option<memmap::Mmap>
qinsoon's avatar
qinsoon committed
101
102
103
}

impl MuStack {
qinsoon's avatar
qinsoon committed
104
    /// creates a new MuStack for given entry function and function address
105
    pub fn new(id: MuID, func_addr: ValueLocation, func: &MuFunction) -> MuStack {
qinsoon's avatar
qinsoon committed
106
107
108
109
110
111
112
113
        // allocate memory for the stack
        let anon_mmap = {
            // reserve two guard pages more than we need for the stack
            let total_size = PAGE_SIZE * 2 + STACK_SIZE;
            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
114
115
        };
        
qinsoon's avatar
qinsoon committed
116
117
        let mmap_start = Address::from_ptr(anon_mmap.ptr());
        debug_assert!(mmap_start.is_aligned_to(PAGE_SIZE));
qinsoon's avatar
qinsoon committed
118
119

        // calculate the addresses
qinsoon's avatar
qinsoon committed
120
        let overflow_guard = mmap_start;
121
122
        let lower_bound = mmap_start + PAGE_SIZE;
        let upper_bound = lower_bound + STACK_SIZE;
qinsoon's avatar
qinsoon committed
123
        let underflow_guard = upper_bound;
qinsoon's avatar
qinsoon committed
124
125

        // protect the guard pages
qinsoon's avatar
qinsoon committed
126
127
128
129
        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
130
        
qinsoon's avatar
qinsoon committed
131
132
133
134
135
136
137
138
        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),
139
            func: Some((func_addr, func.id())),
qinsoon's avatar
qinsoon committed
140
141
142
143
144
145
146
147
148
149
150
151
152
            
            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()},
            
153
            mmap: Some(anon_mmap)
qinsoon's avatar
qinsoon committed
154
        }
qinsoon's avatar
qinsoon committed
155
    }
156

qinsoon's avatar
qinsoon committed
157
158
159
160
161
162
163
164
165
166
    /// sets up arguments for the stack's entry function, so it is ready to be executed.
    /// We use a special calling convention for the entry function: we push all the argument
    /// registers for the platform to the stack. If the argument register is used, we get
    /// its value and push the value. Otherwise we push an empty value (0). swap_to_mu_stack
    /// will consume those values on the stack by popping them one by one.
    /// NOTE: any changes to here need to be reflected in swap_to_mu_stack, which consumes
    /// those values pushed to the stack
    pub fn setup_args(&mut self, vals: Vec<ValueLocation>) {
        use utils::Word;
        use utils::WORD_SIZE;
167
        use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
168
        use compiler::backend::{ARGUMENT_GPRS, ARGUMENT_FPRS};
169
170
171
172

        let mut gpr_used = vec![];
        let mut fpr_used = vec![];

qinsoon's avatar
qinsoon committed
173
        // load values for each argument
174
175
176
177
178
179
180
        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),
181
                RegGroup::GPREX => unimplemented!(),
182
183
184
            }
        }

qinsoon's avatar
qinsoon committed
185
        // store floating point argument registers
186
        let mut stack_ptr = self.sp;
qinsoon's avatar
qinsoon committed
187
        for i in 0..ARGUMENT_FPRS.len() {
188
            stack_ptr -= WORD_SIZE;
189
190
191
192
193
194
195
196
197
198
199
200
            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);}
        }

qinsoon's avatar
qinsoon committed
201
202
        // store general purpose argument registers
        for i in 0..ARGUMENT_GPRS.len() {
203
            stack_ptr -= WORD_SIZE;
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
            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);}
        }

        // save it back
        self.sp = stack_ptr;

qinsoon's avatar
qinsoon committed
219
220
        if cfg!(debug_assertions) {
            self.print_stack(Some(20));
221
        }
222
    }
qinsoon's avatar
qinsoon committed
223
224
225

    /// prints n * POINTER_SIZE slots from the stack top (upper bound)
    /// prints either n slots or until meet the stack bottom (lower bound)
226
    pub fn print_stack(&self, n_entries: Option<usize>) {
qinsoon's avatar
qinsoon committed
227
228
        use utils::Word;
        use utils::WORD_SIZE;
229
        
230
        let mut cursor = self.upper_bound - WORD_SIZE;
231
232
        let mut count = 0;
        
qinsoon's avatar
qinsoon committed
233
        debug!("0x{:x} | UPPER_BOUND", self.upper_bound);
234
235
236
237
        while cursor >= self.lower_bound {
            let val = unsafe{cursor.load::<Word>()};
            
            if cursor == self.sp {
qinsoon's avatar
qinsoon committed
238
239
240
                debug!("0x{:x} | 0x{:x} ({}) <- SP", cursor, val, val);
            } else {
                debug!("0x{:x} | 0x{:x} ({})", cursor, val, val);
241
242
            }
            
243
            cursor -= WORD_SIZE;
244
245
246
            count += 1;
            
            if n_entries.is_some() && count > n_entries.unwrap() {
qinsoon's avatar
qinsoon committed
247
                debug!("...");
248
249
250
251
                break;
            }
        }
        
qinsoon's avatar
qinsoon committed
252
        debug!("0x{:x} | LOWER_BOUND", self.lower_bound);
253
    }
qinsoon's avatar
qinsoon committed
254
255
}

qinsoon's avatar
qinsoon committed
256
/// MuStackState represents the state for a mu stack
qinsoon's avatar
qinsoon committed
257
pub enum MuStackState {
qinsoon's avatar
qinsoon committed
258
259
260
    /// ready to resume when values of given types are supplied (can be empty)
    Ready(Vec<P<MuType>>),
    /// running mu code
qinsoon's avatar
qinsoon committed
261
    Active,
qinsoon's avatar
qinsoon committed
262
    /// can be destroyed
qinsoon's avatar
qinsoon committed
263
264
265
    Dead
}

qinsoon's avatar
qinsoon committed
266
267
268
269
270
271
272
/// MuThread represents metadata for a Mu thread.
/// A Mu thread in Zebu is basically an OS thread (pthread). However, we need to maintain our own
/// thread local info, such as allocator, stack, user-level thread local pointer, exception object, and
/// an Arc reference to the VM.
/// We keep the pointer to MuThread for each thread, so that we can query our MuThread metadata.
/// The user-level thread local pointer can be found within MuThread.
/// The compiler emits code that uses offsets to some fields in this struct.
273
#[repr(C)]
qinsoon's avatar
qinsoon committed
274
pub struct MuThread {
qinsoon's avatar
qinsoon committed
275
    pub hdr: MuEntityHeader,
qinsoon's avatar
qinsoon committed
276
    /// the allocator from memory manager
277
    pub allocator: mm::Mutator,
qinsoon's avatar
qinsoon committed
278
    /// current stack (a thread can execute different stacks, but one stack at a time)
qinsoon's avatar
qinsoon committed
279
    pub stack: Option<Box<MuStack>>,
qinsoon's avatar
qinsoon committed
280
281
    /// native stack pointer before we switch to this mu stack
    /// (when the thread exits, we restore to native stack, and allow proper destruction)
282
    pub native_sp_loc: Address,
qinsoon's avatar
qinsoon committed
283
284
285
    /// user supplied thread local address, can be zero
    pub user_tls: Address,
    /// exception object being thrown by the thread
286
    pub exception_obj: Address,
qinsoon's avatar
qinsoon committed
287
    /// a pointer to the virtual machine
288
    pub vm: Arc<VM>
qinsoon's avatar
qinsoon committed
289
290
}

qinsoon's avatar
qinsoon committed
291
// a few field offsets the compiler uses
292
lazy_static! {
293
294
295
296
    pub static ref ALLOCATOR_OFFSET     : usize = offset_of!(MuThread=>allocator).get_byte_offset();
    pub static ref NATIVE_SP_LOC_OFFSET : usize = offset_of!(MuThread=>native_sp_loc).get_byte_offset();
    pub static ref USER_TLS_OFFSET      : usize = offset_of!(MuThread=>user_tls).get_byte_offset();
    pub static ref EXCEPTION_OBJ_OFFSET : usize = offset_of!(MuThread=>exception_obj).get_byte_offset();
297
298
299
300
301
}

impl fmt::Display for MuThread {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MuThread    @{:?}: {}\n", self as *const MuThread, self.hdr).unwrap();
qinsoon's avatar
qinsoon committed
302
303
        write!(f, "- header    @{:?}\n",     &self.hdr as *const MuEntityHeader).unwrap();
        write!(f, "- allocator @{:?}\n",     &self.allocator as *const mm::Mutator).unwrap();
304
305
306
307
308
309
310
        write!(f, "- stack     @{:?}: {}\n", &self.stack as *const Option<Box<MuStack>>, self.stack.is_some()).unwrap();
        write!(f, "- native sp @{:?}: {}\n", &self.native_sp_loc as *const Address, self.native_sp_loc).unwrap();
        write!(f, "- user_tls  @{:?}: {}\n", &self.user_tls as *const Address, self.user_tls).unwrap();
        write!(f, "- exc obj   @{:?}: {}\n", &self.exception_obj as *const Address, self.exception_obj).unwrap();

        Ok(())
    }
311
312
}

qinsoon's avatar
qinsoon committed
313
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
314
#[cfg(any(target_os = "macos", target_os = "linux"))]
qinsoon's avatar
qinsoon committed
315
#[link(name = "runtime_asm")]
316
extern "C" {
qinsoon's avatar
qinsoon committed
317
318
319
320
321
322
323
    /// swaps from a native stack to a mu stack
    /// we create OS threads with native stack, then before executing any mu code,
    /// we swap to mu stack and execute the entry function
    /// args:
    /// new_sp: stack pointer for the mu stack
    /// entry : entry function for the mu stack
    /// old_sp_loc: the location to store native stack pointer so we can later swap back
324
    fn swap_to_mu_stack(new_sp: Address, entry: Address, old_sp_loc: Address);
qinsoon's avatar
qinsoon committed
325
326
327
328
329
330

    /// swaps from a mu stack back to native stack
    /// emitted by the compiler for THREADEXIT IR
    /// args:
    /// sp_loc: the location of native stack pointer
    #[allow(dead_code)] // we are not using this function directly, but compiler will emit calls to it
331
    fn muentry_swap_back_to_native_stack(sp_loc: Address);
qinsoon's avatar
qinsoon committed
332
333
334
335
336
337
338
339
340
341
342

    /// gets base poniter for current frame
    pub fn get_current_frame_bp() -> Address;

    /// restores exception: restore callee saved registers, then set execution to certain point
    /// (this function will not return)
    /// args:
    /// dest: code address to execute (catch block)
    /// callee_saved: a sequence of value that will be restored in order
    /// sp: stack pointer for the new execution
    pub fn exception_restore(dest: Address, callee_saved: *const Word, sp: Address) -> !;
343
344
}

qinsoon's avatar
qinsoon committed
345
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
346
#[cfg(any(target_os = "macos", target_os = "linux"))]
qinsoon's avatar
qinsoon committed
347
#[link(name = "runtime_c")]
348
349
#[allow(improper_ctypes)]
extern "C" {
qinsoon's avatar
qinsoon committed
350
351
352
    /// sets thread local for Zebu
    /// Note: this thread local points to a MuThread, which contains all the thread local info
    /// for a Mu thread and further contains a pointer to the user-level thread local
353
    pub fn set_thread_local(thread: *mut MuThread);
qinsoon's avatar
qinsoon committed
354
355
    /// gets thread local for Zebu
    /// compiler may emit calls to this
356
    pub fn muentry_get_thread_local() -> Address;
qinsoon's avatar
qinsoon committed
357
358
    /// sets return value for a Zebu executable image
    /// compiler emits calls to this for SetRetval instruction (internal use only)
359
    pub fn muentry_set_retval(val: u32);
360
361
}

qinsoon's avatar
qinsoon committed
362
363
364
365
366
impl MuThread {
    /// creates a new Mu thread with normal execution
    pub fn new_thread_normal(mut stack: Box<MuStack>, threadlocal: Address, vals: Vec<ValueLocation>, vm: Arc<VM>) -> JoinHandle<()> {
        // set up arguments on stack
        stack.setup_args(vals);
367

qinsoon's avatar
qinsoon committed
368
369
        MuThread::mu_thread_launch(vm.next_id(), stack, threadlocal, vm)
    }
370

qinsoon's avatar
qinsoon committed
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    /// creates and launches a mu thread, returns a JoinHandle
    #[no_mangle]
    pub extern fn mu_thread_launch(id: MuID, stack: Box<MuStack>, user_tls: Address, vm: Arc<VM>) -> JoinHandle<()> {
        let new_sp = stack.sp;
        let entry = runtime::resolve_symbol(vm.name_of(stack.func.as_ref().unwrap().1));
        debug!("entry : 0x{:x}", entry);

        match thread::Builder::new().name(format!("Mu Thread #{}", id)).spawn(move || {
            let muthread : *mut MuThread = Box::into_raw(Box::new(MuThread::new(id, mm::new_mutator(), stack, user_tls, vm)));

            // set thread local
            unsafe {set_thread_local(muthread)};

            let addr = unsafe {muentry_get_thread_local()};
385
            let sp_threadlocal_loc = addr + *NATIVE_SP_LOC_OFFSET;
qinsoon's avatar
qinsoon committed
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
            debug!("new sp: 0x{:x}", new_sp);
            debug!("sp_store: 0x{:x}", sp_threadlocal_loc);

            unsafe {
                swap_to_mu_stack(new_sp, entry, sp_threadlocal_loc);
            }

            debug!("returned to Rust stack. Going to quit");
        }) {
            Ok(handle) => handle,
            Err(_) => panic!("failed to create a thread")
        }
    }

    /// creates metadata for a Mu thread
    fn new(id: MuID, allocator: mm::Mutator, stack: Box<MuStack>, user_tls: Address, vm: Arc<VM>) -> MuThread {
qinsoon's avatar
qinsoon committed
402
403
404
405
        MuThread {
            hdr: MuEntityHeader::unnamed(id),
            allocator: allocator,
            stack: Some(stack),
406
            native_sp_loc: unsafe {Address::zero()},
407
408
409
            user_tls: user_tls,
            vm: vm,
            exception_obj: unsafe {Address::zero()}
qinsoon's avatar
qinsoon committed
410
411
        }
    }
qinsoon's avatar
qinsoon committed
412

qinsoon's avatar
qinsoon committed
413
    /// is current thread a Mu thread?
qinsoon's avatar
qinsoon committed
414
415
416
417
    #[inline(always)]
    pub fn has_current() -> bool {
        ! unsafe {muentry_get_thread_local()}.is_zero()
    }
qinsoon's avatar
qinsoon committed
418
419

    /// gets a reference to MuThread for current MuThread
qinsoon's avatar
qinsoon committed
420
    #[inline(always)]
421
422
    pub fn current() -> &'static MuThread {
        unsafe{
qinsoon's avatar
qinsoon committed
423
            muentry_get_thread_local().to_ptr::<MuThread>().as_ref().unwrap()
qinsoon's avatar
qinsoon committed
424
425
        }
    }
qinsoon's avatar
qinsoon committed
426
427

    /// gets a mutable reference to MuThread for current MuThread
qinsoon's avatar
qinsoon committed
428
    #[inline(always)]
429
430
    pub fn current_mut() -> &'static mut MuThread {
        unsafe{
qinsoon's avatar
qinsoon committed
431
            muentry_get_thread_local().to_ptr_mut::<MuThread>().as_mut().unwrap()
432
433
        }
    }
434

qinsoon's avatar
qinsoon committed
435
436
437
    /// disguises current thread as a Mu thread (setup MuThread metadata, thread local for it),
    /// returns true if we have created a MuThread on this call, false means we had MuThread
    /// for current thread before.
438
    pub unsafe fn current_thread_as_mu_thread(threadlocal: Address, vm: Arc<VM>) -> bool {
439
440
        use std::usize;

qinsoon's avatar
qinsoon committed
441
        // build exception table as we may execute mu function
442
443
        vm.build_exception_table();

qinsoon's avatar
qinsoon committed
444
        if !muentry_get_thread_local().is_zero() {
445
            warn!("current thread has a thread local (has a muthread to it)");
446
            return false;
447
448
        }

449
450
        // fake a stack for current thread
        let fake_mu_stack_for_cur = Box::new(MuStack {
qinsoon's avatar
qinsoon committed
451
452
453
454
455
            hdr             : MuEntityHeader::unnamed(vm.next_id()),
            // no entry function
            func            : None,
            // active state
            state           : MuStackState::Active,
456
457
458
            // we do not know anything about current stack
            // treat it as max size
            size: usize::MAX,
qinsoon's avatar
qinsoon committed
459
460
461
462
            overflow_guard  : Address::zero(),
            lower_bound     : Address::zero(),
            upper_bound     : Address::max(),
            underflow_guard : Address::max(),
463
464
            // these will only be used when stack is not active (we still save to these fields)
            // their values do not matter now
qinsoon's avatar
qinsoon committed
465
466
467
            sp              : Address::zero(),
            bp              : Address::zero(),
            ip              : Address::zero(),
468
            // we are not responsible for keeping the memory alive
qinsoon's avatar
qinsoon committed
469
            mmap            : None,
470
471
        });

qinsoon's avatar
qinsoon committed
472
        // fake a thread for current thread
473
        let fake_mu_thread = MuThread {
qinsoon's avatar
qinsoon committed
474
475
476
477
478
479
480
481
482
483
            hdr             : MuEntityHeader::unnamed(vm.next_id()),
            // we need a valid allocator and stack
            allocator       : mm::new_mutator(),
            stack           : Some(fake_mu_stack_for_cur),
            // we do not need native_sp_loc (we do not expect the thread to call THREADEXIT)
            native_sp_loc   : Address::zero(),
            // valid thread local from user
            user_tls        : threadlocal,
            vm              : vm,
            exception_obj   : Address::zero()
484
485
486
        };

        // set thread local
qinsoon's avatar
qinsoon committed
487
488
        let ptr_fake_mu_thread : *mut MuThread = Box::into_raw(Box::new(fake_mu_thread));
        set_thread_local(ptr_fake_mu_thread);
489

490
        true
491
    }
492
493
494

    /// turn this current mu thread back as normal thread
    pub unsafe fn cleanup_current_mu_thread() {
495
        let mu_thread_addr = muentry_get_thread_local();
496
497
498
499

        if !mu_thread_addr.is_zero() {
            let mu_thread : *mut MuThread = mu_thread_addr.to_ptr_mut();

qinsoon's avatar
qinsoon committed
500
501
            // drop allocator
            mm::drop_mutator(&mut (*mu_thread).allocator as *mut mm::Mutator);
502

qinsoon's avatar
qinsoon committed
503
            // set thread local to zero
qinsoon's avatar
qinsoon committed
504
            set_thread_local(ptr::null_mut());
qinsoon's avatar
qinsoon committed
505

qinsoon's avatar
qinsoon committed
506
507
            // get mu thread back to Box (and will get dropped)
            Box::from_raw(mu_thread);
qinsoon's avatar
qinsoon committed
508
509
        }
    }
510
511
}

qinsoon's avatar
qinsoon committed
512
/// PrimordialThreadInfo stores information about primordial thread/entry function for a boot image
qinsoon's avatar
qinsoon committed
513
#[derive(Debug, RustcEncodable, RustcDecodable)]
qinsoon's avatar
qinsoon committed
514
515
pub struct PrimordialThreadInfo {
    /// entry function id
516
    pub func_id: MuID,
qinsoon's avatar
qinsoon committed
517
    /// does user supply some contant arguments to start the primordial thread?
qinsoon's avatar
qinsoon committed
518
    pub has_const_args: bool,
qinsoon's avatar
qinsoon committed
519
    /// arguments
520
    pub args: Vec<Constant>
Kunshan Wang's avatar
Kunshan Wang committed
521
}