Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • martin/relibc
  • ashton/relibc
  • vincent/relibc
  • boomshroom/relibc
  • njskalski/relibc
  • bjorn3/relibc
  • microcolonel/relibc
  • gmacd/relibc
  • 4lDO2/relibc
  • feliwir/relibc
  • devnexen/relibc
  • jamesgraves/relibc
  • oddcoder/relibc
  • andar1an/relibc
  • gugz0r/relibc
  • matijaskala/relibc
  • zen3ger/relibc
  • Majoneza/relibc
  • enygmator/relibc
  • JustAnotherDev/relibc
  • doriancodes/relibc
  • adamantinum/relibc
  • wiredtv/relibc
  • stratact/relibc
  • Ramla-I/relibc
  • bitstr0m/relibc
  • bpisch/relibc
  • henritel/relibc
  • smckay/relibc
  • xTibor/relibc
  • devajithvs/relibc
  • andypython/relibc
  • t-nil/relibc
  • DataTriny/relibc
  • SteveLauC/relibc
  • dlrobertson/relibc
  • AgostonSzepessy/relibc
  • TheDarkula/relibc
  • willnode/relibc
  • bamontan/relibc
  • redoxeon/relibc
  • ayf/relibc
  • heghe/relibc
  • Ivan/relibc
  • hasheddan/relibc
  • dahc/relibc
  • auwardoctor/relibc
  • kodicraft/relibc
  • arthurpaulino/relibc
  • jasonhansel/relibc
  • kel/relibc
  • GrayJack/relibc
  • darley/relibc
  • sahitpj/relibc
  • plimkilde/relibc
  • BjornTheProgrammer/relibc
  • defra/relibc
  • Schyrsivochter/relibc
  • ebalalic/relibc
  • adchacon/relibc
  • aaronjanse/relibc
  • josh_williams/relibc
  • 8tab/relibc
  • josh/relibc
  • nicoan/relibc
  • athei/relibc
  • carrot93/relibc
  • RA_GM1/relibc
  • zhaozhao/relibc
  • JCake/relibc
  • KGrewal1/relibc
  • emturner/relibc
  • LuigiPiucco/relibc
  • bfrascher/relibc
  • starsheriff/relibc
  • kcired/relibc
  • jamespcfrancis/relibc
  • neallred/relibc
  • omar-mohamed-khallaf/relibc
  • jD91mZM2/relibc
  • rw_van/relibc
  • Skallwar/relibc
  • matt-vdv/relibc
  • mati865/relibc
  • SoyaOhnishi/relibc
  • ArniDagur/relibc
  • tlam/relibc
  • glongo/relibc
  • kamirr/relibc
  • abdullah/relibc
  • saeedtabrizi/relibc
  • sajattack/relibc
  • lmiskiew/relibc
  • seanpk/relibc
  • MaikuZ/relibc
  • jamadazi/relibc
  • coolreader18/relibc
  • wt/relibc
  • lebensterben/relibc
  • uuuvn/relibc
  • vadorovsky/relibc
  • ids1024/relibc
  • raffaeleragni/relibc
  • freewilll/relibc
  • LLeny/relibc
  • alfredoyang/relibc
  • batonius/relibc
  • TornaxO7/relibc
  • Arcterus/relibc
  • Tommoa/relibc
  • samuela/relibc
  • mindriot101/relibc
  • redox-os/relibc
  • lygstate/relibc
114 results
Show changes
Commits on Source (20)
Showing
with 488 additions and 167 deletions
......@@ -61,7 +61,6 @@ impl<'a> DerefMut for Buffer<'a> {
/// This struct gets exposed to the C API.
pub struct FILE {
// Can't use spin crate because *_unlocked functions are things in C :(
lock: Mutex<()>,
file: File,
......@@ -417,8 +416,10 @@ pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
/// Insert a string into a stream
#[no_mangle]
pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
let len = strlen(s);
(fwrite(s as *const c_void, 1, len, stream) == len) as c_int - 1
let mut stream = (*stream).lock();
let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
if stream.write_all(&buf).is_ok() { 0 } else { -1 }
}
/// Read `nitems` of size `size` into `ptr` from `stream`
......@@ -577,7 +578,7 @@ pub unsafe extern "C" fn fwrite(
return 0;
}
let mut stream = (*stream).lock();
let buf = slice::from_raw_parts_mut(ptr as *mut u8, size as usize * nitems as usize);
let buf = slice::from_raw_parts(ptr as *const u8, size as usize * nitems as usize);
let mut written = 0;
while written < buf.len() {
match stream.write(&buf[written..]) {
......@@ -798,12 +799,16 @@ pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int {
/// Put a string `s` into `stdout`
#[no_mangle]
pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
let ret = (fputs(s, stdout) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
if ret {
0
} else {
-1
let mut stream = (&mut *stdout).lock();
let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
if stream.write_all(&buf).is_err() {
return -1;
}
if stream.write(&[b'\n']).is_err() {
return -1;
}
0
}
/// Put an integer `w` into `stream`
......
......@@ -35,6 +35,7 @@ pub const MB_CUR_MAX: c_int = 4;
pub const MB_LEN_MAX: c_int = 4;
static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32];
static mut L64A_BUFFER: [c_char; 7] = [0; 7]; // up to 6 digits plus null terminator
static mut RNG: Option<XorShiftRng> = None;
lazy_static! {
......@@ -51,26 +52,27 @@ pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long {
if s.is_null() {
return 0;
}
let mut l: c_long = 0;
// POSIX says only the low-order 32 bits are used.
let mut l: i32 = 0;
// a64l does not support more than 6 characters at once
for x in 0..6 {
let c = *s.offset(x);
if c == 0 {
// string is null terminated
return l;
return c_long::from(l);
}
// ASCII to base64 conversion:
let mut bits: c_long = if c < 58 {
(c - 46) as c_long // ./0123456789
let mut bits: i32 = if c < 58 {
(c - 46) as i32 // ./0123456789
} else if c < 91 {
(c - 53) as c_long // A-Z
(c - 53) as i32 // A-Z
} else {
(c - 59) as c_long // a-z
(c - 59) as i32 // a-z
};
bits <<= 6 * x;
l |= bits;
}
l
c_long::from(l)
}
#[no_mangle]
......@@ -90,7 +92,7 @@ pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut
* difference between aligned_alloc() and memalign(). */
memalign(alignment, size)
} else {
platform::errno = errno::EINVAL;
platform::errno = EINVAL;
ptr::null_mut()
}
}
......@@ -197,8 +199,7 @@ pub unsafe extern "C" fn bsearch(
#[no_mangle]
pub unsafe extern "C" fn calloc(nelem: size_t, elsize: size_t) -> *mut c_void {
//Handle possible integer overflow in size calculation
let size_result = nelem.checked_mul(elsize);
match size_result {
match nelem.checked_mul(elsize) {
Some(size) => {
/* If allocation fails here, errno setting will be handled
* by malloc() */
......@@ -210,7 +211,7 @@ pub unsafe extern "C" fn calloc(nelem: size_t, elsize: size_t) -> *mut c_void {
}
None => {
// For overflowing multiplication, we have to set errno here
platform::errno = errno::ENOMEM;
platform::errno = ENOMEM;
ptr::null_mut()
}
}
......@@ -368,9 +369,37 @@ pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long {
lcg48::int32_from_x(new_xi)
}
// #[no_mangle]
pub extern "C" fn l64a(value: c_long) -> *mut c_char {
unimplemented!();
#[no_mangle]
pub unsafe extern "C" fn l64a(value: c_long) -> *mut c_char {
// POSIX says we should only consider the lower 32 bits of value.
let value_as_i32 = value as i32;
/* If we pretend to extend the 32-bit value with 4 binary zeros, we
* would get a 36-bit integer. The number of base-64 digits to be
* left unused can then be found by taking the number of leading
* zeros, dividing by 6 and rounding down (i.e. using integer
* division). */
let num_output_digits = 6 - (value_as_i32.leading_zeros() + 4) / 6;
// Reset buffer (and have null terminator in place for any result)
L64A_BUFFER = [0; 7];
for i in 0..num_output_digits as usize {
let digit_value = ((value_as_i32 >> 6 * i) & 63) as c_char;
if digit_value < 12 {
// ./0123456789 for values 0 to 11. b'.' == 46
L64A_BUFFER[i] = 46 + digit_value;
} else if digit_value < 38 {
// A-Z for values 12 to 37. b'A' == 65, 65-12 == 53
L64A_BUFFER[i] = 53 + digit_value;
} else {
// a-z for values 38 to 63. b'a' == 97, 97-38 == 59
L64A_BUFFER[i] = 59 + digit_value;
}
}
L64A_BUFFER.as_mut_ptr()
}
#[no_mangle]
......@@ -433,24 +462,21 @@ pub unsafe extern "C" fn lrand48() -> c_long {
pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
let ptr = platform::alloc(size);
if ptr.is_null() {
platform::errno = errno::ENOMEM;
platform::errno = ENOMEM;
}
ptr
}
#[no_mangle]
pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_void {
/* Check if alignment is a (positive) power of two. The second
* expression will never underflow, due to Rust's lazy boolean
* operators. */
if alignment > 0 && (alignment & (alignment - 1)) == 0 {
if alignment.is_power_of_two() {
let ptr = platform::alloc_align(size, alignment);
if ptr.is_null() {
platform::errno = errno::ENOMEM;
platform::errno = ENOMEM;
}
ptr
} else {
platform::errno = errno::EINVAL;
platform::errno = EINVAL;
ptr::null_mut()
}
}
......@@ -696,11 +722,11 @@ pub extern "C" fn random() -> c_long {
#[no_mangle]
pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
let ptr = platform::realloc(ptr, size);
if ptr.is_null() {
platform::errno = errno::ENOMEM;
let new_ptr = platform::realloc(ptr, size);
if new_ptr.is_null() {
platform::errno = ENOMEM;
}
ptr
new_ptr
}
#[no_mangle]
......@@ -1071,7 +1097,7 @@ pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
* EINVAL, hence no call to memalign(). */
let ptr = platform::alloc_align(size, page_size);
if ptr.is_null() {
platform::errno = errno::ENOMEM;
platform::errno = ENOMEM;
}
ptr
}
......
......@@ -2,6 +2,8 @@
use core::mem;
use cbitset::BitSet;
use fs::File;
use header::errno;
use header::sys_epoll::{epoll_create1, epoll_ctl, epoll_data, epoll_event, epoll_wait, EPOLLERR,
......@@ -13,45 +15,18 @@ use platform::types::*;
// fd_set is also defined in C because cbindgen is incompatible with mem::size_of booo
pub const FD_SETSIZE: usize = 1024;
type bitset = BitSet<[c_ulong; FD_SETSIZE / (8 * mem::size_of::<c_ulong>())]>;
#[repr(C)]
pub struct fd_set {
pub fds_bits: [c_ulong; FD_SETSIZE / (8 * mem::size_of::<c_ulong>())],
}
impl fd_set {
fn index(fd: c_int) -> usize {
(fd as usize) / (8 * mem::size_of::<c_ulong>())
}
fn bitmask(fd: c_int) -> c_ulong {
1 << ((fd as usize) & (8 * mem::size_of::<c_ulong>() - 1)) as c_ulong
}
fn zero(&mut self) {
for i in 0..self.fds_bits.len() {
self.fds_bits[i] = 0;
}
}
fn set(&mut self, fd: c_int) {
self.fds_bits[Self::index(fd)] |= Self::bitmask(fd);
}
fn clr(&mut self, fd: c_int) {
self.fds_bits[Self::index(fd)] &= !Self::bitmask(fd);
}
fn isset(&self, fd: c_int) -> bool {
self.fds_bits[Self::index(fd)] & Self::bitmask(fd) > 0
}
pub fds_bits: bitset,
}
pub fn select_epoll(
nfds: c_int,
mut readfds: Option<&mut fd_set>,
mut writefds: Option<&mut fd_set>,
mut exceptfds: Option<&mut fd_set>,
readfds: Option<&mut fd_set>,
writefds: Option<&mut fd_set>,
exceptfds: Option<&mut fd_set>,
timeout: Option<&mut timeval>,
) -> c_int {
if nfds < 0 || nfds > FD_SETSIZE as i32 {
......@@ -67,11 +42,15 @@ pub fn select_epoll(
File::new(epfd)
};
let mut read_bitset : Option<&mut bitset> = readfds.map(|fd_set| &mut fd_set.fds_bits);
let mut write_bitset : Option<&mut bitset> = writefds.map(|fd_set| &mut fd_set.fds_bits);
let mut except_bitset : Option<&mut bitset> = exceptfds.map(|fd_set| &mut fd_set.fds_bits);
// Keep track of the number of file descriptors that do not support epoll
let mut not_epoll = 0;
for fd in 0..nfds {
if let Some(ref mut fd_set) = readfds {
if fd_set.isset(fd) {
if let Some(ref mut fd_set) = read_bitset {
if fd_set.contains(fd as usize) {
let mut event = epoll_event {
events: EPOLLIN,
data: epoll_data { fd },
......@@ -84,12 +63,12 @@ pub fn select_epoll(
return -1;
}
} else {
fd_set.clr(fd);
fd_set.remove(fd as usize);
}
}
}
if let Some(ref mut fd_set) = writefds {
if fd_set.isset(fd) {
if let Some(ref mut fd_set) = write_bitset {
if fd_set.contains(fd as usize) {
let mut event = epoll_event {
events: EPOLLOUT,
data: epoll_data { fd },
......@@ -102,12 +81,12 @@ pub fn select_epoll(
return -1;
}
} else {
fd_set.clr(fd);
fd_set.remove(fd as usize);
}
}
}
if let Some(ref mut fd_set) = exceptfds {
if fd_set.isset(fd) {
if let Some(ref mut fd_set) = except_bitset {
if fd_set.contains(fd as usize) {
let mut event = epoll_event {
events: EPOLLERR,
data: epoll_data { fd },
......@@ -120,7 +99,7 @@ pub fn select_epoll(
return -1;
}
} else {
fd_set.clr(fd);
fd_set.remove(fd as usize);
}
}
}
......@@ -154,22 +133,22 @@ pub fn select_epoll(
let event = &events[i];
let fd = unsafe { event.data.fd };
// TODO: Error status when fd does not match?
if fd >= 0 && fd <= FD_SETSIZE as c_int {
if fd >= 0 && fd < FD_SETSIZE as c_int {
if event.events & EPOLLIN > 0 {
if let Some(ref mut fd_set) = readfds {
fd_set.set(fd);
if let Some(ref mut fd_set) = read_bitset {
fd_set.insert(fd as usize);
count += 1;
}
}
if event.events & EPOLLOUT > 0 {
if let Some(ref mut fd_set) = writefds {
fd_set.set(fd);
if let Some(ref mut fd_set) = write_bitset {
fd_set.insert(fd as usize);
count += 1;
}
}
if event.events & EPOLLERR > 0 {
if let Some(ref mut fd_set) = exceptfds {
fd_set.set(fd);
if let Some(ref mut fd_set) = except_bitset {
fd_set.insert(fd as usize);
count += 1;
}
}
......
//! unistd implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/unistd.h.html
use core::convert::TryFrom;
use core::{mem, ptr, slice};
use alloc::collections::LinkedList;
use c_str::CStr;
use header::errno;
use header::limits;
......@@ -10,9 +12,9 @@ use header::sys_ioctl;
use header::sys_time;
use header::termios;
use header::time::timespec;
use platform;
use platform::types::*;
use platform::{Pal, Sys};
use platform;
pub use self::brk::*;
pub use self::getopt::*;
......@@ -42,6 +44,17 @@ pub const STDIN_FILENO: c_int = 0;
pub const STDOUT_FILENO: c_int = 1;
pub const STDERR_FILENO: c_int = 2;
#[thread_local]
pub static mut fork_hooks_static: Option<[LinkedList<extern "C" fn()>; 3]> = None;
unsafe fn init_fork_hooks<'a>() -> &'a mut [LinkedList<extern "C" fn()>; 3] {
// Transmute the lifetime so we can return here. Should be safe as
// long as one does not access the original fork_hooks.
mem::transmute(fork_hooks_static.get_or_insert_with(|| {
[LinkedList::new(), LinkedList::new(), LinkedList::new()]
}))
}
#[no_mangle]
pub extern "C" fn _exit(status: c_int) {
Sys::exit(status)
......@@ -214,7 +227,21 @@ pub extern "C" fn fdatasync(fildes: c_int) -> c_int {
#[no_mangle]
pub extern "C" fn fork() -> pid_t {
Sys::fork()
let fork_hooks = unsafe { init_fork_hooks() };
for prepare in &fork_hooks[0] {
prepare();
}
let pid = Sys::fork();
if pid == 0 {
for child in &fork_hooks[2] {
child();
}
} else if pid != -1 {
for parent in &fork_hooks[1] {
parent();
}
}
pid
}
#[no_mangle]
......@@ -334,7 +361,21 @@ pub extern "C" fn getlogin_r(name: *mut c_char, namesize: size_t) -> c_int {
#[no_mangle]
pub extern "C" fn getpagesize() -> c_int {
sysconf(_SC_PAGESIZE) as c_int
match c_int::try_from(sysconf(_SC_PAGESIZE)) {
Ok(page_size) => page_size,
Err(_) => {
/* Behavior not specified by POSIX for this case. The -1
* value mimics sysconf()'s behavior, though.
*
* As specified for the limits.h header, the minimum
* acceptable value for {PAGESIZE} is 1. The -1 value thus
* cannot be mistaken for an acceptable value.
*
* POSIX does not specify any possible errors for this
* function, hence no errno setting. */
-1
}
}
}
// #[no_mangle]
......@@ -450,13 +491,23 @@ pub extern "C" fn pread(fildes: c_int, buf: *mut c_void, nbyte: size_t, offset:
res
}
// #[no_mangle]
#[no_mangle]
pub extern "C" fn pthread_atfork(
prepare: Option<extern "C" fn()>,
parent: Option<extern "C" fn()>,
child: Option<extern "C" fn()>,
) -> c_int {
unimplemented!();
let fork_hooks = unsafe { init_fork_hooks() };
if let Some(prepare) = prepare {
fork_hooks[0].push_back(prepare);
}
if let Some(parent) = parent {
fork_hooks[1].push_back(parent);
}
if let Some(child) = child {
fork_hooks[2].push_back(child);
}
0
}
#[no_mangle]
......
use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};
use crate::start::Stack;
use self::tcb::{Tcb, Master};
pub const PAGE_SIZE: usize = 4096;
pub mod linker;
pub mod start;
pub mod tcb;
pub fn static_init(sp: &'static Stack) {
let mut phdr_opt = None;
let mut phent_opt = None;
let mut phnum_opt = None;
let mut auxv = sp.auxv();
loop {
let (kind, value) = unsafe { *auxv };
if kind == 0 {
break;
}
match kind {
3 => phdr_opt = Some(value),
4 => phent_opt = Some(value),
5 => phnum_opt = Some(value),
_ => (),
}
auxv = unsafe { auxv.add(1) };
}
let phdr = phdr_opt.expect("failed to find AT_PHDR");
let phent = phent_opt.expect("failed to find AT_PHENT");
let phnum = phnum_opt.expect("failed to find AT_PHNUM");
for i in 0..phnum {
let ph_addr = phdr + phent * i;
let ph: ProgramHeader = match phent {
program_header32::SIZEOF_PHDR => {
unsafe { *(ph_addr as *const program_header32::ProgramHeader) }.into()
},
program_header64::SIZEOF_PHDR => {
unsafe { *(ph_addr as *const program_header64::ProgramHeader) }.into()
},
_ => panic!("unknown AT_PHENT size {}", phent),
};
let voff = ph.p_vaddr as usize % PAGE_SIZE;
let vaddr = ph.p_vaddr as usize - voff;
let vsize = ((ph.p_memsz as usize + voff + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
match ph.p_type {
program_header::PT_TLS => {
let valign = if ph.p_align > 0 {
((ph.p_memsz + (ph.p_align - 1)) / ph.p_align) * ph.p_align
} else {
ph.p_memsz
} as usize;
let tcb_master = Master {
ptr: ph.p_vaddr as usize as *const u8,
len: ph.p_filesz as usize,
offset: vsize - valign,
};
unsafe {
let tcb = Tcb::new(vsize).expect("failed to allocate TCB");
tcb.set_masters(vec![tcb_master].into_boxed_slice());
tcb.copy_masters().expect("failed to copy TLS master data");
tcb.activate();
}
//TODO: Warning on multiple TLS sections?
return;
}
_ => (),
}
}
}
#[cfg(target_os = "linux")]
pub unsafe fn init(sp: &'static Stack) {
let mut tp = 0usize;
const ARCH_GET_FS: usize = 0x1003;
syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut tp as *mut usize);
if tp == 0 {
static_init(sp);
}
}
#[cfg(target_os = "redox")]
pub unsafe fn init(_sp: &'static Stack) {}
......@@ -4,14 +4,9 @@ use c_str::CStr;
use header::unistd;
use platform::types::c_char;
use crate::start::Stack;
use super::linker::Linker;
#[repr(C)]
pub struct Stack {
argc: isize,
argv0: *const c_char,
}
#[no_mangle]
pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
if sp.argc < 2 {
......@@ -26,7 +21,7 @@ pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack) -> usize {
// Pop the first argument (path to ld_so), and get the path of the program
let path_c = unsafe {
let mut argv = &mut sp.argv0 as *mut *const c_char as *mut usize;
let mut argv = sp.argv() as *mut usize;
// Move arguments
loop {
......
......@@ -42,6 +42,25 @@ macro_rules! eprintln {
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
}
/// Lifted from libstd
#[macro_export]
macro_rules! dbg {
() => {
eprintln!("[{}:{}]", file!(), line!());
};
($val:expr) => {
// Use of `match` here is intentional because it affects the lifetimes
// of temporaries - https://stackoverflow.com/a/48732525/1063961
match $val {
tmp => {
eprintln!("[{}:{}] {} = {:#?}",
file!(), line!(), stringify!($val), &tmp);
tmp
}
}
}
}
#[macro_export]
#[cfg(not(feature = "trace"))]
macro_rules! trace {
......
use core::cell::UnsafeCell;
use core::intrinsics;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::AtomicI32 as AtomicInt;
use core::sync::atomic::Ordering::SeqCst;
use core::sync::atomic;
use platform::types::*;
use platform::{Pal, Sys};
......@@ -9,30 +10,43 @@ pub const FUTEX_WAIT: c_int = 0;
pub const FUTEX_WAKE: c_int = 1;
pub struct Mutex<T> {
lock: UnsafeCell<c_int>,
lock: UnsafeCell<AtomicInt>,
content: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Send> Sync for Mutex<T> {}
impl<T> Mutex<T> {
/// Create a new mutex
pub fn new(content: T) -> Self {
pub const fn new(content: T) -> Self {
Self {
lock: UnsafeCell::new(0),
lock: UnsafeCell::new(AtomicInt::new(0)),
content: UnsafeCell::new(content),
}
}
/// Create a new mutex that is already locked. This is a more
/// efficient way to do the following:
/// ```rust
/// let mut mutex = Mutex::new(());
/// mutex.manual_lock();
/// ```
pub unsafe fn locked(content: T) -> Self {
Self {
lock: UnsafeCell::new(AtomicInt::new(1)),
content: UnsafeCell::new(content),
}
}
unsafe fn atomic(&self) -> &mut AtomicInt {
&mut *self.lock.get()
}
/// Tries to lock the mutex, fails if it's already locked. Manual means
/// it's up to you to unlock it after mutex. Returns the last atomic value
/// on failure. You should probably not worry about this, it's used for
/// internal optimizations.
pub unsafe fn manual_try_lock(&self) -> Result<&mut T, c_int> {
let value = intrinsics::atomic_cxchg(self.lock.get(), 0, 1).0;
if value == 0 {
return Ok(&mut *self.content.get());
}
Err(value)
self.atomic().compare_exchange(0, 1, SeqCst, SeqCst)
.map(|_| &mut *self.content.get())
}
/// Lock the mutex, returning the inner content. After doing this, it's
/// your responsibility to unlock it after usage. Mostly useful for FFI:
......@@ -56,8 +70,8 @@ impl<T> Mutex<T> {
//
// - Skip the atomic operation if the last value was 2, since it most likely hasn't changed.
// - Skip the futex wait if the atomic operation says the mutex is unlocked.
if last == 2 || intrinsics::atomic_cxchg(self.lock.get(), 1, 2).0 != 0 {
Sys::futex(self.lock.get(), FUTEX_WAIT, 2);
if last == 2 || self.atomic().compare_exchange(1, 2, SeqCst, SeqCst).unwrap_or_else(|err| err) != 0 {
Sys::futex(self.atomic().get_mut(), FUTEX_WAIT, 2);
}
last = match self.manual_try_lock() {
......@@ -68,9 +82,9 @@ impl<T> Mutex<T> {
}
/// Unlock the mutex, if it's locked.
pub unsafe fn manual_unlock(&self) {
if intrinsics::atomic_xchg(self.lock.get(), 0) == 2 {
if self.atomic().swap(0, SeqCst) == 2 {
// At least one futex is up, so let's notify it
Sys::futex(self.lock.get(), FUTEX_WAKE, 1);
Sys::futex(self.atomic().get_mut(), FUTEX_WAKE, 1);
}
}
......
......@@ -2,25 +2,25 @@
use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::sync::atomic::{AtomicU32, Ordering};
use core::{intrinsics, ptr};
use header::sys_mman;
use header::time::timespec;
use ld_so::tcb::{Master, Tcb};
use mutex::{FUTEX_WAIT, FUTEX_WAKE};
use mutex::Mutex;
use platform::types::{c_int, c_uint, c_void, pid_t, size_t};
use platform::{Pal, Sys};
pub struct Semaphore {
lock: i32,
lock: Mutex<()>,
count: i32,
}
type pte_osThreadHandle = pid_t;
type pte_osMutexHandle = *mut i32;
type pte_osMutexHandle = *mut Mutex<()>;
type pte_osSemaphoreHandle = *mut Semaphore;
type pte_osThreadEntryPoint = unsafe extern "C" fn(params: *mut c_void) -> c_int;
type pte_osThreadEntryPoint = unsafe extern "C" fn(params: *mut c_void) -> *mut c_void;
#[repr(C)]
#[derive(Eq, PartialEq)]
......@@ -37,15 +37,15 @@ pub enum pte_osResult {
use self::pte_osResult::*;
static mut pid_mutexes: Option<BTreeMap<pte_osThreadHandle, pte_osMutexHandle>> = None;
static mut pid_mutexes_lock: i32 = 0;
static mut pid_mutexes_lock: Mutex<()> = Mutex::new(());
static mut pid_stacks: Option<BTreeMap<pte_osThreadHandle, (*mut c_void, size_t)>> = None;
static mut pid_stacks_lock: i32 = 0;
static mut pid_stacks_lock: Mutex<()> = Mutex::new(());
#[thread_local]
static mut LOCALS: *mut BTreeMap<c_uint, *mut c_void> = ptr::null_mut();
static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
static NEXT_KEY: AtomicU32 = AtomicU32::new(0);
unsafe fn locals() -> &'static mut BTreeMap<c_uint, *mut c_void> {
if LOCALS.is_null() {
......@@ -94,7 +94,7 @@ pub unsafe extern "C" fn pte_osThreadCreate(
ppte_osThreadHandle: *mut pte_osThreadHandle,
) -> pte_osResult {
// Create a locked mutex, unlocked by pte_osThreadStart
let mutex: pte_osMutexHandle = Box::into_raw(Box::new(2));
let mutex: pte_osMutexHandle = Box::into_raw(Box::new(Mutex::locked(())));
let stack_size = if stackSize == 0 {
1024 * 1024
......@@ -278,7 +278,7 @@ pub unsafe extern "C" fn pte_osThreadGetDefaultPriority() -> c_int {
#[no_mangle]
pub unsafe extern "C" fn pte_osMutexCreate(pHandle: *mut pte_osMutexHandle) -> pte_osResult {
*pHandle = Box::into_raw(Box::new(0));
*pHandle = Box::into_raw(Box::new(Mutex::new(())));
PTE_OS_OK
}
......@@ -290,38 +290,13 @@ pub unsafe extern "C" fn pte_osMutexDelete(handle: pte_osMutexHandle) -> pte_osR
#[no_mangle]
pub unsafe extern "C" fn pte_osMutexLock(handle: pte_osMutexHandle) -> pte_osResult {
let mut c = 0;
for _i in 0..100 {
c = intrinsics::atomic_cxchg(handle, 0, 1).0;
if c == 0 {
break;
}
}
if c == 1 {
c = intrinsics::atomic_xchg(handle, 2);
}
while c != 0 {
Sys::futex(handle, FUTEX_WAIT, 2);
c = intrinsics::atomic_xchg(handle, 2);
}
(*handle).manual_lock();
PTE_OS_OK
}
#[no_mangle]
pub unsafe extern "C" fn pte_osMutexUnlock(handle: pte_osMutexHandle) -> pte_osResult {
if *handle == 2 {
*handle = 0;
} else if intrinsics::atomic_xchg(handle, 0) == 1 {
return PTE_OS_OK;
}
for _i in 0..100 {
if *handle != 0 && intrinsics::atomic_cxchg(handle, 1, 2).0 != 0 {
return PTE_OS_OK;
}
}
Sys::futex(handle, FUTEX_WAKE, 1);
(*handle).manual_unlock();
PTE_OS_OK
}
......@@ -331,7 +306,7 @@ pub unsafe extern "C" fn pte_osSemaphoreCreate(
pHandle: *mut pte_osSemaphoreHandle,
) -> pte_osResult {
*pHandle = Box::into_raw(Box::new(Semaphore {
lock: 0,
lock: Mutex::new(()),
count: initialValue,
}));
PTE_OS_OK
......@@ -349,9 +324,8 @@ pub unsafe extern "C" fn pte_osSemaphorePost(
count: c_int,
) -> pte_osResult {
let semaphore = &mut *handle;
pte_osMutexLock(&mut semaphore.lock);
let _guard = semaphore.lock.lock();
intrinsics::atomic_xadd(&mut semaphore.count, 1);
pte_osMutexUnlock(&mut semaphore.lock);
PTE_OS_OK
}
......@@ -364,12 +338,11 @@ pub unsafe extern "C" fn pte_osSemaphorePend(
let semaphore = &mut *handle;
let mut acquired = false;
while !acquired {
pte_osMutexLock(&mut semaphore.lock);
let _guard = semaphore.lock.lock();
if intrinsics::atomic_load(&semaphore.count) > 0 {
intrinsics::atomic_xsub(&mut semaphore.count, 1);
acquired = true;
}
pte_osMutexUnlock(&mut semaphore.lock);
Sys::sched_yield();
}
PTE_OS_OK
......@@ -426,7 +399,7 @@ pub unsafe extern "C" fn pte_osTlsGetValue(index: c_uint) -> *mut c_void {
#[no_mangle]
pub unsafe extern "C" fn pte_osTlsAlloc(pKey: *mut c_uint) -> pte_osResult {
NEXT_KEY.fetch_add(1, Ordering::SeqCst);
*pKey = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
PTE_OS_OK
}
......
......@@ -5,24 +5,31 @@ use header::{stdio, stdlib};
use platform;
use platform::types::*;
use platform::{Pal, Sys};
use ld_so;
#[repr(C)]
pub struct Stack {
argc: isize,
argv0: *const c_char,
pub argc: isize,
pub argv0: *const c_char,
}
impl Stack {
fn argc(&self) -> isize {
self.argc
pub fn argv(&self) -> *const *const c_char {
&self.argv0 as *const _
}
fn argv(&self) -> *const *const c_char {
&self.argv0 as *const _
pub fn envp(&self) -> *const *const c_char {
unsafe { self.argv().offset(self.argc + 1) }
}
fn envp(&self) -> *const *const c_char {
unsafe { self.argv().offset(self.argc() + 1) }
pub fn auxv(&self) -> *const (usize, usize) {
unsafe {
let mut envp = self.envp();
while !(*envp).is_null() {
envp = envp.add(1);
}
envp.add(1) as *const (usize, usize)
}
}
}
......@@ -71,8 +78,10 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
// Ensure correct host system before executing more system calls
relibc_verify_host();
ld_so::init(sp);
// Set up argc and argv
let argc = sp.argc();
let argc = sp.argc;
let argv = sp.argv();
platform::inner_argv = copy_string_array(argv, argc as usize);
platform::argv = platform::inner_argv.as_mut_ptr();
......
......@@ -71,11 +71,13 @@ EXPECT_NAMES=\
time/mktime \
time/strftime \
time/time \
tls \
unistd/access \
unistd/brk \
unistd/dup \
unistd/exec \
unistd/fchdir \
unistd/fork \
unistd/fsync \
unistd/ftruncate \
unistd/getopt \
......@@ -112,6 +114,7 @@ NAMES=\
unistd/getcwd \
unistd/gethostname \
unistd/getid \
unistd/getpagesize \
unistd/link \
unistd/pathconf \
unistd/setid \
......
Correct a64l: azAZ9. = 194301926
Correct a64l: azA = 53222
l64a(0):
l64a(1): /
l64a(2): 0
l64a(11): 9
l64a(12): A
l64a(37): Z
l64a(38): a
l64a(63): z
l64a(64): ./
l64a(65): //
l64a(4095): zz
l64a(4096): ../
l64a(262143): zzz
l64a(262144): .../
l64a(16777215): zzzz
l64a(16777216): ..../
l64a(1073741823): zzzzz
l64a(1073741824): ...../
l64a(2147483647): zzzzz/
a64l(l64a(0)): 0
a64l(l64a(1)): 1
a64l(l64a(2)): 2
a64l(l64a(11)): 11
a64l(l64a(12)): 12
a64l(l64a(37)): 37
a64l(l64a(38)): 38
a64l(l64a(63)): 63
a64l(l64a(64)): 64
a64l(l64a(65)): 65
a64l(l64a(4095)): 4095
a64l(l64a(4096)): 4096
a64l(l64a(262143)): 262143
a64l(l64a(262144)): 262144
a64l(l64a(16777215)): 16777215
a64l(l64a(16777216)): 16777216
a64l(l64a(1073741823)): 1073741823
a64l(l64a(1073741824)): 1073741824
a64l(l64a(2147483647)): 2147483647
l64a(x) (lower 32 bits of x are 1985229328): E61Jq/
a64l(l64a(x)) (lower 32 bits of x are 1985229328): 1985229328
0 == 0
1 == 1
Hello from prepare
Hello from child
Hello from parent
......@@ -20,4 +20,34 @@ int main(void) {
exit(EXIT_FAILURE);
}
printf("Correct a64l: %s = %ld\n", s, l);
/* Test near boundaries of digit character mapping, and near
* boundaries for number of digits */
long l64a_test_values[] = {0, 1, 2, 11, 12, 37, \
38, 63, \
64, 65, 4095, \
4096, 262143, \
262144, 16777215, \
16777216, 1073741823, \
1073741824, 2147483647};
// l64a tests
for (size_t i = 0; i < sizeof(l64a_test_values)/sizeof(long); i++) {
printf("l64a(%ld): %s\n", l64a_test_values[i], l64a(l64a_test_values[i]));
}
// a64l(l64a(x)) round-trip tests
for (size_t i = 0; i < sizeof(l64a_test_values)/sizeof(long); i++) {
printf("a64l(l64a(%ld)): %ld\n", l64a_test_values[i], a64l(l64a(l64a_test_values[i])));
}
/* For testing 32-bit truncation behavior (for platforms where long
* is larger than 32 bits). Note that the behavior for a64l() and
* l64a() is unspecified for negative values. */
int64_t test_value_64bit = 0x7edcba9876543210;
printf("l64a(x) (lower 32 bits of x are %ld): %s\n", ((long)test_value_64bit) & 0xffffffff, l64a((long)test_value_64bit));
/* Test for trunctation in l64a(a64(x)) round trip (POSIX says the
* result of that is "x in the low-order 32-bits". */
printf("a64l(l64a(x)) (lower 32 bits of x are %ld): %ld\n", ((long)test_value_64bit) & 0xffffffff, a64l(l64a((long)test_value_64bit)));
}
......@@ -12,7 +12,7 @@ int main(void) {
size_t sample_realloc_size = sample_alloc_size + 1;
/* ensure values are mapped to variables */
size_t zero = 0;
size_t zero_size = 0;
size_t max_size = SIZE_MAX;
size_t aligned_alloc_alignment = 128;
size_t aligned_alloc_goodsize = 256;
......@@ -22,6 +22,14 @@ int main(void) {
int i;
errno = 0;
char * ptr_zerosize_malloc = (char *)malloc(zero_size);
int malloc_zerosize_errno = errno;
printf("malloc (size 0) : %p, errno: %d = %s\n",
ptr_zerosize_malloc, malloc_zerosize_errno,
strerror(malloc_zerosize_errno));
free(ptr_zerosize_malloc);
errno = 0;
char * ptr_malloc = (char *)malloc(sample_alloc_size);
int malloc_errno = errno;
......@@ -40,6 +48,14 @@ int main(void) {
strerror(malloc_maxsize_errno));
free(ptr_malloc_maxsize);
errno = 0;
char * ptr_zerosize_calloc = (char *)calloc(zero_size, 1);
int calloc_zerosize_errno = errno;
printf("calloc (size 0) : %p, errno: %d = %s\n",
ptr_zerosize_calloc,
calloc_zerosize_errno, strerror(calloc_zerosize_errno));
free(ptr_zerosize_calloc);
errno = 0;
char * ptr_calloc = (char *)calloc(sample_alloc_size, 1);
int calloc_errno = errno;
......@@ -58,6 +74,15 @@ int main(void) {
strerror(calloc_overflow_errno));
free(ptr_calloc_overflow); /* clean up correctly even if overflow is not handled */
char * ptr_realloc_size0 = (char *)malloc(sample_alloc_size);
errno = 0;
ptr_realloc_size0 = (char *)realloc(ptr_realloc_size0, zero_size);
int realloc_size0_errno = errno;
printf("realloc (size 0) : %p, errno: %d = %s\n",
ptr_realloc_size0, realloc_size0_errno,
strerror(realloc_size0_errno));
free(ptr_realloc_size0);
char * ptr_realloc = (char *)malloc(sample_alloc_size);
errno = 0;
ptr_realloc = (char *)realloc(ptr_realloc, sample_realloc_size);
......@@ -78,6 +103,14 @@ int main(void) {
strerror(realloc_maxsize_errno));
free(ptr_realloc_maxsize);
errno = 0;
char * ptr_memalign_size0 = (char *)memalign(256, zero_size);
int memalign_size0_errno = errno;
printf("memalign (size 0) : %p, errno: %d = %s\n",
ptr_memalign_size0, memalign_size0_errno,
strerror(memalign_size0_errno));
free(ptr_memalign_size0);
errno = 0;
char * ptr_memalign = (char *)memalign(256, sample_alloc_size);
int memalign_errno = errno;
......@@ -130,11 +163,20 @@ int main(void) {
strerror(aligned_alloc_badsize_errno));
free(ptr_aligned_alloc_badsize);
errno = 0;
char * ptr_valloc_size0 = (char *)valloc(zero_size);
int valloc_size0_errno = errno;
printf("valloc (size 0) : %p, errno: %d = %s\n",
ptr_valloc_size0, valloc_size0_errno,
strerror(valloc_size0_errno));
free(ptr_valloc_size0);
errno = 0;
char * ptr_valloc = (char *)valloc(sample_alloc_size);
int valloc_errno = errno;
printf("valloc : %p, errno: %d = %s\n",
ptr_valloc, valloc_errno, strerror(valloc_errno));
free(ptr_valloc);
errno = 0;
char * ptr_valloc_maxsize = (char *)valloc(max_size);
......@@ -142,6 +184,7 @@ int main(void) {
printf("valloc (SIZE_MAX) : %p, errno: %d = %s\n",
ptr_valloc_maxsize, valloc_maxsize_errno,
strerror(valloc_maxsize_errno));
free(ptr_valloc_maxsize);
errno = 0;
void * ptr_posix_memalign = NULL;
......@@ -156,20 +199,21 @@ int main(void) {
printf(" errno: %d = %s\n",
posix_memalign_errno,
strerror(posix_memalign_errno));
free(ptr_posix_memalign);
errno = 0;
void * ptr_posix_memalign_align0 = NULL;
int posix_memalign_align0_return = posix_memalign(&ptr_posix_memalign_align0, zero, sample_alloc_size);
int posix_memalign_align0_return = posix_memalign(&ptr_posix_memalign_align0, zero_size, sample_alloc_size);
int posix_memalign_align0_errno = errno;
printf("posix_memalign (alignment 0):\n");
printf(" %p, return value: %d = %s,\n",
ptr_posix_memalign_align0,
posix_memalign_align0_return,
strerror(posix_memalign_align0_return));
printf(" errno: %d = %s\n",
posix_memalign_align0_errno,
strerror(posix_memalign_align0_errno));
free(ptr_posix_memalign_align0);
errno = 0;
void * ptr_posix_memalign_nonpow2mul = NULL;
......@@ -180,24 +224,24 @@ int main(void) {
ptr_posix_memalign_nonpow2mul,
posix_memalign_nonpow2mul_return,
strerror(posix_memalign_nonpow2mul_return));
printf(" errno: %d = %s\n",
posix_memalign_nonpow2mul_errno,
strerror(posix_memalign_nonpow2mul_errno));
free(ptr_posix_memalign_nonpow2mul);
errno = 0;
void * ptr_posix_memalign_size0 = NULL;
int posix_memalign_size0_return = posix_memalign(&ptr_posix_memalign_size0, pow2_mul_voidptr_size, zero);
int posix_memalign_size0_return = posix_memalign(&ptr_posix_memalign_size0, pow2_mul_voidptr_size, zero_size);
int posix_memalign_size0_errno = errno;
printf("posix_memalign (size 0):\n");
printf(" %p, return value: %d = %s,\n",
ptr_posix_memalign_size0,
posix_memalign_size0_return,
strerror(posix_memalign_size0_return));
printf(" errno: %d = %s\n",
posix_memalign_size0_errno,
strerror(posix_memalign_size0_errno));
free(ptr_posix_memalign_size0);
errno = 0;
void * ptr_posix_memalign_maxsize = NULL;
......@@ -208,8 +252,8 @@ int main(void) {
ptr_posix_memalign_maxsize,
posix_memalign_maxsize_return,
strerror(posix_memalign_maxsize_return));
printf(" errno: %d = %s\n",
posix_memalign_maxsize_errno,
strerror(posix_memalign_maxsize_errno));
free(ptr_posix_memalign_maxsize);
}
#include <stdio.h>
_Thread_local int tbss = 0;
_Thread_local int tdata = 1;
int main(int argc, char ** argv) {
printf("%d == 0\n", tbss);
printf("%d == 1\n", tdata);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "test_helpers.h"
void prepare() {
puts("Hello from prepare");
}
void parent() {
// Make sure we print in the right order and also don't exit
// before the fork does.
int us_status = usleep(1000);
ERROR_IF(usleep, us_status, == -1);
UNEXP_IF(usleep, us_status, != 0);
puts("Hello from parent");
}
void child() {
puts("Hello from child");
}
int main(void) {
int status = pthread_atfork(prepare, parent, child);
ERROR_IF(pthread_atfork, status, == -1);
int pid = fork();
ERROR_IF(fork, pid, == -1);
}