***: symlinks, reentrant pthread_mutex, etc

This commit is contained in:
Mark Poliakov 2024-11-28 11:30:09 +02:00
parent 669a0b7b9c
commit a227e5446c
59 changed files with 743 additions and 218 deletions

1
Cargo.lock generated
View File

@ -914,6 +914,7 @@ dependencies = [
"kernel-arch-interface",
"kernel-arch-x86",
"libk-mm-interface",
"log",
"memtables",
"static_assertions",
"tock-registers 0.9.0",

View File

@ -14,3 +14,4 @@ kernel-arch-x86.workspace = true
bitflags.workspace = true
static_assertions.workspace = true
tock-registers.workspace = true
log.workspace = true

View File

@ -536,6 +536,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
for TaskContextImpl<K, PA>
{
fn drop(&mut self) {
log::info!("Drop Context {:#p}", self);
assert_eq!(self.stack_size % 0x1000, 0);
for offset in (0..self.stack_size).step_by(0x1000) {

View File

@ -14,7 +14,11 @@ use alloc::rc::Rc;
use block::BlockAllocator;
use dir::DirectoryNode;
use file::FileNode;
use libk::vfs::{AccessToken, NodeRef};
use libk::vfs::{
impls::{fixed_path_symlink, fixed_symlink, FixedSymlink},
AccessToken, NodeRef,
};
use tar::TarEntry;
use yggdrasil_abi::{
error::Error,
io::{FileMode, FileType, GroupId, UserId},
@ -70,7 +74,6 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
self: &Rc<Self>,
at: &NodeRef,
path: &Path,
kind: FileType,
create: bool,
) -> Result<NodeRef, Error> {
let access = unsafe { AccessToken::authorized() };
@ -91,7 +94,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
return Err(Error::DoesNotExist);
}
let node = self.create_node_initial(kind);
let node = DirectoryNode::<A>::new();
at.add_child(element, node.clone())?;
node
@ -106,14 +109,20 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
Ok(node)
} else {
assert!(node.is_directory());
self.make_path(&node, rest, kind, create)
self.make_path(&node, rest, create)
}
}
fn create_node_initial(self: &Rc<Self>, kind: FileType) -> NodeRef {
fn create_node_initial(self: &Rc<Self>, hdr: &TarEntry) -> Result<NodeRef, Error> {
let kind = hdr.node_kind();
match kind {
FileType::File => FileNode::<A>::new(),
FileType::Directory => DirectoryNode::<A>::new(),
FileType::File => Ok(FileNode::<A>::new()),
FileType::Directory => Ok(DirectoryNode::<A>::new()),
FileType::Symlink => {
let target = hdr.symlink_target()?;
log::info!("symlink {:?}", target);
Ok(fixed_path_symlink(target))
}
_ => todo!(),
}
}
@ -121,6 +130,13 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
fn from_slice_internal(self: &Rc<Self>, tar_data: &'static [u8]) -> Result<NodeRef, Error> {
let root = DirectoryNode::<A>::new();
for item in TarIterator::new(tar_data) {
let Ok((hdr, _)) = item else {
continue;
};
log::info!("{:?}", hdr.name.as_str().unwrap());
}
// 1. Create paths in tar
for item in TarIterator::new(tar_data) {
let Ok((hdr, _)) = item else {
@ -131,8 +147,8 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
log::debug!("Make path {:?}", path);
let (dirname, filename) = path.split_right();
let parent = self.make_path(&root, dirname, FileType::Directory, true)?;
let node = self.create_node_initial(hdr.node_kind());
let parent = self.make_path(&root, dirname, true)?;
let node = self.create_node_initial(hdr)?;
parent.add_child(filename, node)?;
}
@ -144,7 +160,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
};
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
let node = self.make_path(&root, path, FileType::Directory, false)?;
let node = self.make_path(&root, path, false)?;
assert_eq!(node.ty(), hdr.node_kind());
let uid = unsafe { UserId::from_raw(usize::from(&hdr.uid) as u32) };

View File

View File

@ -26,7 +26,7 @@ pub(crate) struct TarEntry {
_mtime: OctalField<12>,
_checksum: OctalField<8>,
type_: u8,
_link_name: TarString<100>,
link_name: TarString<100>,
_magic: [u8; 8],
_user: TarString<32>,
_group: TarString<32>,
@ -82,9 +82,11 @@ impl<'a> Iterator for TarIterator<'a> {
}
// Directory
b'5' => (None, 0),
// Symlink (TODO long symlinks)
b'2' => (None, 0),
// Symlink
_ => {
self.offset += size_aligned + 512;
continue;
todo!("Unhandled entry type: {}", hdr.type_)
}
};
self.offset += size_aligned + 512;
@ -128,10 +130,16 @@ impl TarEntry {
self.name.data[0] == 0
}
// TODO long links
pub fn symlink_target(&self) -> Result<&str, Error> {
self.link_name.as_str()
}
pub fn node_kind(&self) -> FileType {
match self.type_ {
0 | b'0' => FileType::File,
b'5' => FileType::Directory,
b'2' => FileType::Symlink,
_ => todo!(),
}
}

View File

@ -335,6 +335,7 @@ impl<TA: TableAllocator> ProcessAddressSpace<TA> {
ProcessAddressSpaceImpl::<TA>::LOWER_LIMIT_PFN,
ProcessAddressSpaceImpl::<TA>::UPPER_LIMIT_PFN,
);
log::info!("New AddressSpace {:#x}", table.as_address_with_asid());
Ok(Self {
inner: IrqSafeSpinlock::new(Inner { table, allocator }),
})
@ -464,6 +465,7 @@ impl<TA: TableAllocator> ProcessAddressSpace<TA> {
impl<TA: TableAllocator> Drop for ProcessAddressSpace<TA> {
fn drop(&mut self) {
log::info!("Drop AddressSpace {:#x}", self.as_address_with_asid());
self.clear().ok();
}
}

View File

@ -321,12 +321,15 @@ impl Process {
/// Cleans up process resources
fn cleanup(&self, mut inner: IrqSafeRwLockWriteGuard<ProcessInner>) {
self.io.lock().handle_exit();
inner.space = None;
inner.threads.clear();
if let Some(space) = inner.space.take() {
space.clear();
}
}
/// Updates the signal entry point
pub fn set_signal_entry(&self, entry: usize) {
self.signal_entry.store(entry, Ordering::Release);
pub fn set_signal_entry(&self, entry: usize) -> usize {
self.signal_entry.swap(entry, Ordering::Release)
}
/// Retrieves current signal entry of the process
@ -450,6 +453,12 @@ impl Process {
}
}
impl Drop for Process {
fn drop(&mut self) {
log::info!("Drop Process {}", self.id);
}
}
impl FileReadiness for Process {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
self.exit.poll(cx).map(Ok)

View File

@ -1,9 +1,4 @@
use core::{
cell::Cell,
mem::size_of,
ops::Deref,
sync::atomic::{AtomicUsize, Ordering},
};
use core::{cell::Cell, mem::size_of, ops::Deref};
use alloc::{
collections::{btree_map, BTreeMap},
@ -59,6 +54,16 @@ pub struct ThreadDebuggingInfo {
pub breakpoints: BTreeMap<usize, BreakpointType>,
}
#[derive(Default, Clone, Copy, Debug)]
pub struct SignalStack {
pub base: usize,
pub size: usize,
}
pub struct ThreadInfo {
pub signal_stack: SignalStack,
}
/// Describes a single thread within the system
pub struct Thread {
/// Unique thread ID
@ -74,7 +79,7 @@ pub struct Thread {
debug: IrqSafeSpinlock<ThreadDebuggingInfo>,
// inner: IrqSafeSpinlock<ThreadInner>,
signal_stack: AtomicUsize,
info: IrqSafeRwLock<ThreadInfo>,
signal_queue: SegQueue<Signal>,
pub exit: Arc<BoolEvent>,
@ -130,7 +135,9 @@ impl Thread {
process,
space,
signal_stack: AtomicUsize::new(0),
info: IrqSafeRwLock::new(ThreadInfo {
signal_stack: SignalStack::default(),
}),
signal_queue: SegQueue::new(),
exit: Arc::new(BoolEvent::new()),
kill: BoolEvent::new(),
@ -223,8 +230,14 @@ impl Thread {
}
/// Updates the thread signal stack information
pub fn set_signal_stack(&self, stack: usize) {
self.signal_stack.store(stack, Ordering::Release);
pub fn set_signal_stack(&self, stack: SignalStack) -> SignalStack {
let mut info = self.info.write();
core::mem::replace(&mut info.signal_stack, stack)
}
/// Returns the currently set signal stack
pub fn signal_stack(&self) -> SignalStack {
self.info.read().signal_stack
}
/// Returns the thread address space (usually provided by its parent process). If none exists,
@ -476,6 +489,12 @@ impl GlobalThreadList {
}
}
impl Drop for Thread {
fn drop(&mut self) {
log::info!("Drop Thread {}", self.id);
}
}
unsafe impl Sync for Thread {}
impl ArcWake for Thread {
@ -646,10 +665,11 @@ impl CurrentThread {
}
let ip = self.process().signal_entry();
let sp = self.signal_stack.load(Ordering::Acquire);
let signal_stack = self.signal_stack();
let sp = signal_stack.base + signal_stack.size;
// Check if ip and sp are legible for signal entry
if ip == 0 || sp < 4096 {
if ip == 0 || signal_stack.base == 0 || signal_stack.size < 4096 {
log::warn!("No legible signal handler for {}", self.id);
self.exit_process(ExitCode::BySignal(signal));
}

View File

@ -96,6 +96,10 @@ pub struct MemoryDirectory;
pub struct FixedSymlink {
target: NodeRef,
}
/// In-memory symlink with a fixed path
pub struct FixedPathSymlink {
target: String,
}
/// In-memory functional symlink
pub struct FnSymlink<F>
where
@ -382,6 +386,24 @@ impl SymlinkImpl for FixedSymlink {
}
}
// In-memory fixed path symlink
impl CommonImpl for FixedPathSymlink {}
impl SymlinkImpl for FixedPathSymlink {
fn read_link(&self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.len() >= self.target.len() {
buf[..self.target.len()].copy_from_slice(self.target.as_bytes());
Ok(self.target.len())
} else {
Err(Error::BufferTooSmall)
}
}
fn read_to_string(&self) -> Result<String, Error> {
Ok(self.target.clone())
}
}
// In-memory functional symlink
impl<F> FnSymlink<F>
@ -460,6 +482,15 @@ pub fn fixed_symlink(target: NodeRef) -> NodeRef {
Node::symlink(FixedSymlink { target }, NodeFlags::IN_MEMORY_PROPS)
}
pub fn fixed_path_symlink(target: impl Into<String>) -> NodeRef {
Node::symlink(
FixedPathSymlink {
target: target.into(),
},
NodeFlags::IN_MEMORY_PROPS,
)
}
pub fn fn_symlink<R: ReadLinkFn + 'static>(read: R) -> NodeRef {
let data = FnSymlink::new(read);
Node::symlink(

View File

@ -300,6 +300,7 @@ dependencies = [
"kernel-arch-interface",
"kernel-arch-x86",
"libk-mm-interface",
"log",
"memtables",
"static_assertions",
"tock-registers",

View File

@ -5,15 +5,19 @@ use abi::{
io::DeviceRequest,
mem::{MappingFlags, MappingSource},
process::{
ExitCode, MutexOperation, ProcessGroupId, ProcessId, Signal, SpawnFlags, SpawnOption,
SpawnOptions, ThreadOption, ThreadSpawnOptions,
ExitCode, MutexOperation, ProcessGroupId, ProcessId, ProcessOption, Signal, SpawnFlags,
SpawnOption, SpawnOptions, ThreadOption, ThreadSpawnOptions,
},
};
use alloc::sync::Arc;
use libk::{
block,
task::{
binary::LoadOptions, debug::ThreadDebugger, process::Process, runtime, thread::Thread,
binary::LoadOptions,
debug::ThreadDebugger,
process::Process,
runtime,
thread::{SignalStack, Thread},
ThreadId,
},
vfs::IoContext,
@ -192,6 +196,11 @@ pub(crate) fn get_pid() -> ProcessId {
process.id
}
pub(crate) fn get_tid() -> u32 {
let thread = Thread::current();
thread.id.as_user().try_into().unwrap()
}
pub(crate) fn nanosleep(
duration: &Duration,
remaining: &mut MaybeUninit<Duration>,
@ -212,18 +221,6 @@ pub(crate) fn nanosleep(
}
}
pub(crate) fn set_signal_entry(ip: usize, sp: usize) {
let thread = Thread::current();
let process = thread.process();
log::debug!("{}: set_signal_entry({:#x}, {:#x})", thread.id, ip, sp);
if ip != usize::MAX {
process.set_signal_entry(ip);
}
if sp != usize::MAX {
thread.set_signal_stack(sp);
}
}
pub(crate) fn send_signal(pid: ProcessId, signal: Signal) -> Result<(), Error> {
let thread = Thread::current();
let target = Process::get(pid).ok_or(Error::DoesNotExist)?;
@ -312,25 +309,66 @@ pub(crate) fn wait_thread(id: u32) -> Result<(), Error> {
}
pub(crate) fn get_thread_option(option: &mut ThreadOption) -> Result<(), Error> {
let thread = Thread::current();
match option {
// There're better ways to do this, don't ask the kernel
ThreadOption::ThreadPointer(_) => Err(Error::InvalidOperation),
ThreadOption::SignalStack(base, size) => {
let stack = thread.signal_stack();
*base = stack.base;
*size = stack.size;
Ok(())
}
ThreadOption::Name(_) => todo!(),
}
}
pub(crate) fn set_thread_option(option: &ThreadOption) -> Result<(), Error> {
pub(crate) fn set_thread_option(option: &mut ThreadOption) -> Result<(), Error> {
let thread = Thread::current();
match option {
&ThreadOption::ThreadPointer(tp) => {
ThreadOption::ThreadPointer(tp) => {
log::debug!("{:?}: set thread pointer: {:#x}", thread.id, tp);
thread.set_thread_pointer(tp);
thread.set_thread_pointer(*tp);
Ok(())
}
&ThreadOption::Name(name) => {
ThreadOption::SignalStack(base, size) => {
if base.checked_add(*size).is_none() {
return Err(Error::InvalidArgument);
}
let old = thread.set_signal_stack(SignalStack {
base: *base,
size: *size,
});
*base = old.base;
*size = old.size;
Ok(())
}
ThreadOption::Name(name) => {
// Make a kernel-owned string
log::debug!("{:?}: set thread name: {name:?}", thread.id);
thread.set_name(name);
thread.set_name(*name);
Ok(())
}
}
}
pub(crate) fn get_process_option(option: &mut ProcessOption) -> Result<(), Error> {
let thread = Thread::current();
let process = thread.process();
match option {
ProcessOption::SignalEntry(entry) => {
*entry = process.signal_entry();
Ok(())
}
}
}
pub(crate) fn set_process_option(option: &mut ProcessOption) -> Result<(), Error> {
let thread = Thread::current();
let process = thread.process();
match option {
ProcessOption::SignalEntry(entry) => {
*entry = process.set_signal_entry(*entry);
Ok(())
}
}

View File

@ -14,6 +14,7 @@ extern {
#[thin]
type ExitCode = yggdrasil_abi::process::ExitCode;
type ThreadOption = yggdrasil_abi::process::ThreadOption;
type ProcessOption = yggdrasil_abi::process::ProcessOption;
type SocketAddr = core::net::SocketAddr;
type SocketOption = yggdrasil_abi::net::SocketOption;
@ -78,18 +79,20 @@ syscall exit_process(code: ExitCode) -> !;
syscall spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId>;
syscall wait_process(pid: ProcessId, status: &mut ExitCode) -> Result<()>;
syscall get_pid() -> ProcessId;
syscall get_tid() -> u32;
// TODO use ThreadId
syscall spawn_thread(options: &ThreadSpawnOptions) -> Result<u32>;
syscall exit_thread() -> !;
syscall wait_thread(tid: u32) -> Result<()>;
syscall get_thread_option(option: &mut ThreadOption<'_>) -> Result<()>;
syscall set_thread_option(option: &ThreadOption<'_>) -> Result<()>;
syscall set_thread_option(option: &mut ThreadOption<'_>) -> Result<()>;
syscall get_process_option(option: &mut ProcessOption) -> Result<()>;
syscall set_process_option(option: &mut ProcessOption) -> Result<()>;
syscall nanosleep(duration: &Duration, remaining: &mut MaybeUninit<Duration>) -> Result<()>;
syscall exit_signal(frame: &SignalEntryData) -> !;
syscall set_signal_entry(ip: usize, sp: usize);
syscall send_signal(target: ProcessId, signal: Signal) -> Result<()>;
syscall mutex(mutex: &AtomicU32, op: &MutexOperation) -> Result<()>;

View File

@ -29,6 +29,11 @@ pub mod auxv {
pub const NULL: u64 = 0x00;
}
#[derive(Debug)]
pub enum ProcessOption {
SignalEntry(usize),
}
/// Defines an optional argument for controlling process creation
#[derive(Debug)]
pub enum SpawnOption {

View File

@ -1,5 +1,6 @@
#[derive(Debug)]
pub enum ThreadOption<'a> {
ThreadPointer(usize),
SignalStack(usize, usize),
Name(&'a str),
}

View File

@ -4,7 +4,7 @@ use core::ffi::c_int;
use abi::{
error::Error,
mem::{MappingFlags, MappingSource},
process::{ExitCode, Signal, SignalEntryData},
process::{ExitCode, ProcessOption, Signal, SignalEntryData, ThreadOption},
};
use alloc::boxed::Box;
@ -70,11 +70,45 @@ pub unsafe fn set_handler(signal: Signal, handler: SignalHandler) -> SignalHandl
/// below it. It is up to the caller to make sure `sp` points to a proper stack's top.
///
/// TLDR: just use [setup_signal_stack].
pub unsafe fn set_signal_stack(sp: usize) {
crate::sys::set_signal_entry(usize::MAX, sp);
pub unsafe fn set_signal_stack(base: usize, size: usize) -> (usize, usize) {
let mut option = ThreadOption::SignalStack(base, size);
crate::sys::set_thread_option(&mut option).expect("set_signal_stack() failed");
let ThreadOption::SignalStack(base, size) = option else {
unreachable!()
};
(base, size)
}
fn allocate_signal_stack(mut size: usize) -> Result<usize, Error> {
/// Returns the currently set signal stack base:size.
pub fn get_signal_stack() -> (usize, usize) {
let mut option = ThreadOption::SignalStack(0, 0);
unsafe { crate::sys::get_thread_option(&mut option) }.expect("get_signal_stack() failed");
let ThreadOption::SignalStack(base, size) = option else {
unreachable!()
};
(base, size)
}
/// Sets the program's signal entry function.
///
/// # Safety
///
/// `entry` must be an address of a valid signal entry function:
///
/// 1. It must not return, it must call `exit_thread` instead.
/// 2. It must conform to the kernel's signal entry ABI.
pub unsafe fn set_signal_entry(entry: usize) -> usize {
let mut option = ProcessOption::SignalEntry(entry);
crate::sys::set_process_option(&mut option).expect("set_signal_entry() failed");
#[allow(irrefutable_let_patterns)]
let ProcessOption::SignalEntry(entry) = option
else {
unreachable!()
};
entry
}
fn allocate_signal_stack(mut size: usize) -> Result<(usize, usize), Error> {
if size == 0 {
size = 4096;
}
@ -82,8 +116,7 @@ fn allocate_signal_stack(mut size: usize) -> Result<usize, Error> {
let base = unsafe {
crate::sys::map_memory(None, size, MappingFlags::WRITE, &MappingSource::Anonymous)
}?;
let top = base + size;
Ok(top)
Ok((base, size))
}
/// Allocates a signal stack and sets it **for this thread**. Returns an error if allocation fails.
@ -99,8 +132,8 @@ fn allocate_signal_stack(mut size: usize) -> Result<usize, Error> {
/// guarantees on what will happen if a raw syscall to [crate::sys::set_signal_entry] is done
/// after calling this function.
pub fn setup_signal_stack(size: usize) -> Result<(), Error> {
let sp = allocate_signal_stack(size)?;
unsafe { set_signal_stack(sp) };
let (base, size) = allocate_signal_stack(size)?;
unsafe { set_signal_stack(base, size) };
Ok(())
}
@ -117,8 +150,11 @@ pub fn setup_signal_stack(size: usize) -> Result<(), Error> {
///
/// Also see notes for [setup_signal_stack].
pub fn setup_signal_full(size: usize) -> Result<(), Error> {
let sp = allocate_signal_stack(size)?;
unsafe { crate::sys::set_signal_entry(imp::signal_entry as usize, sp) };
let (base, size) = allocate_signal_stack(size)?;
unsafe {
set_signal_stack(base, size);
set_signal_entry(imp::signal_entry as usize);
}
Ok(())
}

View File

@ -134,7 +134,7 @@ impl<R> Thread<R> {
/// Sets the current thread name.
pub fn set_name(name: &str) {
unsafe { crate::sys::set_thread_option(&ThreadOption::Name(name)).ok() };
unsafe { crate::sys::set_thread_option(&mut ThreadOption::Name(name)).ok() };
}
/// # Safety

View File

@ -17,7 +17,7 @@ pub fn get_thread_pointer() -> usize {
/// `value` must hold an address to a structure, first element of which is a pointer to itself.
/// Usual pointer safety requirements apply.
pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> {
crate::sys::set_thread_option(&ThreadOption::ThreadPointer(value))
crate::sys::set_thread_option(&mut ThreadOption::ThreadPointer(value))
}
// ___tls_get_addr, TLS_index structure address gets passed in the %eax register

View File

@ -17,5 +17,5 @@ pub fn get_thread_pointer() -> usize {
/// `value` must hold an address to a structure, first element of which is a pointer to itself.
/// Usual pointer safety requirements apply.
pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> {
crate::sys::set_thread_option(&ThreadOption::ThreadPointer(value))
crate::sys::set_thread_option(&mut ThreadOption::ThreadPointer(value))
}

View File

@ -23,8 +23,8 @@ mod generated {
mem::{MappingFlags, MappingSource},
net::SocketType,
process::{
ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions,
ThreadSpawnOptions,
ExecveOptions, ProcessGroupId, ProcessId, ProcessOption, Signal, SignalEntryData,
SpawnOptions, ThreadSpawnOptions,
},
SyscallFunction,
};

32
test.c
View File

@ -3,32 +3,40 @@
#include <assert.h>
#include <stdio.h>
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mutex;
static void *thread(void *arg) {
const char *name = (const char *) arg;
printf("[%s] wait\n", name);
printf("[child] lock0\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
printf("[child] lock1\n");
pthread_mutex_lock(&mutex);
printf("[child] in inner lock!!!\n");
sleep(3);
pthread_mutex_unlock(&mutex);
printf("[%s] done\n", name);
printf("[child] in outer lock!!!\n");
pthread_mutex_unlock(&mutex);
printf("[child] unlocked!!!\n");
return NULL;
}
int main(int argc, const char **argv) {
pthread_t handle0, handle1;
pthread_create(&handle0, NULL, thread, "thread0");
pthread_create(&handle1, NULL, thread, "thread1");
pthread_mutexattr_t mutex_attr;
pthread_t handle0;
sleep(3);
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex, &mutex_attr);
pthread_create(&handle0, NULL, thread, "thread0");
sleep(1);
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
printf("[main] inside lock\n");
sleep(1);
pthread_mutex_unlock(&mutex);
pthread_join(handle0, NULL);
pthread_join(handle1, NULL);
printf("[main] finished\n");
return 0;

View File

@ -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_TREE_BARRIER")
set(CMAKE_CXX_FLAGS "--target=x86_64-unknown-yggdrasil -fPIC -D_LIBCPP_HAS_NO_TREE_BARRIER")

1
userspace/Cargo.lock generated
View File

@ -378,6 +378,7 @@ dependencies = [
"bytemuck",
"cfg-if",
"elf",
"rustc-demangle",
"thiserror",
"yggdrasil-rt",
]

View File

@ -10,6 +10,7 @@ thiserror.workspace = true
elf = "0.7.4"
bytemuck = "1.19.0"
cfg-if = "1.0.0"
rustc-demangle = { version = "0.1.24" }
[lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(rust_analyzer)'] }

View File

@ -158,15 +158,14 @@ impl State {
}
}
pub fn undefined(&mut self, _source: impl AsRef<Path>, _sym: &Rc<str>) {
todo!()
// let source = source.as_ref();
// let list = if let Some(list) = self.undefined_references.get_mut(source) {
// list
// } else {
// self.undefined_references.try_insert(source.to_owned(), HashSet::new()).unwrap()
// };
// list.insert(sym.clone());
pub fn undefined(&mut self, source: impl AsRef<Path>, sym: &Rc<str>) {
let source = source.as_ref();
let list = if let Some(list) = self.undefined_references.get_mut(source) {
list
} else {
self.undefined_references.try_insert(source.to_owned(), HashSet::new()).unwrap()
};
list.insert(sym.clone());
}
pub fn no_undefined_symbols(&self) -> Result<(), &HashMap<PathBuf, HashSet<Rc<str>>>> {

View File

@ -54,6 +54,7 @@ fn generate_header(config_path: impl AsRef<Path>, header_output: impl AsRef<Path
.rename
.extend(RENAMES.iter().map(|&(x, y)| (x.into(), y.into())));
config.cpp_compat = true;
config.function.no_return = Some("__attribute__((noreturn))".into());
cbindgen::Builder::new()
.with_config(config)

View File

@ -1,8 +1,8 @@
#ifndef _YGGDRASIL_PTHREAD_H
#define _YGGDRASIL_PTHREAD_H 1
// __state
#define PTHREAD_MUTEX_INITIALIZER { 0U }
// __mode, __state, __recursion
#define PTHREAD_MUTEX_INITIALIZER { PTHREAD_MUTEX_DEFAULT, 0U, 0U }
// __read, __write
#define PTHREAD_COND_INITIALIZER { 0U, 0U }

View File

@ -1,10 +1,18 @@
#ifndef _YGGDRASIL_SETJMP_H
#define _YGGDRASIL_SETJMP_H 1
#if defined(__cplusplus)
extern "C" {
#endif
int setjmp(jmp_buf buf);
int _setjmp(jmp_buf buf);
[[noreturn]] void longjmp(jmp_buf buf, int val);
[[noreturn]] void _longjmp(jmp_buf buf, int val);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -19,6 +19,8 @@ int printf(const char *fmt, ...);
int snprintf(char *buf, size_t len, const char *fmt, ...);
int sprintf(char *buf, const char *fmt, ...);
int sscanf(const char *str, const char *fmt, ...);
int scanf(const char *fmt, ...);
int fscanf(FILE *fp, const char *fmt, ...);
#if defined(__cplusplus)
}

View File

@ -0,0 +1,6 @@
#ifndef _YGGDRASIL_SYS_MMAN_H
#define _YGGDRASIL_SYS_MMAN_H 1
#define MAP_FAILED ((void *) -1)
#endif

View File

@ -1,22 +0,0 @@
#ifndef _DLFCN_H
#define _DLFCN_H 1
#define RTLD_LAZY (1 << 0)
#define RTLD_NOW (0 << 0)
#define RTLD_GLOBAL (1 << 1)
#define RTLD_LOCAL (0 << 1)
#if defined(__cplusplus)
extern "C" {
#endif
int dlclose(void *ptr);
char *dlerror(void);
void *dlopen(const char *path, int mode);
void *dlsym(void *handle, const char *sym);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -4,47 +4,58 @@
#include <stddef.h>
#include <stdint.h>
// TODO uppercase hex
#define PRIo64 "lo"
#define PRId64 "ld"
#define PRIu64 "lu"
#define PRIx64 "lx"
#define PRIX64 "lx"
#define PRIo32 "o"
#define PRId32 "d"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "x"
#define PRIo16 "ho"
#define PRId16 "hd"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hx"
#define PRIo8 "hho"
#define PRId8 "hhd"
#define PRIu8 "hhu"
#define PRIx8 "hhx"
#define PRIX8 "hhx"
#define PRIdPTR "zd"
#define PRIxPTR "zx"
#define PRIXPTR "zx"
#define SCNo64 PRIo64
#define SCNd64 PRId64
#define SCNu64 PRIu64
#define SCNx64 PRIx64
#define SCNX64 PRIX64
#define SCNo32 PRIo32
#define SCNd32 PRId32
#define SCNu32 PRIu32
#define SCNx32 PRIx32
#define SCNX32 PRIX32
#define SCNo16 PRIo16
#define SCNd16 PRId16
#define SCNu16 PRIu16
#define SCNx16 PRIx16
#define SCNX16 PRIX16
#define SCNo8 PRIo8
#define SCNd8 PRId8
#define SCNu8 PRIu8
#define SCNx8 PRIx8
#define SCNX8 PRIX8
#endif

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = []
no_includes = true
include_guard = "_DLFCN_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["Dl_info", "dladdr", "dladdr1"]
exclude = []

View File

@ -0,0 +1,50 @@
use core::ffi::{c_char, c_int, c_void};
pub const RTLD_LAZY: c_int = 1 << 0;
pub const RTLD_NOW: c_int = 0 << 0;
pub const RTLD_LOCAL: c_int = 1 << 1;
pub const RTLD_GLOBAL: c_int = 0 << 1;
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Dl_info {
pub dli_fname: *const c_char,
pub dli_fbase: *mut c_void,
pub dli_sname: *const c_char,
pub dli_saddr: *mut c_void,
}
#[no_mangle]
unsafe extern "C" fn dlclose(dl: *mut c_void) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dlerror() -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dlopen(path: *const c_char, flags: c_int) -> *mut c_void {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dlsym(dl: *mut c_void, name: *const c_char) -> *mut c_void {
todo!()
}
// Non-POSIX
#[no_mangle]
unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dladdr1(
addr: *mut c_void,
info: *mut Dl_info,
extra_info: *mut *mut c_void,
flags: c_int,
) -> c_int {
todo!()
}

View File

@ -78,6 +78,11 @@ pub const AT_EACCESS: c_int = 1 << 0;
pub const AT_SYMLINK_NOFOLLOW: c_int = 1 << 1;
pub const AT_REMOVEDIR: c_int = 1 << 2;
pub const R_OK: c_int = 1 << 0;
pub const W_OK: c_int = 1 << 1;
pub const X_OK: c_int = 1 << 2;
pub const F_OK: c_int = 0;
enum OpenMode {
File(OpenOptions, FileMode),
Directory,
@ -174,3 +179,13 @@ unsafe extern "C" fn openat(
) -> CFdResult {
vopenat(atfd, pathname, opts, args.as_va_list())
}
#[no_mangle]
unsafe extern "C" fn faccessat(
atfd: c_int,
path: *const c_char,
mode: c_int,
flags: c_int,
) -> c_int {
todo!()
}

View File

@ -1 +1,4 @@
pub const PATH_MAX: usize = 4096;
pub const _POSIX_ARG_MAX: usize = 4096;
pub const _POSIX_PATH_MAX: usize = 256;

View File

@ -94,6 +94,7 @@
pub mod ctype;
pub mod dirent;
pub mod dlfcn;
pub mod errno;
pub mod fcntl;
pub mod grp;
@ -139,3 +140,6 @@ pub mod sys_wait;
pub mod link;
pub mod sys_yggdrasil;
// Non-POSIX headers
pub mod sys_file;

View File

@ -23,7 +23,7 @@ impl pthread_cond_t {
let value = self.__write.load(Ordering::Acquire);
self.__read.store(value, Ordering::Release);
unsafe { mutex.release() };
unsafe { mutex.release() }?;
// Wait
match deadline {
@ -39,7 +39,7 @@ impl pthread_cond_t {
}
.expect("Mutex wait failed");
// Re-acquire the mutex
mutex.lock();
mutex.lock()?;
}
}

View File

@ -1,4 +1,8 @@
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
use core::{
ffi::c_int,
ptr::NonNull,
sync::atomic::{AtomicU32, Ordering},
};
use yggdrasil_rt::process::MutexOperation;
@ -12,52 +16,114 @@ use crate::{
sys_time::__ygg_timespec_t,
sys_types::{pthread_mutex_t, pthread_mutexattr_t},
},
thread::Thread,
util::PointerExt,
};
use super::{PTHREAD_MUTEX_DEFAULT, PTHREAD_MUTEX_RECURSIVE};
impl pthread_mutex_t {
const UNLOCKED: u32 = 0;
const LOCKED: u32 = 1;
fn try_lock(&self) -> bool {
self.__state
.compare_exchange(
Self::UNLOCKED,
Self::LOCKED,
Ordering::Acquire,
Ordering::Relaxed,
)
.is_ok()
// fn new() -> EResult<Self> {
// Self::new_with(&pthread_mutexattr_t::default())
// }
// fn new_with(attr: &pthread_mutexattr_t) -> EResult<Self> {
// match attr.__mode {
// PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_RECURSIVE => (),
// _ => return EResult::Err(errno::EINVAL)
// }
// EResult::Ok(Self {
// __mode: attr.__mode,
// __state: AtomicU32::new(0),
// __recursion: AtomicU32::new(0)
// })
// }
fn try_lock(&self) -> EResult<bool> {
match self.__mode {
PTHREAD_MUTEX_NORMAL => EResult::Ok(
self.__state
.compare_exchange(0, Self::LOCKED, Ordering::Acquire, Ordering::Relaxed)
.is_ok(),
),
PTHREAD_MUTEX_RECURSIVE => {
let mut thread_id = Thread::this().expect("pthread_self() failed");
if thread_id == 0 {
thread_id = u32::MAX;
}
match self.__state.compare_exchange(0, thread_id, Ordering::Acquire, Ordering::Relaxed) {
// 0 -> thread_id
Ok(_) => {
self.__recursion.fetch_add(1, Ordering::Relaxed);
EResult::Ok(true)
},
Err(t) if t == thread_id => {
self.__recursion.fetch_add(1, Ordering::Relaxed);
EResult::Ok(true)
}
// Other thread owns the lock
Err(_) => {
EResult::Ok(false)
}
}
}
_ => EResult::Err(errno::EINVAL),
}
}
fn try_lock_err(&self) -> EResult<()> {
if self.try_lock() {
if self.try_lock()? {
EResult::Ok(())
} else {
EResult::Err(errno::EBUSY)
}
}
pub fn lock(&self) {
pub fn lock(&self) -> EResult<()> {
loop {
if self.try_lock() {
return;
if self.try_lock()? {
return EResult::Ok(());
}
self.wait();
self.wait()?;
}
}
fn wait(&self) {
fn wait(&self) -> EResult<()> {
unsafe {
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::WaitWhileEqual(Self::LOCKED, None)).ok()
};
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::WaitUntilEqual(0, None))
}?;
EResult::Ok(())
}
pub unsafe fn release(&self) {
if self.__state.swap(Self::UNLOCKED, Ordering::Release) == Self::LOCKED {
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(1)).ok();
// TODO maybe yield for a fairer mutex?
pub unsafe fn release(&self) -> EResult<()> {
match self.__mode {
PTHREAD_MUTEX_NORMAL => {
if self.__state.swap(0, Ordering::Release) == Self::LOCKED {
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(1)).ok();
// TODO maybe yield for a fairer mutex?
}
EResult::Ok(())
}
PTHREAD_MUTEX_RECURSIVE => {
if self.__recursion.fetch_sub(1, Ordering::Relaxed) == 1 {
self.__state.store(0, Ordering::Release);
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(1)).ok();
}
EResult::Ok(())
},
_ => EResult::Err(errno::EINVAL),
}
}
}
impl Default for pthread_mutexattr_t {
fn default() -> Self {
Self {
__mode: PTHREAD_MUTEX_DEFAULT
}
}
}
@ -89,20 +155,28 @@ unsafe extern "C" fn pthread_mutex_getprioceiling(
#[no_mangle]
unsafe extern "C" fn pthread_mutex_init(
mutex: *mut pthread_mutex_t,
_attr: *const pthread_mutexattr_t,
) -> c_int {
attr: *const pthread_mutexattr_t,
) -> CIntZeroResult {
let mutex = mutex.ensure_mut();
mutex
.__state
.store(pthread_mutex_t::UNLOCKED, Ordering::Release);
0
match attr.as_ref() {
Some(attr) => {
// TODO validate mode
mutex.__mode = attr.__mode;
}
None => {
mutex.__mode = PTHREAD_MUTEX_NORMAL;
}
}
mutex.__state.store(0, Ordering::Release);
mutex.__recursion.store(0, Ordering::Release);
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> CIntZeroResult {
let mutex = mutex.ensure_mut();
mutex.lock();
0
mutex.lock()?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
@ -134,15 +208,14 @@ unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> CIntZ
}
#[no_mangle]
unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> CIntZeroResult {
let mutex = mutex.ensure_mut();
mutex.release();
0
mutex.release()?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) -> c_int {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_destroy()");
0
}
@ -195,19 +268,20 @@ unsafe extern "C" fn pthread_mutexattr_getrobust(
#[no_mangle]
unsafe extern "C" fn pthread_mutexattr_gettype(
_attr: *const pthread_mutexattr_t,
attr: *const pthread_mutexattr_t,
ty: *mut c_int,
) -> c_int {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_gettype()");
let attr = attr.ensure();
if let Some(ty) = NonNull::new(ty) {
ty.write(PTHREAD_MUTEX_NORMAL);
ty.write(attr.__mode);
}
0
}
#[no_mangle]
unsafe extern "C" fn pthread_mutexattr_init(_attr: *mut pthread_mutexattr_t) -> c_int {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_init()");
unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
let attr = attr.ensure_mut();
*attr = pthread_mutexattr_t::default();
0
}
@ -264,14 +338,18 @@ unsafe extern "C" fn pthread_mutexattr_setrobust(
#[no_mangle]
unsafe extern "C" fn pthread_mutexattr_settype(
_attr: *mut pthread_mutexattr_t,
attr: *mut pthread_mutexattr_t,
ty: c_int,
) -> CIntZeroResult {
if ty == PTHREAD_MUTEX_NORMAL {
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_settype()");
error::errno = errno::EINVAL;
CIntZeroResult::ERROR
let attr = attr.ensure_mut();
match ty {
PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_RECURSIVE => {
attr.__mode = ty;
CIntZeroResult::SUCCESS
}
_ => {
error::errno = errno::EINVAL;
CIntZeroResult::ERROR
}
}
}

View File

@ -1,8 +1,8 @@
use core::ffi::{c_char, c_int, c_long, c_void};
use core::{ffi::{c_char, c_int, c_long, c_void}, ptr::NonNull};
use yggdrasil_rt::process::Signal;
use yggdrasil_rt::process::{Signal, signal as rt};
use crate::{error::{self, CIntZeroResult, EResult, TryFromExt}, signal, util::PointerExt};
use crate::{error::{self, CIntZeroResult, CResult, EResult, TryFromExt}, signal, util::PointerExt};
use super::{
errno, sys_time::__ygg_timespec_t, sys_types::{pid_t, uid_t}
@ -12,6 +12,13 @@ pub type sig_handler_t = unsafe extern "C" fn(SigNumber);
pub type sigset_t = u64;
#[repr(C)]
pub struct stack_t {
pub ss_sp: *mut c_void,
pub ss_flags: c_int,
pub ss_size: usize,
}
#[repr(C)]
pub struct sigevent {
pub sigev_notify: c_int,
@ -68,6 +75,24 @@ pub const SIGEV_NONE: c_int = 0;
pub const SIGEV_SIGNAL: c_int = 1;
pub const SIGEV_THREAD: c_int = 2;
pub const SIG_BLOCK: c_int = 1;
pub const SIG_UNBLOCK: c_int = 2;
pub const SIG_SETMASK: c_int = 3;
pub const SA_NOCLDSTOP: c_int = 1 << 0;
pub const SA_ONSTACK: c_int = 1 << 2;
pub const SA_RESETHAND: c_int = 1 << 3;
pub const SA_RESTART: c_int = 1 << 4;
pub const SA_SIGINFO: c_int = 1 << 5;
pub const SA_NOCLDWAIT: c_int = 1 << 6;
pub const SA_NODEFER: c_int = 1 << 7;
pub const SS_ONSTACK: c_int = 1 << 8;
pub const SS_DISABLE: c_int = 1 << 9;
pub const MINSIGSTKSZ: usize = 2 * 4096;
pub const SIGSTKSZ: usize = 8 * 4096;
// TODO generate these based on the ABI
pub const SIGSEGV: SigNumber = SigNumber(1);
pub const SIGABRT: SigNumber = SigNumber(2);
@ -183,10 +208,21 @@ unsafe extern "C" fn sigaddset(_mask: *mut sigset_t, _signum: c_int) -> c_int {
todo!()
}
// TODO: stack_t
#[no_mangle]
unsafe extern "C" fn sigaltstack(_new: *const c_void, _old: *const c_void) -> c_int {
todo!()
unsafe extern "C" fn sigaltstack(new: *const stack_t, old: *mut stack_t) -> CIntZeroResult {
if let Some(old) = NonNull::new(old) {
let (base, size) = rt::get_signal_stack();
old.write(stack_t { ss_sp: base as _, ss_flags: 0, ss_size: size });
}
if let Some(new) = new.as_ref() {
// TODO what do with SS_DISABLE?
if new.ss_size < MINSIGSTKSZ {
error::errno = errno::ENOMEM;
return CIntZeroResult::ERROR;
}
rt::set_signal_stack(new.ss_sp.addr(), new.ss_size);
}
CIntZeroResult::SUCCESS
}
#[no_mangle]

View File

@ -48,6 +48,9 @@ unsafe extern "C" fn posix_memalign(
}
#[no_mangle]
unsafe extern "C" fn aligned_alloc(_align: usize, _size: usize) -> *mut c_void {
todo!()
unsafe extern "C" fn aligned_alloc(align: usize, size: usize) -> CPtrResult<c_void> {
if align > 16 {
todo!()
}
malloc(size)
}

View File

@ -1,17 +1,81 @@
use core::ffi::{c_char, c_double, c_int, c_long, c_uint, c_ushort};
// double drand48(void);
// double erand48(unsigned short [3]);
// char *initstate(unsigned, char *, size_t);
// long jrand48(unsigned short [3]);
// void lcong48(unsigned short [7]);
// long lrand48(void);
// long mrand48(void);
// long nrand48(unsigned short [3]);
// int rand(void);
// int rand_r(unsigned *);
// long random(void);
// unsigned short *seed48(unsigned short [3]);
// char *setstate(char *);
// void srand(unsigned);
// void srand48(long);
// void srandom(unsigned);
#[no_mangle]
unsafe extern "C" fn drand48() -> c_double {
todo!()
}
#[no_mangle]
unsafe extern "C" fn erand48(_xsubi: *mut c_ushort) -> c_double {
todo!()
}
#[no_mangle]
unsafe extern "C" fn jrand48(_xsubi: *mut c_ushort) -> c_long {
todo!()
}
#[no_mangle]
unsafe extern "C" fn lcong48(_xsubi: *mut c_ushort) {
todo!()
}
#[no_mangle]
unsafe extern "C" fn lrand48() -> c_long {
todo!()
}
#[no_mangle]
unsafe extern "C" fn mrand48() -> c_long {
todo!()
}
#[no_mangle]
unsafe extern "C" fn nrand48(_xsubi: *mut c_ushort) -> c_long {
todo!()
}
#[no_mangle]
unsafe extern "C" fn rand() -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn rand_r(_seed: *mut c_uint) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn random() -> c_long {
todo!()
}
#[no_mangle]
unsafe extern "C" fn srand(_seed: c_uint) {
todo!()
}
#[no_mangle]
unsafe extern "C" fn srand48(_seed: c_long) {
todo!()
}
#[no_mangle]
unsafe extern "C" fn srandom(_seed: c_uint) {
todo!()
}
#[no_mangle]
unsafe extern "C" fn initstate(_seed: c_uint, _state: *mut c_char, _n: usize) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn setstate(_state: *mut c_char) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn seed48(_xsubi: *mut c_ushort) -> *mut c_ushort {
todo!()
}

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = [
"fcntl.h"
]
no_includes = true
include_guard = "_SYS_FILE_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]

View File

@ -0,0 +1,12 @@
use core::ffi::c_int;
use super::stdio::{SEEK_CUR, SEEK_END, SEEK_SET};
pub const L_SET: c_int = SEEK_SET;
pub const L_INCR: c_int = SEEK_CUR;
pub const L_XTND: c_int = SEEK_END;
pub const LOCK_SH: c_int = 1 << 0; // shared
pub const LOCK_EX: c_int = 1 << 1; // exclusive
pub const LOCK_NB: c_int = 1 << 2; // non-blocking
pub const LOCK_UN: c_int = 1 << 3; // unlock

View File

@ -1,7 +1,7 @@
language = "C"
style = "Tag"
sys_includes = ["sys/types.h", "stddef.h"]
sys_includes = ["sys/types.h", "stddef.h", "bits/sys/mman.h"]
no_includes = true
include_guard = "_SYS_MMAN_H"

View File

@ -1,4 +1,4 @@
use core::ffi::{c_char, c_int, c_void};
use core::{ffi::{c_char, c_int, c_void}, ptr::null_mut};
use crate::error::CPtrResult;

View File

@ -1,10 +1,9 @@
use core::ffi::{c_char, c_int};
use core::{ffi::{c_char, c_int}, ptr::NonNull};
use yggdrasil_rt::io::{FileAttr, FileMode, FileType};
use yggdrasil_rt::io::{FileAttr, FileMode, FileType, RawFd};
use crate::{
error::CIntZeroResult,
util::{self, PointerStrExt},
error::{CIntZeroResult, TryFromExt}, io, util::{self, PointerStrExt}
};
use super::{
@ -164,16 +163,15 @@ unsafe extern "C" fn mknodat(
// File status
#[no_mangle]
unsafe extern "C" fn fstat(_fd: c_int, _statbuf: *mut stat) -> CIntZeroResult {
todo!()
// let fd = RawFd::e_try_from(fd)?;
// let attr = io::get_metadata(Some(fd), "", false)?;
unsafe extern "C" fn fstat(fd: c_int, statbuf: *mut stat) -> CIntZeroResult {
let fd = RawFd::e_try_from(fd)?;
let attr = io::get_metadata(Some(fd), "", false)?;
// if let Some(statbuf) = statbuf.as_mut() {
// *statbuf = attr.into();
// }
if let Some(statbuf) = NonNull::new(statbuf) {
statbuf.write(attr.into());
}
// CIntZeroResult::OK
CIntZeroResult::SUCCESS
}
#[no_mangle]

View File

@ -71,10 +71,14 @@ pub type pthread_key_t = usize;
#[repr(C)]
pub struct pthread_mutex_t {
pub(crate) __state: AtomicU32
pub(crate) __mode: c_int,
pub(crate) __state: AtomicU32,
pub(crate) __recursion: AtomicU32
}
#[repr(C)]
pub struct pthread_mutexattr_t {}
pub struct pthread_mutexattr_t {
pub(crate) __mode: c_int,
}
#[repr(C)]
pub struct pthread_once_t {

View File

@ -4,6 +4,7 @@ style = "Type"
sys_includes = [
"limits.h",
"stddef.h",
"fcntl.h",
"sys/types.h"
]
no_includes = true

View File

@ -27,6 +27,11 @@ unsafe extern "C" fn execp(file: *const c_char, argv: *const *mut c_char) -> c_i
todo!()
}
#[no_mangle]
unsafe extern "C" fn execve(file: *const c_char, argv: *const *mut c_char, envp: *const *mut c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn execvpe(
file: *const c_char,

View File

@ -19,16 +19,6 @@ unsafe extern "C" fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int
todo!()
}
#[no_mangle]
unsafe extern "C" fn faccessat(
atfd: c_int,
path: *const c_char,
mode: c_int,
flags: c_int,
) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fchdir(fd: c_int) -> c_int {
todo!()

View File

@ -6,7 +6,7 @@ use core::{
use yggdrasil_rt::debug_trace;
use crate::{
error::{self, CIntCountResult, CIntZeroResult},
error::{self, CIntCountResult, CIntZeroResult, ResultExt},
headers::{errno, sys_types::{gid_t, pid_t, uid_t}},
process,
};
@ -137,3 +137,10 @@ unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
}
}
}
#[no_mangle]
unsafe extern "C" fn usleep(millis: c_uint) -> CIntZeroResult {
let duration = Duration::from_millis(millis.try_into().unwrap());
process::sleep(duration).e_map_err(|_| errno::EINTR)?;
CIntZeroResult::SUCCESS
}

View File

@ -1,6 +1,16 @@
use core::ffi::{c_char, c_int, c_long, c_uint, c_void};
pub const _SC_PAGE_SIZE: c_int = 1;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[non_exhaustive]
#[repr(C)]
pub enum Sysconf {
_SC_PAGE_SIZE = 1,
_SC_GETGR_R_SIZE_MAX,
_SC_GETPW_R_SIZE_MAX,
_SC_HOST_NAME_MAX,
_SC_LINE_MAX,
_SC_ARG_MAX,
}
#[no_mangle]
unsafe extern "C" fn alarm(value: c_uint) -> c_uint {
@ -34,7 +44,7 @@ unsafe extern "C" fn swab(from: *const c_void, to: *mut c_void, n: isize) {
todo!()
}
#[no_mangle]
unsafe extern "C" fn sysconf(name: c_int) -> c_long {
unsafe extern "C" fn sysconf(name: Sysconf) -> c_long {
todo!()
}
#[no_mangle]

View File

@ -1,7 +1,7 @@
use core::{ffi::c_int, mem::MaybeUninit};
use yggdrasil_rt::{
io::{PipeOptions, RawFd, SeekFrom},
io::{FileAttr, PipeOptions, RawFd, SeekFrom},
sys as syscall,
};
@ -118,6 +118,12 @@ pub fn create_pipe(options: PipeOptions) -> EResult<(RawFd, RawFd)> {
EResult::Ok((fds[0], fds[1]))
}
pub fn get_metadata(at: Option<RawFd>, path: &str, follow: bool) -> EResult<FileAttr> {
let mut metadata = MaybeUninit::uninit();
unsafe { syscall::get_metadata(at, path, &mut metadata, follow) }?;
EResult::Ok(unsafe { metadata.assume_init() })
}
pub unsafe fn init() {
managed::init();
}

View File

@ -13,7 +13,8 @@
non_null_from_ref,
thread_local,
let_chains,
int_roundings
int_roundings,
link_llvm_intrinsics
)]
#![allow(
internal_features,

View File

@ -73,3 +73,8 @@ unsafe extern "C" fn __assert_fail(file: *const c_char, line: c_int, message: *c
abort()
}
#[no_mangle]
unsafe extern "C" fn __cxa_thread_atexit() {
todo!()
}

View File

@ -3,9 +3,15 @@
#[no_mangle]
static mut __stack_chk_guard: usize = 0;
extern "C" {
#[link_name = "llvm.returnaddress"]
fn return_address(arg: i32) -> *const u8;
}
#[no_mangle]
unsafe extern "C" fn __stack_chk_fail() -> ! {
panic!("!!! Stack smashing detected !!!")
let return_address = return_address(0).addr();
panic!("!!! Stack smashing detected @ {:#x} !!!", return_address)
}
#[allow(static_mut_refs)]

View File

@ -32,6 +32,7 @@ pub struct CStringWriter {
}
impl<T> PointerExt for T {
#[track_caller]
unsafe fn ensure(self: *const Self) -> &'static Self {
unsafe { self.as_ref().expect("ensure() failed: NULL pointer") }
}
@ -45,6 +46,7 @@ impl<T> PointerExt for T {
}
}
#[track_caller]
unsafe fn ensure_slice(self: *const Self, len: usize) -> &'static [Self]
where
Self: Sized,
@ -55,6 +57,7 @@ impl<T> PointerExt for T {
unsafe { core::slice::from_raw_parts(self, len) }
}
#[track_caller]
unsafe fn ensure_slice_mut(self: *mut Self, len: usize) -> &'static mut [Self]
where
Self: Sized,
@ -67,12 +70,14 @@ impl<T> PointerExt for T {
}
impl PointerStrExt for c_char {
#[track_caller]
unsafe fn ensure_str(self: *const Self) -> &'static str {
self.ensure_cstr()
.to_str()
.expect("ensure_str() failed: not a valid string")
}
#[track_caller]
unsafe fn ensure_cstr(self: *const Self) -> &'static CStr {
if self.is_null() {
panic!("ensure_str() failed: NULL pointer");

View File

@ -180,8 +180,14 @@ fn pack_initrd<P: AsRef<Path>>(env: &BuildEnv, rootfs_dir: P) -> Result<InitrdGe
if entry.file_type().is_file() {
let mut file = File::open(entry.path())?;
tar.append_file(rel_path, &mut file)?;
} else if entry.file_type().is_symlink() {
let target = fs::read_link(entry.path())?;
let mut header = tar::Header::new_ustar();
header.set_entry_type(tar::EntryType::symlink());
header.set_mode(0o755);
tar.append_link(&mut header, rel_path, target)?;
} else {
todo!();
todo!()
}
}