Skip to content

Commit 078384e

Browse files
sys_epoll_pwait: initial implementation
Signed-off-by: Andy-Python-Programmer <[email protected]>
1 parent df8e560 commit 078384e

File tree

15 files changed

+380
-93
lines changed

15 files changed

+380
-93
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,3 @@ base-files/doom1.wad
2222
# Wayland test client and server executables: (todo: remove these)
2323
base-files/client
2424
base-files/server
25-
26-
userland/.cargo/config.toml

src/aero_kernel/src/drivers/tty.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20+
use aero_syscall::prelude::EPollEventFlags;
2021
use alloc::string::String;
2122
use alloc::sync::{Arc, Weak};
2223
use alloc::vec::Vec;
2324

2425
use crate::fs;
2526
use crate::fs::devfs;
26-
use crate::fs::inode;
27+
use crate::fs::inode::{self, PollTable};
2728
use crate::rendy;
2829

2930
use crate::fs::inode::INodeInterface;
@@ -257,6 +258,17 @@ impl INodeInterface for Tty {
257258
Ok(buffer.len())
258259
}
259260

261+
fn poll(&self, table: Option<&mut PollTable>) -> fs::Result<EPollEventFlags> {
262+
table.map(|e| e.insert(&self.block_queue));
263+
let mut events = EPollEventFlags::default();
264+
265+
if self.stdin.lock_irq().is_complete() {
266+
events.insert(EPollEventFlags::IN);
267+
}
268+
269+
Ok(events)
270+
}
271+
260272
fn ioctl(&self, command: usize, arg: usize) -> fs::Result<usize> {
261273
match command {
262274
aero_syscall::TIOCGWINSZ => {

src/aero_kernel/src/fs/devfs.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::mem::paging::*;
3535
use crate::rendy::RendyInfo;
3636

3737
use super::cache::{DirCacheItem, INodeCacheItem};
38-
use super::inode::INodeInterface;
38+
use super::inode::{INodeInterface, PollTable};
3939
use super::ramfs::RamFs;
4040
use super::FileSystemError;
4141
use super::{FileSystem, Result, MOUNT_MANAGER};
@@ -128,6 +128,10 @@ impl INodeInterface for DevINode {
128128
fn ioctl(&self, command: usize, arg: usize) -> Result<usize> {
129129
self.0.inode().ioctl(command, arg)
130130
}
131+
132+
fn poll(&self, table: Option<&mut PollTable>) -> Result<EPollEventFlags> {
133+
self.0.inode().poll(table)
134+
}
131135
}
132136

133137
/// Implementation of dev filesystem. (See the module-level documentation for more

src/aero_kernel/src/fs/epoll.rs

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20-
use aero_syscall::{prelude::EPollEvent, AeroSyscallError};
20+
use aero_syscall::prelude::EPollEvent;
21+
use aero_syscall::AeroSyscallError;
22+
2123
use alloc::sync::Arc;
2224
use hashbrown::HashMap;
2325

26+
use crate::userland::scheduler;
2427
use crate::utils::sync::Mutex;
2528

26-
use super::inode::INodeInterface;
29+
use super::inode::{INodeInterface, PollTable};
30+
use super::FileSystemError;
2731

2832
pub struct EPoll {
2933
events: Mutex<HashMap<usize, EPollEvent>>,
@@ -50,6 +54,99 @@ impl EPoll {
5054
events.insert(fd, event);
5155
Ok(())
5256
}
57+
58+
/// Retrieves ready events, and delivers them to the caller-supplied event buffer.
59+
///
60+
/// ## Arguments
61+
///
62+
/// * `events`: Used to return information from the ready list about file descriptors in the
63+
/// interest list that have some events available.
64+
///
65+
/// * `max_events`: Maximum number of events.
66+
///
67+
/// * `timeout`: specifies the minimum number of milliseconds that epoll wait will block. Specifying
68+
/// a timeout of `-1` will block indefinitely. While specifing a timeout of `0` will return immediately
69+
/// even if there are available no events.
70+
///
71+
/// ## Return
72+
/// Returns the number of ready events if the call was successful.
73+
///
74+
/// ## Blocking
75+
/// Blocks the current task until either:
76+
///
77+
/// * A file descriptor delivers an event.
78+
/// * The call is interrupted by a signal handler.
79+
/// * The timeout expires.
80+
pub fn wait(
81+
&self,
82+
ret_events: &mut [&mut EPollEvent],
83+
max_events: usize,
84+
_timeout: usize,
85+
) -> Result<usize, FileSystemError> {
86+
let current_task = scheduler::get_scheduler().current_task();
87+
let file_table = &current_task.file_table;
88+
89+
let mut table = self.events.lock();
90+
let mut n = 0;
91+
92+
let mut fds = alloc::vec![];
93+
let mut poll_table = PollTable::default();
94+
95+
// Iterate over all the registered events and check if they are ready.
96+
for (fd, epoll_event) in table.iter_mut() {
97+
if n == max_events {
98+
break;
99+
}
100+
101+
let fd = file_table
102+
.get_handle(*fd)
103+
.ok_or(FileSystemError::NotSupported)?; // EINVAL
104+
105+
let flags = epoll_event.events;
106+
let ready = fd.inode().poll(None)?;
107+
108+
if ready.contains(flags) {
109+
// The registered event is ready; increment the number of ready events
110+
// and set event flags mask for this event in the caller-supplied event
111+
// buffer.
112+
ret_events[n].events = ready & flags;
113+
n += 1;
114+
continue;
115+
}
116+
117+
// Not ready; add the event to the poll table.
118+
fd.inode().poll(Some(&mut poll_table))?;
119+
fds.push(fd);
120+
}
121+
122+
// If all events are ready, we can return now.
123+
if n > 0 {
124+
debug_assert!(fds.len() == 0);
125+
return Ok(n);
126+
}
127+
128+
'search: loop {
129+
// Wait till one of the file descriptor deliever an event.
130+
scheduler::get_scheduler().inner.await_io()?;
131+
132+
for fd in fds.iter() {
133+
let ready = fd.inode().poll(None)?;
134+
let flags = table
135+
.get(&fd.fd)
136+
.ok_or(FileSystemError::NotSupported)?
137+
.events;
138+
139+
if ready.contains(flags) {
140+
// The event is ready; break out of the search loop and set ready
141+
// events to 1.
142+
n = 1;
143+
break 'search;
144+
}
145+
}
146+
}
147+
148+
Ok(n)
149+
}
53150
}
54151

55152
unsafe impl Send for EPoll {}

src/aero_kernel/src/fs/eventfd.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,57 @@
1717
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20+
use aero_syscall::prelude::EPollEventFlags;
2021
use alloc::sync::Arc;
2122

22-
use super::inode::INodeInterface;
23+
use super::inode::{INodeInterface, PollTable};
24+
use crate::utils::sync::{BlockQueue, Mutex};
2325

24-
pub struct EventFd {}
26+
pub struct EventFd {
27+
wq: BlockQueue,
28+
count: Mutex<usize>,
29+
}
2530

2631
impl EventFd {
2732
pub fn new() -> Arc<Self> {
28-
Arc::new(Self {})
33+
Arc::new(Self {
34+
wq: BlockQueue::new(),
35+
count: Mutex::new(0),
36+
})
2937
}
3038
}
3139

3240
impl INodeInterface for EventFd {
3341
fn read_at(&self, _offset: usize, _buffer: &mut [u8]) -> super::Result<usize> {
42+
self.wq.notify_complete();
43+
3444
unimplemented!()
3545
}
3646

3747
fn write_at(&self, _offset: usize, _buffer: &[u8]) -> super::Result<usize> {
48+
self.wq.notify_complete();
49+
3850
unimplemented!()
3951
}
52+
53+
fn poll(&self, table: Option<&mut PollTable>) -> super::Result<EPollEventFlags> {
54+
let count = self.count.lock();
55+
let mut events = EPollEventFlags::default();
56+
57+
table.map(|e| e.insert(&self.wq)); // listen for changes
58+
59+
if *count > 0 {
60+
events.insert(EPollEventFlags::IN);
61+
}
62+
63+
if *count == usize::MAX {
64+
events.insert(EPollEventFlags::ERR);
65+
}
66+
67+
if *count < (usize::MAX - 1) {
68+
events.insert(EPollEventFlags::OUT); // possible to write a value of at least "1" without blocking.
69+
}
70+
71+
Ok(events)
72+
}
4073
}

src/aero_kernel/src/fs/file_table.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ impl FileHandle {
122122
self.inode.inode()
123123
}
124124

125-
pub fn duplicate(&self, flags: OpenFlags) -> super::Result<Arc<FileHandle>> {
125+
pub fn duplicate(&self, dupfd: usize, flags: OpenFlags) -> super::Result<Arc<FileHandle>> {
126126
let flags = self.flags | flags;
127127
let new = Arc::new(Self {
128-
fd: self.fd,
128+
fd: dupfd,
129129
inode: self.inode.clone(),
130130
offset: self.offset.clone(),
131131
flags,
@@ -241,15 +241,15 @@ impl FileTable {
241241
// avaliable file descriptor.
242242
for (i, file) in array.iter_mut().enumerate() {
243243
if file.is_none() {
244-
*file = Some(handle.duplicate(flags)?);
244+
*file = Some(handle.duplicate(i, flags)?);
245245
return Ok(i);
246246
}
247247
}
248248

249-
// We ran out of file descriptors. Grow the table and add the
250-
// file descriptor.
251-
files.push(Some(handle.duplicate(flags)?));
252-
Ok(files.len() - 1)
249+
// We ran out of file descriptors. Grow the FD table and insert the FD.
250+
let fd = files.len();
251+
files.push(Some(handle.duplicate(fd, flags)?));
252+
Ok(fd)
253253
};
254254

255255
match hint {
@@ -258,12 +258,12 @@ impl FileTable {
258258

259259
// Ensure the file descriptor is available.
260260
if files[new_fd].is_none() {
261-
files[new_fd] = Some(handle.duplicate(flags)?);
261+
files[new_fd] = Some(handle.duplicate(new_fd, flags)?);
262262
Ok(0x00)
263263
} else {
264264
// If the file descriptor is not available, then we close the
265265
// old one and set its handle to the new duplicate handle.
266-
let handle = handle.duplicate(flags)?;
266+
let handle = handle.duplicate(new_fd, flags)?;
267267
let old = files[new_fd].take().unwrap();
268268

269269
old.inode.inode().close(old.flags);

src/aero_kernel/src/fs/inode.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@
1919

2020
use core::sync::atomic::{AtomicUsize, Ordering};
2121

22+
use aero_syscall::prelude::EPollEventFlags;
2223
use aero_syscall::{MMapFlags, OpenFlags};
2324

2425
use alloc::string::String;
2526
use alloc::sync::Arc;
2627
use alloc::sync::Weak;
2728

2829
use alloc::vec::Vec;
30+
use intrusive_collections::UnsafeRef;
2931
use spin::Once;
3032

3133
use crate::mem::paging::PhysFrame;
3234
use crate::socket::SocketAddr;
35+
use crate::userland::scheduler;
36+
use crate::utils::sync::BlockQueue;
3337
use crate::utils::sync::Mutex;
3438
use crate::utils::Downcastable;
3539

@@ -42,13 +46,31 @@ use super::{FileSystem, FileSystemError, Result};
4246

4347
static DIR_CACHE_MARKER: AtomicUsize = AtomicUsize::new(0x00);
4448

49+
#[derive(Default)]
50+
pub struct PollTable {
51+
pub queues: Vec<UnsafeRef<BlockQueue>>,
52+
}
53+
54+
impl PollTable {
55+
pub fn insert(&mut self, queue: &BlockQueue) {
56+
queue.insert(scheduler::get_scheduler().current_task());
57+
unsafe { self.queues.push(UnsafeRef::from_raw(queue as *const _)) }
58+
}
59+
}
60+
61+
impl Drop for PollTable {
62+
fn drop(&mut self) {
63+
let ctask = scheduler::get_scheduler().current_task();
64+
for queue in self.queues.iter() {
65+
queue.remove(ctask.clone());
66+
}
67+
}
68+
}
69+
4570
/// An inode describes a file. An inode structure holds metadata of the
4671
/// inode which includes its type, size, the number of links referring to it,
4772
/// and the list of blocks holding the file's content. For example device files,
4873
/// files on the disk, etc...
49-
///
50-
/// This trait requires the implementor to implement [Send], [Sync] and [Downcastable] on
51-
/// the inode structure.
5274
pub trait INodeInterface: Send + Sync + Downcastable {
5375
/// Returns the inode metadata of `this` inode.
5476
fn metadata(&self) -> Result<Metadata> {
@@ -162,6 +184,10 @@ pub trait INodeInterface: Send + Sync + Downcastable {
162184
fn as_unix_socket(&self) -> Result<Arc<dyn INodeInterface>> {
163185
Err(FileSystemError::NotSocket)
164186
}
187+
188+
fn poll(&self, _table: Option<&mut PollTable>) -> Result<EPollEventFlags> {
189+
Err(FileSystemError::NotSupported)
190+
}
165191
}
166192

167193
/// Structure representing the curcial, characteristics of an inode. The metadata

src/aero_kernel/src/fs/ramfs.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
2424
use core::sync::atomic::{AtomicUsize, Ordering};
2525

26+
use aero_syscall::prelude::EPollEventFlags;
2627
use aero_syscall::MMapFlags;
2728
use alloc::collections::BTreeMap;
2829
use alloc::string::String;
@@ -38,7 +39,7 @@ use crate::utils::sync::Mutex;
3839
use super::cache::{self, CacheWeak};
3940
use super::cache::{CachedINode, DirCacheItem, INodeCacheItem, INodeCacheWeakItem};
4041
use super::devfs::DevINode;
41-
use super::inode::{DirEntry, FileType, INodeInterface};
42+
use super::inode::{DirEntry, FileType, INodeInterface, PollTable};
4243
use super::inode::{FileContents, Metadata};
4344
use super::{FileSystem, FileSystemError, Result};
4445

@@ -391,6 +392,21 @@ impl INodeInterface for LockedRamINode {
391392
}
392393
}
393394

395+
fn poll(&self, table: Option<&mut PollTable>) -> Result<EPollEventFlags> {
396+
let this = self.0.read();
397+
398+
match &this.contents {
399+
FileContents::Device(device) => {
400+
let device = device.clone();
401+
drop(this);
402+
403+
device.poll(table)
404+
}
405+
406+
_ => Err(FileSystemError::NotSupported),
407+
}
408+
}
409+
394410
#[inline]
395411
fn weak_filesystem(&self) -> Option<Weak<dyn FileSystem>> {
396412
Some(self.0.read().filesystem.clone())

0 commit comments

Comments
 (0)