blob: 538995b94751ac45565efbd1ac553b49718d4197 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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..
use crate::cmp;
use crate::ffi::CStr;
use crate::io;
use crate::mem;
use crate::num::NonZeroUsize;
use crate::ptr;
use crate::sys::os;
use crate::time::Duration;
use sgx_trts::enclave;
use sgx_types::{sgx_ocalloc, sgx_ocfree, sgx_status_t};
pub struct Thread {
id: libc::pthread_t,
}
// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let p = Box::into_raw(box p);
let mut native: libc::pthread_t = mem::zeroed();
let attr: libc::pthread_attr_t = mem::zeroed();
let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
return if ret != 0 {
// The thread failed to start and as a result p was not consumed. Therefore, it is
// safe to reconstruct the box so that it gets deallocated.
drop(Box::from_raw(p));
if ret == libc::EAGAIN {
Err(io::Error::from_sgx_error(sgx_status_t::SGX_ERROR_OUT_OF_TCS))
} else {
Err(io::Error::from_raw_os_error(ret))
}
} else {
Ok(Thread { id: native })
};
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
unsafe {
// Finally, let's run some code.
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
}
ptr::null_mut()
}
}
pub fn yield_now() {
let ret = unsafe { libc::sched_yield() };
debug_assert_eq!(ret, 0);
}
pub fn set_name(name: &CStr) {
const PR_SET_NAME: libc::c_int = 15;
// pthread wrapper only appeared in glibc 2.12, so we use syscall
// directly.
let name = name.to_bytes_with_nul();
unsafe {
let ptr = sgx_ocalloc(name.len());
if !ptr.is_null() {
ptr::copy_nonoverlapping(name.as_ptr() as *const u8, ptr as *mut u8, name.len());
libc::prctl(PR_SET_NAME, ptr as libc::c_ulong, 0, 0, 0);
sgx_ocfree();
}
}
}
pub fn sleep(dur: Duration) {
let mut secs = dur.as_secs();
let mut nsecs = dur.subsec_nanos() as _;
// If we're awoken with a signal then the return value will be -1 and
// nanosleep will fill in `ts` with the remaining time.
unsafe {
while secs > 0 || nsecs > 0 {
let mut ts = libc::timespec {
tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
tv_nsec: nsecs,
};
secs -= ts.tv_sec as u64;
let ts_ptr = &mut ts as *mut _;
if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
assert_eq!(os::errno(), libc::EINTR);
secs += ts.tv_sec as u64;
nsecs = ts.tv_nsec;
} else {
nsecs = 0;
}
}
}
}
pub fn join(self) {
unsafe {
let ret = libc::pthread_join(self.id, ptr::null_mut());
mem::forget(self);
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
}
}
pub fn id(&self) -> libc::pthread_t {
self.id
}
pub fn into_id(self) -> libc::pthread_t {
let id = self.id;
mem::forget(self);
id
}
}
impl Drop for Thread {
fn drop(&mut self) {
//let ret = unsafe { libc::pthread_detach(self.id) };
//debug_assert_eq!(ret, 0);
}
}
pub fn available_parallelism() -> io::Result<NonZeroUsize> {
let cpus = enclave::rsgx_get_cpu_core_num();
NonZeroUsize::new(cpus as usize).ok_or_else(|| io::const_io_error!(
io::ErrorKind::NotFound,
"The number of hardware threads is not known for the target platform",
))
}
mod libc {
pub use sgx_libc::ocall::{sched_yield, nanosleep, prctl};
pub use sgx_libc::*;
}