Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ Cargo.lock
/rootfs
/prebuilt/linux/alpine*
.idea
scripts/linux/test-result.txt
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Run all (non-panicked) core-tests for CI:

```sh
pip3 install pexpect
cd script && python3 core-tests.py
cd scripts && python3 core-tests.py
# Check `zircon/test-result.txt` for results.
```

Expand All @@ -92,7 +92,7 @@ Run Linux musl libc-tests for CI:

```sh
make rootfs && make libc-test
cd script && python3 libc-tests.py
cd scripts && python3 libc-tests.py
# Check `linux/test-result.txt` for results.
```

Expand Down
5 changes: 5 additions & 0 deletions linux-loader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,11 @@ mod tests {
fs::read("../rootfs/testtruncate").unwrap();
}

#[async_std::test]
async fn test_flock() {
assert_eq!(test("/bin/busybox flock 0").await, 0);
}

// syscall unit test

#[async_std::test]
Expand Down
8 changes: 7 additions & 1 deletion linux-object/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! Linux kernel objects

#![no_std]
#![deny(warnings, unsafe_code, unused_must_use, unreachable_patterns)]
#![deny(
warnings,
unsafe_code,
unused_must_use,
unreachable_patterns,
missing_docs
)]
#![feature(bool_to_option)]

extern crate alloc;
Expand Down
57 changes: 51 additions & 6 deletions linux-object/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use core::sync::atomic::AtomicI32;
use hashbrown::HashMap;
use kernel_hal::VirtAddr;
use rcore_fs::vfs::{FileSystem, INode};
use spin::Mutex;
use spin::*;
use zircon_object::{
object::{KernelObject, KoID, Signal},
signal::Futex,
Expand Down Expand Up @@ -143,6 +143,8 @@ struct LinuxProcessInner {
///
/// Omit leading '/'.
current_working_directory: String,
/// file open number limit
file_limit: RLimit,
/// Opened files
files: HashMap<FileDesc, Arc<dyn FileLike>>,
/// Futexes
Expand All @@ -151,6 +153,25 @@ struct LinuxProcessInner {
children: HashMap<KoID, Arc<Process>>,
}

/// resource limit
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RLimit {
/// soft limit
pub cur: u64,
/// hard limit
pub max: u64,
}

impl Default for RLimit {
fn default() -> Self {
RLimit {
cur: 1024,
max: 1024,
}
}
}

/// process exit code defination
pub type ExitCode = i32;

Expand Down Expand Up @@ -209,16 +230,40 @@ impl LinuxProcess {

/// Add a file to the file descriptor table.
pub fn add_file(&self, file: Arc<dyn FileLike>) -> LxResult<FileDesc> {
let mut inner = self.inner.lock();
let inner = self.inner.lock();
let fd = inner.get_free_fd();
inner.files.insert(fd, file);
Ok(fd)
self.insert_file(inner, fd, file)
}

/// Add a file to the file descriptor table at given `fd`.
pub fn add_file_at(&self, fd: FileDesc, file: Arc<dyn FileLike>) {
pub fn add_file_at(&self, fd: FileDesc, file: Arc<dyn FileLike>) -> LxResult<FileDesc> {
let inner = self.inner.lock();
self.insert_file(inner, fd, file)
}

/// insert a file and fd into the file descriptor table
fn insert_file(
&self,
mut inner: MutexGuard<LinuxProcessInner>,
fd: FileDesc,
file: Arc<dyn FileLike>,
) -> LxResult<FileDesc> {
if inner.files.len() < inner.file_limit.cur as usize {
inner.files.insert(fd, file);
Ok(fd)
} else {
Err(LxError::EMFILE)
}
}

/// get and set file limit number
pub fn file_limit(&self, new_limit: Option<RLimit>) -> RLimit {
let mut inner = self.inner.lock();
inner.files.insert(fd, file);
let old = inner.file_limit;
if let Some(limit) = new_limit {
inner.file_limit = limit;
}
old
}

/// Get the `File` with given `fd`.
Expand Down
30 changes: 27 additions & 3 deletions linux-object/src/sync/event_bus.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! Event bus implement
//!
//! An Eventbus is a mechanism that allows different components to communicate with each other without knowing about each other.
use alloc::boxed::Box;
use alloc::{sync::Arc, vec::Vec};
use bitflags::bitflags;
Expand All @@ -10,45 +13,62 @@ use spin::Mutex;

bitflags! {
#[derive(Default)]
/// event bus Event flags
pub struct Event: u32 {
/// File
/// File: is readable
const READABLE = 1 << 0;
/// File: is writeable
const WRITABLE = 1 << 1;
/// File: has error
const ERROR = 1 << 2;
/// File: is closed
const CLOSED = 1 << 3;

/// Process
/// Process: is Quit
const PROCESS_QUIT = 1 << 10;
/// Process: child process is Quit
const CHILD_PROCESS_QUIT = 1 << 11;
/// Process: received signal
const RECEIVE_SIGNAL = 1 << 12;

/// Semaphore
/// Semaphore: is removed
const SEMAPHORE_REMOVED = 1 << 20;
/// Semaphore: can acquired
const SEMAPHORE_CAN_ACQUIRE = 1 << 21;
}
}

/// handler of event in the event bus
pub type EventHandler = Box<dyn Fn(Event) -> bool + Send>;

/// event bus struct
#[derive(Default)]
pub struct EventBus {
/// event type
event: Event,
/// EventBus callback
callbacks: Vec<EventHandler>,
}

impl EventBus {
/// create an event bus
pub fn new() -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(Self::default()))
}

/// set event flag
pub fn set(&mut self, set: Event) {
self.change(Event::empty(), set);
}

/// clear all event flag
pub fn clear(&mut self, set: Event) {
self.change(set, Event::empty());
}

/// change event flag
/// - `reset`: flag to remove
/// - `set`: flag to insert
pub fn change(&mut self, reset: Event, set: Event) {
let orig = self.event;
let mut new = self.event;
Expand All @@ -60,19 +80,23 @@ impl EventBus {
}
}

/// push a EventHandler into the callback vector
pub fn subscribe(&mut self, callback: EventHandler) {
self.callbacks.push(callback);
}

/// get the callback vector length
pub fn get_callback_len(&self) -> usize {
self.callbacks.len()
}
}

/// wait for a event async
pub fn wait_for_event(bus: Arc<Mutex<EventBus>>, mask: Event) -> impl Future<Output = Event> {
EventBusFuture { bus, mask }
}

/// EventBus future for async
#[must_use = "future does nothing unless polled/`await`-ed"]
struct EventBusFuture {
bus: Arc<Mutex<EventBus>>,
Expand Down
1 change: 1 addition & 0 deletions linux-object/src/sync/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Useful synchronization primitives.
pub use self::event_bus::*;

mod event_bus;
12 changes: 11 additions & 1 deletion linux-syscall/src/file/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,17 @@ impl Syscall<'_> {
// close fd2 first if it is opened
let _ = proc.close_file(fd2);
let file_like = proc.get_file_like(fd1)?;
proc.add_file_at(fd2, file_like);
let fd2 = proc.add_file_at(fd2, file_like)?;
Ok(fd2.into())
}

/// create a copy of the file descriptor fd, and uses the lowest-numbered unused descriptor for the new descriptor.
pub fn sys_dup(&self, fd1: FileDesc) -> SysResult {
info!("dup: from {:?}", fd1);
let proc = self.linux_process();

let file_like = proc.get_file_like(fd1)?;
let fd2 = proc.add_file(file_like)?;
Ok(fd2.into())
}

Expand Down
1 change: 1 addition & 0 deletions linux-syscall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl Syscall<'_> {
Sys::FCHOWN => self.unimplemented("fchown", Ok(0)),
Sys::FCHOWNAT => self.unimplemented("fchownat", Ok(0)),
Sys::FACCESSAT => self.sys_faccessat(a0.into(), a1.into(), a2, a3),
Sys::DUP => self.sys_dup(a0.into()),
Sys::DUP3 => self.sys_dup2(a0.into(), a1.into()), // TODO: handle `flags`
Sys::PIPE2 => self.sys_pipe(a0.into()), // TODO: handle `flags`
Sys::UTIMENSAT => self.sys_utimensat(a0.into(), a1.into(), a2.into(), a3),
Expand Down
14 changes: 3 additions & 11 deletions linux-syscall/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ impl Syscall<'_> {
"prlimit64: pid: {}, resource: {}, new_limit: {:x?}, old_limit: {:x?}",
pid, resource, new_limit, old_limit
);
let proc = self.linux_process();
match resource {
RLIMIT_STACK => {
old_limit.write_if_not_null(RLimit {
Expand All @@ -101,10 +102,8 @@ impl Syscall<'_> {
Ok(0)
}
RLIMIT_NOFILE => {
old_limit.write_if_not_null(RLimit {
cur: 1024,
max: 1024,
})?;
let new_limit = new_limit.read_if_not_null()?;
old_limit.write_if_not_null(proc.file_limit(new_limit))?;
Ok(0)
}
RLIMIT_RSS | RLIMIT_AS => {
Expand Down Expand Up @@ -156,13 +155,6 @@ const RLIMIT_RSS: usize = 5;
const RLIMIT_NOFILE: usize = 7;
const RLIMIT_AS: usize = 9;

#[repr(C)]
#[derive(Debug, Default)]
pub struct RLimit {
cur: u64, // soft limit
max: u64, // hard limit
}

/// sysinfo() return information sturct
#[repr(C)]
#[derive(Debug, Default)]
Expand Down