libc/colors: non-blocking local socket + fixed string bugs in libc

This commit is contained in:
Mark Poliakov 2025-02-26 11:52:05 +02:00
parent 7fdc57fd9f
commit 43acdb9e13
43 changed files with 459 additions and 115 deletions

View File

@ -129,7 +129,7 @@ impl SocketWrapper {
non_blocking: bool,
) -> Result<usize, Error> {
if non_blocking {
todo!()
self.inner.clone().send_nonblocking(message)
} else {
let timeout = self.options.read().send_timeout;
block!(self.inner.clone().send_message(message, timeout).await)?

View File

@ -102,3 +102,7 @@ pub fn set_file_option_with<'de, T: OptionValue<'de>>(
let len = T::store(value, buffer)?;
unsafe { crate::sys::set_file_option(fd, T::VARIANT.into(), &buffer[..len]) }
}
pub fn set_nonblocking(fd: RawFd, nonblocking: bool) -> Result<(), Error> {
set_file_option::<options::NonBlocking>(fd, &nonblocking)
}

16
test.c
View File

@ -1,16 +1,12 @@
#include <string.h>
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
struct Dl_info dl0, dl1;
dladdr(main, &dl0);
dladdr(printf, &dl1);
printf("%s: %p\n", dl1.dli_sname, dl1.dli_saddr);
printf("%s @ %p\n", dl1.dli_fname, dl1.dli_fbase);
printf("%s: %p\n", dl0.dli_sname, dl0.dli_saddr);
printf("%s @ %p\n", dl0.dli_fname, dl0.dli_fbase);
char buffer[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
strncpy(buffer, "abcdefghijkl", sizeof(buffer));
for (int i = 0; i < sizeof(buffer); ++i) {
printf("[%d] 0x%hhx\n", i, buffer[i]);
}
return 0;
}

View File

@ -43,6 +43,8 @@ impl InputState {
b'.' => b'>',
b'`' => b'~',
b'\\' => b'|',
b'[' => b'{',
b']' => b'}',
_ => ch,
}
}

View File

@ -11,7 +11,7 @@ use std::{
use cross::mem::SharedMemory;
use input::InputState;
use libcolors::{
event::{EventData, KeyModifiers, KeyboardKeyEvent, WindowEvent, WindowInfo},
event::{EventData, KeyEvent, KeyModifiers, KeyboardKeyEvent, WindowEvent, WindowInfo},
input::Key,
message::{ClientMessage, CreateWindowInfo, WindowType},
};
@ -67,7 +67,7 @@ impl<'a> Server<'a> {
surface: &mut DisplaySurface,
tx: &mut ServerSender,
peer: &PeerAddress,
info: CreateWindowInfo
info: CreateWindowInfo,
) -> Result<(WindowInfo, RawFd), Error> {
let wid = self.last_window_id;
self.last_window_id += 1;
@ -152,17 +152,22 @@ impl<'a> Server<'a> {
}
}
fn move_window(&mut self, surface: &mut DisplaySurface, tx: &mut ServerSender, direction: Direction) {
fn move_window(
&mut self,
surface: &mut DisplaySurface,
tx: &mut ServerSender,
direction: Direction,
) {
if self.workspace.move_window(direction) {
surface.fill(self.background);
self.flush_dirty_frames(tx);
self.workspace.all_windows().for_each(|(wid, _)| {
if let Some(window) = self.windows.get(&wid) {
tx.send_event(
EventData::WindowEvent(wid, WindowEvent::RedrawRequested),
&window.peer,
);
}
if let Some(window) = self.windows.get(&wid) {
tx.send_event(
EventData::WindowEvent(wid, WindowEvent::RedrawRequested),
&window.peer,
);
}
});
}
}
@ -192,7 +197,8 @@ impl<'a> Server<'a> {
impl WindowServer for Server<'_> {
fn handle_initial(&mut self, mut surface: DisplaySurface) {
self.workspace.resize(surface.width() as u32, surface.height() as u32);
self.workspace
.resize(surface.width() as u32, surface.height() as u32);
surface.fill(self.background);
surface.present();
@ -285,9 +291,9 @@ impl WindowServer for Server<'_> {
) {
self.input_state.update(event.key, event.state);
if event.state {
let input = self.input_state.make_input(event.key);
let input = self.input_state.make_input(event.key);
if event.state {
// Non-window keys
#[allow(clippy::single_match)]
match (input.modifiers, input.key) {
@ -299,11 +305,6 @@ impl WindowServer for Server<'_> {
_ => (),
}
let focus = self.workspace.focused_window().and_then(|wid| {
let window = self.windows.get(&wid)?;
Some((wid, window))
});
match (input.modifiers, input.key) {
(KeyModifiers::ALT, Key::Char(b'l')) => {
self.move_focus(tx, Direction::Right);
@ -344,14 +345,6 @@ impl WindowServer for Server<'_> {
_ => (),
}
if let Some((wid, window)) = focus {
// Deliver event to the window
tx.send_event(
EventData::WindowEvent(wid, WindowEvent::KeyInput(input)),
&window.peer,
);
}
// // Window keys
// if let Some((row, col)) = self.focused_frame {
// let row_len = self.rows[row].frames.len();
@ -361,6 +354,42 @@ impl WindowServer for Server<'_> {
// self.focused_frame = None;
// }
}
let focus = self.workspace.focused_window().and_then(|wid| {
let window = self.windows.get(&wid)?;
Some((wid, window))
});
if let Some((wid, window)) = focus {
if event.state {
tx.send_event(
EventData::WindowEvent(
wid,
WindowEvent::KeyPressed(KeyEvent {
key: event.key,
modifiers: input.modifiers,
}),
),
&window.peer,
);
// Deliver event to the window
tx.send_event(
EventData::WindowEvent(wid, WindowEvent::KeyInput(input)),
&window.peer,
);
} else {
tx.send_event(
EventData::WindowEvent(
wid,
WindowEvent::KeyReleased(KeyEvent {
key: event.key,
modifiers: input.modifiers,
}),
),
&window.peer,
);
}
}
}
}

View File

@ -8,7 +8,7 @@
)]
#![allow(clippy::new_without_default, clippy::missing_transmute_annotations)]
use std::{mem::MaybeUninit, process::ExitCode};
use std::{fs, mem::MaybeUninit, os::yggdrasil::real_binary_path, path::Path, process::ExitCode};
use error::Error;
use object::Object;
@ -27,7 +27,8 @@ pub mod thread_local;
static mut OBJECTS: MaybeUninit<ObjectSet> = MaybeUninit::uninit();
fn run(binary: &str, args: &[String]) -> Result<!, Error> {
fn run(binary: &Path, args: &[String]) -> Result<!, Error> {
log::info!("dyn-loader {binary:?}");
// Open root and its dependencies
let root = Object::open(binary, true)?;
let mut objects = ObjectSet::new(root);
@ -139,6 +140,13 @@ unsafe fn enter(entry: extern "C" fn(usize), argument: usize) -> ! {
}
}
fn real_binary(arg0: &str) -> &Path {
if fs::exists(arg0).unwrap_or(false) {
return arg0.as_ref();
}
real_binary_path()
}
fn main() -> ExitCode {
logsink::setup_logging(false);
let args: Vec<String> = std::env::args().skip(1).collect();
@ -148,7 +156,9 @@ fn main() -> ExitCode {
todo!()
}
let Err(error) = run(&args[0], &args);
let real_binary = real_binary(&args[0]);
let Err(error) = run(real_binary, &args);
eprintln!("Error: {error}");
ExitCode::FAILURE
}

View File

@ -1,5 +1,13 @@
use std::{
cmp, collections::HashMap, ffi::{CStr, CString}, fs::File, io::{BufReader, Read, Seek, SeekFrom}, mem, ops::Range, path::{Path, PathBuf}, ptr, rc::Rc
cmp,
ffi::{CStr, CString},
fs::File,
io::{BufReader, Read, Seek, SeekFrom},
mem,
ops::Range,
path::{Path, PathBuf},
ptr,
rc::Rc,
};
use elf::{

View File

@ -42,7 +42,7 @@ impl Relocation for Rela {
R_X86_64_TPOFF64 => {
// Need to extract fixed global offset
let tls_layout = state.tls_layout.as_ref().unwrap();
log::info!("TPOFF64: module_id={}", tls.module_id);
log::info!("TPOFF64: {name} -> module_id={}", tls.module_id);
// Offset from TLS start
let offset = tls_layout.offset(tls.module_id, tls.offset).unwrap();
let offset_from_tp = -((tls_layout.tp_offset - offset) as i64);

View File

@ -1 +1 @@
export PATH=/bin:/sbin
export PATH=/mnt/bin:/bin:/sbin

View File

@ -1,4 +1,6 @@
.section .text
.global _start
_start:
jmp .
mov $12, %rax
mov $123, %rdi
syscall

View File

@ -1,3 +1,10 @@
void _start(void) {
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
printf("Argument count: %d\n", argc);
for (int i = 0; i < argc; ++i) {
printf("Argument %d is %s\n", i, argv[i]);
}
return EXIT_SUCCESS;
}

6
userspace/etc/test.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <iostream>
int main(int argc, char **argv) {
std::cout << "Test!!!" << std::endl;
return 0;
}

View File

@ -1,4 +1,7 @@
#!/bin/sh
/sbin/mount -t ext2 /dev/vb0p1 /mnt
/mnt/bin/clang -cc1as -filetype obj -main-file-name test.S -target-cpu x86-64 -mrelocation-model pic -triple x86_64-unknown-yggdrasil -o /test.o /etc/test.S
/mnt/bin/ld.lld -nostdlib -o /test /test.o
/bin/ls -lh /

View File

@ -32,6 +32,10 @@ impl LocalPacketSocket {
sys::LocalPacketSocketImpl::bind(path).map(Self)
}
pub fn set_nonblocking(&self, nb: bool) -> io::Result<()> {
self.0.set_nonblocking(nb)
}
pub fn receive(&self, buffer: &mut [u8]) -> io::Result<usize> {
self.0.receive(buffer)
}

View File

@ -70,6 +70,8 @@ pub(crate) trait LocalPacketSocket: AsRawFd + Sized {
fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self>;
fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self>;
fn set_nonblocking(&self, nb: bool) -> io::Result<()>;
fn receive(&self, data: &mut [u8]) -> io::Result<usize>;
fn receive_from(&self, data: &mut [u8]) -> io::Result<(usize, Self::OwnedAddress)>;
fn receive_with_ancillary(&self, data: &mut [u8]) -> io::Result<(usize, Option<OwnedFd>)>;

View File

@ -111,6 +111,11 @@ impl LocalPacketSocket for LocalPacketSocketImpl {
Ok(this)
}
fn set_nonblocking(&self, nb: bool) -> io::Result<()> {
runtime::rt::io::set_nonblocking(self.as_raw_fd(), nb)?;
Ok(())
}
fn receive(&self, data: &mut [u8]) -> io::Result<usize> {
let len = yggdrasil_rt::net::socket::receive(self.as_raw_fd(), data)?;
Ok(len)

View File

@ -25,6 +25,7 @@ pub struct Connection {
impl Connection {
pub fn new() -> Result<Self, Error> {
let channel = Channel::connect(crate::CHANNEL_NAME)?;
channel.set_nonblocking(true)?;
let (sender, receiver) = channel.split();
let timeout = Duration::from_secs(1);
let mut poll = Poll::new()?;
@ -63,6 +64,21 @@ impl Connection {
}
}
pub fn poll_event(&mut self) -> Result<Option<Event>, Error> {
if let Some(event) = self.event_queue.pop_front() {
return Ok(Some(event));
}
match self.receiver.receive_with_file_from() {
Ok((data, file, _)) => {
let ServerMessage::Event(data) = data;
Ok(Some(Event { data, file }))
}
Err(error) if error.is_would_block() => Ok(None),
Err(error) => Err(error.into())
}
}
pub fn receive_event(&mut self) -> Result<Event, Error> {
if let Some(event) = self.event_queue.pop_front() {
return Ok(event);

View File

@ -52,7 +52,7 @@ impl<'a> Application<'a> {
fn run_inner(mut self) -> Result<ExitCode, Error> {
while self.is_running() {
self.poll_events()?;
self.wait_events()?;
}
Ok(ExitCode::SUCCESS)
}
@ -77,7 +77,7 @@ impl<'a> Application<'a> {
Ok(())
}
pub fn poll_events(&mut self) -> Result<(), Error> {
pub fn wait_events(&mut self) -> Result<(), Error> {
let event = {
let mut connection = self.connection.lock().unwrap();
connection.receive_event()?
@ -86,6 +86,22 @@ impl<'a> Application<'a> {
self.handle_event(event)
}
pub fn poll_events(&mut self) -> Result<(), Error> {
loop {
let event = {
let mut connection = self.connection.lock().unwrap();
match connection.poll_event() {
Ok(Some(event)) => event,
Ok(None) => break,
Err(error) => return Err(error),
}
};
self.handle_event(event)?;
}
Ok(())
}
pub fn run(self) -> ExitCode {
match self.run_inner() {
Ok(exit) => exit,

View File

@ -4,7 +4,7 @@ use cross::mem::FileMapping;
use crate::{
error::Error,
event::{EventData, KeyInput, WindowEvent},
event::{EventData, KeyEvent, KeyInput, WindowEvent},
message::{ClientMessage, CreateWindowInfo},
};
@ -14,6 +14,8 @@ pub trait OnCloseRequested = Fn() -> EventOutcome;
pub trait OnKeyInput = Fn(KeyInput) -> EventOutcome;
pub trait OnResized = Fn(u32, u32) -> EventOutcome;
pub trait OnFocusChanged = Fn(bool) -> EventOutcome;
pub trait OnKeyPressed = Fn(KeyEvent) -> EventOutcome;
pub trait OnKeyReleased = Fn(KeyEvent) -> EventOutcome;
pub trait OnRedrawRequested = Fn(&mut [u32], u32, u32);
@ -38,6 +40,8 @@ pub struct Window<'a> {
on_key_input: Box<dyn OnKeyInput>,
on_resized: Box<dyn OnResized>,
on_focus_changed: Box<dyn OnFocusChanged>,
on_key_pressed: Box<dyn OnKeyPressed>,
on_key_released: Box<dyn OnKeyReleased>,
}
impl<'a> Window<'a> {
@ -64,6 +68,8 @@ impl<'a> Window<'a> {
)
};
log::info!("Created window: #{}", create_info.window_id);
Ok(Self {
connection: application.connection.clone(),
window_id: create_info.window_id,
@ -82,6 +88,8 @@ impl<'a> Window<'a> {
dt.fill(0xFF888888);
}),
on_key_input: Box::new(|_ev| EventOutcome::None),
on_key_pressed: Box::new(|_| EventOutcome::None),
on_key_released: Box::new(|_| EventOutcome::None),
on_resized: Box::new(|_w, _h| EventOutcome::Redraw),
on_focus_changed: Box::new(|_| EventOutcome::None),
})
@ -99,6 +107,14 @@ impl<'a> Window<'a> {
self.on_key_input = Box::new(handler);
}
pub fn set_on_key_pressed<H: OnKeyPressed + 'static>(&mut self, handler: H) {
self.on_key_pressed = Box::new(handler);
}
pub fn set_on_key_released<H: OnKeyReleased + 'static>(&mut self, handler: H) {
self.on_key_released = Box::new(handler);
}
pub fn set_on_resized<H: OnResized + 'static>(&mut self, handler: H) {
self.on_resized = Box::new(handler);
}
@ -147,6 +163,8 @@ impl<'a> Window<'a> {
(self.on_resized)(width, height)
}
WindowEvent::KeyPressed(key) => (self.on_key_pressed)(key),
WindowEvent::KeyReleased(key) => (self.on_key_released)(key),
WindowEvent::KeyInput(input) => (self.on_key_input)(input),
WindowEvent::FocusChanged(focused) => {
self.focused = focused;

View File

@ -33,6 +33,15 @@ pub struct Receiver<T> {
_pd: PhantomData<T>,
}
impl Error {
pub fn is_would_block(&self) -> bool {
match self {
Self::Io(error) if error.kind() == io::ErrorKind::WouldBlock => true,
_ => false
}
}
}
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct PeerAddress(OwnedLocalAddress);
@ -48,6 +57,11 @@ impl Channel {
Ok(Self(socket))
}
pub fn set_nonblocking(&self, nb: bool) -> Result<(), Error> {
self.0.set_nonblocking(nb)?;
Ok(())
}
pub fn split<T: Serialize, U: DeserializeOwned>(self) -> (Sender<T>, Receiver<U>) {
let this = Arc::new(self);
let sender = Sender {

View File

@ -1,6 +1,8 @@
#ifndef _YGGDRASIL_SYS_WAIT_H
#define _YGGDRASIL_SYS_WAIT_H 1
// see headers/sys_wait/mod.rs
#define WEXITSTATUS(c) ((int) ((c) & 0xFF))
// TODO

View File

@ -1,6 +1,6 @@
use core::ffi::{c_int, c_void};
use core::ffi::c_void;
use crate::{error::CIntZeroResult, process};
use crate::{error::CIntZeroResult, process, thread::Thread};
#[no_mangle]
unsafe extern "C" fn __cxa_atexit(
@ -14,9 +14,10 @@ unsafe extern "C" fn __cxa_atexit(
#[no_mangle]
unsafe extern "C" fn __cxa_thread_atexit(
_destructor: extern "C" fn(*mut c_void),
_arg: *mut c_void,
_dso_handle: *mut c_void,
) -> c_int {
todo!()
destructor: extern "C" fn(*mut c_void),
arg: *mut c_void,
dso_handle: *mut c_void,
) -> CIntZeroResult {
Thread::at_thread_exit(destructor, arg, dso_handle);
CIntZeroResult::SUCCESS
}

View File

@ -43,6 +43,7 @@ pub trait CResult {
}
#[must_use = "EResult must be converted into its output type with proper errno set"]
#[derive(Debug)]
pub enum EResult<T> {
Ok(T),
Err(Errno),

View File

@ -191,13 +191,16 @@ pub(crate) unsafe extern "C" fn faccessat(
) -> CIntZeroResult {
let atfd = util::at_fd(atfd)?;
let path = path.ensure_str();
let access = match mode {
0 => AccessMode::empty(),
R_OK => AccessMode::READ,
W_OK => AccessMode::WRITE,
X_OK => AccessMode::EXEC,
_ => todo!("{mode:#x}"),
};
let mut access = AccessMode::empty();
if mode & R_OK != 0 {
access |= AccessMode::READ;
}
if mode & W_OK != 0 {
access |= AccessMode::WRITE;
}
if mode & X_OK != 0 {
access |= AccessMode::EXEC;
}
syscall::check_access(atfd, path, access).e_map_err(Errno::from)?;
CIntZeroResult::SUCCESS

View File

@ -119,7 +119,7 @@ unsafe extern "C" fn pthread_mutex_consistent(_mutex: *mut pthread_mutex_t) -> c
#[no_mangle]
unsafe extern "C" fn pthread_mutex_destroy(_mutex: *mut pthread_mutex_t) -> c_int {
log::error!("TODO: pthread_mutex_destroy()");
log::debug!("TODO: pthread_mutex_destroy()");
0
}

View File

@ -1,14 +1,18 @@
use core::ffi::{c_char, c_int, c_short, c_void};
use alloc::vec::Vec;
use yggdrasil_rt::{io::RawFd, process::{SpawnFlags, SpawnOption, SpawnOptions}, sys as syscall};
use yggdrasil_rt::{
io::RawFd,
process::{SpawnFlags, SpawnOption, SpawnOptions},
sys as syscall,
};
use super::{
sched::__ygg_sched_param_t,
sys_types::{mode_t, pid_t},
};
use crate::{
error::{CIntCountResult, CIntZeroResult, ResultExt},
error::{CIntZeroResult, ResultExt},
headers::errno::Errno,
util::{NullTerminatedArrayIter, PointerStrExt},
};
@ -49,9 +53,18 @@ unsafe extern "C" fn posix_spawn(
environment: &[],
directory: None,
optional: &[
SpawnOption::CopyFile { source: RawFd::STDIN, child: RawFd::STDIN },
SpawnOption::CopyFile { source: RawFd::STDOUT, child: RawFd::STDOUT },
SpawnOption::CopyFile { source: RawFd::STDERR, child: RawFd::STDERR },
SpawnOption::CopyFile {
source: RawFd::STDIN,
child: RawFd::STDIN,
},
SpawnOption::CopyFile {
source: RawFd::STDOUT,
child: RawFd::STDOUT,
},
SpawnOption::CopyFile {
source: RawFd::STDERR,
child: RawFd::STDERR,
},
],
flags: SpawnFlags::empty(),
};

View File

@ -56,6 +56,12 @@ impl StringWriter {
position: 0,
}
}
fn finish(&mut self) {
if self.position < self.capacity {
unsafe { self.buffer.add(self.position).write(0) };
}
}
}
impl fmt::Write for StringWriter {
@ -272,5 +278,6 @@ unsafe extern "C" fn vsnprintf(
let mut writer = StringWriter::new(buffer, capacity);
let fmt = fmt.ensure_cstr();
let count = printf_inner(&mut writer, fmt.to_bytes(), args)?;
writer.finish();
CIntCountResult::success(count.try_into().unwrap())
}

View File

@ -66,8 +66,10 @@ unsafe extern "C" fn setkey(_key: *const c_char) {
}
#[no_mangle]
unsafe extern "C" fn system(_command: *const c_char) -> CIntZeroResult {
todo!()
unsafe extern "C" fn system(command: *const c_char) -> CIntZeroResult {
let command = command.ensure_str();
log::warn!("system({command:?})");
CIntZeroResult::ERROR
}
#[no_mangle]

View File

@ -27,8 +27,9 @@ unsafe extern "C" fn stpncpy(dst: *mut c_char, src: *const c_char, n: usize) ->
if dst.is_null() || src.is_null() {
panic!();
}
memset(dst.cast(), 0, n);
mempcpy(dst.cast(), src.cast(), strnlen(src, n)).cast()
let dlen = strnlen(src.cast(), n);
let r = mempcpy(dst.cast(), src.cast(), n);
memset(r.cast(), 0, n - dlen).cast()
}
#[no_mangle]
@ -164,8 +165,21 @@ unsafe extern "C" fn strncmp(mut a: *const c_char, mut b: *const c_char, mut n:
#[no_mangle]
unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
stpncpy(dst, src, n);
if dst.is_null() || src.is_null() {
panic!();
}
let mut i = 0;
while i != n {
let c = *src.add(i);
*dst.add(i) = c;
if c == 0 {
break;
}
i += 1;
}
dst
// stpncpy(dst, src, n);
// dst
}
#[no_mangle]

View File

@ -1,6 +1,6 @@
use core::{
cmp::Ordering,
ffi::{c_char, c_int},
ffi::{c_char, c_int, CStr},
};
use super::locale::locale_t;
@ -26,6 +26,16 @@ unsafe extern "C" fn strcasecmp_l(
#[no_mangle]
unsafe extern "C" fn strncasecmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int {
if s1.is_null() {
if s2.is_null() {
return 0;
} else {
return 1;
}
} else if s2.is_null() {
return -1;
}
for i in 0..n {
let c0 = (*s1.add(i) as u8).to_ascii_lowercase();
let c1 = (*s2.add(i) as u8).to_ascii_lowercase();

View File

@ -10,7 +10,7 @@ use yggdrasil_rt::{
};
use crate::{
error::{self, EResult, ResultExt, TryFromExt},
error::{self, CIntZeroResult, CResult, EResult, ResultExt, TryFromExt},
headers::errno::Errno,
};
@ -51,7 +51,7 @@ unsafe fn mmap_inner(
hint: *mut c_void,
len: usize,
prot: c_int,
flags: c_int,
_flags: c_int,
fd: c_int,
offset: off_t,
) -> EResult<NonNull<c_void>> {
@ -73,9 +73,9 @@ unsafe fn mmap_inner(
if prot & PROT_WRITE != 0 {
mapping_flags |= MappingFlags::WRITE;
}
if flags != MAP_PRIVATE {
todo!("Non-private mappings via mmap(2) are not yet supported");
}
// if flags != MAP_PRIVATE {
// todo!("Non-private mappings via mmap(2) are not yet supported");
// }
let address = syscall::map_memory(hint, len, mapping_flags, &source).e_map_err(Errno::from)?;
assert_ne!(address, 0);
@ -143,8 +143,14 @@ unsafe extern "C" fn mmap(
}
#[no_mangle]
unsafe extern "C" fn munmap(_ptr: *mut c_void, _len: usize) -> c_int {
todo!()
unsafe extern "C" fn munmap(ptr: *mut c_void, len: usize) -> CIntZeroResult {
let address = ptr.addr();
if address == 0 || address == usize::MAX || len == 0 {
error::errno = Errno::EINVAL;
return CIntZeroResult::ERROR;
}
syscall::unmap_memory(address, len).e_map_err(Errno::from)?;
CIntZeroResult::SUCCESS
}
// posix_***

View File

@ -10,4 +10,4 @@ usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["rlimit", "rusage"]
include = ["rlimit", "rusage", "__ygg_rusage_t"]

View File

@ -4,6 +4,8 @@ use super::{sys_time::__ygg_timeval_t, sys_types::id_t};
pub type rlim_t = u64;
pub type __ygg_rusage_t = rusage;
pub const PRIO_PROCESS: c_int = 0;
pub const PRIO_PGRP: c_int = 1;
pub const PRIO_USER: c_int = 2;

View File

@ -73,8 +73,9 @@ impl From<FileAttr> for stat {
let st_uid = u32::from(value.uid).try_into().unwrap();
let st_gid = u32::from(value.gid).try_into().unwrap();
// TODO
let st_blksize = 512;
let st_blksize = value.block_size as _;
let st_blocks = st_size.div_ceil(st_blksize as _).try_into().unwrap();
let st_ino = value.inode.unwrap_or(0) as u64;
Self {
st_mode,
@ -83,6 +84,7 @@ impl From<FileAttr> for stat {
st_gid,
st_blksize,
st_blocks,
st_ino,
..Default::default()
}
}
@ -125,14 +127,13 @@ unsafe extern "C" fn mkdir(pathname: *const c_char, mode: mode_t) -> CIntZeroRes
#[no_mangle]
unsafe extern "C" fn mkdirat(atfd: c_int, pathname: *const c_char, mode: mode_t) -> CIntZeroResult {
let _pathname = pathname.ensure_str();
let _atfd = util::at_fd(atfd)?;
let _mode = FileMode::new((mode & 0o777) as u32);
let pathname = pathname.ensure_str();
let atfd = util::at_fd(atfd)?;
let mode = FileMode::new((mode & 0o777) as u32);
todo!()
// io::create_directory(atfd, pathname, mode)?;
io::create_directory(atfd, pathname, mode)?;
// CIntZeroResult::OK
CIntZeroResult::SUCCESS
}
#[no_mangle]

View File

@ -7,6 +7,7 @@ sys_includes = [
"stdint.h",
"signal.h",
"sys/types.h",
"sys/resource.h",
"bits/sys/wait.h"
]
no_includes = true

View File

@ -1,6 +1,18 @@
use core::ffi::{c_int, c_void};
use super::sys_types::{id_t, pid_t};
use yggdrasil_rt::{
process::{ExitCode, ProcessGroupId, ProcessId, ProcessWait, WaitFlags},
sys as syscall,
};
use crate::error::{self, EResult, ResultExt};
use super::{
errno::Errno,
sys_resource::__ygg_rusage_t,
sys_time::timeval,
sys_types::{id_t, pid_t},
};
pub const WCONTINUED: c_int = 1 << 0;
pub const WNOHANG: c_int = 1 << 1;
@ -16,6 +28,45 @@ pub const P_ALL: idtype_t = 0;
pub const P_PGID: idtype_t = 1;
pub const P_PID: idtype_t = 2;
pub struct WaitResult {
pid: ProcessId,
status: ExitCode,
}
fn wait_inner(what: ProcessWait, nonblocking: bool) -> EResult<WaitResult> {
let mut status = ExitCode::Exited(0);
let mut flags = WaitFlags::empty();
if nonblocking {
flags |= WaitFlags::NON_BLOCKING;
}
let pid = unsafe { syscall::wait_process(&what, &mut status, flags) }.e_map_err(Errno::from)?;
EResult::Ok(WaitResult { pid, status })
}
fn convert_wait_pid(pid: pid_t) -> ProcessWait {
// TODO "any child whose process group ID is equal to that of the calling process"
if pid > 0 {
ProcessWait::Process(unsafe { ProcessId::from_raw(pid as _) })
} else if pid == -1 || pid == 0 {
ProcessWait::AnyChild
} else {
let pgrp = (-pid) as u32;
ProcessWait::Group(unsafe { ProcessGroupId::from_raw(pgrp) })
}
}
fn encode_exit_status(code: ExitCode) -> c_int {
match code {
ExitCode::Exited(status) => status & 0xFF,
ExitCode::BySignal(Ok(sig)) => {
let signum = sig as u32;
(signum + 0x100) as c_int
}
ExitCode::BySignal(Err(signum)) => (signum + 0x100) as c_int,
}
}
#[no_mangle]
unsafe extern "C" fn wait(_status: *mut c_int) -> pid_t {
todo!()
@ -36,3 +87,29 @@ unsafe extern "C" fn waitid(
unsafe extern "C" fn waitpid(_pid: pid_t, _status: *mut c_int, _options: c_int) -> pid_t {
todo!()
}
#[no_mangle]
unsafe extern "C" fn wait4(
pid: pid_t,
wstatus: *mut c_int,
options: c_int,
rusage: *mut __ygg_rusage_t,
) -> pid_t {
let pid = convert_wait_pid(pid);
let result = match wait_inner(pid, options & WNOHANG != 0) {
EResult::Ok(result) => result,
EResult::Err(err) => {
error::errno = err;
return -1;
}
};
if let Some(wstatus) = wstatus.as_mut() {
*wstatus = encode_exit_status(result.status);
}
if let Some(rusage) = rusage.as_mut() {
// TODO not implemented on the kernel level
rusage.ru_utime = timeval::zero();
rusage.ru_stime = timeval::zero();
}
result.pid.bits() as pid_t
}

View File

@ -1,7 +1,7 @@
use core::{ffi::c_int, mem::MaybeUninit};
use yggdrasil_rt::{
io::{FileAttr, RawFd, SeekFrom}, path::{Path, PathBuf}, sys as syscall
io::{FileAttr, FileMode, RawFd, SeekFrom}, path::{Path, PathBuf}, sys as syscall
};
use crate::{
@ -127,6 +127,11 @@ pub fn get_metadata(at: Option<RawFd>, path: &str, follow: bool) -> EResult<File
EResult::Ok(unsafe { metadata.assume_init() })
}
pub fn create_directory(at: Option<RawFd>, path: &str, mode: FileMode) -> EResult<()> {
unsafe { syscall::create_directory(at, path, mode) }?;
EResult::Ok(())
}
pub fn realpath<P: AsRef<Path>>(path: P) -> EResult<PathBuf> {
// Cases:
// * /a/b/c -> /a/b/c

View File

@ -34,6 +34,7 @@ use core::{
use alloc::vec::Vec;
use env::environ;
use thread::Thread;
extern crate alloc;
@ -71,6 +72,13 @@ unsafe extern "C" fn __ygglibc_entry(
signal::init(true);
init::init();
let sp = unsafe {
let sp: usize;
core::arch::asm!("mov %rsp, {0}", out(reg) sp, options(att_syntax));
sp
};
log::info!("sp = {sp:#x}");
// Setup args
let args = env::handle_kernel_argument(arg);
let mut c_args = Vec::new();
@ -86,5 +94,8 @@ unsafe extern "C" fn __ygglibc_entry(
environ.cast(),
);
// Call main thread dtors
Thread::call_thread_dtors();
process::c_exit(status)
}

View File

@ -1,6 +1,6 @@
use core::{ffi::c_void, ptr::null_mut};
use core::{cell::RefCell, ffi::c_void, ptr::null_mut};
use alloc::{boxed::Box, collections::BTreeMap};
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
use yggdrasil_rt::{
process::{
thread::{self as rt, ThreadCreateInfo},
@ -12,13 +12,21 @@ use yggdrasil_rt::{
use crate::{
error::{EResult, OptionExt},
headers::{
errno::Errno, sys_types::{pthread_attr_t, pthread_t}
errno::Errno,
sys_types::{pthread_attr_t, pthread_t},
},
};
pub mod tls;
pub struct ThreadDestructor {
pub destructor: extern "C" fn(*mut c_void),
pub argument: *mut c_void,
}
static THREADS: Mutex<BTreeMap<pthread_t, Thread>> = Mutex::new(BTreeMap::new());
#[thread_local]
static THREAD_LOCAL_DTORS: RefCell<Vec<ThreadDestructor>> = RefCell::new(Vec::new());
pub const DEFAULT_STACK_SIZE: usize = 4096 * 16;
pub const DEFAULT_SIGNAL_STACK_SIZE: usize = 4096 * 8;
@ -49,7 +57,7 @@ impl Thread {
signal_stack: rt::ThreadSignalStack::Allocate(DEFAULT_SIGNAL_STACK_SIZE),
stack,
#[allow(clippy::redundant_closure)]
entry: rt::ThreadFunction::Closure(Box::new(move |arg| entry(arg))),
entry: rt::ThreadFunction::Closure(Box::new(move |arg| Self::thread_main(entry, arg))),
tls_image: tls::TLS_IMAGE.get().as_ref(),
};
let handle = rt::Thread::spawn(info, argument, true)?;
@ -68,6 +76,32 @@ impl Thread {
pub fn this() -> EResult<pthread_t> {
EResult::Ok(unsafe { rt::Thread::<*mut c_void>::current().id() })
}
fn thread_main(
entry: extern "C" fn(*mut c_void) -> *mut c_void,
arg: *mut c_void,
) -> *mut c_void {
let ret = entry(arg);
unsafe { Self::call_thread_dtors() };
ret
}
pub fn at_thread_exit(
destructor: extern "C" fn(*mut c_void),
argument: *mut c_void,
_dso_handle: *mut c_void,
) {
THREAD_LOCAL_DTORS.borrow_mut().push(ThreadDestructor {
destructor,
argument,
});
}
pub unsafe fn call_thread_dtors() {
for dtor in THREAD_LOCAL_DTORS.borrow().iter() {
(dtor.destructor)(dtor.argument);
}
}
}
pub fn init_main_thread(arg: &ProgramArgumentInner) {

View File

@ -141,7 +141,7 @@ fn lex_identifier(i: &str) -> IResult<&str, &str> {
recognize(many1_count(alt((alphanumeric1, is_a("-_")))))(i)
}
fn lex_filename(i: &str) -> IResult<&str, &str> {
recognize(many1_count(alt((alphanumeric1, is_a("./-_:")))))(i)
recognize(many1_count(alt((alphanumeric1, is_a("./-_:+")))))(i)
}
fn lex_braced_var(i: &str) -> IResult<&str, &str> {

View File

@ -1,12 +1,14 @@
use std::{io::{stdout, Write}, process::Command};
#![feature(seek_stream_len)]
use std::{fs::File, io::{stdout, Seek, Write}};
use cross::mem::FileMapping;
fn main() {
let output = Command::new("/bin/ls").output().unwrap();
println!("status = {:?}", output.status);
println!("stdout:");
stdout().write_all(&output.stdout).ok();
println!();
println!("stderr:");
stdout().write_all(&output.stderr).ok();
println!();
let mut file = File::open("/etc/test.txt").unwrap();
let size = file.stream_len().unwrap();
let mapping = FileMapping::map(file, size as usize).unwrap();
let mut data = vec![0; size as usize];
data.copy_from_slice(&mapping[..]);
stdout().write_all(&data).unwrap();
}

View File

@ -362,6 +362,7 @@ impl Terminal<'_> {
static ABORT: AtomicBool = AtomicBool::new(false);
fn main() -> ExitCode {
logsink::setup_logging(false);
let font = PcScreenFont::default();
let term = Terminal::new(font).unwrap();

View File

@ -1,3 +1,4 @@
#![allow(unused)]
use std::{
fs,
path::{Path, PathBuf},
@ -126,19 +127,25 @@ fn build_test_c_program(
fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> {
log::info!("Installing ygglibc into LLVM sysroot");
let dst_lib_dir = env.llvm_sysroot.join("lib");
let dst_include_dir = env.llvm_sysroot.join("usr/include");
// let dst_lib_dir = env.llvm_sysroot.join("lib");
// let dst_include_dir = env.llvm_sysroot.join("usr/include");
let _ = env;
let _ = ygglibc.crt0_file;
fs::create_dir_all(&dst_lib_dir)?;
fs::create_dir_all(&dst_include_dir)?;
// fs::create_dir_all(&dst_lib_dir)?;
// fs::create_dir_all(&dst_include_dir)?;
fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
// fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
// fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
// fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
for path in ygglibc.include_paths.iter() {
util::copy_dir_recursive(path, &dst_include_dir)?;
}
let _ = ygglibc.static_lib_file;
let _ = ygglibc.shared_lib_file;
let _ = ygglibc.include_paths;
// for path in ygglibc.include_paths.iter() {
// util::copy_dir_recursive(path, &dst_include_dir)?;
// }
Ok(())
}
@ -212,7 +219,8 @@ fn install_openlibm(env: &BuildEnv, libm: &Openlibm) -> Result<(), Error> {
fs::copy(&libm.static_lib_file, env.llvm_sysroot.join("lib/libm.a"))?;
fs::copy(&libm.shared_lib_file, env.llvm_sysroot.join("lib/libm.so"))?;
util::copy_dir_recursive(&libm.include_path, env.llvm_sysroot.join("usr/include"))?;
let _ = libm.include_path;
// util::copy_dir_recursive(&libm.include_path, env.llvm_sysroot.join("usr/include"))?;
Ok(())
}
@ -241,6 +249,7 @@ pub fn build_c(env: &BuildEnv, install: &mut Vec<(PathBuf, PathBuf)>) -> Result<
"lib/libc++.so".into(),
));
}
install.push((ygglibc.crt0_file, "lib/crt0.o".into()));
install.push((ygglibc.shared_lib_file, "lib/libygglibc.so".into()));
install.push((libm.shared_lib_file, "lib/libopenlibm.so.4".into()));