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
|
// self.wait_predicate(|value| value != compare_value).await
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// Wakes up a single task waiting on the mutex
|
/// Wakes up at most `limit` threads waiting on this mutex
|
||||||
pub fn wake(&self) {
|
pub fn wake(&self, limit: usize) {
|
||||||
self.queue.wake_one();
|
self.queue.wake_some(limit);
|
||||||
}
|
|
||||||
|
|
||||||
/// Wakes up all tasks waiting on the mutex
|
|
||||||
pub fn wake_all(&self) {
|
|
||||||
self.queue.wake_all();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ use core::arch::global_asm;
|
|||||||
use aarch64_cpu::{
|
use aarch64_cpu::{
|
||||||
asm::barrier,
|
asm::barrier,
|
||||||
registers::{
|
registers::{
|
||||||
ELR_EL1, ESR_EL1, FAR_EL1, SCTLR_EL1, TCR_EL1, TPIDR_EL0, TPIDR_EL1, TTBR0_EL1, TTBR1_EL1,
|
ELR_EL1, ESR_EL1, FAR_EL1, SCTLR_EL1, SP_EL0, TCR_EL1, TPIDR_EL0, TPIDR_EL1, TTBR0_EL1,
|
||||||
VBAR_EL1,
|
TTBR1_EL1, VBAR_EL1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use abi::{process::Signal, SyscallFunction};
|
use abi::{process::Signal, SyscallFunction};
|
||||||
@ -17,6 +17,7 @@ use tock_registers::interfaces::{Readable, Writeable};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
debug::LogLevel,
|
debug::LogLevel,
|
||||||
|
mem::KERNEL_VIRT_OFFSET,
|
||||||
syscall::{self, raw_syscall_handler},
|
syscall::{self, raw_syscall_handler},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,12 +34,15 @@ pub fn init_exceptions() {
|
|||||||
|
|
||||||
fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
|
fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
|
||||||
let cpu = Cpu::try_local();
|
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, "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, "ELR: {:#x}\n", ELR_EL1.get());
|
||||||
log_print_raw!(LogLevel::Fatal, "ESR: {:#x}\n", ESR_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, "TTBR1_EL1: {:#x}\n", TTBR1_EL1.get());
|
||||||
log_print_raw!(LogLevel::Fatal, "Register dump:\n");
|
log_print_raw!(LogLevel::Fatal, "Register dump:\n");
|
||||||
log_print_raw!(LogLevel::Fatal, "{:?}\n", frame);
|
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 {
|
if let Some(current) = current {
|
||||||
log_print_raw!(LogLevel::Fatal, "In thread {}\n", current.id);
|
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) => {
|
&MutexOperation::WaitUntilSet(mask, _timeout) => {
|
||||||
block! { mutex.wait_until(|v| v & mask == v).await }?
|
block! { mutex.wait_until(|v| v & mask == v).await }?
|
||||||
}
|
}
|
||||||
MutexOperation::Wake => {
|
MutexOperation::Wake(limit) => {
|
||||||
mutex.wake();
|
mutex.wake(*limit as _);
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
MutexOperation::WakeAll => {
|
|
||||||
mutex.wake_all();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,8 @@ pub enum MutexOperation {
|
|||||||
WaitWhileSet(u32, Option<Duration>),
|
WaitWhileSet(u32, Option<Duration>),
|
||||||
/// Waits on the mutex object until `mutex & A != 0`
|
/// Waits on the mutex object until `mutex & A != 0`
|
||||||
WaitUntilSet(u32, Option<Duration>),
|
WaitUntilSet(u32, Option<Duration>),
|
||||||
/// Wakes a single mutex-waiting thread
|
/// Wakes at most N mutex-waiting threads
|
||||||
Wake,
|
Wake(u32),
|
||||||
/// Wakes all threads waiting on the mutex
|
|
||||||
WakeAll,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides some amount of process-related information
|
/// Provides some amount of process-related information
|
||||||
|
@ -142,11 +142,12 @@ impl Dtv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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() {
|
if key == 0 || key > list.len() {
|
||||||
panic!("Out-of-bounds TLS key: {key}")
|
return false;
|
||||||
}
|
}
|
||||||
list[key - 1] = value;
|
list[key - 1] = value;
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a value assocaited with a given thread-specific key.
|
/// 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 == 0.
|
||||||
/// Will panic if key is longer than the DTV itself.
|
/// Will panic if key is longer than the DTV itself.
|
||||||
pub fn set_specific(&mut self, key: usize, value: *mut c_void, grow: bool) {
|
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 {
|
if key > self.entries.len() && grow {
|
||||||
self.specific.resize(key, null_mut());
|
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.
|
/// 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() {
|
if key > self.entries.len() {
|
||||||
self.entries.resize(key, null_mut());
|
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) {
|
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) {
|
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) {
|
fn wait_initialized(&self) {
|
||||||
|
@ -142,7 +142,7 @@ impl<T> RwLock<T> {
|
|||||||
fn notify_readable(&self) {}
|
fn notify_readable(&self) {}
|
||||||
|
|
||||||
fn notify_writeable(&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 <assert.h>
|
||||||
#include <stdio.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) {
|
static void *thread(void *arg) {
|
||||||
pthread_t self = pthread_self();
|
const char *name = (const char *) arg;
|
||||||
printf("[child] pthread_self() = %u\n", self);
|
printf("[%s] wait\n", name);
|
||||||
sleep(3);
|
pthread_mutex_lock(&mutex);
|
||||||
return arg;
|
pthread_cond_wait(&cond, &mutex);
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
printf("[%s] done\n", name);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
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();
|
pthread_mutex_lock(&mutex);
|
||||||
printf("[main] pthread_self() = %u\n", self);
|
pthread_cond_broadcast(&cond);
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
|
||||||
void *result;
|
pthread_join(handle0, NULL);
|
||||||
assert(pthread_join(id, &result) == 0);
|
pthread_join(handle1, NULL);
|
||||||
printf("[main] result: %p\n", result);
|
printf("[main] finished\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
22
test.cpp
22
test.cpp
@ -1,21 +1,21 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::vector<int> items;
|
std::cout << "Spawning a thread" << std::endl;
|
||||||
items.push_back(1);
|
std::cout << "Main thread is: " << std::this_thread::get_id() << std::endl;
|
||||||
items.push_back(2);
|
std::cout << "Hardware concurrency: " << std::thread::hardware_concurrency() << std::endl;
|
||||||
items.push_back(3);
|
|
||||||
|
|
||||||
for (const auto &item: items) {
|
std::thread t1([]() {
|
||||||
std::cout << "Item: " << item << std::endl;
|
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 << "Waiting for a thread" << std::endl;
|
||||||
std::cout << "errno = " << errno << std::endl;
|
t1.join();
|
||||||
open("/xxxsaa", 0, 0);
|
std::cout << "Thread finished" << std::endl;
|
||||||
std::cout << "errno = " << errno << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,6 @@ set(CMAKE_ASM_COMPILER_TARGET "aarch64-unknown-yggdrasil")
|
|||||||
# set(CMAKE_SHARED_LINKER_FLAGS "-v")
|
# set(CMAKE_SHARED_LINKER_FLAGS "-v")
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "--target=aarch64-unknown-yggdrasil -fPIC")
|
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
|
# 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_SHARED_LINKER_FLAGS "-v")
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "--target=i686-unknown-yggdrasil -fPIC -m32")
|
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
|
# 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_SHARED_LINKER_FLAGS "-v")
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "--target=x86_64-unknown-yggdrasil -fPIC")
|
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
|
// 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;
|
let tp_offset = layout.tp_offset;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ const RENAMES: &[(&str, &str)] = &[
|
|||||||
("COffsetResult", "off_t"),
|
("COffsetResult", "off_t"),
|
||||||
("CPidResult", "pid_t"),
|
("CPidResult", "pid_t"),
|
||||||
("AtomicU32", "uint32_t"),
|
("AtomicU32", "uint32_t"),
|
||||||
|
("AtomicBool", "bool"),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn include_dir(d: &DirEntry) -> bool {
|
fn include_dir(d: &DirEntry) -> bool {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
#ifndef _YGGDRASIL_PTHREAD_H
|
#ifndef _YGGDRASIL_PTHREAD_H
|
||||||
#define _YGGDRASIL_PTHREAD_H 1
|
#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
|
#endif
|
||||||
|
@ -47,7 +47,7 @@ impl pthread_barrier_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signal(&self) {
|
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 {
|
fn check(&self) -> bool {
|
||||||
|
@ -1,16 +1,171 @@
|
|||||||
|
|
||||||
// PTHREAD_COND_INITIALIZER (macro)
|
// PTHREAD_COND_INITIALIZER (macro)
|
||||||
|
|
||||||
|
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
|
||||||
|
|
||||||
// int pthread_cond_broadcast(pthread_cond_t *);
|
use yggdrasil_rt::process::MutexOperation;
|
||||||
// int pthread_cond_destroy(pthread_cond_t *);
|
|
||||||
// int pthread_cond_init(pthread_cond_t *restrict, const pthread_condattr_t *restrict);
|
use crate::{
|
||||||
// int pthread_cond_signal(pthread_cond_t *);
|
error::{self, CIntZeroResult, CResult, EResult},
|
||||||
// int pthread_cond_timedwait(pthread_cond_t *restrict, pthread_mutex_t *restrict, const struct timespec *restrict);
|
headers::{
|
||||||
// int pthread_cond_wait(pthread_cond_t *restrict, pthread_mutex_t *restrict);
|
errno,
|
||||||
// int pthread_condattr_destroy(pthread_condattr_t *);
|
sys_time::__ygg_timespec_t,
|
||||||
// int pthread_condattr_getclock(const pthread_condattr_t *restrict, clockid_t *restrict);
|
sys_types::{clockid_t, pthread_cond_t, pthread_condattr_t, pthread_mutex_t},
|
||||||
// int pthread_condattr_getpshared(const pthread_condattr_t *restrict, int *restrict);
|
time::CLOCK_MONOTONIC,
|
||||||
// int pthread_condattr_init(pthread_condattr_t *);
|
},
|
||||||
// int pthread_condattr_setclock(pthread_condattr_t *, clockid_t);
|
util::PointerExt,
|
||||||
// int pthread_condattr_setpshared(pthread_condattr_t *, int);
|
};
|
||||||
|
|
||||||
|
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 barrier;
|
||||||
pub mod cond;
|
pub mod cond;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
|
pub mod once;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
pub mod spin;
|
pub mod spin;
|
||||||
pub mod thread;
|
pub mod thread;
|
||||||
@ -14,7 +15,6 @@ pub mod tls;
|
|||||||
// PTHREAD_CANCEL_DEFERRED
|
// PTHREAD_CANCEL_DEFERRED
|
||||||
// PTHREAD_CANCEL_DISABLE
|
// PTHREAD_CANCEL_DISABLE
|
||||||
// PTHREAD_CANCELED
|
// PTHREAD_CANCELED
|
||||||
// PTHREAD_ONCE_INIT
|
|
||||||
//
|
//
|
||||||
|
|
||||||
// Thread
|
// 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_STALLED: c_int = 0;
|
||||||
pub const PTHREAD_MUTEX_ROBUST: c_int = 1;
|
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 {
|
loop {
|
||||||
if self.try_lock() {
|
if self.try_lock() {
|
||||||
return;
|
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 {
|
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?
|
// 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);
|
use yggdrasil_rt::process::thread_local;
|
||||||
// int pthread_key_create(pthread_key_t *, void (*)(void*));
|
|
||||||
// int pthread_key_delete(pthread_key_t);
|
use crate::{
|
||||||
// int pthread_setspecific(pthread_key_t, const void *);
|
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"
|
language = "C"
|
||||||
style = "Type"
|
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
|
no_includes = true
|
||||||
|
|
||||||
include_guard = "_SYS_TYPES_H"
|
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))]
|
#[cfg(any(target_pointer_width = "64", rust_analyzer))]
|
||||||
mod bits64;
|
mod bits64;
|
||||||
@ -61,11 +61,13 @@ pub struct pthread_barrierattr_t {}
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct pthread_cond_t {
|
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_condattr_t {}
|
||||||
|
|
||||||
pub struct pthread_key_t {}
|
pub type pthread_key_t = usize;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct pthread_mutex_t {
|
pub struct pthread_mutex_t {
|
||||||
@ -74,7 +76,10 @@ pub struct pthread_mutex_t {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct pthread_mutexattr_t {}
|
pub struct pthread_mutexattr_t {}
|
||||||
|
|
||||||
pub struct pthread_once_t {}
|
#[repr(C)]
|
||||||
|
pub struct pthread_once_t {
|
||||||
|
pub(crate) __state: AtomicBool
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct pthread_rwlock_t {
|
pub struct pthread_rwlock_t {
|
||||||
|
@ -2,10 +2,10 @@ language = "C"
|
|||||||
style = "Tag"
|
style = "Tag"
|
||||||
|
|
||||||
sys_includes = [
|
sys_includes = [
|
||||||
|
"sys/types.h",
|
||||||
"stddef.h",
|
"stddef.h",
|
||||||
"stdint.h",
|
"stdint.h",
|
||||||
"locale.h",
|
"locale.h",
|
||||||
"sys/types.h",
|
|
||||||
"sys/time.h",
|
"sys/time.h",
|
||||||
"bits/time.h",
|
"bits/time.h",
|
||||||
]
|
]
|
||||||
|
@ -19,3 +19,44 @@ pub extern "C" fn init() {
|
|||||||
io::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,
|
main: extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int,
|
||||||
arg: usize,
|
arg: usize,
|
||||||
) {
|
) {
|
||||||
|
init::call_constructors();
|
||||||
signal::init(true);
|
signal::init(true);
|
||||||
init::init();
|
init::init();
|
||||||
|
|
||||||
|
@ -74,10 +74,15 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
|||||||
|
|
||||||
match PANIC_COUNT.fetch_add(1, Ordering::Relaxed) {
|
match PANIC_COUNT.fetch_add(1, Ordering::Relaxed) {
|
||||||
0 => {
|
0 => {
|
||||||
let pthread_self = Thread::this();
|
|
||||||
let mut printer = PanicPrinter::new();
|
let mut printer = PanicPrinter::new();
|
||||||
|
|
||||||
writeln!(printer, "!!! ygglibc panic !!!").ok();
|
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 let EResult::Ok(this) = pthread_self {
|
||||||
if this == 0 {
|
if this == 0 {
|
||||||
writeln!(printer, "* Main thread panicked *").ok();
|
writeln!(printer, "* Main thread panicked *").ok();
|
||||||
@ -85,14 +90,11 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
|||||||
writeln!(printer, "* Thread {} panicked*", this).ok();
|
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();
|
printer.flush();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
|
yggdrasil_rt::debug_trace!("{pi:?}");
|
||||||
yggdrasil_rt::debug_trace!("!!! ygglibc panicked while panicking !!!");
|
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()));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,12 +125,12 @@ pub fn install_llvm_cxx_runtime(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error
|
|||||||
command
|
command
|
||||||
.arg(format!("--toolchain={}", toolchain_cmake.display()))
|
.arg(format!("--toolchain={}", toolchain_cmake.display()))
|
||||||
.arg("-GNinja")
|
.arg("-GNinja")
|
||||||
.arg("-DCMAKE_BUILD_TYPE=RelWithDebInfo")
|
.arg("-DCMAKE_BUILD_TYPE=Debug")
|
||||||
.arg("-DLLVM_ENABLE_RUNTIMES=libcxxabi;libcxx")
|
.arg("-DLLVM_ENABLE_RUNTIMES=libcxxabi;libcxx")
|
||||||
.arg("-DLIBCXXABI_ENABLE_STATIC=ON")
|
.arg("-DLIBCXXABI_ENABLE_STATIC=ON")
|
||||||
.arg("-DLIBCXXABI_ENABLE_SHARED=OFF")
|
.arg("-DLIBCXXABI_ENABLE_SHARED=OFF")
|
||||||
.arg("-DLIBCXXABI_USE_COMPILER_RT=ON")
|
.arg("-DLIBCXXABI_USE_COMPILER_RT=ON")
|
||||||
.arg("-DLIBCXXABI_ENABLE_THREADS=OFF")
|
.arg("-DLIBCXXABI_ENABLE_THREADS=ON")
|
||||||
.arg("-DLIBCXXABI_ENABLE_EXCEPTIONS=OFF")
|
.arg("-DLIBCXXABI_ENABLE_EXCEPTIONS=OFF")
|
||||||
.arg("-DLIBCXXABI_USE_LLVM_UNWINDER=OFF")
|
.arg("-DLIBCXXABI_USE_LLVM_UNWINDER=OFF")
|
||||||
.arg("-DLIBCXX_CXX_ABI=libcxxabi")
|
.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_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY=ON")
|
||||||
.arg("-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON")
|
.arg("-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON")
|
||||||
.arg("-DLIBCXX_ENABLE_FILESYSTEM=ON")
|
.arg("-DLIBCXX_ENABLE_FILESYSTEM=ON")
|
||||||
.arg("-DLIBCXX_ENABLE_THREADS=OFF")
|
.arg("-DLIBCXX_ENABLE_THREADS=ON")
|
||||||
.arg("-DLIBCXX_ENABLE_EXCEPTIONS=OFF")
|
.arg("-DLIBCXX_ENABLE_EXCEPTIONS=OFF")
|
||||||
.arg("-DLIBCXX_ENABLE_SHARED=ON")
|
.arg("-DLIBCXX_ENABLE_SHARED=ON")
|
||||||
.arg("-DLIBCXX_ENABLE_STATIC=ON")
|
.arg("-DLIBCXX_ENABLE_STATIC=ON")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user