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
}