***: symlinks, reentrant pthread_mutex, etc
This commit is contained in:
parent
669a0b7b9c
commit
a227e5446c
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -914,6 +914,7 @@ dependencies = [
|
||||
"kernel-arch-interface",
|
||||
"kernel-arch-x86",
|
||||
"libk-mm-interface",
|
||||
"log",
|
||||
"memtables",
|
||||
"static_assertions",
|
||||
"tock-registers 0.9.0",
|
||||
|
@ -14,3 +14,4 @@ kernel-arch-x86.workspace = true
|
||||
bitflags.workspace = true
|
||||
static_assertions.workspace = true
|
||||
tock-registers.workspace = true
|
||||
log.workspace = true
|
||||
|
@ -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) {
|
||||
|
@ -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) };
|
||||
|
0
kernel/driver/fs/memfs/src/symlink.rs
Normal file
0
kernel/driver/fs/memfs/src/symlink.rs
Normal 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!(),
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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(
|
||||
|
1
kernel/modules/test_mod/Cargo.lock
generated
1
kernel/modules/test_mod/Cargo.lock
generated
@ -300,6 +300,7 @@ dependencies = [
|
||||
"kernel-arch-interface",
|
||||
"kernel-arch-x86",
|
||||
"libk-mm-interface",
|
||||
"log",
|
||||
"memtables",
|
||||
"static_assertions",
|
||||
"tock-registers",
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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<()>;
|
||||
|
@ -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 {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#[derive(Debug)]
|
||||
pub enum ThreadOption<'a> {
|
||||
ThreadPointer(usize),
|
||||
SignalStack(usize, usize),
|
||||
Name(&'a str),
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
32
test.c
@ -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;
|
||||
|
@ -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
1
userspace/Cargo.lock
generated
@ -378,6 +378,7 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"elf",
|
||||
"rustc-demangle",
|
||||
"thiserror",
|
||||
"yggdrasil-rt",
|
||||
]
|
||||
|
@ -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)'] }
|
||||
|
@ -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>>>> {
|
||||
|
@ -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)
|
||||
|
@ -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 }
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
6
userspace/lib/ygglibc/include/bits/sys/mman.h
Normal file
6
userspace/lib/ygglibc/include/bits/sys/mman.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef _YGGDRASIL_SYS_MMAN_H
|
||||
#define _YGGDRASIL_SYS_MMAN_H 1
|
||||
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
|
||||
#endif
|
@ -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
|
@ -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
|
||||
|
14
userspace/lib/ygglibc/src/headers/dlfcn/cbindgen.toml
Normal file
14
userspace/lib/ygglibc/src/headers/dlfcn/cbindgen.toml
Normal 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 = []
|
50
userspace/lib/ygglibc/src/headers/dlfcn/mod.rs
Normal file
50
userspace/lib/ygglibc/src/headers/dlfcn/mod.rs
Normal 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!()
|
||||
}
|
@ -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!()
|
||||
}
|
||||
|
@ -1 +1,4 @@
|
||||
pub const PATH_MAX: usize = 4096;
|
||||
|
||||
pub const _POSIX_ARG_MAX: usize = 4096;
|
||||
pub const _POSIX_PATH_MAX: usize = 256;
|
||||
|
@ -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;
|
||||
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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!()
|
||||
}
|
||||
|
14
userspace/lib/ygglibc/src/headers/sys_file/cbindgen.toml
Normal file
14
userspace/lib/ygglibc/src/headers/sys_file/cbindgen.toml
Normal 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]
|
12
userspace/lib/ygglibc/src/headers/sys_file/mod.rs
Normal file
12
userspace/lib/ygglibc/src/headers/sys_file/mod.rs
Normal 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
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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 {
|
||||
|
@ -4,6 +4,7 @@ style = "Type"
|
||||
sys_includes = [
|
||||
"limits.h",
|
||||
"stddef.h",
|
||||
"fcntl.h",
|
||||
"sys/types.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
@ -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,
|
||||
|
@ -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!()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -13,7 +13,8 @@
|
||||
non_null_from_ref,
|
||||
thread_local,
|
||||
let_chains,
|
||||
int_roundings
|
||||
int_roundings,
|
||||
link_llvm_intrinsics
|
||||
)]
|
||||
#![allow(
|
||||
internal_features,
|
||||
|
@ -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!()
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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");
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user