(index<- )        ./libstd/io/test.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Sat Apr 19 11:22:39 2014
   1  // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /*! Various utility functions useful for writing I/O tests */
  12  
  13  #![macro_escape]
  14  
  15  use libc;
  16  use os;
  17  use prelude::*;
  18  use std::io::net::ip::*;
  19  use sync::atomics::{AtomicUint, INIT_ATOMIC_UINT, Relaxed};
  20  
  21  macro_rules! iotest (
  22      { fn $name:ident() $b:block $(#[$a:meta])} => (
  23          mod $name {
  24              #![allow(unused_imports)]
  25  
  26              use super::super::*;
  27              use super::*;
  28              use io;
  29              use prelude::*;
  30              use io::*;
  31              use io::fs::*;
  32              use io::test::*;
  33              use io::net::tcp::*;
  34              use io::net::ip::*;
  35              use io::net::udp::*;
  36              #[cfg(unix)]
  37              use io::net::unix::*;
  38              use io::timer::*;
  39              use io::process::*;
  40              use unstable::running_on_valgrind;
  41              use str;
  42  
  43              fn f() $b
  44  
  45              $(#[$a])* #[test] fn green() { f() }
  46              $(#[$a])* #[test] fn native() {
  47                  use native;
  48                  let (tx, rx) = channel();
  49                  native::task::spawn(proc() { tx.send(f()) });
  50                  rx.recv();
  51              }
  52          }
  53      )
  54  )
  55  
  56  /// Get a port number, starting at 9600, for use in tests
  57  pub fn next_test_port() -> u16 {
  58      static mut next_offset: AtomicUint = INIT_ATOMIC_UINT;
  59      unsafe {
  60          base_port() + next_offset.fetch_add(1, Relaxed) as u16
  61      }
  62  }
  63  
  64  /// Get a temporary path which could be the location of a unix socket
  65  pub fn next_test_unix() -> Path {
  66      static mut COUNT: AtomicUint = INIT_ATOMIC_UINT;
  67      // base port and pid are an attempt to be unique between multiple
  68      // test-runners of different configurations running on one
  69      // buildbot, the count is to be unique within this executable.
  70      let string = format!("rust-test-unix-path-{}-{}-{}",
  71                           base_port(),
  72                           unsafe {libc::getpid()},
  73                           unsafe {COUNT.fetch_add(1, Relaxed)});
  74      if cfg!(unix) {
  75          os::tmpdir().join(string)
  76      } else {
  77          Path::new(r"\\.\pipe\" + string)
  78      }
  79  }
  80  
  81  /// Get a unique IPv4 localhost:port pair starting at 9600
  82  pub fn next_test_ip4() -> SocketAddr {
  83      SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() }
  84  }
  85  
  86  /// Get a unique IPv6 localhost:port pair starting at 9600
  87  pub fn next_test_ip6() -> SocketAddr {
  88      SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), port: next_test_port() }
  89  }
  90  
  91  /*
  92  XXX: Welcome to MegaHack City.
  93  
  94  The bots run multiple builds at the same time, and these builds
  95  all want to use ports. This function figures out which workspace
  96  it is running in and assigns a port range based on it.
  97  */
  98  fn base_port() -> u16 {
  99  
 100      let base = 9600u16;
 101      let range = 1000u16;
 102  
 103      let bases = [
 104          ("32-opt", base + range * 1),
 105          ("32-nopt", base + range * 2),
 106          ("64-opt", base + range * 3),
 107          ("64-nopt", base + range * 4),
 108          ("64-opt-vg", base + range * 5),
 109          ("all-opt", base + range * 6),
 110          ("snap3", base + range * 7),
 111          ("dist", base + range * 8)
 112      ];
 113  
 114      // FIXME (#9639): This needs to handle non-utf8 paths
 115      let path = os::getcwd();
 116      let path_s = path.as_str().unwrap();
 117  
 118      let mut final_base = base;
 119  
 120      for &(dir, base) in bases.iter() {
 121          if path_s.contains(dir) {
 122              final_base = base;
 123              break;
 124          }
 125      }
 126  
 127      return final_base;
 128  }
 129  
 130  /// Raises the file descriptor limit when running tests if necessary
 131  pub fn raise_fd_limit() {
 132      unsafe { darwin_fd_limit::raise_fd_limit() }
 133  }
 134  
 135  #[cfg(target_os="macos")]
 136  #[allow(non_camel_case_types)]
 137  mod darwin_fd_limit {
 138      /*!
 139       * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the
 140       * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low
 141       * for our multithreaded scheduler testing, depending on the number of cores available.
 142       *
 143       * This fixes issue #7772.
 144       */
 145  
 146      use libc;
 147      type rlim_t = libc::uint64_t;
 148      struct rlimit {
 149          rlim_cur: rlim_t,
 150          rlim_max: rlim_t
 151      }
 152      extern {
 153          // name probably doesn't need to be mut, but the C function doesn't specify const
 154          fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
 155                    oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
 156                    newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
 157          fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
 158          fn setrlimit(resource: libc::c_int, rlp: *rlimit) -> libc::c_int;
 159      }
 160      static CTL_KERN: libc::c_int = 1;
 161      static KERN_MAXFILESPERPROC: libc::c_int = 29;
 162      static RLIMIT_NOFILE: libc::c_int = 8;
 163  
 164      pub unsafe fn raise_fd_limit() {
 165          // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
 166          // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
 167          use ptr::mut_null;
 168          use mem::size_of_val;
 169          use os::last_os_error;
 170  
 171          // Fetch the kern.maxfilesperproc value
 172          let mut mib: [libc::c_int, ..2] = [CTL_KERN, KERN_MAXFILESPERPROC];
 173          let mut maxfiles: libc::c_int = 0;
 174          let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
 175          if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
 176                    mut_null(), 0) != 0 {
 177              let err = last_os_error();
 178              fail!("raise_fd_limit: error calling sysctl: {}", err);
 179          }
 180  
 181          // Fetch the current resource limits
 182          let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
 183          if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
 184              let err = last_os_error();
 185              fail!("raise_fd_limit: error calling getrlimit: {}", err);
 186          }
 187  
 188          // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit
 189          rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max);
 190  
 191          // Set our newly-increased resource limit
 192          if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
 193              let err = last_os_error();
 194              fail!("raise_fd_limit: error calling setrlimit: {}", err);
 195          }
 196      }
 197  }
 198  
 199  #[cfg(not(target_os="macos"))]
 200  mod darwin_fd_limit {
 201      pub unsafe fn raise_fd_limit() {}
 202  }