Skip to main content

strat9_kernel/syscall/
poll.rs

1use crate::{
2    memory::{UserSliceRead, UserSliceWrite},
3    process::current_task_clone,
4    syscall::error::SyscallError,
5};
6
7const POLLIN: i16 = 0x0001;
8const POLLOUT: i16 = 0x0004;
9const POLLNVAL: i16 = 0x0020;
10
11const POLLFD_SIZE: usize = 8; // sizeof(pollfd) = i32 + i16 + i16
12
13/// Reads pollfd.
14fn read_pollfd(buf: &[u8], i: usize) -> (i32, i16) {
15    let off = i * POLLFD_SIZE;
16    let fd = i32::from_le_bytes([buf[off], buf[off + 1], buf[off + 2], buf[off + 3]]);
17    let events = i16::from_le_bytes([buf[off + 4], buf[off + 5]]);
18    (fd, events)
19}
20
21/// Writes revents.
22fn write_revents(buf: &mut [u8], i: usize, revents: i16) {
23    let off = i * POLLFD_SIZE + 6;
24    let bytes = revents.to_le_bytes();
25    buf[off] = bytes[0];
26    buf[off + 1] = bytes[1];
27}
28
29/// Performs the sys poll operation.
30pub fn sys_poll(fds_ptr: u64, nfds: u64, _timeout_ms: u64) -> Result<u64, SyscallError> {
31    if nfds == 0 {
32        return Ok(0);
33    }
34    if nfds > 1024 {
35        return Err(SyscallError::InvalidArgument);
36    }
37    let n = nfds as usize;
38    let byte_len = n * POLLFD_SIZE;
39
40    let task = current_task_clone().ok_or(SyscallError::Fault)?;
41    let fd_table = unsafe { &*task.process.fd_table.get() };
42
43    let reader = UserSliceRead::new(fds_ptr, byte_len)?;
44    let mut buf = alloc::vec![0u8; byte_len];
45    reader.copy_to(&mut buf);
46
47    let mut ready_count = 0u64;
48    for i in 0..n {
49        let (fd, events) = read_pollfd(&buf, i);
50        let revents = if fd < 0 {
51            0i16
52        } else {
53            match fd_table.get(fd as u32) {
54                Ok(_) => {
55                    let mut r = 0i16;
56                    if events & POLLIN != 0 {
57                        r |= POLLIN;
58                    }
59                    if events & POLLOUT != 0 {
60                        r |= POLLOUT;
61                    }
62                    r
63                }
64                Err(_) => POLLNVAL,
65            }
66        };
67        write_revents(&mut buf, i, revents);
68        if revents != 0 {
69            ready_count += 1;
70        }
71    }
72
73    let writer = UserSliceWrite::new(fds_ptr, byte_len)?;
74    writer.copy_from(&buf);
75
76    Ok(ready_count)
77}