123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- //! sys/select.h implementation
- use core::mem;
- use fs::File;
- use header::errno;
- use header::sys_epoll::{
- epoll_create1, EPOLL_CLOEXEC,
- epoll_ctl, EPOLL_CTL_ADD,
- epoll_wait,
- EPOLLIN, EPOLLOUT, EPOLLERR,
- epoll_data, epoll_event
- };
- use header::sys_time::timeval;
- use platform;
- use platform::types::*;
- // fd_set is also defined in C because cbindgen is incompatible with mem::size_of booo
- pub const FD_SETSIZE: usize = 1024;
- #[repr(C)]
- pub struct fd_set {
- pub fds_bits: [c_ulong; FD_SETSIZE / (8 * mem::size_of::<c_ulong>())],
- }
- impl fd_set {
- fn index(fd: c_int) -> usize {
- (fd as usize) / (8 * mem::size_of::<c_ulong>())
- }
- fn bitmask(fd: c_int) -> c_ulong {
- 1 << ((fd as usize) & (8 * mem::size_of::<c_ulong>() - 1)) as c_ulong
- }
- fn zero(&mut self) {
- for i in 0..self.fds_bits.len() {
- self.fds_bits[i] = 0;
- }
- }
- fn set(&mut self, fd: c_int) {
- self.fds_bits[Self::index(fd)] |= Self::bitmask(fd);
- }
- fn clr(&mut self, fd: c_int) {
- self.fds_bits[Self::index(fd)] &= !Self::bitmask(fd);
- }
- fn isset(&self, fd: c_int) -> bool {
- self.fds_bits[Self::index(fd)] & Self::bitmask(fd) > 0
- }
- }
- pub fn select_epoll(
- nfds: c_int,
- mut readfds: Option<&mut fd_set>,
- mut writefds: Option<&mut fd_set>,
- mut exceptfds: Option<&mut fd_set>,
- timeout: Option<&mut timeval>
- ) -> c_int {
- if nfds < 0 || nfds > FD_SETSIZE as i32 {
- unsafe { platform::errno = errno::EINVAL };
- return -1;
- };
- let ep = {
- let epfd = epoll_create1(EPOLL_CLOEXEC);
- if epfd < 0 {
- return -1;
- }
- File::new(epfd)
- };
- for fd in 0..nfds {
- if let Some(ref fd_set) = readfds {
- if fd_set.isset(fd) {
- let mut event = epoll_event {
- events: EPOLLIN,
- data: epoll_data {
- fd: fd,
- },
- };
- if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
- return -1;
- }
- }
- }
- if let Some(ref fd_set) = writefds {
- if fd_set.isset(fd) {
- let mut event = epoll_event {
- events: EPOLLOUT,
- data: epoll_data {
- fd: fd,
- },
- };
- if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
- return -1;
- }
- }
- }
- if let Some(ref fd_set) = exceptfds {
- if fd_set.isset(fd) {
- let mut event = epoll_event {
- events: EPOLLERR,
- data: epoll_data {
- fd: fd,
- },
- };
- if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
- return -1;
- }
- }
- }
- }
- let mut events: [epoll_event; 32] = unsafe { mem::zeroed() };
- let res = epoll_wait(
- *ep,
- events.as_mut_ptr(),
- events.len() as c_int,
- match timeout {
- Some(timeout) => {
- //TODO: Check for overflow
- ((timeout.tv_sec as c_int) * 1000) +
- ((timeout.tv_usec as c_int) / 1000)
- },
- None => -1
- }
- );
- if res < 0 {
- return -1;
- }
- if let Some(ref mut fd_set) = readfds {
- fd_set.zero();
- }
- if let Some(ref mut fd_set) = writefds {
- fd_set.zero();
- }
- if let Some(ref mut fd_set) = exceptfds {
- fd_set.zero();
- }
- let mut count = 0;
- for i in 0..res as usize {
- let event = &events[i];
- let fd = unsafe { event.data.fd };
- // TODO: Error status when fd does not match?
- if fd >= 0 && fd <= FD_SETSIZE as c_int {
- if event.events & EPOLLIN > 0 {
- if let Some(ref mut fd_set) = readfds {
- fd_set.set(fd);
- count += 1;
- }
- }
- if event.events & EPOLLOUT > 0 {
- if let Some(ref mut fd_set) = writefds {
- fd_set.set(fd);
- count += 1;
- }
- }
- if event.events & EPOLLERR > 0 {
- if let Some(ref mut fd_set) = exceptfds {
- fd_set.set(fd);
- count += 1;
- }
- }
- }
- }
- count
- }
- #[no_mangle]
- pub unsafe extern "C" fn select(
- nfds: c_int,
- readfds: *mut fd_set,
- writefds: *mut fd_set,
- exceptfds: *mut fd_set,
- timeout: *mut timeval,
- ) -> c_int {
- trace_expr!(
- select_epoll(
- nfds,
- if readfds.is_null() {
- None
- } else {
- Some(&mut *readfds)
- },
- if writefds.is_null() {
- None
- } else {
- Some(&mut *writefds)
- },
- if exceptfds.is_null() {
- None
- } else {
- Some(&mut *exceptfds)
- },
- if timeout.is_null() {
- None
- } else {
- Some(&mut *timeout)
- }
- ),
- "select({}, {:p}, {:p}, {:p}, {:p})",
- nfds,
- readfds,
- writefds,
- exceptfds,
- timeout
- )
- }
|