libc: implement threads for libcxx
This commit is contained in:
parent
0742edc516
commit
588e9e2936
@ -64,14 +64,9 @@ impl UserspaceMutex {
|
||||
// self.wait_predicate(|value| value != compare_value).await
|
||||
// }
|
||||
|
||||
/// Wakes up a single task waiting on the mutex
|
||||
pub fn wake(&self) {
|
||||
self.queue.wake_one();
|
||||
}
|
||||
|
||||
/// Wakes up all tasks waiting on the mutex
|
||||
pub fn wake_all(&self) {
|
||||
self.queue.wake_all();
|
||||
/// Wakes up at most `limit` threads waiting on this mutex
|
||||
pub fn wake(&self, limit: usize) {
|
||||
self.queue.wake_some(limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,8 @@ use core::arch::global_asm;
|
||||
use aarch64_cpu::{
|
||||
asm::barrier,
|
||||
registers::{
|
||||
ELR_EL1, ESR_EL1, FAR_EL1, SCTLR_EL1, TCR_EL1, TPIDR_EL0, TPIDR_EL1, TTBR0_EL1, TTBR1_EL1,
|
||||
VBAR_EL1,
|
||||
ELR_EL1, ESR_EL1, FAR_EL1, SCTLR_EL1, SP_EL0, TCR_EL1, TPIDR_EL0, TPIDR_EL1, TTBR0_EL1,
|
||||
TTBR1_EL1, VBAR_EL1,
|
||||
},
|
||||
};
|
||||
use abi::{process::Signal, SyscallFunction};
|
||||
@ -17,6 +17,7 @@ use tock_registers::interfaces::{Readable, Writeable};
|
||||
|
||||
use crate::{
|
||||
debug::LogLevel,
|
||||
mem::KERNEL_VIRT_OFFSET,
|
||||
syscall::{self, raw_syscall_handler},
|
||||
};
|
||||
|
||||
@ -33,12 +34,15 @@ pub fn init_exceptions() {
|
||||
|
||||
fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
|
||||
let cpu = Cpu::try_local();
|
||||
let far = FAR_EL1.get() as usize;
|
||||
let ttbr0 = TTBR0_EL1.get();
|
||||
|
||||
log_print_raw!(LogLevel::Fatal, "SYNC exception:\n");
|
||||
log_print_raw!(LogLevel::Fatal, "FAR: {:#x}\n", FAR_EL1.get());
|
||||
log_print_raw!(LogLevel::Fatal, "FAR: {:#x}\n", far);
|
||||
log_print_raw!(LogLevel::Fatal, "ELR: {:#x}\n", ELR_EL1.get());
|
||||
log_print_raw!(LogLevel::Fatal, "ESR: {:#x}\n", ESR_EL1.get());
|
||||
log_print_raw!(LogLevel::Fatal, "TTBR0_EL1: {:#x}\n", TTBR0_EL1.get());
|
||||
log_print_raw!(LogLevel::Fatal, "SP_EL0: {:#x}\n", SP_EL0.get());
|
||||
log_print_raw!(LogLevel::Fatal, "TTBR0_EL1: {:#x}\n", ttbr0);
|
||||
log_print_raw!(LogLevel::Fatal, "TTBR1_EL1: {:#x}\n", TTBR1_EL1.get());
|
||||
log_print_raw!(LogLevel::Fatal, "Register dump:\n");
|
||||
log_print_raw!(LogLevel::Fatal, "{:?}\n", frame);
|
||||
@ -49,6 +53,19 @@ fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
|
||||
|
||||
if let Some(current) = current {
|
||||
log_print_raw!(LogLevel::Fatal, "In thread {}\n", current.id);
|
||||
|
||||
let space = current.address_space();
|
||||
if far < KERNEL_VIRT_OFFSET && space.as_address_with_asid() == ttbr0 {
|
||||
match space.translate(far) {
|
||||
Ok(phys) => log_print_raw!(
|
||||
LogLevel::Fatal,
|
||||
"FAR translation: {:#x} -> {:#x}\n",
|
||||
far,
|
||||
phys
|
||||
),
|
||||
Err(_) => log_print_raw!(LogLevel::Fatal, "FAR does not translate\n"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,12 +252,8 @@ pub(crate) fn mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<(), Error>
|
||||
&MutexOperation::WaitUntilSet(mask, _timeout) => {
|
||||
block! { mutex.wait_until(|v| v & mask == v).await }?
|
||||
}
|
||||
MutexOperation::Wake => {
|
||||
mutex.wake();
|
||||
Ok(())
|
||||
}
|
||||
MutexOperation::WakeAll => {
|
||||
mutex.wake_all();
|
||||
MutexOperation::Wake(limit) => {
|
||||
mutex.wake(*limit as _);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -60,10 +60,8 @@ pub enum MutexOperation {
|
||||
WaitWhileSet(u32, Option<Duration>),
|
||||
/// Waits on the mutex object until `mutex & A != 0`
|
||||
WaitUntilSet(u32, Option<Duration>),
|
||||
/// Wakes a single mutex-waiting thread
|
||||
Wake,
|
||||
/// Wakes all threads waiting on the mutex
|
||||
WakeAll,
|
||||
/// Wakes at most N mutex-waiting threads
|
||||
Wake(u32),
|
||||
}
|
||||
|
||||
/// Provides some amount of process-related information
|
||||
|
@ -142,11 +142,12 @@ impl Dtv {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_key(list: &mut [*mut c_void], key: usize, value: *mut c_void) {
|
||||
fn set_key(list: &mut [*mut c_void], key: usize, value: *mut c_void) -> bool {
|
||||
if key == 0 || key > list.len() {
|
||||
panic!("Out-of-bounds TLS key: {key}")
|
||||
return false;
|
||||
}
|
||||
list[key - 1] = value;
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns a value assocaited with a given thread-specific key.
|
||||
@ -166,10 +167,24 @@ impl Dtv {
|
||||
/// Will panic if key == 0.
|
||||
/// Will panic if key is longer than the DTV itself.
|
||||
pub fn set_specific(&mut self, key: usize, value: *mut c_void, grow: bool) {
|
||||
self.try_set_specific(key, value, grow)
|
||||
.expect("Dtv::set_specific(): invalid key")
|
||||
}
|
||||
|
||||
/// Sets a DTV entry for a thread-specific key.
|
||||
pub fn try_set_specific(
|
||||
&mut self,
|
||||
key: usize,
|
||||
value: *mut c_void,
|
||||
grow: bool,
|
||||
) -> Result<(), Error> {
|
||||
if key > self.entries.len() && grow {
|
||||
self.specific.resize(key, null_mut());
|
||||
}
|
||||
Self::set_key(&mut self.specific, key, value)
|
||||
if !Self::set_key(&mut self.specific, key, value) {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Allocates a new thread-specific key in the DTV, filling it with a NULL value.
|
||||
@ -197,7 +212,9 @@ impl Dtv {
|
||||
if key > self.entries.len() {
|
||||
self.entries.resize(key, null_mut());
|
||||
}
|
||||
Self::set_key(&mut self.entries, key, value)
|
||||
if !Self::set_key(&mut self.entries, key, value) {
|
||||
panic!("Dtv::set(): invalid key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ impl RawMutex {
|
||||
}
|
||||
|
||||
fn notify_one(&self) {
|
||||
unsafe { crate::sys::mutex(&self.state, &MutexOperation::Wake).ok() };
|
||||
unsafe { crate::sys::mutex(&self.state, &MutexOperation::Wake(1)).ok() };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ impl<T> Once<T> {
|
||||
}
|
||||
|
||||
fn notify(&self) {
|
||||
unsafe { crate::sys::mutex(&self.state, &MutexOperation::WakeAll) }.ok();
|
||||
unsafe { crate::sys::mutex(&self.state, &MutexOperation::Wake(u32::MAX)) }.ok();
|
||||
}
|
||||
|
||||
fn wait_initialized(&self) {
|
||||
|
@ -142,7 +142,7 @@ impl<T> RwLock<T> {
|
||||
fn notify_readable(&self) {}
|
||||
|
||||
fn notify_writeable(&self) {
|
||||
unsafe { crate::sys::mutex(&self.state, &MutexOperation::Wake) }.ok();
|
||||
unsafe { crate::sys::mutex(&self.state, &MutexOperation::Wake(1)) }.ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
31
test.c
31
test.c
@ -3,24 +3,33 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void *thread(void *arg) {
|
||||
pthread_t self = pthread_self();
|
||||
printf("[child] pthread_self() = %u\n", self);
|
||||
sleep(3);
|
||||
return arg;
|
||||
const char *name = (const char *) arg;
|
||||
printf("[%s] wait\n", name);
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_wait(&cond, &mutex);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
printf("[%s] done\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
pthread_t id;
|
||||
pthread_t handle0, handle1;
|
||||
pthread_create(&handle0, NULL, thread, "thread0");
|
||||
pthread_create(&handle1, NULL, thread, "thread1");
|
||||
|
||||
assert(pthread_create(&id, NULL, thread, (void *) 0x1234) == 0);
|
||||
sleep(3);
|
||||
|
||||
pthread_t self = pthread_self();
|
||||
printf("[main] pthread_self() = %u\n", self);
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
void *result;
|
||||
assert(pthread_join(id, &result) == 0);
|
||||
printf("[main] result: %p\n", result);
|
||||
pthread_join(handle0, NULL);
|
||||
pthread_join(handle1, NULL);
|
||||
printf("[main] finished\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
22
test.cpp
22
test.cpp
@ -1,21 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
std::vector<int> items;
|
||||
items.push_back(1);
|
||||
items.push_back(2);
|
||||
items.push_back(3);
|
||||
std::cout << "Spawning a thread" << std::endl;
|
||||
std::cout << "Main thread is: " << std::this_thread::get_id() << std::endl;
|
||||
std::cout << "Hardware concurrency: " << std::thread::hardware_concurrency() << std::endl;
|
||||
|
||||
for (const auto &item: items) {
|
||||
std::cout << "Item: " << item << std::endl;
|
||||
}
|
||||
std::thread t1([]() {
|
||||
std::cout << "Hello from a thread!!!" << std::endl;
|
||||
std::cout << "This is thread: " << std::this_thread::get_id() << std::endl;
|
||||
});
|
||||
|
||||
std::cout << "&errno = " << &errno << std::endl;
|
||||
std::cout << "errno = " << errno << std::endl;
|
||||
open("/xxxsaa", 0, 0);
|
||||
std::cout << "errno = " << errno << std::endl;
|
||||
std::cout << "Waiting for a thread" << std::endl;
|
||||
t1.join();
|
||||
std::cout << "Thread finished" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,6 +17,6 @@ set(CMAKE_ASM_COMPILER_TARGET "aarch64-unknown-yggdrasil")
|
||||
# set(CMAKE_SHARED_LINKER_FLAGS "-v")
|
||||
|
||||
set(CMAKE_C_FLAGS "--target=aarch64-unknown-yggdrasil -fPIC")
|
||||
set(CMAKE_CXX_FLAGS "--target=aarch64-unknown-yggdrasil -nostdlib++ -fPIC -D_LIBCPP_HAS_NO_MONOTONIC_CLOCK=1 -D_LIBCPP_HAS_NO_TREE_BARRIER")
|
||||
set(CMAKE_CXX_FLAGS "--target=aarch64-unknown-yggdrasil -nostdlib++ -fPIC -D_LIBCPP_HAS_NO_TREE_BARRIER")
|
||||
|
||||
# Specify any additional include paths or linker flags as needed
|
||||
|
@ -17,6 +17,6 @@ set(CMAKE_ASM_COMPILER_TARGET "i686-unknown-yggdrasil")
|
||||
# set(CMAKE_SHARED_LINKER_FLAGS "-v")
|
||||
|
||||
set(CMAKE_C_FLAGS "--target=i686-unknown-yggdrasil -fPIC -m32")
|
||||
set(CMAKE_CXX_FLAGS "--target=i686-unknown-yggdrasil -m32 -nostdlib++ -fPIC -D_LIBCPP_HAS_NO_MONOTONIC_CLOCK=1 -D_LIBCPP_HAS_NO_TREE_BARRIER")
|
||||
set(CMAKE_CXX_FLAGS "--target=i686-unknown-yggdrasil -m32 -nostdlib++ -fPIC -D_LIBCPP_HAS_NO_TREE_BARRIER")
|
||||
|
||||
# Specify any additional include paths or linker flags as needed
|
||||
|
@ -17,4 +17,4 @@ set(CMAKE_ASM_COMPILER_TARGET "x86_64-unknown-yggdrasil")
|
||||
# set(CMAKE_SHARED_LINKER_FLAGS "-v")
|
||||
|
||||
set(CMAKE_C_FLAGS "--target=x86_64-unknown-yggdrasil -fPIC")
|
||||
set(CMAKE_CXX_FLAGS "--target=x86_64-unknown-yggdrasil -nostdlib++ -fPIC -D_LIBCPP_HAS_NO_MONOTONIC_CLOCK=1 -D_LIBCPP_HAS_NO_TREE_BARRIER")
|
||||
set(CMAKE_CXX_FLAGS "--target=x86_64-unknown-yggdrasil -nostdlib++ -fPIC -D_LIBCPP_HAS_NO_TREE_BARRIER")
|
||||
|
@ -62,7 +62,7 @@ pub fn build_tls_image(
|
||||
};
|
||||
|
||||
// Create a master image based on this layout
|
||||
let mut image_data = Mapping::new(layout.total_size, MappingFlags::empty())?;
|
||||
let mut image_data = Mapping::new(layout.total_size, MappingFlags::WRITE)?;
|
||||
|
||||
let tp_offset = layout.tp_offset;
|
||||
|
||||
|
@ -16,6 +16,7 @@ const RENAMES: &[(&str, &str)] = &[
|
||||
("COffsetResult", "off_t"),
|
||||
("CPidResult", "pid_t"),
|
||||
("AtomicU32", "uint32_t"),
|
||||
("AtomicBool", "bool"),
|
||||
];
|
||||
|
||||
fn include_dir(d: &DirEntry) -> bool {
|
||||
|
@ -1,6 +1,10 @@
|
||||
#ifndef _YGGDRASIL_PTHREAD_H
|
||||
#define _YGGDRASIL_PTHREAD_H 1
|
||||
|
||||
#define PTHREAD_MUTEX_INITIALIZER { 0 }
|
||||
// __state
|
||||
#define PTHREAD_MUTEX_INITIALIZER { 0U }
|
||||
|
||||
// __read, __write
|
||||
#define PTHREAD_COND_INITIALIZER { 0U, 0U }
|
||||
|
||||
#endif
|
||||
|
@ -47,7 +47,7 @@ impl pthread_barrier_t {
|
||||
}
|
||||
|
||||
fn signal(&self) {
|
||||
unsafe { yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::WakeAll).ok() };
|
||||
unsafe { yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(u32::MAX)).ok() };
|
||||
}
|
||||
|
||||
fn check(&self) -> bool {
|
||||
|
@ -1,16 +1,171 @@
|
||||
|
||||
// PTHREAD_COND_INITIALIZER (macro)
|
||||
|
||||
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
|
||||
|
||||
// int pthread_cond_broadcast(pthread_cond_t *);
|
||||
// int pthread_cond_destroy(pthread_cond_t *);
|
||||
// int pthread_cond_init(pthread_cond_t *restrict, const pthread_condattr_t *restrict);
|
||||
// int pthread_cond_signal(pthread_cond_t *);
|
||||
// int pthread_cond_timedwait(pthread_cond_t *restrict, pthread_mutex_t *restrict, const struct timespec *restrict);
|
||||
// int pthread_cond_wait(pthread_cond_t *restrict, pthread_mutex_t *restrict);
|
||||
// int pthread_condattr_destroy(pthread_condattr_t *);
|
||||
// int pthread_condattr_getclock(const pthread_condattr_t *restrict, clockid_t *restrict);
|
||||
// int pthread_condattr_getpshared(const pthread_condattr_t *restrict, int *restrict);
|
||||
// int pthread_condattr_init(pthread_condattr_t *);
|
||||
// int pthread_condattr_setclock(pthread_condattr_t *, clockid_t);
|
||||
// int pthread_condattr_setpshared(pthread_condattr_t *, int);
|
||||
use yggdrasil_rt::process::MutexOperation;
|
||||
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, CResult, EResult},
|
||||
headers::{
|
||||
errno,
|
||||
sys_time::__ygg_timespec_t,
|
||||
sys_types::{clockid_t, pthread_cond_t, pthread_condattr_t, pthread_mutex_t},
|
||||
time::CLOCK_MONOTONIC,
|
||||
},
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
use super::PTHREAD_PROCESS_PRIVATE;
|
||||
|
||||
impl pthread_cond_t {
|
||||
fn wait(&self, mutex: &pthread_mutex_t, deadline: Option<&__ygg_timespec_t>) -> EResult<()> {
|
||||
// mutex is locked on entry
|
||||
let value = self.__write.load(Ordering::Acquire);
|
||||
self.__read.store(value, Ordering::Release);
|
||||
|
||||
unsafe { mutex.release() };
|
||||
|
||||
// Wait
|
||||
match deadline {
|
||||
Some(_deadline) => {
|
||||
todo!()
|
||||
}
|
||||
None => {
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::mutex(
|
||||
&self.__write,
|
||||
&MutexOperation::WaitWhileEqual(value, None),
|
||||
)
|
||||
}
|
||||
.expect("Mutex wait failed");
|
||||
// Re-acquire the mutex
|
||||
mutex.lock();
|
||||
}
|
||||
}
|
||||
|
||||
EResult::Ok(())
|
||||
}
|
||||
|
||||
fn signal(&self, n: u32) {
|
||||
// this is guarded by a mutex on entry
|
||||
let value = self.__read.load(Ordering::Acquire);
|
||||
self.__write.store(value.wrapping_add(1), Ordering::Release);
|
||||
unsafe { yggdrasil_rt::sys::mutex(&self.__write, &MutexOperation::Wake(n)).ok() };
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_cond_init(
|
||||
cond: *mut pthread_cond_t,
|
||||
_attr: *const pthread_condattr_t,
|
||||
) -> CIntZeroResult {
|
||||
let cond = cond.ensure_mut();
|
||||
cond.__read.store(0, Ordering::Release);
|
||||
cond.__write.store(0, Ordering::Release);
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_cond_destroy(_cond: *mut pthread_cond_t) -> CIntZeroResult {
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_cond_wait(
|
||||
cond: *mut pthread_cond_t,
|
||||
mutex: *mut pthread_mutex_t,
|
||||
) -> CIntZeroResult {
|
||||
let cond = cond.ensure_mut();
|
||||
let mutex = mutex.ensure_mut();
|
||||
cond.wait(mutex, None)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_cond_timedwait(
|
||||
cond: *mut pthread_cond_t,
|
||||
mutex: *mut pthread_mutex_t,
|
||||
timeout: *const __ygg_timespec_t,
|
||||
) -> CIntZeroResult {
|
||||
let cond = cond.ensure_mut();
|
||||
let mutex = mutex.ensure_mut();
|
||||
let timeout = timeout.ensure();
|
||||
cond.wait(mutex, Some(timeout))?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> CIntZeroResult {
|
||||
let cond = cond.ensure_mut();
|
||||
cond.signal(1);
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> CIntZeroResult {
|
||||
let cond = cond.ensure_mut();
|
||||
cond.signal(u32::MAX);
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
// Attributes
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_condattr_init(_attr: *mut pthread_condattr_t) -> CIntZeroResult {
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_condattr_destroy(_attr: *mut pthread_condattr_t) -> CIntZeroResult {
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_condattr_getclock(
|
||||
_attr: *const pthread_condattr_t,
|
||||
clockid: *mut clockid_t,
|
||||
) -> CIntZeroResult {
|
||||
if let Some(clockid) = NonNull::new(clockid) {
|
||||
clockid.write(CLOCK_MONOTONIC);
|
||||
}
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_condattr_getpshared(
|
||||
_attr: *const pthread_condattr_t,
|
||||
shared: *mut c_int,
|
||||
) -> CIntZeroResult {
|
||||
if let Some(shared) = NonNull::new(shared) {
|
||||
shared.write(PTHREAD_PROCESS_PRIVATE);
|
||||
}
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_condattr_setclock(
|
||||
_attr: *mut pthread_condattr_t,
|
||||
clockid: clockid_t,
|
||||
) -> CIntZeroResult {
|
||||
if clockid == CLOCK_MONOTONIC {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_condattr_setclock()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_condattr_setpshared(
|
||||
_attr: *mut pthread_condattr_t,
|
||||
shared: c_int,
|
||||
) -> CIntZeroResult {
|
||||
if shared == PTHREAD_PROCESS_PRIVATE {
|
||||
CIntZeroResult::SUCCESS
|
||||
} else {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_condattr_setpshared()");
|
||||
error::errno = errno::EINVAL;
|
||||
CIntZeroResult::ERROR
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ pub mod attr;
|
||||
pub mod barrier;
|
||||
pub mod cond;
|
||||
pub mod mutex;
|
||||
pub mod once;
|
||||
pub mod rwlock;
|
||||
pub mod spin;
|
||||
pub mod thread;
|
||||
@ -14,7 +15,6 @@ pub mod tls;
|
||||
// PTHREAD_CANCEL_DEFERRED
|
||||
// PTHREAD_CANCEL_DISABLE
|
||||
// PTHREAD_CANCELED
|
||||
// PTHREAD_ONCE_INIT
|
||||
//
|
||||
|
||||
// Thread
|
||||
@ -43,5 +43,3 @@ pub const PTHREAD_MUTEX_DEFAULT: c_int = PTHREAD_MUTEX_NORMAL;
|
||||
|
||||
pub const PTHREAD_MUTEX_STALLED: c_int = 0;
|
||||
pub const PTHREAD_MUTEX_ROBUST: c_int = 1;
|
||||
|
||||
// int pthread_once(pthread_once_t *, void (*)(void));
|
||||
|
@ -38,7 +38,7 @@ impl pthread_mutex_t {
|
||||
}
|
||||
}
|
||||
|
||||
fn lock(&self) {
|
||||
pub fn lock(&self) {
|
||||
loop {
|
||||
if self.try_lock() {
|
||||
return;
|
||||
@ -54,9 +54,9 @@ impl pthread_mutex_t {
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn release(&self) {
|
||||
pub unsafe fn release(&self) {
|
||||
if self.__state.swap(Self::UNLOCKED, Ordering::Release) == Self::LOCKED {
|
||||
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake).ok();
|
||||
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(1)).ok();
|
||||
// TODO maybe yield for a fairer mutex?
|
||||
}
|
||||
}
|
||||
|
27
userspace/lib/ygglibc/src/headers/pthread/once.rs
Normal file
27
userspace/lib/ygglibc/src/headers/pthread/once.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// As macro: PTHREAD_ONCE_INIT
|
||||
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use crate::{error::CIntZeroResult, headers::sys_types::pthread_once_t, util::PointerExt};
|
||||
|
||||
impl pthread_once_t {
|
||||
fn once(&self, constructor: extern "C" fn()) {
|
||||
if self.__state.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() {
|
||||
return;
|
||||
}
|
||||
constructor();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_once(
|
||||
once: *mut pthread_once_t,
|
||||
constructor: extern "C" fn(),
|
||||
) -> CIntZeroResult {
|
||||
let once = once.ensure_mut();
|
||||
assert_ne!(constructor as usize, 0);
|
||||
|
||||
once.once(constructor);
|
||||
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
@ -1,5 +1,50 @@
|
||||
use core::{ffi::c_void, ptr::null_mut};
|
||||
|
||||
// void *pthread_getspecific(pthread_key_t);
|
||||
// int pthread_key_create(pthread_key_t *, void (*)(void*));
|
||||
// int pthread_key_delete(pthread_key_t);
|
||||
// int pthread_setspecific(pthread_key_t, const void *);
|
||||
use yggdrasil_rt::process::thread_local;
|
||||
|
||||
use crate::{
|
||||
error::{self, CIntZeroResult, ResultExt},
|
||||
headers::{errno, sys_types::pthread_key_t},
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_key_create(
|
||||
key: *mut pthread_key_t,
|
||||
_destructor: extern "C" fn(*mut c_void),
|
||||
) -> CIntZeroResult {
|
||||
let key = key.ensure_mut();
|
||||
let dtv = thread_local::get_dtv();
|
||||
*key = dtv.new_specific();
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_key_delete(_key: pthread_key_t) -> CIntZeroResult {
|
||||
yggdrasil_rt::debug_trace!("TODO: pthread_key_delete()");
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
|
||||
let dtv = thread_local::get_dtv();
|
||||
if key == 0 {
|
||||
error::errno = errno::EINVAL;
|
||||
return null_mut();
|
||||
}
|
||||
match dtv.get_specific(key) {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
error::errno = errno::EINVAL;
|
||||
null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> CIntZeroResult {
|
||||
let dtv = thread_local::get_dtv();
|
||||
dtv.try_set_specific(key, value, false)
|
||||
.e_map_err(|_| errno::EINVAL)?;
|
||||
CIntZeroResult::SUCCESS
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = ["stdint.h", "stddef.h", "bits/sys_types.h"]
|
||||
sys_includes = [
|
||||
"stdbool.h",
|
||||
"stdint.h",
|
||||
"stddef.h",
|
||||
"bits/sys_types.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_SYS_TYPES_H"
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::{ffi::{c_int, c_ulong, c_void}, ptr::NonNull, sync::atomic::AtomicU32};
|
||||
use core::{ffi::{c_int, c_ulong, c_void}, ptr::NonNull, sync::atomic::{AtomicBool, AtomicU32}};
|
||||
|
||||
#[cfg(any(target_pointer_width = "64", rust_analyzer))]
|
||||
mod bits64;
|
||||
@ -61,11 +61,13 @@ pub struct pthread_barrierattr_t {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_cond_t {
|
||||
__dummy: c_int
|
||||
pub(crate) __read: AtomicU32,
|
||||
pub(crate) __write: AtomicU32,
|
||||
}
|
||||
#[repr(C)]
|
||||
pub struct pthread_condattr_t {}
|
||||
|
||||
pub struct pthread_key_t {}
|
||||
pub type pthread_key_t = usize;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_mutex_t {
|
||||
@ -74,7 +76,10 @@ pub struct pthread_mutex_t {
|
||||
#[repr(C)]
|
||||
pub struct pthread_mutexattr_t {}
|
||||
|
||||
pub struct pthread_once_t {}
|
||||
#[repr(C)]
|
||||
pub struct pthread_once_t {
|
||||
pub(crate) __state: AtomicBool
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_rwlock_t {
|
||||
|
@ -2,10 +2,10 @@ language = "C"
|
||||
style = "Tag"
|
||||
|
||||
sys_includes = [
|
||||
"sys/types.h",
|
||||
"stddef.h",
|
||||
"stdint.h",
|
||||
"locale.h",
|
||||
"sys/types.h",
|
||||
"sys/time.h",
|
||||
"bits/time.h",
|
||||
]
|
||||
|
@ -7,7 +7,7 @@ static INIT_COMPLETE: AtomicBool = AtomicBool::new(false);
|
||||
// TODO implement topological sorting for proper .init_array calls in dyn-loader
|
||||
#[link_section = ".preinit_array"]
|
||||
#[used]
|
||||
static PREINIT_ARRAY: [extern "C" fn (); 1] = [init];
|
||||
static PREINIT_ARRAY: [extern "C" fn(); 1] = [init];
|
||||
|
||||
pub extern "C" fn init() {
|
||||
if INIT_COMPLETE.swap(true, Ordering::Acquire) {
|
||||
@ -19,3 +19,44 @@ pub extern "C" fn init() {
|
||||
io::init();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn call_constructor_list(start: usize, end: usize) {
|
||||
yggdrasil_rt::debug_trace!("call_constructor_list {:#x?}", start..end);
|
||||
let base = start as *const usize;
|
||||
let len = (end - start) / size_of::<usize>();
|
||||
for i in 0..len {
|
||||
let addr = base.add(i).read();
|
||||
if addr == 0 {
|
||||
continue;
|
||||
}
|
||||
yggdrasil_rt::debug_trace!("call constructor: {:#x}", addr);
|
||||
let func = core::mem::transmute::<_, extern "C" fn()>(addr);
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call_constructors() {
|
||||
extern "C" {
|
||||
static __preinit_array_start: u8;
|
||||
static __preinit_array_end: u8;
|
||||
|
||||
static __init_array_start: u8;
|
||||
static __init_array_end: u8;
|
||||
}
|
||||
|
||||
// Global constructors already called
|
||||
if INIT_COMPLETE.load(Ordering::Acquire) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
call_constructor_list(
|
||||
(&raw const __preinit_array_start).addr(),
|
||||
(&raw const __preinit_array_end).addr(),
|
||||
);
|
||||
call_constructor_list(
|
||||
(&raw const __init_array_start).addr(),
|
||||
(&raw const __init_array_end).addr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ unsafe extern "C" fn __ygglibc_entry(
|
||||
main: extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int,
|
||||
arg: usize,
|
||||
) {
|
||||
init::call_constructors();
|
||||
signal::init(true);
|
||||
init::init();
|
||||
|
||||
|
@ -74,10 +74,15 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
||||
|
||||
match PANIC_COUNT.fetch_add(1, Ordering::Relaxed) {
|
||||
0 => {
|
||||
let pthread_self = Thread::this();
|
||||
let mut printer = PanicPrinter::new();
|
||||
|
||||
writeln!(printer, "!!! ygglibc panic !!!").ok();
|
||||
if let Some(location) = pi.location() {
|
||||
writeln!(printer, "{}:{}:", location.file(), location.line()).ok();
|
||||
}
|
||||
writeln!(printer, " {}", pi.message()).ok();
|
||||
|
||||
let pthread_self = Thread::this();
|
||||
if let EResult::Ok(this) = pthread_self {
|
||||
if this == 0 {
|
||||
writeln!(printer, "* Main thread panicked *").ok();
|
||||
@ -85,14 +90,11 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
||||
writeln!(printer, "* Thread {} panicked*", this).ok();
|
||||
}
|
||||
}
|
||||
if let Some(location) = pi.location() {
|
||||
writeln!(printer, "{}:{}:", location.file(), location.line()).ok();
|
||||
}
|
||||
writeln!(printer, " {}", pi.message()).ok();
|
||||
|
||||
printer.flush();
|
||||
}
|
||||
1 => {
|
||||
yggdrasil_rt::debug_trace!("{pi:?}");
|
||||
yggdrasil_rt::debug_trace!("!!! ygglibc panicked while panicking !!!");
|
||||
}
|
||||
_ => {}
|
||||
|
@ -57,6 +57,22 @@ fn build_test_cpp_program(
|
||||
|
||||
install.push((target_dir.join("cpp-test"), "cpp-test".into()));
|
||||
|
||||
log::info!("Building a test C++ program [static]");
|
||||
let target_dir = &env.userspace_output_dir;
|
||||
|
||||
let mut command = llvm.c_clangpp(env);
|
||||
command
|
||||
.args(["-static", "-O0", "-ggdb", "-fstack-protector-strong"])
|
||||
.arg("-o")
|
||||
.arg(target_dir.join("cpp-test-static"))
|
||||
.arg(env.workspace_root.join("test.cpp"));
|
||||
|
||||
if !command.status()?.success() {
|
||||
return Err(Error::ExternalCommandFailed);
|
||||
}
|
||||
|
||||
install.push((target_dir.join("cpp-test-static"), "cpp-test-static".into()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -125,12 +125,12 @@ pub fn install_llvm_cxx_runtime(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error
|
||||
command
|
||||
.arg(format!("--toolchain={}", toolchain_cmake.display()))
|
||||
.arg("-GNinja")
|
||||
.arg("-DCMAKE_BUILD_TYPE=RelWithDebInfo")
|
||||
.arg("-DCMAKE_BUILD_TYPE=Debug")
|
||||
.arg("-DLLVM_ENABLE_RUNTIMES=libcxxabi;libcxx")
|
||||
.arg("-DLIBCXXABI_ENABLE_STATIC=ON")
|
||||
.arg("-DLIBCXXABI_ENABLE_SHARED=OFF")
|
||||
.arg("-DLIBCXXABI_USE_COMPILER_RT=ON")
|
||||
.arg("-DLIBCXXABI_ENABLE_THREADS=OFF")
|
||||
.arg("-DLIBCXXABI_ENABLE_THREADS=ON")
|
||||
.arg("-DLIBCXXABI_ENABLE_EXCEPTIONS=OFF")
|
||||
.arg("-DLIBCXXABI_USE_LLVM_UNWINDER=OFF")
|
||||
.arg("-DLIBCXX_CXX_ABI=libcxxabi")
|
||||
@ -138,7 +138,7 @@ pub fn install_llvm_cxx_runtime(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error
|
||||
.arg("-DLIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY=ON")
|
||||
.arg("-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON")
|
||||
.arg("-DLIBCXX_ENABLE_FILESYSTEM=ON")
|
||||
.arg("-DLIBCXX_ENABLE_THREADS=OFF")
|
||||
.arg("-DLIBCXX_ENABLE_THREADS=ON")
|
||||
.arg("-DLIBCXX_ENABLE_EXCEPTIONS=OFF")
|
||||
.arg("-DLIBCXX_ENABLE_SHARED=ON")
|
||||
.arg("-DLIBCXX_ENABLE_STATIC=ON")
|
||||
|
Loading…
x
Reference in New Issue
Block a user