1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
use crate::{
fs::File,
task::{current_user_token, signal::Signals},
timer::TimeSpec,
};
use alloc::vec::Vec;
use core::ptr::{null, null_mut};
use crate::{
mm::{copy_from_user_array, copy_to_user_array},
task::{current_task, sigprocmask, suspend_current_and_run_next, SigMaskHow},
};
/// A scheduling scheme whereby the local process periodically checks until the pre-specified events (for example, read, write) have occurred.
/// The PollFd struct in 32-bit style.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PollFd {
/// File descriptor
fd: u32,
/// Requested events
events: PollEvent,
/// Returned events
revents: PollEvent,
}
bitflags! {
/// Event types that can be polled for.
///
/// These bits may be set in `events`(see `ppoll()`) to indicate the interesting event types;
///
/// they will appear in `revents` to indicate the status of the file descriptor.
struct PollEvent:u16 {
/// There is data to read.
const POLLIN = 0x001;
/// There is urgent data to read.
const POLLPRI = 0x002;
/// Writing now will not block.
const POLLOUT = 0x004;
// These values are defined in XPG4.2.
/// Normal data may be read.
const POLLRDNORM = 0x040;
/// Priority data may be read.
const POLLRDBAND = 0x080;
/// Writing now will not block.
const POLLWRNORM = 0x100;
/// Priority data may be written.
const POLLWRBAND = 0x200;
/// Linux Extension.
const POLLMSG = 0x400;
/// Linux Extension.
const POLLREMOVE = 0x1000;
/// Linux Extension.
const POLLRDHUP = 0x2000;
/* Event types always implicitly polled for.
These bits need not be set in `events',
but they will appear in `revents' to indicate the status of the file descriptor.*/
/// Implicitly polled for only.
/// Error condition.
const POLLERR = 0x008;
/// Implicitly polled for only.
/// Hung up.
const POLLHUP = 0x010;
/// Implicitly polled for only.
/// Invalid polling request.
const POLLNVAL = 0x020;
}
}
impl PollFd {
/* fn get_inode(&self) -> OSInode {} */
}
#[allow(unused)]
/// `ppoll()` witout `sigmask`. See `ppoll` for more information.
pub fn poll(poll_fd: usize, nfds: usize, time_spec: usize) -> isize {
ppoll(poll_fd, nfds, time_spec, null::<Signals>())
}
/// Wait for one of the events in `poll_fd_p` to happen, or the time limit to run out if any.
/// Unlike the function family of `select()` which are basically AND'S,
/// `poll()`'s act like OR's for polling the files.
/// # Arguments
/// * `poll_fd`: The USER pointer to the array of file descriptors to be polled
/// * `nfds`: The number stored in the previous array.
/// * `time_spec`: The time, see `timer::TimeSpec` for information. NOT SUPPORTED and will be ignored!
/// * `sigmask`: The pointer to the sigmask in use during the poll.
/// # Note
/// * `POLLHUP`, `POLLNVAL` and `POLLERR` are ALWAYS polled for all given files,
/// regardless of whether it is set in the array.
/// # Unsupported Features
/// * Timeout is not yet supported.
/// * Other implementations are supported by specific files and may not be used by
/// * Currently only user space structs are supported.
/// # Return Conditions
/// The call will block until either:
/// * a file descriptor becomes ready;
/// * the call is interrupted by a signal handler; or
/// * the timeout expires.
/// # Return Values and Side-effects
/// * On success, a positive number is returned; this is the number of structures
/// which have nonzero revents fields (in other words, those descriptors
/// with events or errors reported).
/// * A value of 0 indicates that the call timed out and no file descriptors were ready.
/// * On error, -1 is returned, and errno is set appropriately.
/// * The observed event is written back to the array, with others cleared.
pub fn ppoll(poll_fd_p: usize, nfds: usize, time_spec: usize, sigmask: *const Signals) -> isize {
/*support only POLLIN for currently*/
let oldsig = &mut Signals::empty();
let mut has_mask = false;
if sigmask as usize != 0 {
has_mask = true;
sigprocmask(SigMaskHow::SIG_SETMASK.bits(), sigmask, oldsig);
}
let mut done: isize = 0;
let mut no_abs: bool = true;
let mut poll_fd: alloc::vec::Vec<PollFd> = alloc::vec::Vec::with_capacity(nfds);
poll_fd.resize(
nfds,
PollFd {
fd: 0,
events: PollEvent::empty(),
revents: PollEvent::empty(),
},
);
let token = current_user_token();
// println!("poll_fd:{:?}, Hi!", poll_fd);
copy_from_user_array(
token,
poll_fd_p as *const PollFd,
poll_fd.as_mut_ptr(),
nfds,
);
//return 1;
//poll_fd.len()
log::info!("[ppoll] polling files:");
for i in poll_fd.iter_mut() {
i.revents = PollEvent::empty();
log::info!("[ppoll] {:?}", i);
}
if poll_fd.len() != 0 {
loop {
let mut i = 0;
let task = current_task().unwrap();
let inner = task.acquire_inner_lock();
//
while i != poll_fd.len() {
let j = {
if poll_fd[i].fd as usize >= inner.fd_table.len()
|| inner.fd_table[poll_fd[i].fd as usize].is_none()
{
None
} else {
/*should be "poll_fd[i].fd as usize"*/
Some(
inner.fd_table[poll_fd[i].fd as usize]
.as_ref()
.unwrap()
.clone(),
)
}
};
match j.unwrap().file {
super::FileLike::Abstract(file) => {
no_abs = false;
if file.hang_up() {
poll_fd[i].revents |= PollEvent::POLLHUP;
done += 1 as isize;
break;
}
if (poll_fd[i].events.contains(PollEvent::POLLIN)) && file.r_ready() {
poll_fd[i].revents |= PollEvent::POLLIN;
//poll_fd[i].revents |= PollEvent::POLLHUP;
done += 1 as isize;
break;
}
}
super::FileLike::Regular(file) => {}
};
i += 1;
}
if no_abs || done != 0 {
if has_mask {
sigprocmask(
SigMaskHow::SIG_SETMASK.bits(),
oldsig,
null_mut::<Signals>(),
);
}
break done;
} else {
copy_to_user_array(token, &poll_fd[0], poll_fd_p as *mut PollFd, nfds);
drop(inner);
drop(task);
suspend_current_and_run_next();
}
}
} else {
0
}
}
// This may be unsafe since the size of bits is undefined.
#[derive(Debug)]
#[repr(C)]
/// Bitmap used by `pselect()` and `select` to indicate the event to wait for.
pub struct FdSet {
bits: [u64; 16],
}
use crate::lang_items::Bytes;
impl FdSet {
/// Return an empty bitmap for further manipulation
pub fn empty() -> Self {
Self { bits: [0; 16] }
}
/// Divide `d` by 64 to decide the `u64` in `bits` to visit.
fn fd_elt(d: usize) -> usize {
d >> 6
}
/// Mod `d` by 64 for the position of `d` in the `fd_elt()` bitmap.
fn fd_mask(d: usize) -> u64 {
1 << (d & 0x3F)
}
/// Clear the current struct.
pub fn clr_all(&mut self) {
for i in 0..16 {
self.bits[i] = 0;
}
}
/// Collect all fds with their bits set.
pub fn get_fd_vec(&self) -> Vec<usize> {
let mut v = Vec::new();
for i in 0..1024 {
if self.is_set(i) {
v.push(i);
}
}
v
}
/// The total number of set bits.
pub fn set_num(&self) -> u32 {
let mut sum: u32 = 0;
for i in self.bits.iter() {
sum += i.count_ones();
}
sum
}
pub fn set(&mut self, d: usize) {
self.bits[Self::fd_elt(d)] |= Self::fd_mask(d);
}
/// Clear a certain bit `d` to stop waiting for the event of the correspond fd.
pub fn clr(&mut self, d: usize) {
self.bits[Self::fd_elt(d)] &= !Self::fd_mask(d);
}
/// Predicate for whether the bit is set for the `d`
pub fn is_set(&self, d: usize) -> bool {
(Self::fd_mask(d) & self.bits[Self::fd_elt(d)]) != 0
}
}
impl Bytes<FdSet> for FdSet {
fn as_bytes(&self) -> &[u8] {
let size = core::mem::size_of::<FdSet>();
unsafe {
core::slice::from_raw_parts(
self as *const _ as *const FdSet as usize as *const u8,
size,
)
}
}
fn as_bytes_mut(&mut self) -> &mut [u8] {
let size = core::mem::size_of::<FdSet>();
unsafe {
core::slice::from_raw_parts_mut(self as *mut _ as *mut FdSet as usize as *mut u8, size)
}
}
}
/// Poll each of the file discriptors
/// until certain events.
///
/// # Arguments
///
/// * `nfds`: the highest-numbered file descriptor in any of the three sets
///
/// * `read_fds`: files to be watched to see if characters become available for reading
///
/// * `write_fds`: files to be watched to see if characters become available for writing
///
/// * `except_fds`: exceptional conditions
///
/// (For examples of some exceptional conditions, see the discussion of POLLPRI in [poll(2)].)
/// * `timeout`: argument specifies the interval that pselect() should block waiting for a file descriptor to become ready
///
/// * `sigmask`: the sigmask used by the process during the poll, as in ppoll
///
/// # Return Value
///
/// * On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens.
///
/// * On error, -1 is returned, the file descriptor sets are unmodified, and timeout becomes undefined.
///
/// * If both fields of the timeval structure are zero,
/// then select() returns immediately.
/// (This is useful for polling.)
/// If timeout is NULL (no timeout), select() can block indefinitely.
pub fn pselect(
nfds: usize,
read_fds: Option<&mut FdSet>,
write_fds: Option<&mut FdSet>,
exception_fds: Option<&mut FdSet>,
/*
*/
timeout: Option<&TimeSpec>,
sigmask: *const Signals,
) -> isize {
/*
// this piece of code should be in sys_pselect instead of being here.
if max(exception_fds.len(), max(read_fds.len(), write_fds.len())) != nfds || nfds < 0 {
return -1;
}
*/
let mut trg = crate::timer::TimeSpec::now();
log::warn!("[pselect] Hi!");
if let Some(_) = timeout {
trg = *timeout.unwrap() + trg;
log::warn!("[pselect] timeout {:?}", timeout.unwrap());
}
let mut done = false;
let start = crate::timer::get_time_sec();
let oldsig = &mut Signals::empty();
let mut has_mask = false;
if sigmask as usize != 0 {
has_mask = true;
sigprocmask(SigMaskHow::SIG_SETMASK.bits(), sigmask, oldsig);
}
let mut ret = 2048;
loop {
let task = current_task().unwrap();
let inner = task.acquire_inner_lock();
let fd_table = &inner.fd_table;
ret = 2048;
macro_rules! do_chk {
($f:ident,$func:ident,$fds:ident,$i:ident) => {
if !$f.$func() {
ret = 0;
break;
}
};
}
macro_rules! chk_fds {
($fds:ident,$func:ident,$chk_func:ident,$($ref_info:ident)?) => {
if let Some($($ref_info)? j) = $fds {
for i in 0..nfds {
if j.is_set(i) {
//log::warn!("[myselect] i:{}", i);
if let Some(k) = fd_table[i].as_ref() {
match &k.file {
super::FileLike::Abstract(file) => {
$chk_func!(file, $func,j,i);
}
super::FileLike::Regular(file) => {
$chk_func!(file, $func,j,i);
}
}
} else {
log::error!("[myselect] quiting with -1!");
return -1;
}
}
}
}
};
}
chk_fds!(read_fds, r_ready, do_chk, ref);
chk_fds!(write_fds, w_ready, do_chk, ref);
if ret == 2048 {
//The SUPPORTED fds are all ready since the ret was NOT assigned.
ret = 0;
log::warn!("fds are all ready now.");
ret += if let Some(ref i) = read_fds {
i.set_num()
} else {
0
};
ret += if let Some(ref i) = write_fds {
i.set_num()
} else {
0
};
// 我们曾把exception赋值放在这里,但当时
// 似乎有个race:要么
// 另外,这里if let 不加ref会导致move, 不知道有没有更好的办法不ref也不move却能
break;
}
ret = 0;
match &timeout {
None => {}
Some(_) => {
//log::trace!("{:?} to {:?}", trg, TimeSpec::now());
if (trg - TimeSpec::now()).to_ns() == 0 {
ret = 0;
macro_rules! do_chk_end {
($f:ident,$func:ident,$fds:ident,$i:ident) => {
if !$f.$func() {
$fds.clr($i);
}
};
}
chk_fds!(read_fds, r_ready, do_chk_end,);
chk_fds!(write_fds, w_ready, do_chk_end,);
break;
}
}
}
// There SHOULD be ORDER REQ. for dropping?!
drop(fd_table);
drop(inner);
drop(task);
suspend_current_and_run_next();
}
// 这个问题: 由于exception_fds检查未支持,必须在最后
if exception_fds.is_some() {
match &timeout {
Some(_) => {
if let Some(i) = exception_fds {
*i = FdSet::empty();
}
loop {
if (trg - TimeSpec::now()).to_ns() == 0 {
break;
} else {
suspend_current_and_run_next();
}
}
}
None => loop {},
}
}
if has_mask {
sigprocmask(
SigMaskHow::SIG_SETMASK.bits(),
oldsig,
null_mut::<Signals>(),
);
}
log::warn!("[pselect] quiting pselect. {}", ret);
// look up according to TimeVal
ret as isize
}