]> git.lizzy.rs Git - rust.git/commitdiff
Add supporting for vxWorks
authorBaoshan Pang <baoshan.pang@windriver.com>
Tue, 16 Jul 2019 06:57:53 +0000 (23:57 -0700)
committerBaoshan Pang <baoshan.pang@windriver.com>
Tue, 16 Jul 2019 07:13:07 +0000 (00:13 -0700)
r? @alexcrichton

69 files changed:
src/bootstrap/cc_detect.rs
src/librustc_target/spec/aarch64_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/arm_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/arm_wrs_vxworks_sf.rs [new file with mode: 0644]
src/librustc_target/spec/armv7_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/i586_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/i686_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/i686_wrs_vxworks_gnu.rs [new file with mode: 0644]
src/librustc_target/spec/mod.rs
src/librustc_target/spec/powerpc64_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/powerpc64_wrs_vxworks_gnusf.rs [new file with mode: 0644]
src/librustc_target/spec/powerpc_wrs_vxworks.rs [new file with mode: 0644]
src/librustc_target/spec/powerpc_wrs_vxworks_gnusf.rs [new file with mode: 0644]
src/librustc_target/spec/powerpc_wrs_vxworks_gnuspesf.rs [new file with mode: 0644]
src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs [new file with mode: 0644]
src/librustc_target/spec/vxworks_base.rs [new file with mode: 0644]
src/librustc_target/spec/x86_64_wrs_vxworks.rs [new file with mode: 0644]
src/libstd/os/mod.rs
src/libstd/os/raw/mod.rs
src/libstd/os/vxworks/fs.rs [new file with mode: 0644]
src/libstd/os/vxworks/mod.rs [new file with mode: 0644]
src/libstd/os/vxworks/raw.rs [new file with mode: 0644]
src/libstd/sys/mod.rs
src/libstd/sys/vxworks/alloc.rs [new file with mode: 0644]
src/libstd/sys/vxworks/android.rs [new file with mode: 0644]
src/libstd/sys/vxworks/args.rs [new file with mode: 0644]
src/libstd/sys/vxworks/backtrace/mod.rs [new file with mode: 0644]
src/libstd/sys/vxworks/backtrace/printing/dladdr.rs [new file with mode: 0644]
src/libstd/sys/vxworks/backtrace/printing/mod.rs [new file with mode: 0644]
src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs [new file with mode: 0644]
src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs [new file with mode: 0644]
src/libstd/sys/vxworks/backtrace/tracing/mod.rs [new file with mode: 0644]
src/libstd/sys/vxworks/cmath.rs [new file with mode: 0644]
src/libstd/sys/vxworks/condvar.rs [new file with mode: 0644]
src/libstd/sys/vxworks/env.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/ffi.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/fs.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/io.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/mod.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/net.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/process.rs [new file with mode: 0644]
src/libstd/sys/vxworks/ext/raw.rs [new file with mode: 0644]
src/libstd/sys/vxworks/fast_thread_local.rs [new file with mode: 0644]
src/libstd/sys/vxworks/fd.rs [new file with mode: 0644]
src/libstd/sys/vxworks/fs.rs [new file with mode: 0644]
src/libstd/sys/vxworks/io.rs [new file with mode: 0644]
src/libstd/sys/vxworks/l4re.rs [new file with mode: 0644]
src/libstd/sys/vxworks/memchr.rs [new file with mode: 0644]
src/libstd/sys/vxworks/mod.rs [new file with mode: 0644]
src/libstd/sys/vxworks/mutex.rs [new file with mode: 0644]
src/libstd/sys/vxworks/net.rs [new file with mode: 0644]
src/libstd/sys/vxworks/os.rs [new file with mode: 0644]
src/libstd/sys/vxworks/path.rs [new file with mode: 0644]
src/libstd/sys/vxworks/pipe.rs [new file with mode: 0644]
src/libstd/sys/vxworks/process/mod.rs [new file with mode: 0644]
src/libstd/sys/vxworks/process/process_common.rs [new file with mode: 0644]
src/libstd/sys/vxworks/process/process_vxworks.rs [new file with mode: 0644]
src/libstd/sys/vxworks/process/rtp.rs [new file with mode: 0644]
src/libstd/sys/vxworks/rand.rs [new file with mode: 0644]
src/libstd/sys/vxworks/rwlock.rs [new file with mode: 0644]
src/libstd/sys/vxworks/stack_overflow.rs [new file with mode: 0644]
src/libstd/sys/vxworks/stdio.rs [new file with mode: 0644]
src/libstd/sys/vxworks/thread.rs [new file with mode: 0644]
src/libstd/sys/vxworks/thread_local.rs [new file with mode: 0644]
src/libstd/sys/vxworks/time.rs [new file with mode: 0644]
src/libstd/sys/vxworks/weak.rs [new file with mode: 0644]
src/libtest/lib.rs
src/tools/compiletest/src/runtest.rs
src/tools/compiletest/src/util.rs

index 400375cd201c4dca8a8579a3f9c170b2d24f4404..c58a98bac36783dccffe786a65c76f1d8a2b14f0 100644 (file)
@@ -45,6 +45,8 @@ fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
         Some(PathBuf::from("ar"))
     } else if target.contains("openbsd") {
         Some(PathBuf::from("ar"))
+    } else if target.contains("vxworks") {
+        Some(PathBuf::from("vx-ar"))
     } else {
         let parent = cc.parent().unwrap();
         let file = cc.file_name().unwrap().to_str().unwrap();
diff --git a/src/librustc_target/spec/aarch64_wrs_vxworks.rs b/src/librustc_target/spec/aarch64_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..6ad6632
--- /dev/null
@@ -0,0 +1,24 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.max_atomic_width = Some(128);
+
+    Ok(Target {
+        llvm_target: "aarch64-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        target_env: "gnu".to_string(),
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: "aarch64".to_string(),
+        target_os: "vxworks".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            target_mcount: "\u{1}_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/arm_wrs_vxworks.rs b/src/librustc_target/spec/arm_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..7db587d
--- /dev/null
@@ -0,0 +1,32 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+// This target is for glibc Linux on ARMv7 without NEON or
+// thumb-mode. See the thumbv7neon variant for enabling both.
+
+pub fn target() -> TargetResult {
+    let base = super::vxworks_base::opts();
+    Ok(Target {
+        llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+
+        options: TargetOptions {
+            // Info about features at https://wiki.debian.org/ArmHardFloatPort
+            features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(),
+            cpu: "generic".to_string(),
+            max_atomic_width: Some(64),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+//          tls_model: "local-exec".to_string(),
+            position_independent_executables: false,
+            .. base
+        }
+    })
+}
diff --git a/src/librustc_target/spec/arm_wrs_vxworks_sf.rs b/src/librustc_target/spec/arm_wrs_vxworks_sf.rs
new file mode 100644 (file)
index 0000000..bde903d
--- /dev/null
@@ -0,0 +1,25 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.max_atomic_width = Some(64);
+    Ok(Target {
+        llvm_target: "arm-unknown-linux-gnueabi".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+
+        options: TargetOptions {
+            features: "+strict-align,+v6".to_string(),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/armv7_wrs_vxworks.rs b/src/librustc_target/spec/armv7_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..7db587d
--- /dev/null
@@ -0,0 +1,32 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+// This target is for glibc Linux on ARMv7 without NEON or
+// thumb-mode. See the thumbv7neon variant for enabling both.
+
+pub fn target() -> TargetResult {
+    let base = super::vxworks_base::opts();
+    Ok(Target {
+        llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+
+        options: TargetOptions {
+            // Info about features at https://wiki.debian.org/ArmHardFloatPort
+            features: "+v7,+vfp3,+d16,+thumb2,-neon".to_string(),
+            cpu: "generic".to_string(),
+            max_atomic_width: Some(64),
+            abi_blacklist: super::arm_base::abi_blacklist(),
+            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+//          tls_model: "local-exec".to_string(),
+            position_independent_executables: false,
+            .. base
+        }
+    })
+}
diff --git a/src/librustc_target/spec/i586_wrs_vxworks.rs b/src/librustc_target/spec/i586_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..355250e
--- /dev/null
@@ -0,0 +1,8 @@
+use crate::spec::TargetResult;
+
+pub fn target() -> TargetResult {
+    let mut base = super::i686_wrs_vxworks::target()?;
+    base.options.cpu = "pentium".to_string();
+    base.llvm_target = "i586-unknown-linux-gnu".to_string();
+    Ok(base)
+}
diff --git a/src/librustc_target/spec/i686_wrs_vxworks.rs b/src/librustc_target/spec/i686_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..4b1ff5c
--- /dev/null
@@ -0,0 +1,23 @@
+use crate::spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.cpu = "pentium4".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.stack_probes = true;
+
+    Ok(Target {
+        llvm_target: "i686-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        arch: "x86".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}
diff --git a/src/librustc_target/spec/i686_wrs_vxworks_gnu.rs b/src/librustc_target/spec/i686_wrs_vxworks_gnu.rs
new file mode 100644 (file)
index 0000000..4b1ff5c
--- /dev/null
@@ -0,0 +1,23 @@
+use crate::spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.cpu = "pentium4".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.stack_probes = true;
+
+    Ok(Target {
+        llvm_target: "i686-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128".to_string(),
+        arch: "x86".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}
index 3054ffabb4f1f21745d703f6606545ec56ca55b8..1fdc9b015ba395e4ed93c5439c8cd32bdfc0a798 100644 (file)
@@ -66,6 +66,7 @@
 mod redox_base;
 mod riscv_base;
 mod wasm32_base;
+mod vxworks_base;
 
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash,
          RustcEncodable, RustcDecodable)]
@@ -361,7 +362,6 @@ fn $module() {
     ("thumbv7neon-unknown-linux-gnueabihf", thumbv7neon_unknown_linux_gnueabihf),
     ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
     ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
-
     ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl),
     ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
     ("i686-unknown-linux-musl", i686_unknown_linux_musl),
@@ -476,6 +476,15 @@ fn $module() {
     ("x86_64-unknown-uefi", x86_64_unknown_uefi),
 
     ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda),
+
+    ("x86_64-wrs-vxworks", x86_64_wrs_vxworks),
+    ("i686-wrs-vxworks", i686_wrs_vxworks),
+    ("i586-wrs-vxworks", i586_wrs_vxworks),
+    ("armv7-wrs-vxworks", armv7_wrs_vxworks),
+    ("aarch64-wrs-vxworks", aarch64_wrs_vxworks),
+    ("powerpc-wrs-vxworks", powerpc_wrs_vxworks),
+    ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
+    ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
 }
 
 /// Everything `rustc` knows about how to compile for a specific target.
diff --git a/src/librustc_target/spec/powerpc64_wrs_vxworks.rs b/src/librustc_target/spec/powerpc64_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..a952070
--- /dev/null
@@ -0,0 +1,25 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.cpu = "ppc64".to_string();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    base.max_atomic_width = Some(64);
+
+    Ok(Target {
+        llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64".to_string(),
+        arch: "powerpc64".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            target_mcount: "_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/powerpc64_wrs_vxworks_gnusf.rs b/src/librustc_target/spec/powerpc64_wrs_vxworks_gnusf.rs
new file mode 100644 (file)
index 0000000..c2dae85
--- /dev/null
@@ -0,0 +1,26 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.cpu = "ppc64".to_string();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    base.max_atomic_width = Some(64);
+
+    Ok(Target {
+        llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-i64:64-n32:64".to_string(),
+        arch: "powerpc64".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "unknown".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            features: "-hard-float".to_string(),
+            target_mcount: "_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks.rs b/src/librustc_target/spec/powerpc_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..2e833ee
--- /dev/null
@@ -0,0 +1,26 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
+    base.max_atomic_width = Some(32);
+
+    Ok(Target {
+        llvm_target: "powerpc-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+        arch: "powerpc".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "wrs".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            features: "+secure-plt".to_string(),
+            target_mcount: "_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks_gnusf.rs b/src/librustc_target/spec/powerpc_wrs_vxworks_gnusf.rs
new file mode 100644 (file)
index 0000000..43723ea
--- /dev/null
@@ -0,0 +1,26 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
+    base.max_atomic_width = Some(32);
+
+    Ok(Target {
+        llvm_target: "powerpc-unknown-linux-gnu".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+        arch: "powerpc".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "wrs".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            features: "+secure-plt,-hard-float".to_string(),
+            target_mcount: "_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks_gnuspesf.rs b/src/librustc_target/spec/powerpc_wrs_vxworks_gnuspesf.rs
new file mode 100644 (file)
index 0000000..8f23623
--- /dev/null
@@ -0,0 +1,27 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
+    base.max_atomic_width = Some(32);
+
+    Ok(Target {
+        llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+        arch: "powerpc".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "wrs".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            // feature msync would disable instruction 'fsync' which is not supported by fsl_p1p2
+            features: "+secure-plt,+msync,-hard-float".to_string(),
+            target_mcount: "_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs b/src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs
new file mode 100644 (file)
index 0000000..2305b4b
--- /dev/null
@@ -0,0 +1,27 @@
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
+    base.max_atomic_width = Some(32);
+
+    Ok(Target {
+        llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
+        target_endian: "big".to_string(),
+        target_pointer_width: "32".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+        arch: "powerpc".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "wrs".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: TargetOptions {
+            // feature msync would disable instruction 'fsync' which is not supported by fsl_p1p2
+            features: "+secure-plt,+msync".to_string(),
+            target_mcount: "_mcount".to_string(),
+            .. base
+        },
+    })
+}
diff --git a/src/librustc_target/spec/vxworks_base.rs b/src/librustc_target/spec/vxworks_base.rs
new file mode 100644 (file)
index 0000000..6db56c5
--- /dev/null
@@ -0,0 +1,41 @@
+use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel};
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+    let mut args = LinkArgs::new();
+    args.insert(LinkerFlavor::Gcc, vec![
+        // We want to be able to strip as much executable code as possible
+        // from the linker command line, and this flag indicates to the
+        // linker that it can avoid linking in dynamic libraries that don't
+        // actually satisfy any symbols up to that point (as with many other
+        // resolutions the linker does). This option only applies to all
+        // following libraries so we're sure to pass it as one of the first
+        // arguments.
+        "-Wl,--as-needed".to_string(),
+
+        // Always enable NX protection when it is available
+        "-Wl,-z,noexecstack".to_string(),
+    ]);
+
+    let mut late_lk_args = LinkArgs::new();
+    late_lk_args.insert(LinkerFlavor::Gcc, vec![
+        "-lnet".to_string(),
+        "-lunix".to_string(),
+    ]);
+
+    TargetOptions {
+        linker: Some("vx-cxx".to_string()),
+        exe_suffix: ".vxe".to_string(),
+        late_link_args: late_lk_args,
+        dynamic_linking: true,
+        executables: true,
+        target_family: Some("unix".to_string()),
+        linker_is_gnu: true,
+        has_rpath: true,
+        pre_link_args: args,
+        position_independent_executables: true,
+        relro_level: RelroLevel::Full,
+        has_elf_tls: true,
+        .. Default::default()
+    }
+}
diff --git a/src/librustc_target/spec/x86_64_wrs_vxworks.rs b/src/librustc_target/spec/x86_64_wrs_vxworks.rs
new file mode 100644 (file)
index 0000000..eac7cd7
--- /dev/null
@@ -0,0 +1,23 @@
+use crate::spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+    let mut base = super::vxworks_base::opts();
+    base.cpu = "x86-64".to_string();
+    base.max_atomic_width = Some(64);
+    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    base.stack_probes = true;
+
+    Ok(Target {
+        llvm_target: "x86_64-unknown-linux-gnu".to_string(),
+        target_endian: "little".to_string(),
+        target_pointer_width: "64".to_string(),
+        target_c_int_width: "32".to_string(),
+        data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+        arch: "x86_64".to_string(),
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "wrs".to_string(),
+        linker_flavor: LinkerFlavor::Gcc,
+        options: base,
+    })
+}
index 94e8b7805cf933325615e09a16bb6ed25aaae65b..c9aa5f4de95531b921b59232dee744298b797cba 100644 (file)
@@ -24,7 +24,7 @@
         // If we're not documenting libstd then we just expose the main modules
         // as we otherwise would.
 
-        #[cfg(any(target_os = "redox", unix))]
+        #[cfg(any(target_os = "redox", unix, target_os = "vxworks"))]
         #[stable(feature = "rust1", since = "1.0.0")]
         pub use crate::sys::ext as unix;
 
@@ -51,6 +51,7 @@
 #[cfg(target_os = "fuchsia")]    pub mod fuchsia;
 #[cfg(target_os = "hermit")]     pub mod hermit;
 #[cfg(target_os = "wasi")]       pub mod wasi;
+#[cfg(target_os = "vxworks")]    pub mod vxworks;
 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx;
 
 pub mod raw;
index e9043b4b40d73d0474f265e9505f6ef4ce355a56..c0b0b6d40d891a742ff08dfa8841843ec96ce4da 100644 (file)
                                         target_arch = "arm",
                                         target_arch = "powerpc")),
           all(target_os = "openbsd", target_arch = "aarch64"),
+          all(target_os = "vxworks", any(target_arch = "aarch64",
+                                         target_arch = "arm",
+                                         target_arch = "powerpc64",
+                                         target_arch = "powerpc")),
           all(target_os = "fuchsia", target_arch = "aarch64")))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
 #[doc(include = "os/raw/char.md")]
                                             target_arch = "arm",
                                             target_arch = "powerpc")),
               all(target_os = "openbsd", target_arch = "aarch64"),
+              all(target_os = "vxworks", any(target_arch = "aarch64",
+                                             target_arch = "arm",
+                                             target_arch = "powerpc64",
+                                             target_arch = "powerpc")),
               all(target_os = "fuchsia", target_arch = "aarch64"))))]
 #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
 #[doc(include = "os/raw/schar.md")]
diff --git a/src/libstd/os/vxworks/fs.rs b/src/libstd/os/vxworks/fs.rs
new file mode 100644 (file)
index 0000000..57ab4fb
--- /dev/null
@@ -0,0 +1,84 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_dev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ino(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mode(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_nlink(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_uid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_gid(&self) -> u32;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_rdev(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_size(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_atime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_mtime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_ctime(&self) -> i64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blksize(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_blocks(&self) -> u64;
+    #[stable(feature = "metadata_ext2", since = "1.8.0")]
+    fn st_attrib(&self) -> u8;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+    fn st_dev(&self) -> u64 {
+        self.as_inner().as_inner().st_dev as u64
+    }
+    fn st_ino(&self) -> u64 {
+        self.as_inner().as_inner().st_ino as u64
+    }
+    fn st_mode(&self) -> u32 {
+        self.as_inner().as_inner().st_mode as u32
+    }
+    fn st_nlink(&self) -> u64 {
+        self.as_inner().as_inner().st_nlink as u64
+    }
+    fn st_uid(&self) -> u32 {
+        self.as_inner().as_inner().st_uid as u32
+    }
+    fn st_gid(&self) -> u32 {
+        self.as_inner().as_inner().st_gid as u32
+    }
+    fn st_rdev(&self) -> u64 {
+        self.as_inner().as_inner().st_rdev as u64
+    }
+    fn st_size(&self) -> u64 {
+        self.as_inner().as_inner().st_size as u64
+    }
+    fn st_atime(&self) -> i64 {
+        self.as_inner().as_inner().st_atime as i64
+    }
+    fn st_mtime(&self) -> i64 {
+        self.as_inner().as_inner().st_mtime as i64
+    }
+    fn st_ctime(&self) -> i64 {
+        self.as_inner().as_inner().st_ctime as i64
+    }
+    fn st_blksize(&self) -> u64 {
+        self.as_inner().as_inner().st_blksize as u64
+    }
+    fn st_blocks(&self) -> u64 {
+        self.as_inner().as_inner().st_blocks as u64
+    }
+    fn st_attrib(&self) -> u8 {
+        self.as_inner().as_inner().st_attrib as u8
+    }
+}
diff --git a/src/libstd/os/vxworks/mod.rs b/src/libstd/os/vxworks/mod.rs
new file mode 100644 (file)
index 0000000..2255a10
--- /dev/null
@@ -0,0 +1,6 @@
+//! VxWorks-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod raw;
+pub mod fs;
diff --git a/src/libstd/os/vxworks/raw.rs b/src/libstd/os/vxworks/raw.rs
new file mode 100644 (file)
index 0000000..ae0560a
--- /dev/null
@@ -0,0 +1,7 @@
+//! VxWorks-specific raw type definitions
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::os::raw::{c_ulong};
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
index 21360e2e0f0286c8da5bcf8c16b30ddccd039018..35972b54e39d253a8d38b53367c6a67dc8bde99c 100644 (file)
 #![allow(missing_debug_implementations)]
 
 cfg_if::cfg_if! {
-    if #[cfg(unix)] {
+    if #[cfg(target_os = "vxworks")] {
+        mod vxworks;
+        pub use self::vxworks::*;
+    } else if #[cfg(unix)] {
         mod unix;
         pub use self::unix::*;
     } else if #[cfg(windows)] {
diff --git a/src/libstd/sys/vxworks/alloc.rs b/src/libstd/sys/vxworks/alloc.rs
new file mode 100644 (file)
index 0000000..c60d1b8
--- /dev/null
@@ -0,0 +1,83 @@
+use crate::ptr;
+use crate::sys_common::alloc::{MIN_ALIGN, realloc_fallback};
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+            libc::malloc(layout.size()) as *mut u8
+        } else {
+            aligned_malloc(&layout)
+        }
+    }
+
+    #[inline]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+            libc::calloc(layout.size(), 1) as *mut u8
+        } else {
+            let ptr = self.alloc(layout.clone());
+            if !ptr.is_null() {
+                ptr::write_bytes(ptr, 0, layout.size());
+            }
+            ptr
+        }
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        libc::free(ptr as *mut libc::c_void)
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+            libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+        } else {
+            realloc_fallback(self, ptr, layout, new_size)
+        }
+    }
+}
+
+#[cfg(any(target_os = "android",
+          target_os = "hermit",
+          target_os = "redox",
+          target_os = "solaris"))]
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+    // On android we currently target API level 9 which unfortunately
+    // doesn't have the `posix_memalign` API used below. Instead we use
+    // `memalign`, but this unfortunately has the property on some systems
+    // where the memory returned cannot be deallocated by `free`!
+    //
+    // Upon closer inspection, however, this appears to work just fine with
+    // Android, so for this platform we should be fine to call `memalign`
+    // (which is present in API level 9). Some helpful references could
+    // possibly be chromium using memalign [1], attempts at documenting that
+    // memalign + free is ok [2] [3], or the current source of chromium
+    // which still uses memalign on android [4].
+    //
+    // [1]: https://codereview.chromium.org/10796020/
+    // [2]: https://code.google.com/p/android/issues/detail?id=35391
+    // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+    // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+    //                                       /memory/aligned_memory.cc
+    libc::memalign(layout.align(), layout.size()) as *mut u8
+}
+
+#[cfg(not(any(target_os = "android",
+              target_os = "hermit",
+              target_os = "redox",
+              target_os = "solaris")))]
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+    let mut out = ptr::null_mut();
+    let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
+    if ret != 0 {
+        ptr::null_mut()
+    } else {
+        out as *mut u8
+    }
+}
diff --git a/src/libstd/sys/vxworks/android.rs b/src/libstd/sys/vxworks/android.rs
new file mode 100644 (file)
index 0000000..6774160
--- /dev/null
@@ -0,0 +1,160 @@
+//! Android ABI-compatibility module
+//!
+//! The ABI of Android has changed quite a bit over time, and libstd attempts to
+//! be both forwards and backwards compatible as much as possible. We want to
+//! always work with the most recent version of Android, but we also want to
+//! work with older versions of Android for whenever projects need to.
+//!
+//! Our current minimum supported Android version is `android-9`, e.g., Android
+//! with API level 9. We then in theory want to work on that and all future
+//! versions of Android!
+//!
+//! Some of the detection here is done at runtime via `dlopen` and
+//! introspection. Other times no detection is performed at all and we just
+//! provide a fallback implementation as some versions of Android we support
+//! don't have the function.
+//!
+//! You'll find more details below about why each compatibility shim is needed.
+
+#![cfg(target_os = "android")]
+
+use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
+use libc::{ftruncate, pread, pwrite};
+
+use crate::io;
+use super::{cvt, cvt_r};
+
+// The `log2` and `log2f` functions apparently appeared in android-18, or at
+// least you can see they're not present in the android-17 header [1] and they
+// are present in android-18 [2].
+//
+// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
+//                                       /android-17/arch-arm/usr/include/math.h
+// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
+//                                       /android-18/arch-arm/usr/include/math.h
+//
+// Note that these shims are likely less precise than directly calling `log2`,
+// but hopefully that should be enough for now...
+//
+// Note that mathematically, for any arbitrary `y`:
+//
+//      log_2(x) = log_y(x) / log_y(2)
+//               = log_y(x) / (1 / log_2(y))
+//               = log_y(x) * log_2(y)
+//
+// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
+// and get:
+//
+//      log_2(x) = ln(x) * log_2(e)
+
+#[cfg(not(test))]
+pub fn log2f32(f: f32) -> f32 {
+    f.ln() * crate::f32::consts::LOG2_E
+}
+
+#[cfg(not(test))]
+pub fn log2f64(f: f64) -> f64 {
+    f.ln() * crate::f64::consts::LOG2_E
+}
+
+// Back in the day [1] the `signal` function was just an inline wrapper
+// around `bsd_signal`, but starting in API level android-20 the `signal`
+// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
+// removed [3].
+//
+// Basically this means that if we want to be binary compatible with multiple
+// Android releases (oldest being 9 and newest being 21) then we need to check
+// for both symbols and not actually link against either.
+//
+// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
+//                                       /android-18/arch-arm/usr/include/signal.h
+// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
+//                                       /platforms/android-20/arch-arm
+//                                       /usr/include/signal.h
+// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
+//                                       /android-21/arch-arm/usr/include/signal.h
+pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
+    weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
+    weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);
+
+    let f = signal.get().or_else(|| bsd_signal.get());
+    let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
+    f(signum, handler)
+}
+
+// The `ftruncate64` symbol apparently appeared in android-12, so we do some
+// dynamic detection to see if we can figure out whether `ftruncate64` exists.
+//
+// If it doesn't we just fall back to `ftruncate`, generating an error for
+// too-large values.
+#[cfg(target_pointer_width = "32")]
+pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
+    weak!(fn ftruncate64(c_int, i64) -> c_int);
+
+    unsafe {
+        match ftruncate64.get() {
+            Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
+            None => {
+                if size > i32::max_value() as u64 {
+                    Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                       "cannot truncate >2GB"))
+                } else {
+                    cvt_r(|| ftruncate(fd, size as i32)).map(|_| ())
+                }
+            }
+        }
+    }
+}
+
+#[cfg(target_pointer_width = "64")]
+pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
+    unsafe {
+        cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
+    }
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    use crate::convert::TryInto;
+    weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
+    pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+        if let Ok(o) = offset.try_into() {
+            cvt(pread(fd, buf, count, o))
+        } else {
+            Err(io::Error::new(io::ErrorKind::InvalidInput,
+                               "cannot pread >2GB"))
+        }
+    })
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    use crate::convert::TryInto;
+    weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
+    pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+        if let Ok(o) = offset.try_into() {
+            cvt(pwrite(fd, buf, count, o))
+        } else {
+            Err(io::Error::new(io::ErrorKind::InvalidInput,
+                               "cannot pwrite >2GB"))
+        }
+    })
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    cvt(pread(fd, buf, count, offset))
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    cvt(pwrite(fd, buf, count, offset))
+}
diff --git a/src/libstd/sys/vxworks/args.rs b/src/libstd/sys/vxworks/args.rs
new file mode 100644 (file)
index 0000000..11c3cb7
--- /dev/null
@@ -0,0 +1,85 @@
+#![allow(dead_code)] // runtime init functions not used during testing
+use crate::ffi::OsString;
+use crate::marker::PhantomData;
+use crate::vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+    imp::args()
+}
+
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        self.iter.as_slice()
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+mod imp {
+    use crate::ptr;
+    use crate::ffi::{CStr, OsString};
+    use crate::marker::PhantomData;
+    use libc;
+    use super::Args;
+
+    use crate::sys_common::mutex::Mutex;
+
+    static mut ARGC: isize = 0;
+    static mut ARGV: *const *const u8 = ptr::null();
+    static LOCK: Mutex = Mutex::new();
+
+    pub unsafe fn init(argc: isize, argv: *const *const u8) {
+        let _guard = LOCK.lock();
+        ARGC = argc;
+        ARGV = argv;
+    }
+
+    pub unsafe fn cleanup() {
+        let _guard = LOCK.lock();
+        ARGC = 0;
+        ARGV = ptr::null();
+    }
+
+    pub fn args() -> Args {
+        Args {
+            iter: clone().into_iter(),
+            _dont_send_or_sync_me: PhantomData
+        }
+    }
+
+    fn clone() -> Vec<OsString> {
+        unsafe {
+            let _guard = LOCK.lock();
+            let ret = (0..ARGC).map(|i| {
+                let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
+                use crate::sys::vxworks::ext::ffi::OsStringExt;
+                OsStringExt::from_vec(cstr.to_bytes().to_vec())
+            }).collect();
+            return ret
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/backtrace/mod.rs b/src/libstd/sys/vxworks/backtrace/mod.rs
new file mode 100644 (file)
index 0000000..0887e5a
--- /dev/null
@@ -0,0 +1,110 @@
+/// Backtrace support built on libgcc with some extra OS-specific support
+///
+/// Some methods of getting a backtrace:
+///
+/// * The backtrace() functions on unix. It turns out this doesn't work very
+///   well for green threads on macOS, and the address to symbol portion of it
+///   suffers problems that are described below.
+///
+/// * Using libunwind. This is more difficult than it sounds because libunwind
+///   isn't installed everywhere by default. It's also a bit of a hefty library,
+///   so possibly not the best option. When testing, libunwind was excellent at
+///   getting both accurate backtraces and accurate symbols across platforms.
+///   This route was not chosen in favor of the next option, however.
+///
+/// * We're already using libgcc_s for exceptions in rust (triggering thread
+///   unwinding and running destructors on the stack), and it turns out that it
+///   conveniently comes with a function that also gives us a backtrace. All of
+///   these functions look like _Unwind_*, but it's not quite the full
+///   repertoire of the libunwind API. Due to it already being in use, this was
+///   the chosen route of getting a backtrace.
+///
+/// After choosing libgcc_s for backtraces, the sad part is that it will only
+/// give us a stack trace of instruction pointers. Thankfully these instruction
+/// pointers are accurate (they work for green and native threads), but it's
+/// then up to us again to figure out how to translate these addresses to
+/// symbols. As with before, we have a few options. Before, that, a little bit
+/// of an interlude about symbols. This is my very limited knowledge about
+/// symbol tables, and this information is likely slightly wrong, but the
+/// general idea should be correct.
+///
+/// When talking about symbols, it's helpful to know a few things about where
+/// symbols are located. Some symbols are located in the dynamic symbol table
+/// of the executable which in theory means that they're available for dynamic
+/// linking and lookup. Other symbols end up only in the local symbol table of
+/// the file. This loosely corresponds to pub and priv functions in Rust.
+///
+/// Armed with this knowledge, we know that our solution for address to symbol
+/// translation will need to consult both the local and dynamic symbol tables.
+/// With that in mind, here's our options of translating an address to
+/// a symbol.
+///
+/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
+///   behind the scenes to translate, and this is why backtrace() was not used.
+///   Conveniently, this method works fantastically on macOS. It appears dladdr()
+///   uses magic to consult the local symbol table, or we're putting everything
+///   in the dynamic symbol table anyway. Regardless, for macOS, this is the
+///   method used for translation. It's provided by the system and easy to do.o
+///
+///   Sadly, all other systems have a dladdr() implementation that does not
+///   consult the local symbol table. This means that most functions are blank
+///   because they don't have symbols. This means that we need another solution.
+///
+/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
+///   libgcc_s version of the libunwind api), but involves taking a dependency
+///   to libunwind. We may pursue this route in the future if we bundle
+///   libunwind, but libunwind was unwieldy enough that it was not chosen at
+///   this time to provide this functionality.
+///
+/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
+///   semi-reasonable solution. The stdlib already knows how to spawn processes,
+///   so in theory it could invoke readelf, parse the output, and consult the
+///   local/dynamic symbol tables from there. This ended up not getting chosen
+///   due to the craziness of the idea plus the advent of the next option.
+///
+/// * Use `libbacktrace`. It turns out that this is a small library bundled in
+///   the gcc repository which provides backtrace and symbol translation
+///   functionality. All we really need from it is the backtrace functionality,
+///   and we only really need this on everything that's not macOS, so this is the
+///   chosen route for now.
+///
+/// In summary, the current situation uses libgcc_s to get a trace of stack
+/// pointers, and we use dladdr() or libbacktrace to translate these addresses
+/// to symbols. This is a bit of a hokey implementation as-is, but it works for
+/// all unix platforms we support right now, so it at least gets the job done.
+
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+
+// tracing impls:
+mod tracing;
+// symbol resolvers:
+mod printing;
+
+#[cfg(not(target_os = "emscripten"))]
+pub mod gnu {
+    use crate::io;
+    use crate::fs;
+
+    use libc::c_char;
+
+    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+    pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+        Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+        use crate::env;
+        use crate::os::unix::ffi::OsStrExt;
+
+        let filename = env::current_exe()?;
+        let file = fs::File::open(&filename)?;
+        let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter()
+            .map(|&x| x as c_char).collect();
+        filename_cstr.push(0); // Null terminate
+        Ok((filename_cstr, file))
+    }
+}
+
+pub struct BacktraceContext;
diff --git a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs b/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs
new file mode 100644 (file)
index 0000000..202164d
--- /dev/null
@@ -0,0 +1,35 @@
+use crate::io;
+use crate::intrinsics;
+use crate::ffi::CStr;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+pub fn resolve_symname<F>(frame: Frame,
+                          callback: F,
+                          _: &BacktraceContext) -> io::Result<()>
+    where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    unsafe {
+        let mut info: Dl_info = intrinsics::init();
+        let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
+                         info.dli_sname.is_null() {
+            None
+        } else {
+            CStr::from_ptr(info.dli_sname).to_str().ok()
+        };
+        callback(symname)
+    }
+}
+
+#[repr(C)]
+struct Dl_info {
+    dli_fname: *const libc::c_char,
+    dli_fbase: *mut libc::c_void,
+    dli_sname: *const libc::c_char,
+    dli_saddr: *mut libc::c_void,
+}
+
+extern {
+    #[ link_name = "_rtld_dladdr" ]
+    fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
+}
diff --git a/src/libstd/sys/vxworks/backtrace/printing/mod.rs b/src/libstd/sys/vxworks/backtrace/printing/mod.rs
new file mode 100644 (file)
index 0000000..d090cae
--- /dev/null
@@ -0,0 +1,33 @@
+mod dladdr;
+
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+use crate::io;
+
+#[cfg(target_os = "emscripten")]
+pub use self::dladdr::resolve_symname;
+
+#[cfg(target_os = "emscripten")]
+pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
+where
+    F: FnMut(&[u8], u32) -> io::Result<()>
+{
+    Ok(false)
+}
+
+#[cfg(not(target_os = "emscripten"))]
+pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline;
+
+#[cfg(not(target_os = "emscripten"))]
+pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
+where
+    F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
+        if symname.is_some() {
+            callback(symname)
+        } else {
+            dladdr::resolve_symname(frame, callback, bc)
+        }
+    }, bc)
+}
diff --git a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs
new file mode 100644 (file)
index 0000000..a628d10
--- /dev/null
@@ -0,0 +1,39 @@
+/// As always - iOS on arm uses SjLj exceptions and
+/// _Unwind_Backtrace is even not available there. Still,
+/// backtraces could be extracted using a backtrace function,
+/// which thanks god is public
+///
+/// As mentioned in a huge comment block in `super::super`, backtrace
+/// doesn't play well with green threads, so while it is extremely nice and
+/// simple to use it should be used only on iOS devices as the only viable
+/// option.
+
+use crate::io;
+use crate::ptr;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    const FRAME_LEN: usize = 100;
+    assert!(FRAME_LEN >= frames.len());
+    let mut raw_frames = [ptr::null_mut(); FRAME_LEN];
+    let nb_frames = unsafe {
+        backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
+    } as usize;
+    for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
+        *to = Frame {
+            exact_position: *from as *mut u8,
+            symbol_addr: *from as *mut u8,
+            inline_context: 0,
+        };
+    }
+    Ok((nb_frames as usize, BacktraceContext))
+}
+
+extern {
+    fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
+}
diff --git a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs b/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs
new file mode 100644 (file)
index 0000000..e637913
--- /dev/null
@@ -0,0 +1,99 @@
+use crate::error::Error;
+use crate::fmt;
+use crate::io;
+use crate::sys::backtrace::BacktraceContext;
+use crate::sys_common::backtrace::Frame;
+
+use unwind as uw;
+
+struct Context<'a> {
+    idx: usize,
+    frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+    fn description(&self) -> &'static str {
+        "unexpected return value while unwinding"
+    }
+}
+
+impl fmt::Display for UnwindError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}: {:?}", self.description(), self.0)
+    }
+}
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+                 // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+    -> io::Result<(usize, BacktraceContext)>
+{
+    let mut cx = Context {
+        idx: 0,
+        frames,
+    };
+    let result_unwind = unsafe {
+        uw::_Unwind_Backtrace(trace_fn,
+                              &mut cx as *mut Context<'_>
+                              as *mut libc::c_void)
+    };
+    // See libunwind:src/unwind/Backtrace.c for the return values.
+    // No, there is no doc.
+    match result_unwind {
+        // These return codes seem to be benign and need to be ignored for backtraces
+        // to show up properly on all tested platforms.
+        uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+            Ok((cx.idx, BacktraceContext))
+        }
+        _ => {
+            Err(io::Error::new(io::ErrorKind::Other,
+                               UnwindError(result_unwind)))
+        }
+    }
+}
+
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+                   arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+    let cx = unsafe { &mut *(arg as *mut Context<'_>) };
+    if cx.idx >= cx.frames.len() {
+        return uw::_URC_NORMAL_STOP;
+    }
+
+    let mut ip_before_insn = 0;
+    let mut ip = unsafe {
+        uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+    };
+    if !ip.is_null() && ip_before_insn == 0 {
+        // this is a non-signaling frame, so `ip` refers to the address
+        // after the calling instruction. account for that.
+        ip = (ip as usize - 1) as *mut _;
+    }
+
+    // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+    // it appears to work fine without it, so we only use
+    // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+    // slightly more accurate stack trace in the process.
+    //
+    // This is often because panic involves the last instruction of a
+    // function being "call std::rt::begin_unwind", with no ret
+    // instructions after it. This means that the return instruction
+    // pointer points *outside* of the calling function, and by
+    // unwinding it we go back to the original function.
+    let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+        ip
+    } else {
+        unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+    };
+
+    cx.frames[cx.idx] = Frame {
+        symbol_addr: symaddr as *mut u8,
+        exact_position: ip as *mut u8,
+        inline_context: 0,
+    };
+    cx.idx += 1;
+
+    uw::_URC_NO_REASON
+}
diff --git a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs b/src/libstd/sys/vxworks/backtrace/tracing/mod.rs
new file mode 100644 (file)
index 0000000..11863e6
--- /dev/null
@@ -0,0 +1,8 @@
+pub use self::imp::*;
+
+#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
+#[path = "gcc_s.rs"]
+mod imp;
+#[cfg(all(target_os = "ios", target_arch = "arm"))]
+#[path = "backtrace_fn.rs"]
+mod imp;
diff --git a/src/libstd/sys/vxworks/cmath.rs b/src/libstd/sys/vxworks/cmath.rs
new file mode 100644 (file)
index 0000000..f6bb589
--- /dev/null
@@ -0,0 +1,33 @@
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+    pub fn acos(n: c_double) -> c_double;
+    pub fn acosf(n: c_float) -> c_float;
+    pub fn asin(n: c_double) -> c_double;
+    pub fn asinf(n: c_float) -> c_float;
+    pub fn atan(n: c_double) -> c_double;
+    pub fn atan2(a: c_double, b: c_double) -> c_double;
+    pub fn atan2f(a: c_float, b: c_float) -> c_float;
+    pub fn atanf(n: c_float) -> c_float;
+    pub fn cbrt(n: c_double) -> c_double;
+    pub fn cbrtf(n: c_float) -> c_float;
+    pub fn cosh(n: c_double) -> c_double;
+    pub fn coshf(n: c_float) -> c_float;
+    pub fn expm1(n: c_double) -> c_double;
+    pub fn expm1f(n: c_float) -> c_float;
+    pub fn fdim(a: c_double, b: c_double) -> c_double;
+    pub fn fdimf(a: c_float, b: c_float) -> c_float;
+    pub fn hypot(x: c_double, y: c_double) -> c_double;
+    pub fn hypotf(x: c_float, y: c_float) -> c_float;
+    pub fn log1p(n: c_double) -> c_double;
+    pub fn log1pf(n: c_float) -> c_float;
+    pub fn sinh(n: c_double) -> c_double;
+    pub fn sinhf(n: c_float) -> c_float;
+    pub fn tan(n: c_double) -> c_double;
+    pub fn tanf(n: c_float) -> c_float;
+    pub fn tanh(n: c_double) -> c_double;
+    pub fn tanhf(n: c_float) -> c_float;
+}
diff --git a/src/libstd/sys/vxworks/condvar.rs b/src/libstd/sys/vxworks/condvar.rs
new file mode 100644 (file)
index 0000000..4d22126
--- /dev/null
@@ -0,0 +1,169 @@
+use crate::cell::UnsafeCell;
+use crate::sys::mutex::{self, Mutex};
+use crate::time::Duration;
+
+pub struct Condvar { inner: UnsafeCell<libc::pthread_cond_t> }
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+const TIMESPEC_MAX: libc::timespec = libc::timespec {
+    tv_sec: <libc::time_t>::max_value(),
+    tv_nsec: 1_000_000_000 - 1,
+};
+
+fn saturating_cast_to_time_t(value: u64) -> libc::time_t {
+    if value > <libc::time_t>::max_value() as u64 {
+        <libc::time_t>::max_value()
+    } else {
+        value as libc::time_t
+    }
+}
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        // Might be moved and address is changing it is better to avoid
+        // initialization of potentially opaque OS data before it landed
+        Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) }
+    }
+
+    pub unsafe fn init(&mut self) {
+        use crate::mem::MaybeUninit;
+        let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit();
+        let r = libc::pthread_condattr_init(attr.as_mut_ptr());
+        assert_eq!(r, 0);
+        let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC);
+        assert_eq!(r, 0);
+        let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr());
+        assert_eq!(r, 0);
+        let r = libc::pthread_condattr_destroy(attr.as_mut_ptr());
+        assert_eq!(r, 0);
+    }
+
+    #[inline]
+    pub unsafe fn notify_one(&self) {
+        let r = libc::pthread_cond_signal(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+
+    #[inline]
+    pub unsafe fn notify_all(&self) {
+        let r = libc::pthread_cond_broadcast(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+
+    #[inline]
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex));
+        debug_assert_eq!(r, 0);
+    }
+
+    // This implementation is used on systems that support pthread_condattr_setclock
+    // where we configure condition variable to use monotonic clock (instead of
+    // default system clock). This approach avoids all problems that result
+    // from changes made to the system time.
+    #[cfg(not(any(target_os = "macos",
+                  target_os = "ios",
+                  target_os = "android",
+                  target_os = "hermit")))]
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        use crate::mem;
+
+        let mut now: libc::timespec = mem::zeroed();
+        let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now);
+        assert_eq!(r, 0);
+
+        // Nanosecond calculations can't overflow because both values are below 1e9.
+        let nsec = dur.subsec_nanos() + now.tv_nsec as u32;
+
+        let sec = saturating_cast_to_time_t(dur.as_secs())
+            .checked_add((nsec / 1_000_000_000) as libc::time_t)
+            .and_then(|s| s.checked_add(now.tv_sec));
+        let nsec = nsec % 1_000_000_000;
+
+        let timeout = sec.map(|s| {
+            libc::timespec { tv_sec: s, tv_nsec: nsec as _}
+        }).unwrap_or(TIMESPEC_MAX);
+
+        let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
+                                            &timeout);
+        assert!(r == libc::ETIMEDOUT || r == 0);
+        r == 0
+    }
+
+
+    // This implementation is modeled after libcxx's condition_variable
+    // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
+    // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
+        use crate::ptr;
+        use crate::time::Instant;
+
+        // 1000 years
+        let max_dur = Duration::from_secs(1000 * 365 * 86400);
+
+        if dur > max_dur {
+            // OSX implementation of `pthread_cond_timedwait` is buggy
+            // with super long durations. When duration is greater than
+            // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
+            // in macOS Sierra return error 316.
+            //
+            // This program demonstrates the issue:
+            // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
+            //
+            // To work around this issue, and possible bugs of other OSes, timeout
+            // is clamped to 1000 years, which is allowable per the API of `wait_timeout`
+            // because of spurious wakeups.
+
+            dur = max_dur;
+        }
+
+        // First, figure out what time it currently is, in both system and
+        // stable time.  pthread_cond_timedwait uses system time, but we want to
+        // report timeout based on stable time.
+        let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
+        let stable_now = Instant::now();
+        let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
+        debug_assert_eq!(r, 0);
+
+        let nsec = dur.subsec_nanos() as libc::c_long +
+                   (sys_now.tv_usec * 1000) as libc::c_long;
+        let extra = (nsec / 1_000_000_000) as libc::time_t;
+        let nsec = nsec % 1_000_000_000;
+        let seconds = saturating_cast_to_time_t(dur.as_secs());
+
+        let timeout = sys_now.tv_sec.checked_add(extra).and_then(|s| {
+            s.checked_add(seconds)
+        }).map(|s| {
+            libc::timespec { tv_sec: s, tv_nsec: nsec }
+        }).unwrap_or(TIMESPEC_MAX);
+
+        // And wait!
+        let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
+                                            &timeout);
+        debug_assert!(r == libc::ETIMEDOUT || r == 0);
+
+        // ETIMEDOUT is not a totally reliable method of determining timeout due
+        // to clock shifts, so do the check ourselves
+        stable_now.elapsed() < dur
+    }
+
+    #[inline]
+    #[cfg(not(target_os = "dragonfly"))]
+    pub unsafe fn destroy(&self) {
+        let r = libc::pthread_cond_destroy(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+
+    #[inline]
+    #[cfg(target_os = "dragonfly")]
+    pub unsafe fn destroy(&self) {
+        let r = libc::pthread_cond_destroy(self.inner.get());
+        // On DragonFly pthread_cond_destroy() returns EINVAL if called on
+        // a condvar that was just initialized with
+        // libc::PTHREAD_COND_INITIALIZER. Once it is used or
+        // pthread_cond_init() is called, this behaviour no longer occurs.
+        debug_assert!(r == 0 || r == libc::EINVAL);
+    }
+}
diff --git a/src/libstd/sys/vxworks/env.rs b/src/libstd/sys/vxworks/env.rs
new file mode 100644 (file)
index 0000000..fe1aedd
--- /dev/null
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "vxworks";
+    pub const OS: &str = "vxworks";
+    pub const DLL_PREFIX: &str = "lib";
+    pub const DLL_SUFFIX: &str = ".so";
+    pub const DLL_EXTENSION: &str = "so";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/vxworks/ext/ffi.rs b/src/libstd/sys/vxworks/ext/ffi.rs
new file mode 100644 (file)
index 0000000..76b34a6
--- /dev/null
@@ -0,0 +1,38 @@
+//! Unix-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::unix::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::unix::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use crate::sys_common::os_str_bytes::*;
diff --git a/src/libstd/sys/vxworks/ext/fs.rs b/src/libstd/sys/vxworks/ext/fs.rs
new file mode 100644 (file)
index 0000000..7ab7f2a
--- /dev/null
@@ -0,0 +1,801 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs::{self, Permissions};
+use crate::io;
+use libc;
+use crate::path::Path;
+use crate::sys;
+use crate::sys_common::{FromInner, AsInner, AsInnerMut};
+use crate::sys::platform::fs::MetadataExt as UnixMetadataExt;
+
+/// Unix-specific extensions to [`File`].
+///
+/// [`File`]: ../../../../std/fs/struct.File.html
+#[stable(feature = "file_offset", since = "1.15.0")]
+pub trait FileExt {
+    /// Reads a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Note that similar to [`File::read`], it is not an error to return with a
+    /// short read.
+    ///
+    /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs::File;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut buf = [0u8; 8];
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now read 8 bytes from the offset 10.
+    ///     let num_bytes_read = file.read_at(&mut buf, 10)?;
+    ///     println!("read {} bytes: {:?}", num_bytes_read, buf);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+    /// Reads the exact number of byte required to fill `buf` from the given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+    ///
+    /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
+    /// [`read_at`]: #tymethod.read_at
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If this function encounters an "end of file" before completely filling
+    /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+    /// The contents of `buf` are unspecified in this case.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. The contents of `buf` are unspecified in this case.
+    ///
+    /// If this function returns an error, it is unspecified how many bytes it
+    /// has read, but it will never read more than would be necessary to
+    /// completely fill the buffer.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(rw_exact_all_at)]
+    /// use std::io;
+    /// use std::fs::File;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut buf = [0u8; 8];
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now read exactly 8 bytes from the offset 10.
+    ///     file.read_exact_at(&mut buf, 10)?;
+    ///     println!("read {} bytes: {:?}", buf.len(), buf);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.read_at(buf, offset) {
+                Ok(0) => break,
+                Ok(n) => {
+                    let tmp = buf;
+                    buf = &mut tmp[n..];
+                    offset += n as u64;
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        if !buf.is_empty() {
+            Err(io::Error::new(io::ErrorKind::UnexpectedEof,
+                               "failed to fill whole buffer"))
+        } else {
+            Ok(())
+        }
+    }
+
+    /// Writes a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// When writing beyond the end of the file, the file is appropriately
+    /// extended and the intermediate bytes are initialized with the value 0.
+    ///
+    /// Note that similar to [`File::write`], it is not an error to return a
+    /// short write.
+    ///
+    /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now write at the offset 10.
+    ///     file.write_at(b"sushi", 10)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_offset", since = "1.15.0")]
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+
+    /// Attempts to write an entire buffer starting from a given offset.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// This method will continuously call [`write_at`] until there is no more data
+    /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+    /// returned. This method will not return until the entire buffer has been
+    /// successfully written or such an error occurs. The first error that is
+    /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+    /// returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error of
+    /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+    ///
+    /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+    /// [`write_at`]: #tymethod.write_at
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(rw_exact_all_at)]
+    /// use std::fs::File;
+    /// use std::io;
+    /// use std::os::unix::prelude::FileExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let file = File::open("foo.txt")?;
+    ///
+    ///     // We now write at the offset 10.
+    ///     file.write_all_at(b"sushi", 10)?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rw_exact_all_at", since = "1.33.0")]
+    fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+        while !buf.is_empty() {
+            match self.write_at(buf, offset) {
+                Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero,
+                                                   "failed to write whole buffer")),
+                Ok(n) => {
+                    buf = &buf[n..];
+                    offset += n as u64
+                }
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+}
+
+#[stable(feature = "file_offset", since = "1.15.0")]
+impl FileExt for fs::File {
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().read_at(buf, offset)
+    }
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().write_at(buf, offset)
+    }
+}
+
+/// Unix-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+    /// Returns the underlying raw `st_mode` bits that contain the standard
+    /// Unix permissions for this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let permissions = metadata.permissions();
+    ///
+    ///     println!("permissions: {}", permissions.mode());
+    ///     Ok(()) }
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn mode(&self) -> u32;
+
+    /// Sets the underlying raw bits for this set of permissions.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::create("foo.txt")?;
+    ///     let metadata = f.metadata()?;
+    ///     let mut permissions = metadata.permissions();
+    ///
+    ///     permissions.set_mode(0o644); // Read/write for owner and read for others.
+    ///     assert_eq!(permissions.mode(), 0o644);
+    ///     Ok(()) }
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn set_mode(&mut self, mode: u32);
+
+    /// Creates a new instance of `Permissions` from the given set of Unix
+    /// permission bits.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs::Permissions;
+    /// use std::os::unix::fs::PermissionsExt;
+    ///
+    /// // Read/write for owner and read for others.
+    /// let permissions = Permissions::from_mode(0o644);
+    /// assert_eq!(permissions.mode(), 0o644);
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+    fn mode(&self) -> u32 {
+        self.as_inner().mode()
+    }
+
+    fn set_mode(&mut self, mode: u32) {
+        *self = Permissions::from_inner(FromInner::from_inner(mode));
+    }
+
+    fn from_mode(mode: u32) -> Permissions {
+        Permissions::from_inner(FromInner::from_inner(mode))
+    }
+}
+
+/// Unix-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+    /// Sets the mode bits that a new file will be created with.
+    ///
+    /// If a new file is created as part of a `File::open_opts` call then this
+    /// specified `mode` will be used as the permission bits for the new file.
+    /// If no `mode` is set, the default of `0o666` will be used.
+    /// The operating system masks out bits with the systems `umask`, to produce
+    /// the final permissions.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// # fn main() {
+    /// let mut options = OpenOptions::new();
+    /// options.mode(0o644); // Give read/write for owner and read for others.
+    /// let file = options.open("foo.txt");
+    /// # }
+    /// ```
+    #[stable(feature = "fs_ext", since = "1.1.0")]
+    fn mode(&mut self, mode: u32) -> &mut Self;
+
+    /// Pass custom flags to the `flags` argument of `open`.
+    ///
+    /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+    /// ensure they do not interfere with the access mode set by Rusts options.
+    ///
+    /// Custom flags can only set flags, not remove flags set by Rusts options.
+    /// This options overwrites any previously set custom flags.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// # #![feature(libc)]
+    /// extern crate libc;
+    /// use std::fs::OpenOptions;
+    /// use std::os::unix::fs::OpenOptionsExt;
+    ///
+    /// # fn main() {
+    /// let mut options = OpenOptions::new();
+    /// options.write(true);
+    /// if cfg!(unix) {
+    ///     options.custom_flags(libc::O_NOFOLLOW);
+    /// }
+    /// let file = options.open("foo.txt");
+    /// # }
+    /// ```
+    #[stable(feature = "open_options_ext", since = "1.10.0")]
+    fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+/*#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+    fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+        self.as_inner_mut().mode(mode); self
+    }
+
+    fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+        self.as_inner_mut().custom_flags(flags); self
+    }
+}
+*/
+
+/// Unix-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+    /// Returns the ID of the device containing the file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let dev_id = meta.dev();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn dev(&self) -> u64;
+    /// Returns the inode number.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let inode = meta.ino();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ino(&self) -> u64;
+    /// Returns the rights applied to this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let mode = meta.mode();
+    ///     let user_has_write_access      = mode & 0o200;
+    ///     let user_has_read_write_access = mode & 0o600;
+    ///     let group_has_read_access      = mode & 0o040;
+    ///     let others_have_exec_access    = mode & 0o001;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mode(&self) -> u32;
+    /// Returns the number of hard links pointing to this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    ///  use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nb_hard_links = meta.nlink();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn nlink(&self) -> u64;
+    /// Returns the user ID of the owner of this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let user_id = meta.uid();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn uid(&self) -> u32;
+    /// Returns the group ID of the owner of this file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let group_id = meta.gid();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn gid(&self) -> u32;
+    /// Returns the device ID of this file (if it is a special one).
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let device_id = meta.rdev();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn rdev(&self) -> u64;
+    /// Returns the total size of this file in bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let file_size = meta.size();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn size(&self) -> u64;
+    /// Returns the time of the last access to the file.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let last_access_time = meta.atime();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn atime(&self) -> i64;
+    /// Returns the time of the last access to the file in nanoseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_access_time = meta.atime_nsec();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn mtime(&self) -> i64;
+    /// Returns the time of the last modification of the file in nanoseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_modification_time = meta.mtime_nsec();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn ctime(&self) -> i64;
+    /// Returns the time of the last status change of the file in nanoseconds.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let nano_last_status_change_time = meta.ctime_nsec();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn blksize(&self) -> u64;
+    /// Returns the number of blocks allocated to the file, in 512-byte units.
+    ///
+    /// Please note that this may be smaller than `st_size / 512` when the file has holes.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::MetadataExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("some_file")?;
+    ///     let blocks = meta.blocks();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn blocks(&self) -> u64;
+    #[stable(feature = "metadata_ext", since = "1.1.0")]
+    fn attrib(&self) -> u8;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+    fn dev(&self) -> u64 { self.st_dev() }
+    fn ino(&self) -> u64 { self.st_ino() }
+    fn mode(&self) -> u32 { self.st_mode() }
+    fn nlink(&self) -> u64 { self.st_nlink() }
+    fn uid(&self) -> u32 { self.st_uid() }
+    fn gid(&self) -> u32 { self.st_gid() }
+    fn rdev(&self) -> u64 { self.st_rdev() }
+    fn size(&self) -> u64 { self.st_size() }
+    fn atime(&self) -> i64 { self.st_atime() }
+    fn mtime(&self) -> i64 { self.st_mtime() }
+    fn ctime(&self) -> i64 { self.st_ctime() }
+    fn blksize(&self) -> u64 { self.st_blksize() }
+    fn blocks(&self) -> u64 { self.st_blocks() }
+    fn attrib(&self) -> u8 {self.st_attrib() }
+}
+
+/// Unix-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+    /// Returns whether this file type is a block device.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("block_device_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_block_device());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_block_device(&self) -> bool;
+    /// Returns whether this file type is a char device.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("char_device_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_char_device());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_char_device(&self) -> bool;
+    /// Returns whether this file type is a fifo.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("fifo_file")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_fifo());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_fifo(&self) -> bool;
+    /// Returns whether this file type is a socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs;
+    /// use std::os::unix::fs::FileTypeExt;
+    /// use std::io;
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let meta = fs::metadata("unix.socket")?;
+    ///     let file_type = meta.file_type();
+    ///     assert!(file_type.is_socket());
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "file_type_ext", since = "1.5.0")]
+    fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+    fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
+    fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
+    fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
+    fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
+}
+
+/// Unix-specific extension methods for [`fs::DirEntry`].
+///
+/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+pub trait DirEntryExt {
+    /// Returns the underlying `d_ino` field in the contained `dirent`
+    /// structure.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::fs;
+    /// use std::os::unix::fs::DirEntryExt;
+    ///
+    /// if let Ok(entries) = fs::read_dir(".") {
+    ///     for entry in entries {
+    ///         if let Ok(entry) = entry {
+    ///             // Here, `entry` is a `DirEntry`.
+    ///             println!("{:?}: {}", entry.file_name(), entry.ino());
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[stable(feature = "dir_entry_ext", since = "1.1.0")]
+    fn ino(&self) -> u64;
+}
+
+#[stable(feature = "dir_entry_ext", since = "1.1.0")]
+impl DirEntryExt for fs::DirEntry {
+    fn ino(&self) -> u64 { self.as_inner().ino() }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory.  Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory.  Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::fs;
+///
+/// fn main() -> std::io::Result<()> {
+///     fs::symlink("a.txt", "b.txt")?;
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+    sys::fs::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Unix-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+    /// Sets the mode to create new directories with. This option defaults to
+    /// 0o777.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::DirBuilder;
+    /// use std::os::unix::fs::DirBuilderExt;
+    ///
+    /// let mut builder = DirBuilder::new();
+    /// builder.mode(0o755);
+    /// ```
+    #[stable(feature = "dir_builder", since = "1.6.0")]
+    fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+    fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+        self.as_inner_mut().set_mode(mode);
+        self
+    }
+}
diff --git a/src/libstd/sys/vxworks/ext/io.rs b/src/libstd/sys/vxworks/ext/io.rs
new file mode 100644 (file)
index 0000000..6bcc594
--- /dev/null
@@ -0,0 +1,112 @@
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::fs;
+use crate::os::raw;
+use crate::sys;
+use crate::io;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+    /// Constructs a new instance of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    #[stable(feature = "from_raw_os", since = "1.1.0")]
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+    /// Consumes this object, returning the raw underlying file descriptor.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    #[stable(feature = "into_raw_os", since = "1.4.0")]
+    fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+        fs::File::from_inner(sys::fs::File::from_inner(fd))
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+    fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+    fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+    fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio_locks", since = "1.35.0")]
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
diff --git a/src/libstd/sys/vxworks/ext/mod.rs b/src/libstd/sys/vxworks/ext/mod.rs
new file mode 100644 (file)
index 0000000..c2ebc38
--- /dev/null
@@ -0,0 +1,20 @@
+// Uhhh
+#![stable(feature = "rust1", since = "1.0.0")]
+#![allow(missing_docs)]
+
+pub mod io;
+pub mod ffi;
+pub mod fs;
+pub mod raw;
+pub mod process;
+pub mod net;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
+}
diff --git a/src/libstd/sys/vxworks/ext/net.rs b/src/libstd/sys/vxworks/ext/net.rs
new file mode 100644 (file)
index 0000000..41090ca
--- /dev/null
@@ -0,0 +1,1850 @@
+#![stable(feature = "unix_socket", since = "1.10.0")]
+
+//! Unix-specific networking functionality
+
+#[cfg(unix)]
+use libc;
+
+// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
+#[cfg(not(unix))]
+mod libc {
+    pub use libc::c_int;
+    pub type socklen_t = u32;
+    pub struct sockaddr;
+    #[derive(Clone)]
+    pub struct sockaddr_un;
+}
+
+use crate::ascii;
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::mem;
+use crate::net::{self, Shutdown};
+use crate::os::unix::ffi::OsStrExt;
+use crate::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+use crate::path::Path;
+use crate::time::Duration;
+use crate::sys::{self, cvt};
+use crate::sys::net::Socket;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+#[cfg(any(target_os = "linux", target_os = "android",
+          target_os = "dragonfly", target_os = "freebsd",
+          target_os = "openbsd", target_os = "netbsd",
+          target_os = "haiku"))]
+use libc::MSG_NOSIGNAL;
+#[cfg(not(any(target_os = "linux", target_os = "android",
+              target_os = "dragonfly", target_os = "freebsd",
+              target_os = "openbsd", target_os = "netbsd",
+              target_os = "haiku")))]
+const MSG_NOSIGNAL: libc::c_int = 0x0;
+
+fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
+    // Work with an actual instance of the type since using a null pointer is UB
+    let base = addr as *const _ as usize;
+    let path = &addr.sun_path as *const _ as usize;
+    path - base
+}
+
+unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+    let mut addr: libc::sockaddr_un = mem::zeroed();
+    addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
+
+    let bytes = path.as_os_str().as_bytes();
+
+    if bytes.contains(&0) {
+        return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                  "paths may not contain interior null bytes"));
+    }
+
+    if bytes.len() >= addr.sun_path.len() {
+        return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                  "path must be shorter than SUN_LEN"));
+    }
+    for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
+        *dst = *src as libc::c_char;
+    }
+    // null byte for pathname addresses is already there because we zeroed the
+    // struct
+
+    let mut len = sun_path_offset(&addr) + bytes.len();
+    match bytes.get(0) {
+        Some(&0) | None => {}
+        Some(_) => len += 1,
+    }
+    Ok((addr, len as libc::socklen_t))
+}
+
+enum AddressKind<'a> {
+    Unnamed,
+    Pathname(&'a Path),
+    Abstract(&'a [u8]),
+}
+
+/// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+///     Ok(sock) => sock,
+///     Err(e) => {
+///         println!("Couldn't bind: {:?}", e);
+///         return
+///     }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct SocketAddr {
+    addr: libc::sockaddr_un,
+    len: libc::socklen_t,
+}
+
+impl SocketAddr {
+    fn new<F>(f: F) -> io::Result<SocketAddr>
+        where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int
+    {
+        unsafe {
+            let mut addr: libc::sockaddr_un = mem::zeroed();
+            let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
+            cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
+            SocketAddr::from_parts(addr, len)
+        }
+    }
+
+    fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
+        if len == 0 {
+            // When there is a datagram from unnamed unix socket
+            // linux returns zero bytes of address
+            len = sun_path_offset(&addr) as libc::socklen_t;  // i.e., zero-length address
+        } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
+            return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                      "file descriptor did not correspond to a Unix socket"));
+        }
+
+        Ok(SocketAddr {
+            addr,
+            len,
+        })
+    }
+
+    /// Returns `true` if the address is unnamed.
+    ///
+    /// # Examples
+    ///
+    /// A named address:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.is_unnamed(), false);
+    /// ```
+    ///
+    /// An unnamed address:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.is_unnamed(), true);
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn is_unnamed(&self) -> bool {
+        if let AddressKind::Unnamed = self.address() {
+            true
+        } else {
+            false
+        }
+    }
+
+    /// Returns the contents of this address if it is a `pathname` address.
+    ///
+    /// # Examples
+    ///
+    /// With a pathname:
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    /// use std::path::Path;
+    ///
+    /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+    /// ```
+    ///
+    /// Without a pathname:
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// assert_eq!(addr.as_pathname(), None);
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn as_pathname(&self) -> Option<&Path> {
+        if let AddressKind::Pathname(path) = self.address() {
+            Some(path)
+        } else {
+            None
+        }
+    }
+
+    fn address<'a>(&'a self) -> AddressKind<'a> {
+        let len = self.len as usize - sun_path_offset(&self.addr);
+        let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
+
+        // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses
+        if len == 0
+            || (cfg!(not(any(target_os = "linux", target_os = "android")))
+                && self.addr.sun_path[0] == 0)
+        {
+            AddressKind::Unnamed
+        } else if self.addr.sun_path[0] == 0 {
+            AddressKind::Abstract(&path[1..len])
+        } else {
+            AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
+        }
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for SocketAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.address() {
+            AddressKind::Unnamed => write!(fmt, "(unnamed)"),
+            AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
+            AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
+        }
+    }
+}
+
+struct AsciiEscaped<'a>(&'a [u8]);
+
+impl<'a> fmt::Display for AsciiEscaped<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(fmt, "\"")?;
+        for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
+            write!(fmt, "{}", byte as char)?;
+        }
+        write!(fmt, "\"")
+    }
+}
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
+/// stream.write_all(b"hello world").unwrap();
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response).unwrap();
+/// println!("{}", response);
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixStream(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixStream {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixStream");
+        builder.field("fd", self.0.as_inner());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        if let Ok(addr) = self.peer_addr() {
+            builder.field("peer", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixStream {
+    /// Connects to the socket named by `path`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = match UnixStream::connect("/tmp/sock") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+        fn inner(path: &Path) -> io::Result<UnixStream> {
+            unsafe {
+                let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+                let (addr, len) = sockaddr_un(path)?;
+
+                cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
+                Ok(UnixStream(inner))
+            }
+        }
+        inner(path.as_ref())
+    }
+
+    /// Creates an unnamed pair of connected sockets.
+    ///
+    /// Returns two `UnixStream`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let (sock1, sock2) = match UnixStream::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't create a pair of sockets: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+        let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
+        Ok((UnixStream(i1), UnixStream(i2)))
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixStream` is a reference to the same stream that this
+    /// object references. Both handles will read and write the same stream of
+    /// data, and options set on one stream will be propagated to the other
+    /// stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn try_clone(&self) -> io::Result<UnixStream> {
+        self.0.duplicate().map(UnixStream)
+    }
+
+    /// Returns the socket address of the local half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let addr = socket.local_addr().expect("Couldn't get local address");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Returns the socket address of the remote half of this connection.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Sets the read timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`read`] calls will block
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+    /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+    }
+
+    /// Sets the write timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`write`] calls will block
+    /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+    /// passed to this method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+    /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::net::UdpSocket;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+    /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+    }
+
+    /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+    /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_RCVTIMEO)
+    }
+
+    /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+    /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_SNDTIMEO)
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// if let Ok(Some(err)) = socket.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns `None`.
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0.take_error()
+    }
+
+    /// Shuts down the read, write, or both halves of this connection.
+    ///
+    /// This function will cause all pending and future I/O calls on the
+    /// specified portions to immediately return with an appropriate value
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixStream;
+    /// use std::net::Shutdown;
+    ///
+    /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+    /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        self.0.shutdown(how)
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Read for UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        io::Read::read(&mut &*self, buf)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        io::Read::read_vectored(&mut &*self, bufs)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Read for &'a UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl io::Write for UnixStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        io::Write::write(&mut &*self, buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        io::Write::write_vectored(&mut &*self, bufs)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        io::Write::flush(&mut &*self)
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> io::Write for &'a UnixStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixStream {
+    fn as_raw_fd(&self) -> RawFd {
+        *self.0.as_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+        UnixStream(Socket::from_inner(fd))
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixStream {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_inner()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+    fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
+    }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+        let socket = sys::net::Socket::from_inner(fd);
+        net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_socket().into_inner()
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_socket().into_inner()
+    }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_socket().into_inner()
+    }
+}
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+///     match stream {
+///         Ok(stream) => {
+///             /* connection succeeded */
+///             thread::spawn(|| handle_client(stream));
+///         }
+///         Err(err) => {
+///             /* connection failed */
+///             break;
+///         }
+///     }
+/// }
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixListener(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixListener {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixListener");
+        builder.field("fd", self.0.as_inner());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixListener {
+    /// Creates a new `UnixListener` bound to the specified socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = match UnixListener::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+        fn inner(path: &Path) -> io::Result<UnixListener> {
+            unsafe {
+                let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
+                let (addr, len) = sockaddr_un(path)?;
+
+                cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
+                cvt(libc::listen(*inner.as_inner(), 128))?;
+
+                Ok(UnixListener(inner))
+            }
+        }
+        inner(path.as_ref())
+    }
+
+    /// Accepts a new incoming connection to this listener.
+    ///
+    /// This function will block the calling thread until a new Unix connection
+    /// is established. When established, the corresponding [`UnixStream`] and
+    /// the remote peer's address will be returned.
+    ///
+    /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// match listener.accept() {
+    ///     Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+    ///     Err(e) => println!("accept function failed: {:?}", e),
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+        let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
+        let mut len = mem::size_of_val(&storage) as libc::socklen_t;
+        let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
+        let addr = SocketAddr::from_parts(storage, len)?;
+        Ok((UnixStream(sock), addr))
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixListener` is a reference to the same socket that this
+    /// object references. Both handles can be used to accept incoming
+    /// connections and options set on one listener will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let listener_copy = listener.try_clone().expect("try_clone failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn try_clone(&self) -> io::Result<UnixListener> {
+        self.0.duplicate().map(UnixListener)
+    }
+
+    /// Returns the local socket address of this listener.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = listener.local_addr().expect("Couldn't get local address");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixListener;
+    ///
+    /// let listener = UnixListener::bind("/tmp/sock").unwrap();
+    ///
+    /// if let Ok(Some(err)) = listener.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
+    ///
+    /// # Platform specific
+    /// On Redox this always returns `None`.
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0.take_error()
+    }
+
+    /// Returns an iterator over incoming connections.
+    ///
+    /// The iterator will never return [`None`] and will also not yield the
+    /// peer's [`SocketAddr`] structure.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`SocketAddr`]: struct.SocketAddr.html
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::thread;
+    /// use std::os::unix::net::{UnixStream, UnixListener};
+    ///
+    /// fn handle_client(stream: UnixStream) {
+    ///     // ...
+    /// }
+    ///
+    /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+    ///
+    /// for stream in listener.incoming() {
+    ///     match stream {
+    ///         Ok(stream) => {
+    ///             thread::spawn(|| handle_client(stream));
+    ///         }
+    ///         Err(err) => {
+    ///             break;
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn incoming<'a>(&'a self) -> Incoming<'a> {
+        Incoming { listener: self }
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixListener {
+    fn as_raw_fd(&self) -> RawFd {
+        *self.0.as_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixListener {
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+        UnixListener(Socket::from_inner(fd))
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixListener {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> IntoIterator for &'a UnixListener {
+    type Item = io::Result<UnixStream>;
+    type IntoIter = Incoming<'a>;
+
+    fn into_iter(self) -> Incoming<'a> {
+        self.incoming()
+    }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+/// [`UnixListener`]: struct.UnixListener.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+///     // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// for stream in listener.incoming() {
+///     match stream {
+///         Ok(stream) => {
+///             thread::spawn(|| handle_client(stream));
+///         }
+///         Err(err) => {
+///             break;
+///         }
+///     }
+/// }
+/// ```
+#[derive(Debug)]
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct Incoming<'a> {
+    listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl<'a> Iterator for Incoming<'a> {
+    type Item = io::Result<UnixStream>;
+
+    fn next(&mut self) -> Option<io::Result<UnixStream>> {
+        Some(self.listener.accept().map(|s| s.0))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (usize::max_value(), None)
+    }
+}
+
+/// A Unix datagram socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixDatagram;
+///
+/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap();
+/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap();
+/// let mut buf = [0; 100];
+/// let (count, address) = socket.recv_from(&mut buf).unwrap();
+/// println!("socket {:?} sent {:?}", address, &buf[..count]);
+/// ```
+#[stable(feature = "unix_socket", since = "1.10.0")]
+pub struct UnixDatagram(Socket);
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl fmt::Debug for UnixDatagram {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut builder = fmt.debug_struct("UnixDatagram");
+        builder.field("fd", self.0.as_inner());
+        if let Ok(addr) = self.local_addr() {
+            builder.field("local", &addr);
+        }
+        if let Ok(addr) = self.peer_addr() {
+            builder.field("peer", &addr);
+        }
+        builder.finish()
+    }
+}
+
+impl UnixDatagram {
+    /// Creates a Unix datagram socket bound to the given path.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't bind: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
+        fn inner(path: &Path) -> io::Result<UnixDatagram> {
+            unsafe {
+                let socket = UnixDatagram::unbound()?;
+                let (addr, len) = sockaddr_un(path)?;
+
+                cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
+
+                Ok(socket)
+            }
+        }
+        inner(path.as_ref())
+    }
+
+    /// Creates a Unix Datagram socket which is not bound to any address.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = match UnixDatagram::unbound() {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't unbound: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn unbound() -> io::Result<UnixDatagram> {
+        let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+        Ok(UnixDatagram(inner))
+    }
+
+    /// Creates an unnamed pair of connected sockets.
+    ///
+    /// Returns two `UnixDatagrams`s which are connected to each other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let (sock1, sock2) = match UnixDatagram::pair() {
+    ///     Ok((sock1, sock2)) => (sock1, sock2),
+    ///     Err(e) => {
+    ///         println!("Couldn't unbound: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
+        let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
+        Ok((UnixDatagram(i1), UnixDatagram(i2)))
+    }
+
+    /// Connects the socket to the specified address.
+    ///
+    /// The [`send`] method may be used to send data to the specified address.
+    /// [`recv`] and [`recv_from`] will only receive data from that address.
+    ///
+    /// [`send`]: #method.send
+    /// [`recv`]: #method.recv
+    /// [`recv_from`]: #method.recv_from
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// match sock.connect("/path/to/the/socket") {
+    ///     Ok(sock) => sock,
+    ///     Err(e) => {
+    ///         println!("Couldn't connect: {:?}", e);
+    ///         return
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+        fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> {
+            unsafe {
+                let (addr, len) = sockaddr_un(path)?;
+
+                cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?;
+
+                Ok(())
+            }
+        }
+        inner(self, path.as_ref())
+    }
+
+    /// Creates a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UnixDatagram` is a reference to the same socket that this
+    /// object references. Both handles can be used to accept incoming
+    /// connections and options set on one side will affect the other.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let sock_copy = sock.try_clone().expect("try_clone failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn try_clone(&self) -> io::Result<UnixDatagram> {
+        self.0.duplicate().map(UnixDatagram)
+    }
+
+    /// Returns the address of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = sock.local_addr().expect("Couldn't get local address");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn local_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Returns the address of this socket's peer.
+    ///
+    /// The [`connect`] method will connect the socket to a peer.
+    ///
+    /// [`connect`]: #method.connect
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.connect("/path/to/the/socket").unwrap();
+    ///
+    /// let addr = sock.peer_addr().expect("Couldn't get peer address");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
+    }
+
+    /// Receives data from the socket.
+    ///
+    /// On success, returns the number of bytes read and the address from
+    /// whence the data came.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// let mut buf = vec![0; 10];
+    /// match sock.recv_from(buf.as_mut_slice()) {
+    ///     Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender),
+    ///     Err(e) => println!("recv_from function failed: {:?}", e),
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        let mut count = 0;
+        let addr = SocketAddr::new(|addr, len| {
+            unsafe {
+                count = libc::recvfrom(*self.0.as_inner(),
+                                       buf.as_mut_ptr() as *mut _,
+                                       buf.len(),
+                                       0,
+                                       addr,
+                                       len);
+                if count > 0 {
+                    1
+                } else if count == 0 {
+                    0
+                } else {
+                    -1
+                }
+            }
+        })?;
+
+        Ok((count as usize, addr))
+    }
+
+    /// Receives data from the socket.
+    ///
+    /// On success, returns the number of bytes read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
+    /// let mut buf = vec![0; 10];
+    /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    /// Sends data on the socket to the specified address.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
+        fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
+            unsafe {
+                let (addr, len) = sockaddr_un(path)?;
+
+                let count = cvt(libc::sendto(*d.0.as_inner(),
+                                             buf.as_ptr() as *const _,
+                                             buf.len(),
+                                             MSG_NOSIGNAL,
+                                             &addr as *const _ as *const _,
+                                             len))?;
+                Ok(count as usize)
+            }
+        }
+        inner(self, buf, path.as_ref())
+    }
+
+    /// Sends data on the socket to the socket's peer.
+    ///
+    /// The peer address may be set by the `connect` method, and this method
+    /// will return an error if the socket has not already been connected.
+    ///
+    /// On success, returns the number of bytes written.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.connect("/some/sock").expect("Couldn't connect");
+    /// sock.send(b"omelette au fromage").expect("send_to function failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    /// Sets the read timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
+    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
+    /// is passed to this method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+    /// [`recv`]: #method.recv
+    /// [`recv_from`]: #method.recv_from
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
+    }
+
+    /// Sets the write timeout for the socket.
+    ///
+    /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
+    /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method.
+    ///
+    /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+    /// [`send`]: #method.send
+    /// [`send_to`]: #method.send_to
+    /// [`Duration`]: ../../../../std/time/struct.Duration.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+    ///     .expect("set_write_timeout function failed");
+    /// ```
+    ///
+    /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+    /// method:
+    ///
+    /// ```no_run
+    /// use std::io;
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let socket = UnixDatagram::unbound().unwrap();
+    /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+    /// let err = result.unwrap_err();
+    /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
+        self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
+    }
+
+    /// Returns the read timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
+    /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_RCVTIMEO)
+    }
+
+    /// Returns the write timeout of this socket.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::time::Duration;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_write_timeout(Some(Duration::new(1, 0)))
+    ///     .expect("set_write_timeout function failed");
+    /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        self.0.timeout(libc::SO_SNDTIMEO)
+    }
+
+    /// Moves the socket into or out of nonblocking mode.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        self.0.set_nonblocking(nonblocking)
+    }
+
+    /// Returns the value of the `SO_ERROR` option.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// if let Ok(Some(err)) = sock.take_error() {
+    ///     println!("Got error: {:?}", err);
+    /// }
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        self.0.take_error()
+    }
+
+    /// Shut down the read, write, or both halves of this connection.
+    ///
+    /// This function will cause all pending and future I/O calls on the
+    /// specified portions to immediately return with an appropriate value
+    /// (see the documentation of [`Shutdown`]).
+    ///
+    /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+    ///
+    /// ```no_run
+    /// use std::os::unix::net::UnixDatagram;
+    /// use std::net::Shutdown;
+    ///
+    /// let sock = UnixDatagram::unbound().unwrap();
+    /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
+    /// ```
+    #[stable(feature = "unix_socket", since = "1.10.0")]
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        self.0.shutdown(how)
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl AsRawFd for UnixDatagram {
+    fn as_raw_fd(&self) -> RawFd {
+        *self.0.as_inner()
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl FromRawFd for UnixDatagram {
+    unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
+        UnixDatagram(Socket::from_inner(fd))
+    }
+}
+
+#[stable(feature = "unix_socket", since = "1.10.0")]
+impl IntoRawFd for UnixDatagram {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_inner()
+    }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod test {
+    use crate::thread;
+    use crate::io::{self, ErrorKind};
+    use crate::io::prelude::*;
+    use crate::time::Duration;
+    use crate::sys_common::io::test::tmpdir;
+
+    use super::*;
+
+    macro_rules! or_panic {
+        ($e:expr) => {
+            match $e {
+                Ok(e) => e,
+                Err(e) => panic!("{}", e),
+            }
+        }
+    }
+
+    #[test]
+    fn basic() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+        let msg1 = b"hello";
+        let msg2 = b"world!";
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+        let thread = thread::spawn(move || {
+            let mut stream = or_panic!(listener.accept()).0;
+            let mut buf = [0; 5];
+            or_panic!(stream.read(&mut buf));
+            assert_eq!(&msg1[..], &buf[..]);
+            or_panic!(stream.write_all(msg2));
+        });
+
+        let mut stream = or_panic!(UnixStream::connect(&socket_path));
+        assert_eq!(Some(&*socket_path),
+                   stream.peer_addr().unwrap().as_pathname());
+        or_panic!(stream.write_all(msg1));
+        let mut buf = vec![];
+        or_panic!(stream.read_to_end(&mut buf));
+        assert_eq!(&msg2[..], &buf[..]);
+        drop(stream);
+
+        thread.join().unwrap();
+    }
+
+    #[test]
+    fn vectored() {
+        let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+
+        let len = or_panic!(s1.write_vectored(
+            &[IoSlice::new(b"hello"), IoSlice::new(b" "), IoSlice::new(b"world!")],
+        ));
+        assert_eq!(len, 12);
+
+        let mut buf1 = [0; 6];
+        let mut buf2 = [0; 7];
+        let len = or_panic!(s2.read_vectored(
+            &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],
+        ));
+        assert_eq!(len, 12);
+        assert_eq!(&buf1, b"hello ");
+        assert_eq!(&buf2, b"world!\0");
+    }
+
+    #[test]
+    fn pair() {
+        let msg1 = b"hello";
+        let msg2 = b"world!";
+
+        let (mut s1, mut s2) = or_panic!(UnixStream::pair());
+        let thread = thread::spawn(move || {
+            // s1 must be moved in or the test will hang!
+            let mut buf = [0; 5];
+            or_panic!(s1.read(&mut buf));
+            assert_eq!(&msg1[..], &buf[..]);
+            or_panic!(s1.write_all(msg2));
+        });
+
+        or_panic!(s2.write_all(msg1));
+        let mut buf = vec![];
+        or_panic!(s2.read_to_end(&mut buf));
+        assert_eq!(&msg2[..], &buf[..]);
+        drop(s2);
+
+        thread.join().unwrap();
+    }
+
+    #[test]
+    fn try_clone() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+        let msg1 = b"hello";
+        let msg2 = b"world";
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+        let thread = thread::spawn(move || {
+            let mut stream = or_panic!(listener.accept()).0;
+            or_panic!(stream.write_all(msg1));
+            or_panic!(stream.write_all(msg2));
+        });
+
+        let mut stream = or_panic!(UnixStream::connect(&socket_path));
+        let mut stream2 = or_panic!(stream.try_clone());
+
+        let mut buf = [0; 5];
+        or_panic!(stream.read(&mut buf));
+        assert_eq!(&msg1[..], &buf[..]);
+        or_panic!(stream2.read(&mut buf));
+        assert_eq!(&msg2[..], &buf[..]);
+
+        thread.join().unwrap();
+    }
+
+    #[test]
+    fn iter() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+        let thread = thread::spawn(move || {
+            for stream in listener.incoming().take(2) {
+                let mut stream = or_panic!(stream);
+                let mut buf = [0];
+                or_panic!(stream.read(&mut buf));
+            }
+        });
+
+        for _ in 0..2 {
+            let mut stream = or_panic!(UnixStream::connect(&socket_path));
+            or_panic!(stream.write_all(&[0]));
+        }
+
+        thread.join().unwrap();
+    }
+
+    #[test]
+    fn long_path() {
+        let dir = tmpdir();
+        let socket_path = dir.path()
+                             .join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
+                                    sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf");
+        match UnixStream::connect(&socket_path) {
+            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+            Err(e) => panic!("unexpected error {}", e),
+            Ok(_) => panic!("unexpected success"),
+        }
+
+        match UnixListener::bind(&socket_path) {
+            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+            Err(e) => panic!("unexpected error {}", e),
+            Ok(_) => panic!("unexpected success"),
+        }
+
+        match UnixDatagram::bind(&socket_path) {
+            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
+            Err(e) => panic!("unexpected error {}", e),
+            Ok(_) => panic!("unexpected success"),
+        }
+    }
+
+    #[test]
+    fn timeouts() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+        let stream = or_panic!(UnixStream::connect(&socket_path));
+        let dur = Duration::new(15410, 0);
+
+        assert_eq!(None, or_panic!(stream.read_timeout()));
+
+        or_panic!(stream.set_read_timeout(Some(dur)));
+        assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
+
+        assert_eq!(None, or_panic!(stream.write_timeout()));
+
+        or_panic!(stream.set_write_timeout(Some(dur)));
+        assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
+
+        or_panic!(stream.set_read_timeout(None));
+        assert_eq!(None, or_panic!(stream.read_timeout()));
+
+        or_panic!(stream.set_write_timeout(None));
+        assert_eq!(None, or_panic!(stream.write_timeout()));
+    }
+
+    #[test]
+    fn test_read_timeout() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let _listener = or_panic!(UnixListener::bind(&socket_path));
+
+        let mut stream = or_panic!(UnixStream::connect(&socket_path));
+        or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+        let mut buf = [0; 10];
+        let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+        assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+                "unexpected_error: {:?}", kind);
+    }
+
+    #[test]
+    fn test_read_with_timeout() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+
+        let mut stream = or_panic!(UnixStream::connect(&socket_path));
+        or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+        let mut other_end = or_panic!(listener.accept()).0;
+        or_panic!(other_end.write_all(b"hello world"));
+
+        let mut buf = [0; 11];
+        or_panic!(stream.read(&mut buf));
+        assert_eq!(b"hello world", &buf[..]);
+
+        let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
+        assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
+                "unexpected_error: {:?}", kind);
+    }
+
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_unix_stream_timeout_zero_duration() {
+        let dir = tmpdir();
+        let socket_path = dir.path().join("sock");
+
+        let listener = or_panic!(UnixListener::bind(&socket_path));
+        let stream = or_panic!(UnixStream::connect(&socket_path));
+
+        let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        drop(listener);
+    }
+
+    #[test]
+    fn test_unix_datagram() {
+        let dir = tmpdir();
+        let path1 = dir.path().join("sock1");
+        let path2 = dir.path().join("sock2");
+
+        let sock1 = or_panic!(UnixDatagram::bind(&path1));
+        let sock2 = or_panic!(UnixDatagram::bind(&path2));
+
+        let msg = b"hello world";
+        or_panic!(sock1.send_to(msg, &path2));
+        let mut buf = [0; 11];
+        or_panic!(sock2.recv_from(&mut buf));
+        assert_eq!(msg, &buf[..]);
+    }
+
+    #[test]
+    fn test_unnamed_unix_datagram() {
+        let dir = tmpdir();
+        let path1 = dir.path().join("sock1");
+
+        let sock1 = or_panic!(UnixDatagram::bind(&path1));
+        let sock2 = or_panic!(UnixDatagram::unbound());
+
+        let msg = b"hello world";
+        or_panic!(sock2.send_to(msg, &path1));
+        let mut buf = [0; 11];
+        let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
+        assert_eq!(usize, 11);
+        assert!(addr.is_unnamed());
+        assert_eq!(msg, &buf[..]);
+    }
+
+    #[test]
+    fn test_connect_unix_datagram() {
+        let dir = tmpdir();
+        let path1 = dir.path().join("sock1");
+        let path2 = dir.path().join("sock2");
+
+        let bsock1 = or_panic!(UnixDatagram::bind(&path1));
+        let bsock2 = or_panic!(UnixDatagram::bind(&path2));
+        let sock = or_panic!(UnixDatagram::unbound());
+        or_panic!(sock.connect(&path1));
+
+        // Check send()
+        let msg = b"hello there";
+        or_panic!(sock.send(msg));
+        let mut buf = [0; 11];
+        let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
+        assert_eq!(usize, 11);
+        assert!(addr.is_unnamed());
+        assert_eq!(msg, &buf[..]);
+
+        // Changing default socket works too
+        or_panic!(sock.connect(&path2));
+        or_panic!(sock.send(msg));
+        or_panic!(bsock2.recv_from(&mut buf));
+    }
+
+    #[test]
+    fn test_unix_datagram_recv() {
+        let dir = tmpdir();
+        let path1 = dir.path().join("sock1");
+
+        let sock1 = or_panic!(UnixDatagram::bind(&path1));
+        let sock2 = or_panic!(UnixDatagram::unbound());
+        or_panic!(sock2.connect(&path1));
+
+        let msg = b"hello world";
+        or_panic!(sock2.send(msg));
+        let mut buf = [0; 11];
+        let size = or_panic!(sock1.recv(&mut buf));
+        assert_eq!(size, 11);
+        assert_eq!(msg, &buf[..]);
+    }
+
+    #[test]
+    fn datagram_pair() {
+        let msg1 = b"hello";
+        let msg2 = b"world!";
+
+        let (s1, s2) = or_panic!(UnixDatagram::pair());
+        let thread = thread::spawn(move || {
+            // s1 must be moved in or the test will hang!
+            let mut buf = [0; 5];
+            or_panic!(s1.recv(&mut buf));
+            assert_eq!(&msg1[..], &buf[..]);
+            or_panic!(s1.send(msg2));
+        });
+
+        or_panic!(s2.send(msg1));
+        let mut buf = [0; 6];
+        or_panic!(s2.recv(&mut buf));
+        assert_eq!(&msg2[..], &buf[..]);
+        drop(s2);
+
+        thread.join().unwrap();
+    }
+
+    // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
+    // when passed zero Durations
+    #[test]
+    fn test_unix_datagram_timeout_zero_duration() {
+        let dir = tmpdir();
+        let path = dir.path().join("sock");
+
+        let datagram = or_panic!(UnixDatagram::bind(&path));
+
+        let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+
+        let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
+        let err = result.unwrap_err();
+        assert_eq!(err.kind(), ErrorKind::InvalidInput);
+    }
+
+    #[test]
+    fn abstract_namespace_not_allowed() {
+        assert!(UnixStream::connect("\0asdf").is_err());
+    }
+}
diff --git a/src/libstd/sys/vxworks/ext/process.rs b/src/libstd/sys/vxworks/ext/process.rs
new file mode 100644 (file)
index 0000000..4de72fa
--- /dev/null
@@ -0,0 +1,213 @@
+//! Unix-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use crate::io;
+use crate::sys::vxworks::ext::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
+use crate::process;
+use crate::sys;
+use crate::sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+    /// Sets the child process's user ID. This translates to a
+    /// `setuid` call in the child process. Failure in the `setuid`
+    /// call will cause the spawn to fail.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn uid(&mut self, id: u16) -> &mut process::Command;
+
+    /// Similar to `uid`, but sets the group ID of the child process. This has
+    /// the same semantics as the `uid` field.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn gid(&mut self, id: u16) -> &mut process::Command;
+
+    /// Schedules a closure to be run just before the `exec` function is
+    /// invoked.
+    ///
+    /// The closure is allowed to return an I/O error whose OS error code will
+    /// be communicated back to the parent and returned as an error from when
+    /// the spawn was requested.
+    ///
+    /// Multiple closures can be registered and they will be called in order of
+    /// their registration. If a closure returns `Err` then no further closures
+    /// will be called and the spawn operation will immediately return with a
+    /// failure.
+    ///
+    /// # Notes and Safety
+    ///
+    /// This closure will be run in the context of the child process after a
+    /// `fork`. This primarily means that any modifications made to memory on
+    /// behalf of this closure will **not** be visible to the parent process.
+    /// This is often a very constrained environment where normal operations
+    /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+    /// other threads perhaps still running when the `fork` was run).
+    ///
+    /// This also means that all resources such as file descriptors and
+    /// memory-mapped regions got duplicated. It is your responsibility to make
+    /// sure that the closure does not violate library invariants by making
+    /// invalid use of these duplicates.
+    ///
+    /// When this closure is run, aspects such as the stdio file descriptors and
+    /// working directory have successfully been changed, so output to these
+    /// locations may not appear where intended.
+    #[stable(feature = "process_pre_exec", since = "1.34.0")]
+    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+        where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+    /// Schedules a closure to be run just before the `exec` function is
+    /// invoked.
+    ///
+    /// This method is stable and usable, but it should be unsafe. To fix
+    /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+    ///
+    /// [`pre_exec`]: #tymethod.pre_exec
+    #[stable(feature = "process_exec", since = "1.15.0")]
+    #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")]
+    fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+        where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+    {
+        unsafe { self.pre_exec(f) }
+    }
+
+    /// Performs all the required setup by this `Command`, followed by calling
+    /// the `execvp` syscall.
+    ///
+    /// On success this function will not return, and otherwise it will return
+    /// an error indicating why the exec (or another part of the setup of the
+    /// `Command`) failed.
+    ///
+    /// `exec` not returning has the same implications as calling
+    /// [`process::exit`] â€“ no destructors on the current stack or any other
+    /// thread’s stack will be run. Therefore, it is recommended to only call
+    /// `exec` at a point where it is fine to not run any destructors. Note,
+    /// that the `execvp` syscall independently guarantees that all memory is
+    /// freed and all file descriptors with the `CLOEXEC` option (set by default
+    /// on all file descriptors opened by the standard library) are closed.
+    ///
+    /// This function, unlike `spawn`, will **not** `fork` the process to create
+    /// a new child. Like spawn, however, the default behavior for the stdio
+    /// descriptors will be to inherited from the current process.
+    ///
+    /// [`process::exit`]: ../../../process/fn.exit.html
+    ///
+    /// # Notes
+    ///
+    /// The process may be in a "broken state" if this function returns in
+    /// error. For example the working directory, environment variables, signal
+    /// handling settings, various user/group information, or aspects of stdio
+    /// file descriptors may have changed. If a "transactional spawn" is
+    /// required to gracefully handle errors it is recommended to use the
+    /// cross-platform `spawn` instead.
+    #[stable(feature = "process_exec2", since = "1.9.0")]
+    fn exec(&mut self) -> io::Error;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+    fn uid(&mut self, id: u16) -> &mut process::Command {
+        self.as_inner_mut().uid(id);
+        self
+    }
+
+    fn gid(&mut self, id: u16) -> &mut process::Command {
+        self.as_inner_mut().gid(id);
+        self
+    }
+
+    unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
+        where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+    {
+        self.as_inner_mut().pre_exec(Box::new(f));
+        self
+    }
+
+    fn exec(&mut self) -> io::Error {
+        self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+    }
+}
+
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+    /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
+    /// a process.
+    #[stable(feature = "exit_status_from", since = "1.12.0")]
+    fn from_raw(raw: i32) -> Self;
+
+    /// If the process was terminated by a signal, returns that signal.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+    fn from_raw(raw: i32) -> Self {
+        process::ExitStatus::from_inner(From::from(raw))
+    }
+
+    fn signal(&self) -> Option<i32> {
+        self.as_inner().signal()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+    unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+        let fd = sys::fd::FileDesc::new(fd);
+        let io = sys::process::Stdio::Fd(fd);
+        process::Stdio::from_inner(io)
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+    fn as_raw_fd(&self) -> RawFd {
+        self.as_inner().fd().raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+    fn into_raw_fd(self) -> RawFd {
+        self.into_inner().into_fd().into_raw()
+    }
+}
+
+/// Returns the OS-assigned process identifier associated with this process's parent.
+#[stable(feature = "unix_ppid", since = "1.27.0")]
+pub fn parent_id() -> u32 {
+    crate::sys::os::getppid()
+}
diff --git a/src/libstd/sys/vxworks/ext/raw.rs b/src/libstd/sys/vxworks/ext/raw.rs
new file mode 100644 (file)
index 0000000..1f134f4
--- /dev/null
@@ -0,0 +1,5 @@
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use crate::sys::platform::raw::pthread_t;
diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs
new file mode 100644 (file)
index 0000000..f5a2e26
--- /dev/null
@@ -0,0 +1,36 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+// Since what appears to be glibc 2.18 this symbol has been shipped which
+// GCC and clang both use to invoke destructors in thread_local globals, so
+// let's do the same!
+//
+// Note, however, that we run on lots older linuxes, as well as cross
+// compiling from a newer linux to an older linux, so we also have a
+// fallback implementation to use as well.
+//
+// Due to rust-lang/rust#18804, make sure this is not generic!
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    use crate::mem;
+    use crate::sys_common::thread_local::register_dtor_fallback;
+
+    extern {
+        #[linkage = "extern_weak"]
+        static __dso_handle: *mut u8;
+        #[linkage = "extern_weak"]
+        static __cxa_thread_atexit_impl: *const libc::c_void;
+    }
+    if !__cxa_thread_atexit_impl.is_null() {
+        type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
+                                  arg: *mut u8,
+                                  dso_handle: *mut u8) -> libc::c_int;
+        mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
+            (dtor, t, &__dso_handle as *const _ as *mut _);
+        return
+    }
+    register_dtor_fallback(t, dtor);
+}
+
+pub fn requires_move_before_drop() -> bool {
+    false
+}
diff --git a/src/libstd/sys/vxworks/fd.rs b/src/libstd/sys/vxworks/fd.rs
new file mode 100644 (file)
index 0000000..db2865d
--- /dev/null
@@ -0,0 +1,188 @@
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use crate::cmp;
+use crate::io::{self, Read, Initializer, IoSlice, IoSliceMut};
+use crate::mem;
+use crate::sys::cvt;
+use crate::sys_common::AsInner;
+
+use libc::{self, c_int, c_void, ssize_t};
+
+#[derive(Debug)]
+pub struct FileDesc {
+    fd: c_int,
+}
+
+fn max_len() -> usize {
+    // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
+    // with the man page quoting that if the count of bytes to read is
+    // greater than `SSIZE_MAX` the result is "unspecified".
+    <ssize_t>::max_value() as usize
+}
+
+impl FileDesc {
+    pub fn new(fd: c_int) -> FileDesc {
+        FileDesc { fd: fd }
+    }
+
+    pub fn raw(&self) -> c_int { self.fd }
+
+    /// Extracts the actual filedescriptor without closing it.
+    pub fn into_raw(self) -> c_int {
+        let fd = self.fd;
+        mem::forget(self);
+        fd
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            libc::read(self.fd,
+                       buf.as_mut_ptr() as *mut c_void,
+                       cmp::min(buf.len(), max_len()))
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            libc::readv(self.fd,
+                        bufs.as_ptr() as *const libc::iovec,
+                        cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
+    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        unsafe fn cvt_pread(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
+            -> io::Result<isize>
+        {
+            use libc::pread;
+            cvt(pread(fd, buf, count, offset))
+        }
+
+        unsafe {
+            cvt_pread(self.fd,
+                buf.as_mut_ptr() as *mut c_void,
+                cmp::min(buf.len(), max_len()),
+                offset as i64)
+            .map(|n| n as usize)
+        }
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            libc::write(self.fd,
+            buf.as_ptr() as *const c_void,
+            cmp::min(buf.len(), max_len()))
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            libc::writev(self.fd,
+                         bufs.as_ptr() as *const libc::iovec,
+                         cmp::min(bufs.len(), c_int::max_value() as usize) as c_int)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        unsafe fn cvt_pwrite(fd: c_int, buf: *const c_void, count: usize, offset: i64)
+            -> io::Result<isize>
+        {
+            use libc::pwrite;
+            cvt(pwrite(fd, buf, count, offset))
+        }
+
+        unsafe {
+            cvt_pwrite(self.fd,
+                buf.as_ptr() as *const c_void,
+                cmp::min(buf.len(), max_len()),
+                offset as i64)
+                .map(|n| n as usize)
+        }
+    }
+
+    pub fn get_cloexec(&self) -> io::Result<bool> {
+        unsafe {
+            Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0)
+        }
+    }
+
+    pub fn set_cloexec(&self) -> io::Result<()> {
+        unsafe {
+            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
+            let new = previous | libc::FD_CLOEXEC;
+            if new != previous {
+                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
+            }
+            Ok(())
+        }
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        unsafe {
+            let v = nonblocking as c_int;
+            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
+            Ok(())
+        }
+    }
+
+    // refer to pxPipeDrv library documentation.
+    // VxWorks uses fcntl to set O_NONBLOCK to the pipes
+    pub fn set_nonblocking_pipe(&self, nonblocking: bool) -> io::Result<()> {
+        unsafe {
+            let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?;
+            flags = if nonblocking {
+                flags | libc::O_NONBLOCK
+            } else {
+                flags & !libc::O_NONBLOCK
+            };
+            cvt(libc::fcntl(self.fd, libc::F_SETFL, flags))?;
+            Ok(())
+        }
+    }
+
+
+    pub fn duplicate(&self) -> io::Result<FileDesc> {
+        let fd = self.raw();
+        match cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }) {
+            Ok(newfd) => {
+                Ok(FileDesc::new(newfd))
+            }
+            Err(e) => return Err(e),
+        }
+    }
+}
+
+impl<'a> Read for &'a FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+
+    #[inline]
+    unsafe fn initializer(&self) -> Initializer {
+        Initializer::nop()
+    }
+}
+
+impl AsInner<c_int> for FileDesc {
+    fn as_inner(&self) -> &c_int { &self.fd }
+}
+
+impl Drop for FileDesc {
+    fn drop(&mut self) {
+        // Note that errors are ignored when closing a file descriptor. The
+        // reason for this is that if an error occurs we don't actually know if
+        // the file descriptor was closed or not, and if we retried (for
+        // something like EINTR), we might close another valid file descriptor
+        // (opened after we closed ours.
+        let _ = unsafe { libc::close(self.fd) };
+    }
+}
diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs
new file mode 100644 (file)
index 0000000..4eb185c
--- /dev/null
@@ -0,0 +1,590 @@
+// copies from linuxx
+use crate::ffi::{CString, CStr, OsString, OsStr};
+use crate::sys::vxworks::ext::ffi::OsStrExt;
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind, SeekFrom, IoSlice, IoSliceMut};
+use crate::mem;
+use crate::path::{Path, PathBuf};
+use crate::ptr;
+use crate::sync::Arc;
+use crate::sys::fd::FileDesc;
+use crate::sys::time::SystemTime;
+use crate::sys::{cvt, cvt_r};
+use crate::sys_common::{AsInner, FromInner};
+use libc::{self, c_int, mode_t, stat64, off_t};
+use libc::{ftruncate, lseek, dirent, readdir_r as readdir64_r, open};
+use crate::sys::vxworks::ext::ffi::OsStringExt;
+pub struct File(FileDesc);
+
+#[derive(Clone)]
+pub struct FileAttr {
+    stat: stat64,
+}
+
+// all DirEntry's will have a reference to this struct
+struct InnerReadDir {
+    dirp: Dir,
+    root: PathBuf,
+}
+
+#[derive(Clone)]
+pub struct ReadDir {
+    inner: Arc<InnerReadDir>,
+    end_of_stream: bool,
+}
+
+struct Dir(*mut libc::DIR);
+
+unsafe impl Send for Dir {}
+unsafe impl Sync for Dir {}
+
+pub struct DirEntry {
+    entry: dirent,
+    dir: ReadDir,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    // generic
+    read: bool,
+    write: bool,
+    append: bool,
+    truncate: bool,
+    create: bool,
+    create_new: bool,
+    // system-specific
+    custom_flags: i32,
+    mode: mode_t,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions { mode: mode_t }
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType { mode: mode_t }
+
+#[derive(Debug)]
+pub struct DirBuilder { mode: mode_t }
+
+impl FileAttr {
+    pub fn size(&self) -> u64 { self.stat.st_size as u64 }
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions { mode: (self.stat.st_mode as mode_t) }
+    }
+
+    pub fn file_type(&self) -> FileType {
+        FileType { mode: self.stat.st_mode as mode_t }
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(libc::timespec {
+            tv_sec: self.stat.st_mtime as libc::time_t,
+            tv_nsec: 0, // hack 2.0;
+        }))
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from(libc::timespec {
+        tv_sec: self.stat.st_atime as libc::time_t,
+        tv_nsec: 0, // hack - a proper fix would be better
+        }))
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        Err(io::Error::new(io::ErrorKind::Other,
+                           "creation time is not available on this platform currently"))
+    }
+
+}
+
+impl AsInner<stat64> for FileAttr {
+    fn as_inner(&self) -> &stat64 { &self.stat }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        // check if any class (owner, group, others) has write permission
+        self.mode & 0o222 == 0
+    }
+
+    pub fn set_readonly(&mut self, readonly: bool) {
+        if readonly {
+            // remove write permission for all classes; equivalent to `chmod a-w <file>`
+            self.mode &= !0o222;
+        } else {
+            // add write permission for all classes; equivalent to `chmod a+w <file>`
+            self.mode |= 0o222;
+        }
+    }
+    pub fn mode(&self) -> u32 { self.mode as u32 }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) }
+    pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) }
+    pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) }
+
+    pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode }
+}
+
+impl FromInner<u32> for FilePermissions {
+    fn from_inner(mode: u32) -> FilePermissions {
+        FilePermissions { mode: mode as mode_t }
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+        // Thus the result will be e g 'ReadDir("/home")'
+        fmt::Debug::fmt(&*self.inner.root, f)
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        if self.end_of_stream {
+            return None;
+        }
+
+        unsafe {
+            let mut ret = DirEntry {
+                entry: mem::zeroed(),
+                dir: self.clone(),
+            };
+            let mut entry_ptr = ptr::null_mut();
+            loop {
+                if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+                    if entry_ptr.is_null() {
+                        // We encountered an error (which will be returned in this iteration), but
+                        // we also reached the end of the directory stream. The `end_of_stream`
+                        // flag is enabled to make sure that we return `None` in the next iteration
+                        // (instead of looping forever)
+                        self.end_of_stream = true;
+                    }
+                    return Some(Err(Error::last_os_error()))
+                }
+                if entry_ptr.is_null() {
+                    return None
+                }
+                if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+                    return Some(Ok(ret))
+                }
+            }
+        }
+    }
+}
+
+impl Drop for Dir {
+    fn drop(&mut self) {
+        let r = unsafe { libc::closedir(self.0) };
+        debug_assert_eq!(r, 0);
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+            use crate::sys::vxworks::ext::ffi::OsStrExt;
+            self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
+    }
+
+    pub fn file_name(&self) -> OsString {
+        OsStr::from_bytes(self.name_bytes()).to_os_string()
+    }
+
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        lstat(&self.path())
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        lstat(&self.path()).map(|m| m.file_type())
+
+    }
+
+    pub fn ino(&self) -> u64 {
+        self.entry.d_ino as u64
+    }
+
+    fn name_bytes(&self) -> &[u8] {
+        unsafe {
+            //&*self.name
+            CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
+        }
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {
+            // generic
+            read: false,
+            write: false,
+            append: false,
+            truncate: false,
+            create: false,
+            create_new: false,
+            // system-specific
+            custom_flags: 0,
+            mode: 0o666,
+        }
+    }
+
+    pub fn read(&mut self, read: bool) { self.read = read; }
+    pub fn write(&mut self, write: bool) { self.write = write; }
+    pub fn append(&mut self, append: bool) { self.append = append; }
+    pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+    pub fn create(&mut self, create: bool) { self.create = create; }
+    pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+    pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; }
+
+    fn get_access_mode(&self) -> io::Result<c_int> {
+        match (self.read, self.write, self.append) {
+            (true,  false, false) => Ok(libc::O_RDONLY),
+            (false, true,  false) => Ok(libc::O_WRONLY),
+            (true,  true,  false) => Ok(libc::O_RDWR),
+            (false, _,     true)  => Ok(libc::O_WRONLY | libc::O_APPEND),
+            (true,  _,     true)  => Ok(libc::O_RDWR | libc::O_APPEND),
+            (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
+        }
+    }
+
+    fn get_creation_mode(&self) -> io::Result<c_int> {
+        match (self.write, self.append) {
+            (true, false) => {}
+            (false, false) =>
+                if self.truncate || self.create || self.create_new {
+                    return Err(Error::from_raw_os_error(libc::EINVAL));
+                },
+            (_, true) =>
+                if self.truncate && !self.create_new {
+                    return Err(Error::from_raw_os_error(libc::EINVAL));
+                },
+        }
+
+        Ok(match (self.create, self.truncate, self.create_new) {
+                (false, false, false) => 0,
+                (true,  false, false) => libc::O_CREAT,
+                (false, true,  false) => libc::O_TRUNC,
+                (true,  true,  false) => libc::O_CREAT | libc::O_TRUNC,
+                (_,      _,    true)  => libc::O_CREAT | libc::O_EXCL,
+           })
+    }
+}
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        let path = cstr(path)?;
+        File::open_c(&path, opts)
+    }
+
+    pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
+        let flags = libc::O_CLOEXEC |
+                opts.get_access_mode()? |
+                opts.get_creation_mode()? |
+                (opts.custom_flags as c_int & !libc::O_ACCMODE);
+        let fd = cvt_r(|| unsafe {
+            open(path.as_ptr(), flags, opts.mode as c_int)
+        })?;
+        let fd = FileDesc::new(fd);
+        // Currently the standard library supports Linux 2.6.18 which did not
+        // have the O_CLOEXEC flag (passed above). If we're running on an older
+        // Linux kernel then the flag is just ignored by the OS. After we open
+        // the first file, we check whether it has CLOEXEC set. If it doesn't,
+        // we will explicitly ask for a CLOEXEC fd for every further file we
+        // open, if it does, we will skip that step.
+        //
+        // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
+        // that we support, so we only do this on Linux currently.
+        fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
+            Ok(())
+        }
+
+        ensure_cloexec(&fd)?;
+        Ok(File(fd))
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        let mut stat: stat64 = unsafe { mem::zeroed() };
+        cvt(unsafe {
+            ::libc::fstat(self.0.raw(), &mut stat)
+        })?;
+        Ok(FileAttr { stat: stat })
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
+        Ok(())
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
+        return Ok(());
+        unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } //not supported
+    }
+
+    pub fn truncate(&self, size: u64) -> io::Result<()> {
+        return cvt_r(|| unsafe {
+            ftruncate(self.0.raw(), size as off_t)
+        }).map(|_| ());
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+
+    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.0.read_at(buf, offset)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.0.write_at(buf, offset)
+    }
+
+    pub fn flush(&self) -> io::Result<()> { Ok(()) }
+
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        let (whence, pos) = match pos {
+            // Casting to `i64` is fine, too large values will end up as
+            // negative which will cause an error in `"lseek64"`.
+            SeekFrom::Start(off) => (libc::SEEK_SET, off as i64),
+            SeekFrom::End(off) => (libc::SEEK_END, off),
+            SeekFrom::Current(off) => (libc::SEEK_CUR, off),
+        };
+        let n = cvt(unsafe { lseek(self.0.raw(), pos, whence) })?;
+        Ok(n as u64)
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        self.0.duplicate().map(File)
+    }
+
+    pub fn fd(&self) -> &FileDesc { &self.0 }
+
+    pub fn into_fd(self) -> FileDesc { self.0 }
+
+    pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+        cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
+        Ok(())
+    }
+
+    pub fn diverge(&self) -> ! {
+        panic!()
+    }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder { mode: 0o777 }
+    }
+
+    pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+        let p = cstr(p)?;
+        cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?;
+        Ok(())
+    }
+
+    pub fn set_mode(&mut self, mode: u32) {
+        self.mode = mode as mode_t;
+    }
+}
+
+fn cstr(path: &Path) -> io::Result<CString> {
+    use crate::sys::vxworks::ext::ffi::OsStrExt;
+    Ok(CString::new(path.as_os_str().as_bytes())?)
+}
+
+impl FromInner<c_int> for File {
+    fn from_inner(fd: c_int) -> File {
+        File(FileDesc::new(fd))
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fn get_path(_fd: c_int) -> Option<PathBuf> {
+            // FIXME(#:(): implement this for VxWorks
+            None
+        }
+        fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
+            // FIXME(#:(): implement this for VxWorks
+            None
+        }
+
+        let fd = self.0.raw();
+        let mut b = f.debug_struct("File");
+        b.field("fd", &fd);
+        if let Some(path) = get_path(fd) {
+            b.field("path", &path);
+        }
+        if let Some((read, write)) = get_mode(fd) {
+            b.field("read", &read).field("write", &write);
+        }
+        b.finish()
+    }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+    let root = p.to_path_buf();
+    let p = cstr(p)?;
+    unsafe {
+        let ptr = libc::opendir(p.as_ptr());
+        if ptr.is_null() {
+            Err(Error::last_os_error())
+        } else {
+            let inner = InnerReadDir { dirp: Dir(ptr), root };
+            Ok(ReadDir{
+                inner: Arc::new(inner),
+                end_of_stream: false,
+            })
+        }
+    }
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+    let p = cstr(p)?;
+    cvt(unsafe { libc::unlink(p.as_ptr()) })?;
+    Ok(())
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+    let old = cstr(old)?;
+    let new = cstr(new)?;
+    cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?;
+    Ok(())
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+    let p = cstr(p)?;
+    cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?;
+    Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+    let p = cstr(p)?;
+    cvt(unsafe { libc::rmdir(p.as_ptr()) })?;
+    Ok(())
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+    let filetype = lstat(path)?.file_type();
+    if filetype.is_symlink() {
+        unlink(path)
+    } else {
+        remove_dir_all_recursive(path)
+    }
+}
+
+fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
+    for child in readdir(path)? {
+        let child = child?;
+        if child.file_type()?.is_dir() {
+            remove_dir_all_recursive(&child.path())?;
+        } else {
+            unlink(&child.path())?;
+        }
+    }
+    rmdir(path)
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+    let c_path = cstr(p)?;
+    let p = c_path.as_ptr();
+
+    let mut buf = Vec::with_capacity(256);
+
+    loop {
+        let buf_read = cvt(unsafe {
+            libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity())
+        })? as usize;
+
+        unsafe { buf.set_len(buf_read); }
+
+        if buf_read != buf.capacity() {
+            buf.shrink_to_fit();
+
+            return Ok(PathBuf::from(OsString::from_vec(buf)));
+        }
+
+        // Trigger the internal buffer resizing logic of `Vec` by requiring
+        // more space than the current capacity. The length is guaranteed to be
+        // the same as the capacity due to the if statement above.
+        buf.reserve(1);
+    }
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+    let src = cstr(src)?;
+    let dst = cstr(dst)?;
+    cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?;
+    Ok(())
+}
+
+pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
+    let src = cstr(src)?;
+    let dst = cstr(dst)?;
+    cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+    Ok(())
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+    let p = cstr(p)?;
+    let mut stat: stat64 = unsafe { mem::zeroed() };
+    cvt(unsafe {
+        libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _)
+    })?;
+    Ok(FileAttr { stat })
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    let p = cstr(p)?;
+    let mut stat: stat64 = unsafe { mem::zeroed() };
+    cvt(unsafe {
+        ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _)
+    })?;
+    Ok(FileAttr { stat })
+}
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+    use crate::sys::vxworks::ext::ffi::OsStrExt;
+    let path = CString::new(p.as_os_str().as_bytes())?;
+    let buf;
+    unsafe {
+        let r = libc::realpath(path.as_ptr(), ptr::null_mut());
+        if r.is_null() {
+            return Err(io::Error::last_os_error())
+        }
+        buf = CStr::from_ptr(r).to_bytes().to_vec();
+        libc::free(r as *mut _);
+    }
+    Ok(PathBuf::from(OsString::from_vec(buf)))
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    use crate::fs::File;
+    if !from.is_file() {
+        return Err(Error::new(ErrorKind::InvalidInput,
+                              "the source path is not an existing regular file"))
+    }
+
+    let mut reader = File::open(from)?;
+    let mut writer = File::create(to)?;
+    let perm = reader.metadata()?.permissions();
+
+    let ret = io::copy(&mut reader, &mut writer)?;
+    writer.set_permissions(perm)?;
+    Ok(ret)
+}
diff --git a/src/libstd/sys/vxworks/io.rs b/src/libstd/sys/vxworks/io.rs
new file mode 100644 (file)
index 0000000..72954ff
--- /dev/null
@@ -0,0 +1,62 @@
+use crate::marker::PhantomData;
+use crate::slice;
+
+use libc::{iovec, c_void};
+
+#[repr(transparent)]
+pub struct IoSlice<'a> {
+    vec: iovec,
+    _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoSlice<'a> {
+    #[inline]
+    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        IoSlice {
+            vec: iovec {
+                iov_base: buf.as_ptr() as *mut u8 as *mut c_void,
+                iov_len: buf.len()
+            },
+            _p: PhantomData,
+        }
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len)
+        }
+    }
+}
+
+pub struct IoSliceMut<'a> {
+    vec: iovec,
+    _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoSliceMut<'a> {
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        IoSliceMut {
+            vec: iovec {
+                iov_base: buf.as_mut_ptr() as *mut c_void,
+                iov_len: buf.len()
+            },
+            _p: PhantomData,
+        }
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len)
+        }
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len)
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/l4re.rs b/src/libstd/sys/vxworks/l4re.rs
new file mode 100644 (file)
index 0000000..b3dd1cf
--- /dev/null
@@ -0,0 +1,469 @@
+macro_rules! unimpl {
+    () => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));)
+}
+
+pub mod net {
+    #![allow(warnings)]
+    use crate::fmt;
+    use crate::io::{self, IoVec, IoVecMut};
+    use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+    use crate::sys_common::{AsInner, FromInner, IntoInner};
+    use crate::sys::fd::FileDesc;
+    use crate::time::Duration;
+    use crate::convert::TryFrom;
+
+    #[allow(unused_extern_crates)]
+    pub extern crate libc as netc;
+
+    pub struct Socket(FileDesc);
+    impl Socket {
+        pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
+            unimpl!();
+        }
+
+        pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t)
+                  -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<Socket> {
+            unimpl!();
+        }
+
+        pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn nodelay(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+    }
+
+    impl AsInner<libc::c_int> for Socket {
+        fn as_inner(&self) -> &libc::c_int { self.0.as_inner() }
+    }
+
+    impl FromInner<libc::c_int> for Socket {
+        fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) }
+    }
+
+    impl IntoInner<libc::c_int> for Socket {
+        fn into_inner(self) -> libc::c_int { self.0.into_raw() }
+    }
+
+    pub struct TcpStream {
+        inner: Socket,
+    }
+
+    impl TcpStream {
+        pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+            unimpl!();
+        }
+
+        pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+            unimpl!();
+        }
+
+        pub fn socket(&self) -> &Socket { &self.inner }
+
+        pub fn into_socket(self) -> Socket { self.inner }
+
+        pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<TcpStream> {
+            unimpl!();
+        }
+
+        pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn nodelay(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn ttl(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+    }
+
+    impl FromInner<Socket> for TcpStream {
+        fn from_inner(socket: Socket) -> TcpStream {
+            TcpStream { inner: socket }
+        }
+    }
+
+    impl fmt::Debug for TcpStream {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "No networking support available on L4Re")
+        }
+    }
+
+    pub struct TcpListener {
+        inner: Socket,
+    }
+
+    impl TcpListener {
+        pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+            unimpl!();
+        }
+
+        pub fn socket(&self) -> &Socket { &self.inner }
+
+        pub fn into_socket(self) -> Socket { self.inner }
+
+        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<TcpListener> {
+            unimpl!();
+        }
+
+        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn ttl(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn only_v6(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+    }
+
+    impl FromInner<Socket> for TcpListener {
+        fn from_inner(socket: Socket) -> TcpListener {
+            TcpListener { inner: socket }
+        }
+    }
+
+    impl fmt::Debug for TcpListener {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "No networking support available on L4Re.")
+        }
+    }
+
+    pub struct UdpSocket {
+        inner: Socket,
+    }
+
+    impl UdpSocket {
+        pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+            unimpl!();
+        }
+
+        pub fn socket(&self) -> &Socket { &self.inner }
+
+        pub fn into_socket(self) -> Socket { self.inner }
+
+        pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+            unimpl!();
+        }
+
+        pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+            unimpl!();
+        }
+
+        pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn duplicate(&self) -> io::Result<UdpSocket> {
+            unimpl!();
+        }
+
+        pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
+        pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn broadcast(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+            unimpl!();
+        }
+
+        pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                             -> io::Result<()> {
+                                 unimpl!();
+        }
+
+        pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                             -> io::Result<()> {
+                                 unimpl!();
+        }
+
+        pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                              -> io::Result<()> {
+                                  unimpl!();
+        }
+
+        pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                              -> io::Result<()> {
+                                  unimpl!();
+        }
+
+        pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn ttl(&self) -> io::Result<u32> {
+            unimpl!();
+        }
+
+        pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+            unimpl!();
+        }
+
+        pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+            unimpl!();
+        }
+
+        pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+            unimpl!();
+        }
+    }
+
+    impl FromInner<Socket> for UdpSocket {
+        fn from_inner(socket: Socket) -> UdpSocket {
+            UdpSocket { inner: socket }
+        }
+    }
+
+    impl fmt::Debug for UdpSocket {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "No networking support on L4Re available.")
+        }
+    }
+
+    pub struct LookupHost {
+        original: *mut libc::addrinfo,
+        cur: *mut libc::addrinfo,
+    }
+
+    impl Iterator for LookupHost {
+        type Item = SocketAddr;
+        fn next(&mut self) -> Option<SocketAddr> {
+            None
+        }
+    }
+
+    impl LookupHost {
+        pub fn port(&self) -> u16 {
+            unimpl!();
+        }
+    }
+
+    unsafe impl Sync for LookupHost {}
+    unsafe impl Send for LookupHost {}
+
+
+    impl TryFrom<&str> for LookupHost {
+        type Error = io::Error;
+
+        fn try_from(_v: &str) -> io::Result<LookupHost> {
+            unimpl!();
+        }
+    }
+
+    impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+        type Error = io::Error;
+
+        fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+            unimpl!();
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/memchr.rs b/src/libstd/sys/vxworks/memchr.rs
new file mode 100644 (file)
index 0000000..1984678
--- /dev/null
@@ -0,0 +1,43 @@
+// Original implementation taken from rust-memchr.
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    let p = unsafe {
+        libc::memchr(
+            haystack.as_ptr() as *const libc::c_void,
+            needle as libc::c_int,
+            haystack.len())
+    };
+    if p.is_null() {
+        None
+    } else {
+        Some(p as usize - (haystack.as_ptr() as usize))
+    }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+
+    #[cfg(target_os = "linux")]
+    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+        // GNU's memrchr() will - unlike memchr() - error if haystack is empty.
+        if haystack.is_empty() {return None}
+        let p = unsafe {
+            libc::memrchr(
+                haystack.as_ptr() as *const libc::c_void,
+                needle as libc::c_int,
+                haystack.len())
+        };
+        if p.is_null() {
+            None
+        } else {
+            Some(p as usize - (haystack.as_ptr() as usize))
+        }
+    }
+
+    #[cfg(not(target_os = "linux"))]
+    fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
+        core::slice::memchr::memrchr(needle, haystack)
+    }
+
+    memrchr_specific(needle, haystack)
+}
diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs
new file mode 100644 (file)
index 0000000..b01bea0
--- /dev/null
@@ -0,0 +1,139 @@
+#![allow(dead_code)]
+#![allow(missing_docs, nonstandard_style)]
+
+use crate::io::ErrorKind;
+
+pub use crate::os::vxworks as platform;
+pub use self::rand::hashmap_random_keys;
+pub use libc::strlen;
+
+#[macro_use]
+pub mod weak;
+
+pub mod alloc;
+pub mod args;
+pub mod android;
+//#[cfg(feature = "backtrace")]
+//pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod ext;
+pub mod fast_thread_local;
+pub mod fd;
+pub mod fs;
+pub mod memchr;
+pub mod io;
+pub mod mutex;
+#[cfg(not(target_os = "l4re"))]
+pub mod net;
+#[cfg(target_os = "l4re")]
+mod l4re;
+#[cfg(target_os = "l4re")]
+pub use self::l4re::net;
+pub mod os;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+pub mod stdio;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+
+#[cfg(not(test))]
+pub fn init() {
+    // By default, some platforms will send a *signal* when an EPIPE error
+    // would otherwise be delivered. This runtime doesn't install a SIGPIPE
+    // handler, causing it to kill the program, which isn't exactly what we
+    // want!
+    //
+    // Hence, we set SIGPIPE to ignore when the program starts up in order
+    // to prevent this problem.
+    unsafe {
+        reset_sigpipe();
+    }
+
+    unsafe fn reset_sigpipe() { }
+}
+
+#[cfg(target_os = "android")]
+pub use crate::sys::android::signal;
+#[cfg(not(target_os = "android"))]
+pub use libc::signal;
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+    match errno as libc::c_int {
+        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        libc::ECONNRESET => ErrorKind::ConnectionReset,
+        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
+        libc::EPIPE => ErrorKind::BrokenPipe,
+        libc::ENOTCONN => ErrorKind::NotConnected,
+        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
+        libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+        libc::EADDRINUSE => ErrorKind::AddrInUse,
+        libc::ENOENT => ErrorKind::NotFound,
+        libc::EINTR => ErrorKind::Interrupted,
+        libc::EINVAL => ErrorKind::InvalidInput,
+        libc::ETIMEDOUT => ErrorKind::TimedOut,
+        libc::EEXIST => ErrorKind::AlreadyExists,
+
+        // These two constants can have the same value on some systems,
+        // but different values on others, so we can't use a match
+        // clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+            ErrorKind::WouldBlock,
+
+        _ => ErrorKind::Other,
+    }
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+    if t.is_minus_one() {
+        Err(crate::io::Error::last_os_error())
+    } else {
+        Ok(t)
+    }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+    where T: IsMinusOne,
+          F: FnMut() -> T
+{
+    loop {
+        match cvt(f()) {
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+            other => return other,
+        }
+    }
+}
+
+// On Unix-like platforms, libc::abort will unregister signal handlers
+// including the SIGABRT handler, preventing the abort from being blocked, and
+// fclose streams, with the side effect of flushing them so libc bufferred
+// output will be printed.  Additionally the shell will generally print a more
+// understandable error message like "Abort trap" rather than "Illegal
+// instruction" that intrinsics::abort would cause, as intrinsics::abort is
+// implemented as an illegal instruction.
+pub unsafe fn abort_internal() -> ! {
+    libc::abort()
+}
diff --git a/src/libstd/sys/vxworks/mutex.rs b/src/libstd/sys/vxworks/mutex.rs
new file mode 100644 (file)
index 0000000..b43af8f
--- /dev/null
@@ -0,0 +1,127 @@
+use crate::cell::UnsafeCell;
+use crate::mem::MaybeUninit;
+
+pub struct Mutex { inner: UnsafeCell<libc::pthread_mutex_t> }
+
+#[inline]
+pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t {
+    m.inner.get()
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+#[allow(dead_code)] // sys isn't exported yet
+impl Mutex {
+    pub const fn new() -> Mutex {
+        // Might be moved to a different address, so it is better to avoid
+        // initialization of potentially opaque OS data before it landed.
+        // Be very careful using this newly constructed `Mutex`, reentrant
+        // locking is undefined behavior until `init` is called!
+        Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
+    }
+    #[inline]
+    pub unsafe fn init(&mut self) {
+        // Issue #33770
+        //
+        // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have
+        // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you
+        // try to re-lock it from the same thread when you already hold a lock.
+        //
+        // In practice, glibc takes advantage of this undefined behavior to
+        // implement hardware lock elision, which uses hardware transactional
+        // memory to avoid acquiring the lock. While a transaction is in
+        // progress, the lock appears to be unlocked. This isn't a problem for
+        // other threads since the transactional memory will abort if a conflict
+        // is detected, however no abort is generated if re-locking from the
+        // same thread.
+        //
+        // Since locking the same mutex twice will result in two aliasing &mut
+        // references, we instead create the mutex with type
+        // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
+        // re-lock it from the same thread, thus avoiding undefined behavior.
+        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
+        let r = libc::pthread_mutexattr_init(attr.as_mut_ptr());
+        debug_assert_eq!(r, 0);
+        let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL);
+        debug_assert_eq!(r, 0);
+        let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr());
+        debug_assert_eq!(r, 0);
+        let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
+        debug_assert_eq!(r, 0);
+    }
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let r = libc::pthread_mutex_lock(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        let r = libc::pthread_mutex_unlock(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        libc::pthread_mutex_trylock(self.inner.get()) == 0
+    }
+    #[inline]
+    #[cfg(not(target_os = "dragonfly"))]
+    pub unsafe fn destroy(&self) {
+        let r = libc::pthread_mutex_destroy(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+    #[inline]
+    #[cfg(target_os = "dragonfly")]
+    pub unsafe fn destroy(&self) {
+        let r = libc::pthread_mutex_destroy(self.inner.get());
+        // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a
+        // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER.
+        // Once it is used (locked/unlocked) or pthread_mutex_init() is called,
+        // this behaviour no longer occurs.
+        debug_assert!(r == 0 || r == libc::EINVAL);
+    }
+}
+
+pub struct ReentrantMutex { inner: UnsafeCell<libc::pthread_mutex_t> }
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+    pub unsafe fn uninitialized() -> ReentrantMutex {
+        ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
+    }
+
+    pub unsafe fn init(&mut self) {
+        let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
+        let result = libc::pthread_mutexattr_init(attr.as_mut_ptr());
+        debug_assert_eq!(result, 0);
+        let result = libc::pthread_mutexattr_settype(attr.as_mut_ptr(),
+                                                    libc::PTHREAD_MUTEX_RECURSIVE);
+        debug_assert_eq!(result, 0);
+        let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr());
+        debug_assert_eq!(result, 0);
+        let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr());
+        debug_assert_eq!(result, 0);
+    }
+
+    pub unsafe fn lock(&self) {
+        let result = libc::pthread_mutex_lock(self.inner.get());
+        debug_assert_eq!(result, 0);
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        libc::pthread_mutex_trylock(self.inner.get()) == 0
+    }
+
+    pub unsafe fn unlock(&self) {
+        let result = libc::pthread_mutex_unlock(self.inner.get());
+        debug_assert_eq!(result, 0);
+    }
+
+    pub unsafe fn destroy(&self) {
+        let result = libc::pthread_mutex_destroy(self.inner.get());
+        debug_assert_eq!(result, 0);
+    }
+}
diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs
new file mode 100644 (file)
index 0000000..686cea4
--- /dev/null
@@ -0,0 +1,374 @@
+use crate::ffi::CStr;
+use crate::io;
+use crate::io::{IoSlice, IoSliceMut};
+use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK};
+use crate::mem;
+use crate::net::{SocketAddr, Shutdown};
+use crate::str;
+use crate::sys::fd::FileDesc;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::time::{Duration, Instant};
+use crate::cmp;
+
+pub use crate::sys::{cvt, cvt_r};
+
+#[allow(unused_extern_crates)]
+pub extern crate libc as netc;
+
+pub type wrlen_t = size_t;
+
+
+const SOCK_CLOEXEC: c_int = 0;
+const SO_NOSIGPIPE: c_int = 0;
+
+pub struct Socket(FileDesc);
+
+pub fn init() {}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 {
+        return Ok(())
+    }
+
+    // We may need to trigger a glibc workaround. See on_resolver_failure() for details.
+    on_resolver_failure();
+
+    if err == EAI_SYSTEM {
+        return Err(io::Error::last_os_error())
+    }
+
+    let detail = unsafe {
+        str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap()
+            .to_owned()
+    };
+    Err(io::Error::new(io::ErrorKind::Other,
+                       &format!("failed to lookup address information: {}",
+                                detail)[..]))
+}
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match *addr {
+            SocketAddr::V4(..) => libc::AF_INET,
+            SocketAddr::V6(..) => libc::AF_INET6,
+        };
+        Socket::new_raw(fam, ty)
+    }
+
+    pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+        unsafe {
+            // On linux we first attempt to pass the SOCK_CLOEXEC flag to
+            // atomically create the socket and set it as CLOEXEC. Support for
+            // this option, however, was added in 2.6.27, and we still support
+            // 2.6.18 as a kernel, so if the returned error is EINVAL we
+            // fallthrough to the fallback.
+            if cfg!(target_os = "linux") {
+                match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
+                    Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+                    Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+                    Err(e) => return Err(e),
+                }
+            }
+
+            let fd = cvt(libc::socket(fam, ty, 0))?;
+            let fd = FileDesc::new(fd);
+            fd.set_cloexec()?;
+            let socket = Socket(fd);
+            Ok(socket)
+        }
+    }
+
+    pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> {
+            unimplemented!();
+    }
+
+    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+        self.set_nonblocking(true)?;
+        let r = unsafe {
+            let (addrp, len) = addr.into_inner();
+            cvt(libc::connect(self.0.raw(), addrp, len))
+        };
+        self.set_nonblocking(false)?;
+
+        match r {
+            Ok(_) => return Ok(()),
+            // there's no ErrorKind for EINPROGRESS :(
+            Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
+            Err(e) => return Err(e),
+        }
+
+        let mut pollfd = libc::pollfd {
+            fd: self.0.raw(),
+            events: libc::POLLOUT,
+            revents: 0,
+        };
+
+        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+            return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                      "cannot set a 0 duration timeout"));
+        }
+
+        let start = Instant::now();
+
+        loop {
+            let elapsed = start.elapsed();
+            if elapsed >= timeout {
+                return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out"));
+            }
+
+            let timeout = timeout - elapsed;
+            let mut timeout = timeout.as_secs()
+                .saturating_mul(1_000)
+                .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+            if timeout == 0 {
+                timeout = 1;
+            }
+
+            let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
+
+            match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
+                -1 => {
+                    let err = io::Error::last_os_error();
+                    if err.kind() != io::ErrorKind::Interrupted {
+                        return Err(err);
+                    }
+                }
+                0 => {}
+                _ => {
+                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+                    // for POLLHUP rather than read readiness
+                    if pollfd.revents & libc::POLLHUP != 0 {
+                        let e = self.take_error()?
+                            .unwrap_or_else(|| {
+                                io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+                            });
+                        return Err(e);
+                    }
+
+                    return Ok(());
+                }
+            }
+        }
+    }
+
+    pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
+                  -> io::Result<Socket> {
+        // Unfortunately the only known way right now to accept a socket and
+        // atomically set the CLOEXEC flag is to use the `accept4` syscall on
+        // Linux. This was added in 2.6.28, however, and because we support
+        // 2.6.18 we must detect this support dynamically.
+        let fd = cvt_r(|| unsafe {
+            libc::accept(self.0.raw(), storage, len)
+        })?;
+        let fd = FileDesc::new(fd);
+        fd.set_cloexec()?;
+        Ok(Socket(fd))
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        self.0.duplicate().map(Socket)
+    }
+
+    fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            libc::recv(self.0.raw(),
+                       buf.as_mut_ptr() as *mut c_void,
+                       buf.len(),
+                       flags)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.recv_with_flags(buf, 0)
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.recv_with_flags(buf, MSG_PEEK)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+
+    fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
+                            -> io::Result<(usize, SocketAddr)> {
+        let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
+
+        let n = cvt(unsafe {
+            libc::recvfrom(self.0.raw(),
+                        buf.as_mut_ptr() as *mut c_void,
+                        buf.len(),
+                        flags,
+                        &mut storage as *mut _ as *mut _,
+                        &mut addrlen)
+        })?;
+        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, 0)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, MSG_PEEK)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+        let timeout = match dur {
+            Some(dur) => {
+                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+                    return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                              "cannot set a 0 duration timeout"));
+                }
+
+                let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
+                    libc::time_t::max_value()
+                } else {
+                    dur.as_secs() as libc::time_t
+                };
+                let mut timeout = libc::timeval {
+                    tv_sec: secs,
+                    tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
+                };
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
+                timeout
+            }
+            None => {
+                libc::timeval {
+                    tv_sec: 0,
+                    tv_usec: 0,
+                }
+            }
+        };
+        setsockopt(self, libc::SOL_SOCKET, kind, timeout)
+    }
+
+    pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
+        let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?;
+        if raw.tv_sec == 0 && raw.tv_usec == 0 {
+            Ok(None)
+        } else {
+            let sec = raw.tv_sec as u64;
+            let nsec = (raw.tv_usec as u32) * 1000;
+            Ok(Some(Duration::new(sec, nsec)))
+        }
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        let how = match how {
+            Shutdown::Write => libc::SHUT_WR,
+            Shutdown::Read => libc::SHUT_RD,
+            Shutdown::Both => libc::SHUT_RDWR,
+        };
+        cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
+        Ok(())
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut nonblocking = nonblocking as libc::c_int;
+        cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ())
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
+        if raw == 0 {
+            Ok(None)
+        } else {
+            Ok(Some(io::Error::from_raw_os_error(raw as i32)))
+        }
+    }
+}
+
+impl AsInner<c_int> for Socket {
+    fn as_inner(&self) -> &c_int { self.0.as_inner() }
+}
+
+impl FromInner<c_int> for Socket {
+    fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) }
+}
+
+impl IntoInner<c_int> for Socket {
+    fn into_inner(self) -> c_int { self.0.into_raw() }
+}
+
+// In versions of glibc prior to 2.26, there's a bug where the DNS resolver
+// will cache the contents of /etc/resolv.conf, so changes to that file on disk
+// can be ignored by a long-running program. That can break DNS lookups on e.g.
+// laptops where the network comes and goes. See
+// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some
+// distros including Debian have patched glibc to fix this for a long time.
+//
+// A workaround for this bug is to call the res_init libc function, to clear
+// the cached configs. Unfortunately, while we believe glibc's implementation
+// of res_init is thread-safe, we know that other implementations are not
+// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// try to synchronize its res_init calls with a Mutex, but that wouldn't
+// protect programs that call into libc in other ways. So instead of calling
+// res_init unconditionally, we call it only when we detect we're linking
+// against glibc version < 2.26. (That is, when we both know its needed and
+// believe it's thread-safe).
+#[cfg(target_env = "gnu")]
+fn on_resolver_failure() {
+/*
+    use crate::sys;
+
+    // If the version fails to parse, we treat it the same as "not glibc".
+    if let Some(version) = sys::os::glibc_version() {
+        if version < (2, 26) {
+            unsafe { libc::res_init() };
+        }
+    }
+    */
+}
+
+#[cfg(not(target_env = "gnu"))]
+fn on_resolver_failure() {}
+
+#[cfg(all(test, taget_env = "gnu"))]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_res_init() {
+        // This mostly just tests that the weak linkage doesn't panic wildly...
+        res_init_if_glibc_before_2_26().unwrap();
+    }
+
+    #[test]
+    fn test_parse_glibc_version() {
+        let cases = [
+            ("0.0", Some((0, 0))),
+            ("01.+2", Some((1, 2))),
+            ("3.4.5.six", Some((3, 4))),
+            ("1", None),
+            ("1.-2", None),
+            ("1.foo", None),
+            ("foo.1", None),
+        ];
+        for &(version_str, parsed) in cases.iter() {
+            assert_eq!(parsed, parse_glibc_version(version_str));
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/os.rs b/src/libstd/sys/vxworks/os.rs
new file mode 100644 (file)
index 0000000..5dc35a6
--- /dev/null
@@ -0,0 +1,324 @@
+use crate::error::Error as StdError;
+use crate::ffi::{CString, CStr, OsString, OsStr};
+use crate::fmt;
+use crate::io;
+use crate::iter;
+use libc::{self, c_int, c_char /*,c_void */};
+use crate::marker::PhantomData;
+use crate::mem;
+use crate::memchr;
+use crate::path::{self, PathBuf, Path};
+use crate::ptr;
+use crate::slice;
+use crate::str;
+use crate::sys_common::mutex::Mutex;
+use crate::sys::cvt;
+/*use sys::fd; this one is probably important */
+use crate::vec;
+
+const TMPBUF_SZ: usize = 128;
+static ENV_LOCK: Mutex = Mutex::new();
+
+
+// This is a terrible fix
+use crate::sys::os_str::Buf;
+use crate::sys_common::{FromInner, IntoInner, AsInner};
+
+pub trait OsStringExt {
+    fn from_vec(vec: Vec<u8>) -> Self;
+    fn into_vec(self) -> Vec<u8>;
+}
+
+impl OsStringExt for OsString {
+    fn from_vec(vec: Vec<u8>) -> OsString {
+        FromInner::from_inner(Buf { inner: vec })
+    }
+    fn into_vec(self) -> Vec<u8> {
+        self.into_inner().inner
+    }
+}
+
+pub trait OsStrExt {
+    fn from_bytes(slice: &[u8]) -> &Self;
+    fn as_bytes(&self) -> &[u8];
+}
+
+impl OsStrExt for OsStr {
+    fn from_bytes(slice: &[u8]) -> &OsStr {
+        unsafe { mem::transmute(slice) }
+    }
+    fn as_bytes(&self) -> &[u8] {
+        &self.as_inner().inner
+    }
+}
+
+pub fn errno() -> i32 {
+    unsafe { libc::errnoGet() }
+}
+
+pub fn set_errno(e: i32) {
+    unsafe { libc::errnoSet(e as c_int); }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+    let mut buf = [0 as c_char; TMPBUF_SZ];
+    extern {
+        fn strerror_r(
+            errnum: c_int,
+            buf: *mut c_char,
+            buflen: libc::size_t
+        ) -> c_int;
+    }
+
+    let p = buf.as_mut_ptr();
+    unsafe {
+        if strerror_r(errno as c_int, p, buf.len()) < 0 {
+            panic!("strerror_r failure");
+        }
+        let p = p as *const _;
+        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
+    }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    let mut buf = Vec::with_capacity(512);
+    loop {
+        unsafe {
+            let ptr = buf.as_mut_ptr() as *mut libc::c_char;
+            if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() {
+                let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
+                buf.set_len(len);
+                buf.shrink_to_fit();
+                return Ok(PathBuf::from(OsString::from_vec(buf)));
+            } else {
+                let error = io::Error::last_os_error();
+                if error.raw_os_error() != Some(libc::ERANGE) {
+                    return Err(error);
+                }
+            }
+            // Trigger the internal buffer resizing logic of `Vec` by requiring
+            // more space than the current capacity.
+            let cap = buf.capacity();
+            buf.set_len(cap);
+            buf.reserve(1);
+        }
+    }
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+    let p: &OsStr = p.as_ref();
+    let p = CString::new(p.as_bytes())?;
+    unsafe {
+        match libc::chdir(p.as_ptr()) == (0 as c_int) {
+            true => Ok(()),
+            false => Err(io::Error::last_os_error()),
+        }
+    }
+}
+
+pub struct SplitPaths<'a> {
+    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
+            fn(&'a [u8]) -> PathBuf>,
+}
+
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
+    fn bytes_to_path(b: &[u8]) -> PathBuf {
+        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
+    }
+    fn is_colon(b: &u8) -> bool { *b == b':' }
+    let unparsed = unparsed.as_bytes();
+    SplitPaths {
+        iter: unparsed.split(is_colon as fn(&u8) -> bool)
+                        .map(bytes_to_path as fn(&[u8]) -> PathBuf)
+    }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+    let mut joined = Vec::new();
+    let sep = b':';
+
+    for (i, path) in paths.enumerate() {
+        let path = path.as_ref().as_bytes();
+        if i > 0 {
+            joined.push(sep)
+        }
+        if path.contains(&sep) {
+            return Err(JoinPathsError)
+        }
+        joined.extend_from_slice(path);
+    }
+    Ok(OsStringExt::from_vec(joined))
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "path segment contains separator `:`".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str { "failed to join paths" }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    #[cfg(test)]
+    use realstd::env;
+
+    #[cfg(not(test))]
+    use crate::env;
+
+    let exe_path = env::args().next().unwrap();
+    let path = Path::new(&exe_path);
+    path.canonicalize()
+}
+
+pub struct Env {
+    iter: vec::IntoIter<(OsString, OsString)>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+pub unsafe fn environ() -> *mut *const *const c_char {
+    extern { static mut environ: *const *const c_char; }
+    &mut environ
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+    unsafe {
+        let _guard = ENV_LOCK.lock();
+        let mut environ = *environ();
+        if environ == ptr::null() {
+            panic!("os::env() failure getting env string from OS: {}",
+                io::Error::last_os_error());
+        }
+        let mut result = Vec::new();
+        while *environ != ptr::null() {
+            if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+                result.push(key_value);
+            }
+            environ = environ.offset(1);
+        }
+        return Env {
+            iter: result.into_iter(),
+            _dont_send_or_sync_me: PhantomData,
+        }
+    }
+
+    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+        // Strategy (copied from glibc): Variable name and value are separated
+        // by an ASCII equals sign '='. Since a variable name must not be
+        // empty, allow variable names starting with an equals sign. Skip all
+        // malformed lines.
+        if input.is_empty() {
+            return None;
+        }
+        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+        pos.map(|p| (
+            OsStringExt::from_vec(input[..p].to_vec()),
+            OsStringExt::from_vec(input[p+1..].to_vec()),
+        ))
+    }
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+    // environment variables with a nul byte can't be set, so their value is
+    // always None as well
+    let k = CString::new(k.as_bytes())?;
+    unsafe {
+        let _guard = ENV_LOCK.lock();
+        let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+        let ret = if s.is_null() {
+            None
+        } else {
+            Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
+        };
+        Ok(ret)
+    }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    let k = CString::new(k.as_bytes())?;
+    let v = CString::new(v.as_bytes())?;
+
+    unsafe {
+        let _guard = ENV_LOCK.lock();
+        cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
+    }
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+    let nbuf = CString::new(n.as_bytes())?;
+
+    unsafe {
+        let _guard = ENV_LOCK.lock();
+        cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
+    }
+}
+
+pub fn page_size() -> usize {
+    unsafe {
+        libc::sysconf(libc::_SC_PAGESIZE) as usize
+    }
+}
+
+pub fn temp_dir() -> PathBuf {
+    crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
+        PathBuf::from("/tmp")
+    })
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    return crate::env::var_os("HOME").or_else(|| unsafe {
+        fallback()
+    }).map(PathBuf::from);
+
+    unsafe fn fallback() -> Option<OsString> {
+        let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
+            n if n < 0 => 512 as usize,
+            n => n as usize,
+        };
+        let mut buf = Vec::with_capacity(amt);
+        let mut passwd: libc::passwd = mem::zeroed();
+        let mut result = ptr::null_mut();
+        match libc::getpwuid_r(libc::getuid(), &mut passwd, buf.as_mut_ptr(),
+                                buf.capacity(), &mut result) {
+            0 if !result.is_null() => {
+                let ptr = passwd.pw_dir as *const _;
+                let bytes = CStr::from_ptr(ptr).to_bytes().to_vec();
+                Some(OsStringExt::from_vec(bytes))
+            },
+            _ => None,
+        }
+    }
+}
+
+pub fn exit(code: i32) -> ! {
+    unsafe { libc::exit(code as c_int) }
+}
+
+pub fn getpid() -> u32 {
+    unsafe { libc::getpid() as u32 }
+}
+
+pub fn getppid() -> u32 {
+    unsafe { libc::getppid() as u32 }
+}
diff --git a/src/libstd/sys/vxworks/path.rs b/src/libstd/sys/vxworks/path.rs
new file mode 100644 (file)
index 0000000..7a18395
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+    None
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/vxworks/pipe.rs b/src/libstd/sys/vxworks/pipe.rs
new file mode 100644 (file)
index 0000000..8363783
--- /dev/null
@@ -0,0 +1,100 @@
+use crate::io::{self, IoSlice, IoSliceMut};
+use libc::{self /*, c_int apparently not used? */};
+use crate::mem;
+use crate::sync::atomic::{AtomicBool};
+use crate::sys::fd::FileDesc;
+use crate::sys::{cvt, cvt_r};
+
+pub struct AnonPipe(FileDesc);
+
+pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+    static INVALID: AtomicBool = AtomicBool::new(false);
+
+    let mut fds = [0; 2];
+
+    // Unfortunately the only known way right now to create atomically set the
+    // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
+    // 2.6.27, however, and because we support 2.6.18 we must detect this
+    // support dynamically.
+    cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
+
+    let fd0 = FileDesc::new(fds[0]);
+    let fd1 = FileDesc::new(fds[1]);
+    fd0.set_cloexec()?;
+    fd1.set_cloexec()?;
+    Ok((AnonPipe(fd0), AnonPipe(fd1)))
+}
+
+impl AnonPipe {
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+                self.0.read_vectored(bufs)
+        }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+        pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+                self.0.write_vectored(bufs)
+        }
+
+    pub fn fd(&self) -> &FileDesc { &self.0 }
+    pub fn into_fd(self) -> FileDesc { self.0 }
+    pub fn diverge(&self) -> ! {
+        panic!()
+     }
+}
+
+pub fn read2(p1: AnonPipe,
+             v1: &mut Vec<u8>,
+             p2: AnonPipe,
+             v2: &mut Vec<u8>) -> io::Result<()> {
+
+    // Set both pipes into nonblocking mode as we're gonna be reading from both
+    // in the `select` loop below, and we wouldn't want one to block the other!
+    let p1 = p1.into_fd();
+    let p2 = p2.into_fd();
+    p1.set_nonblocking_pipe(true)?;
+    p2.set_nonblocking_pipe(true)?;
+
+    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
+    fds[0].fd = p1.raw();
+    fds[0].events = libc::POLLIN;
+    fds[1].fd = p2.raw();
+    fds[1].events = libc::POLLIN;
+    loop {
+        // wait for either pipe to become readable using `poll`
+        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
+
+        if fds[0].revents != 0 && read(&p1, v1)? {
+            p2.set_nonblocking_pipe(false)?;
+            return p2.read_to_end(v2).map(|_| ());
+        }
+        if fds[1].revents != 0 && read(&p2, v2)? {
+            p1.set_nonblocking_pipe(false)?;
+            return p1.read_to_end(v1).map(|_| ());
+        }
+    }
+
+    // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+    // EAGAIN. If we hit EOF, then this will happen because the underlying
+    // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+    // this case we flip the other fd back into blocking mode and read
+    // whatever's leftover on that file descriptor.
+    fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> {
+        match fd.read_to_end(dst) {
+            Ok(_) => Ok(true),
+            Err(e) => {
+                if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+                   e.raw_os_error() == Some(libc::EAGAIN) {
+                    Ok(false)
+                } else {
+                    Err(e)
+                }
+            }
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/process/mod.rs b/src/libstd/sys/vxworks/process/mod.rs
new file mode 100644 (file)
index 0000000..4dc7060
--- /dev/null
@@ -0,0 +1,7 @@
+pub use self::process_common::{Command, ExitStatus, ExitCode, Stdio, StdioPipes};
+pub use self::process_inner::Process;
+
+mod process_common;
+#[path = "process_vxworks.rs"]
+mod process_inner;
+mod rtp;
diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs
new file mode 100644 (file)
index 0000000..db4e80c
--- /dev/null
@@ -0,0 +1,503 @@
+use crate::os::unix::prelude::*;
+
+use crate::ffi::{OsString, OsStr, CString, CStr};
+use crate::fmt;
+use crate::io;
+use crate::ptr;
+use crate::sys::fd::FileDesc;
+use crate::sys::fs::{File, OpenOptions};
+use crate::sys::pipe::{self, AnonPipe};
+use crate::sys_common::process::{CommandEnv, DefaultEnvKey};
+use crate::collections::BTreeMap;
+
+use libc::{c_int, gid_t, uid_t, c_char, EXIT_SUCCESS, EXIT_FAILURE};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    // Currently we try hard to ensure that the call to `.exec()` doesn't
+    // actually allocate any memory. While many platforms try to ensure that
+    // memory allocation works after a fork in a multithreaded process, it's
+    // been observed to be buggy and somewhat unreliable, so we do our best to
+    // just not do it at all!
+    //
+    // Along those lines, the `argv` and `envp` raw pointers here are exactly
+    // what's gonna get passed to `execvp`. The `argv` array starts with the
+    // `program` and ends with a NULL, and the `envp` pointer, if present, is
+    // also null-terminated.
+    //
+    // Right now we don't support removing arguments, so there's no much fancy
+    // support there, but we support adding and removing environment variables,
+    // so a side table is used to track where in the `envp` array each key is
+    // located. Whenever we add a key we update it in place if it's already
+    // present, and whenever we remove a key we update the locations of all
+    // other keys.
+    program: CString,
+    args: Vec<CString>,
+    argv: Argv,
+    env: CommandEnv<DefaultEnvKey>,
+
+    cwd: Option<CString>,
+    uid: Option<uid_t>,
+    gid: Option<gid_t>,
+    saw_nul: bool,
+    closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
+    stdin: Option<Stdio>,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
+}
+
+// Create a new type for argv, so that we can make it `Send`
+struct Argv(Vec<*const c_char>);
+
+// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args`
+unsafe impl Send for Argv {}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+// passed to do_exec() with configuration of what the child stdio should look
+// like
+pub struct ChildPipes {
+    pub stdin: ChildStdio,
+    pub stdout: ChildStdio,
+    pub stderr: ChildStdio,
+}
+
+pub enum ChildStdio {
+    Inherit,
+    Explicit(c_int),
+    Owned(FileDesc),
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+    Fd(FileDesc),
+}
+
+impl Command {
+    pub fn new(program: &OsStr) -> Command {
+        let mut saw_nul = false;
+        let program = os2c(program, &mut saw_nul);
+        Command {
+            argv: Argv(vec![program.as_ptr(), ptr::null()]),
+            program,
+            args: Vec::new(),
+            env: Default::default(),
+            cwd: None,
+            uid: None,
+            gid: None,
+            saw_nul,
+            closures: Vec::new(),
+            stdin: None,
+            stdout: None,
+            stderr: None,
+        }
+    }
+
+    pub fn arg(&mut self, arg: &OsStr) {
+        // Overwrite the trailing NULL pointer in `argv` and then add a new null
+        // pointer.
+        let arg = os2c(arg, &mut self.saw_nul);
+        self.argv.0[self.args.len() + 1] = arg.as_ptr();
+        self.argv.0.push(ptr::null());
+
+        // Also make sure we keep track of the owned value to schedule a
+        // destructor for this memory.
+        self.args.push(arg);
+    }
+
+    pub fn cwd(&mut self, dir: &OsStr) {
+        self.cwd = Some(os2c(dir, &mut self.saw_nul));
+    }
+    pub fn uid(&mut self, id: uid_t) {
+        self.uid = Some(id);
+    }
+    pub fn gid(&mut self, id: gid_t) {
+        self.gid = Some(id);
+    }
+
+    pub fn saw_nul(&self) -> bool {
+        self.saw_nul
+    }
+    pub fn get_argv(&self) -> &Vec<*const c_char> {
+        &self.argv.0
+    }
+
+    #[allow(dead_code)]
+    pub fn get_cwd(&self) -> &Option<CString> {
+        &self.cwd
+    }
+    #[allow(dead_code)]
+    pub fn get_uid(&self) -> Option<uid_t> {
+        self.uid
+    }
+    #[allow(dead_code)]
+    pub fn get_gid(&self) -> Option<gid_t> {
+        self.gid
+    }
+
+    pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
+        &mut self.closures
+    }
+
+    pub unsafe fn pre_exec(
+        &mut self,
+        _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>,
+    ) {
+        // Fork() is not supported in vxWorks so no way to run the closure in the new procecss.
+        unimplemented!();;
+    }
+
+    pub fn stdin(&mut self, stdin: Stdio) {
+        self.stdin = Some(stdin);
+    }
+
+    pub fn stdout(&mut self, stdout: Stdio) {
+        self.stdout = Some(stdout);
+    }
+
+    pub fn stderr(&mut self, stderr: Stdio) {
+        self.stderr = Some(stderr);
+    }
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+        &mut self.env
+    }
+
+    pub fn capture_env(&mut self) -> Option<CStringArray> {
+        let maybe_env = self.env.capture_if_changed();
+        maybe_env.map(|env| construct_envp(env, &mut self.saw_nul))
+    }
+    #[allow(dead_code)]
+    pub fn env_saw_path(&self) -> bool {
+        self.env.have_changed_path()
+    }
+
+    pub fn setup_io(&self, default: Stdio, needs_stdin: bool)
+                -> io::Result<(StdioPipes, ChildPipes)> {
+        let null = Stdio::Null;
+        let default_stdin = if needs_stdin {&default} else {&null};
+        let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+        let stdout = self.stdout.as_ref().unwrap_or(&default);
+        let stderr = self.stderr.as_ref().unwrap_or(&default);
+        let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
+        let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
+        let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
+        let ours = StdioPipes {
+            stdin: our_stdin,
+            stdout: our_stdout,
+            stderr: our_stderr,
+        };
+        let theirs = ChildPipes {
+            stdin: their_stdin,
+            stdout: their_stdout,
+            stderr: their_stderr,
+        };
+        Ok((ours, theirs))
+    }
+}
+
+fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
+    CString::new(s.as_bytes()).unwrap_or_else(|_e| {
+        *saw_nul = true;
+        CString::new("<string-with-nul>").unwrap()
+    })
+}
+
+// Helper type to manage ownership of the strings within a C-style array.
+pub struct CStringArray {
+    items: Vec<CString>,
+    ptrs: Vec<*const c_char>
+}
+
+impl CStringArray {
+    pub fn with_capacity(capacity: usize) -> Self {
+        let mut result = CStringArray {
+            items: Vec::with_capacity(capacity),
+            ptrs: Vec::with_capacity(capacity+1)
+        };
+        result.ptrs.push(ptr::null());
+        result
+    }
+    pub fn push(&mut self, item: CString) {
+        let l = self.ptrs.len();
+        self.ptrs[l-1] = item.as_ptr();
+        self.ptrs.push(ptr::null());
+        self.items.push(item);
+    }
+    pub fn as_ptr(&self) -> *const *const c_char {
+        self.ptrs.as_ptr()
+    }
+}
+
+fn construct_envp(env: BTreeMap<DefaultEnvKey, OsString>, saw_nul: &mut bool) -> CStringArray {
+    let mut result = CStringArray::with_capacity(env.len());
+    for (k, v) in env {
+        let mut k: OsString = k.into();
+
+        // Reserve additional space for '=' and null terminator
+        k.reserve_exact(v.len() + 2);
+        k.push("=");
+        k.push(&v);
+
+        // Add the new entry into the array
+        if let Ok(item) = CString::new(k.into_vec()) {
+            result.push(item);
+        } else {
+            *saw_nul = true;
+        }
+    }
+
+    result
+}
+
+impl Stdio {
+    pub fn to_child_stdio(&self, readable: bool)
+                      -> io::Result<(ChildStdio, Option<AnonPipe>)> {
+        match *self {
+            Stdio::Inherit => {
+                Ok((ChildStdio::Inherit, None))
+            },
+
+            // Make sure that the source descriptors are not an stdio
+            // descriptor, otherwise the order which we set the child's
+            // descriptors may blow away a descriptor which we are hoping to
+            // save. For example, suppose we want the child's stderr to be the
+            // parent's stdout, and the child's stdout to be the parent's
+            // stderr. No matter which we dup first, the second will get
+            // overwritten prematurely.
+            Stdio::Fd(ref fd) => {
+                if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO {
+                    Ok((ChildStdio::Owned(fd.duplicate()?), None))
+                } else {
+                    Ok((ChildStdio::Explicit(fd.raw()), None))
+                }
+            }
+
+            Stdio::MakePipe => {
+                let (reader, writer) = pipe::anon_pipe()?;
+                let (ours, theirs) = if readable {
+                    (writer, reader)
+                } else {
+                    (reader, writer)
+                };
+                Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+            }
+
+            Stdio::Null => {
+                let mut opts = OpenOptions::new();
+                opts.read(readable);
+                opts.write(!readable);
+                let path = unsafe {
+                    CStr::from_ptr("/null\0".as_ptr() as *const _)
+                };
+                let fd = File::open_c(&path, &opts)?;
+                Ok((ChildStdio::Owned(fd.into_fd()), None))
+            }
+        }
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        Stdio::Fd(pipe.into_fd())
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(file: File) -> Stdio {
+        Stdio::Fd(file.into_fd())
+    }
+}
+
+impl ChildStdio {
+    pub fn fd(&self) -> Option<c_int> {
+        match *self {
+            ChildStdio::Inherit => None,
+            ChildStdio::Explicit(fd) => Some(fd),
+            ChildStdio::Owned(ref fd) => Some(fd.raw()),
+        }
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self.program)?;
+        for arg in &self.args {
+            write!(f, " {:?}", arg)?;
+        }
+        Ok(())
+    }
+}
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(c_int);
+
+impl ExitStatus {
+    pub fn new(status: c_int) -> ExitStatus {
+        ExitStatus(status)
+    }
+
+    fn exited(&self) -> bool {
+        /*unsafe*/ { libc::WIFEXITED(self.0) }
+    }
+
+    pub fn success(&self) -> bool {
+        self.code() == Some(0)
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        if self.exited() {
+            Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) })
+        } else {
+            None
+        }
+    }
+
+    pub fn signal(&self) -> Option<i32> {
+        if !self.exited() {
+            Some(/*unsafe*/ { libc::WTERMSIG(self.0) })
+        } else {
+            None
+        }
+    }
+}
+
+impl From<c_int> for ExitStatus {
+    fn from(a: c_int) -> ExitStatus {
+        ExitStatus(a)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(code) = self.code() {
+            write!(f, "exit code: {}", code)
+        } else {
+            let signal = self.signal().unwrap();
+            write!(f, "signal: {}", signal)
+        }
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+    pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+    #[inline]
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
+#[cfg(all(test, not(target_os = "emscripten")))]
+mod tests {
+    use super::*;
+
+    use crate::ffi::OsStr;
+    use crate::mem;
+    use crate::ptr;
+    use crate::sys::cvt;
+
+    macro_rules! t {
+        ($e:expr) => {
+            match $e {
+                Ok(t) => t,
+                Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+            }
+        }
+    }
+
+    // Android with api less than 21 define sig* functions inline, so it is not
+    // available for dynamic link. Implementing sigemptyset and sigaddset allow us
+    // to support older Android version (independent of libc version).
+    // The following implementations are based on https://git.io/vSkNf
+
+    #[cfg(not(target_os = "android"))]
+    extern {
+        #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
+        fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int;
+
+        #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
+        fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
+    }
+
+    #[cfg(target_os = "android")]
+    unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int {
+        libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>());
+        return 0;
+    }
+
+    #[cfg(target_os = "android")]
+    unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
+        use crate::slice;
+
+        let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
+        let bit = (signum - 1) as usize;
+        raw[bit / 8] |= 1 << (bit % 8);
+        return 0;
+    }
+
+    // See #14232 for more information, but it appears that signal delivery to a
+    // newly spawned process may just be raced in the macOS, so to prevent this
+    // test from being flaky we ignore it on macOS.
+    #[test]
+    #[cfg_attr(target_os = "macos", ignore)]
+    // When run under our current QEMU emulation test suite this test fails,
+    // although the reason isn't very clear as to why. For now this test is
+    // ignored there.
+    #[cfg_attr(target_arch = "arm", ignore)]
+    #[cfg_attr(target_arch = "aarch64", ignore)]
+    fn test_process_mask() {
+        unsafe {
+            // Test to make sure that a signal mask does not get inherited.
+            let mut cmd = Command::new(OsStr::new("cat"));
+
+            let mut set: libc::sigset_t = mem::uninitialized();
+            let mut old_set: libc::sigset_t = mem::uninitialized();
+            t!(cvt(sigemptyset(&mut set)));
+            t!(cvt(sigaddset(&mut set, libc::SIGINT)));
+            t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
+
+            cmd.stdin(Stdio::MakePipe);
+            cmd.stdout(Stdio::MakePipe);
+
+            let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
+            let stdin_write = pipes.stdin.take().unwrap();
+            let stdout_read = pipes.stdout.take().unwrap();
+
+            t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
+                                         ptr::null_mut())));
+
+            t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
+            // We need to wait until SIGINT is definitely delivered. The
+            // easiest way is to write something to cat, and try to read it
+            // back: if SIGINT is unmasked, it'll get delivered when cat is
+            // next scheduled.
+            let _ = stdin_write.write(b"Hello");
+            drop(stdin_write);
+
+            // Either EOF or failure (EPIPE) is okay.
+            let mut buf = [0; 5];
+            if let Ok(ret) = stdout_read.read(&mut buf) {
+                assert_eq!(ret, 0);
+            }
+
+            t!(cat.wait());
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/process/process_vxworks.rs b/src/libstd/sys/vxworks/process/process_vxworks.rs
new file mode 100644 (file)
index 0000000..d06d63b
--- /dev/null
@@ -0,0 +1,167 @@
+use crate::io::{self, Error, ErrorKind};
+use libc::{self, c_int};
+use libc::{RTP_ID};
+
+use crate::sys::cvt;
+use crate::sys::process::rtp;
+use crate::sys::process::process_common::*;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+impl Command {
+    pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+                 -> io::Result<(Process, StdioPipes)> {
+        use crate::sys::{cvt_r};
+        const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
+
+        let envp = self.capture_env();
+
+        if self.saw_nul() {
+            return Err(io::Error::new(ErrorKind::InvalidInput,
+                                      "nul byte found in provided data"));
+        }
+        let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+        let mut p = Process { pid: 0, status: None };
+
+        unsafe {
+            macro_rules! t {
+                ($e:expr) => (match $e {
+                    Ok(e) => e,
+                    Err(e) => return Err(e.into()),
+                })
+            }
+
+            let mut orig_stdin = libc::STDIN_FILENO;
+            let mut orig_stdout = libc::STDOUT_FILENO;
+            let mut orig_stderr = libc::STDERR_FILENO;
+
+            if let Some(fd) = theirs.stdin.fd() {
+                orig_stdin = t!(cvt_r(|| libc::dup(libc::STDIN_FILENO)));
+                t!(cvt_r(|| libc::dup2(fd, libc::STDIN_FILENO)));
+            }
+            if let Some(fd) = theirs.stdout.fd() {
+                orig_stdout = t!(cvt_r(|| libc::dup(libc::STDOUT_FILENO)));
+                t!(cvt_r(|| libc::dup2(fd, libc::STDOUT_FILENO)));
+            }
+            if let Some(fd) = theirs.stderr.fd() {
+                orig_stderr = t!(cvt_r(|| libc::dup(libc::STDERR_FILENO)));
+                t!(cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO)));
+            }
+
+            if let Some(ref cwd) = *self.get_cwd() {
+                t!(cvt(libc::chdir(cwd.as_ptr())));
+            }
+
+            //            let envp = envp.map(|c| c.as_ptr())
+            //                .unwrap_or(*sys::os::environ() as *const _);
+            // FIXME: https://github.com/rust-lang/rust/issues/61993
+            let envp_empty = CStringArray::with_capacity(0);
+            let envp = match envp {
+                Some(x) => x,
+                None => envp_empty,
+            };
+            let envp = envp.as_ptr();
+            let ret = rtp::rtpSpawn(
+                self.get_argv()[0],                   // executing program
+                self.get_argv().as_ptr() as *const _, // argv
+                envp as *const _,                     // environment variable pointers
+                100 as c_int,                         // initial priority
+                0x16000,                                    // initial stack size. 0 defaults
+                                                      // to 0x4000 in 32 bit and 0x8000 in 64 bit
+                0,                                    // options
+                0                                     // task options
+            );
+
+            // Because FileDesc was not used, each duplicated file descriptor
+            // needs to be closed manually
+            if orig_stdin != libc::STDIN_FILENO {
+                t!(cvt_r(|| libc::dup2(orig_stdin, libc::STDIN_FILENO)));
+                libc::close(orig_stdin);
+            }
+            if orig_stdout != libc::STDOUT_FILENO {
+                t!(cvt_r(|| libc::dup2(orig_stdout, libc::STDOUT_FILENO)));
+                libc::close(orig_stdout);
+            }
+            if orig_stderr != libc::STDERR_FILENO {
+                t!(cvt_r(|| libc::dup2(orig_stderr, libc::STDERR_FILENO)));
+                libc::close(orig_stderr);
+            }
+
+            if ret != rtp::RTP_ID_ERROR {
+                p.pid = ret;
+                Ok((p, ours))
+            } else {
+                Err(io::Error::last_os_error())
+            }
+        }
+    }
+
+    pub fn exec(&mut self, default: Stdio) -> io::Error {
+        let ret = Command::spawn(self, default, false);
+        match ret {
+            Ok(t) => unsafe {
+                let mut status = 0 as c_int;
+                libc::waitpid(t.0.pid, &mut status, 0);
+                libc::exit(0);
+            },
+            Err(e) => e,
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// The unique id of the process (this should never be negative).
+pub struct Process {
+    pid: RTP_ID,
+    status: Option<ExitStatus>,
+}
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        self.pid as u32
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        // If we've already waited on this process then the pid can be recycled
+        // and used for another process, and we probably shouldn't be killing
+        // random processes, so just return an error.
+        if self.status.is_some() {
+            Err(Error::new(ErrorKind::InvalidInput,
+                           "invalid argument: can't kill an exited process"))
+        } else {
+            cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
+        }
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        use crate::sys::cvt_r;
+        if let Some(status) = self.status {
+            return Ok(status)
+        }
+        let mut status = 0 as c_int;
+        cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
+        self.status = Some(ExitStatus::new(status));
+        Ok(ExitStatus::new(status))
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        if let Some(status) = self.status {
+            return Ok(Some(status))
+        }
+        let mut status = 0 as c_int;
+        let pid = cvt(unsafe {
+            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
+        })?;
+        if pid == 0 {
+            Ok(None)
+        } else {
+            self.status = Some(ExitStatus::new(status));
+            Ok(Some(ExitStatus::new(status)))
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/process/rtp.rs b/src/libstd/sys/vxworks/process/rtp.rs
new file mode 100644 (file)
index 0000000..3e6e001
--- /dev/null
@@ -0,0 +1,298 @@
+#![allow(non_camel_case_types, unused)]
+
+use libc::{self, c_int, size_t, c_char, BOOL, RTP_DESC, RTP_ID, TASK_ID};
+
+
+// Copied directly from rtpLibCommon.h, rtpLib.h, signal.h and taskLibCommon.h (for task options)
+
+// ****     definitions for rtpLibCommon.h    ****
+
+pub const RTP_GLOBAL_SYMBOLS     : c_int = 0x01; // register global symbols for RTP
+pub const RTP_LOCAL_SYMBOLS      : c_int = 0x02; // idem for local symbols
+pub const RTP_ALL_SYMBOLS        : c_int = (RTP_GLOBAL_SYMBOLS | RTP_LOCAL_SYMBOLS);
+pub const RTP_DEBUG              : c_int = 0x10; // set RTP in debug mode when created
+pub const RTP_BUFFER_VAL_OFF     : c_int = 0x20; // disable buffer validation for all
+                                                 // system calls issued from the RTP
+pub const RTP_LOADED_WAIT        : c_int = 0x40; // Wait until the RTP is loaded
+pub const RTP_CPU_AFFINITY_NONE  : c_int = 0x80; // Remove any CPU affinity (SMP)
+
+// Error Status codes
+
+pub const M_rtpLib : c_int = 178 << 16;
+
+pub const S_rtpLib_INVALID_FILE                   : c_int = (M_rtpLib | 1);
+pub const S_rtpLib_INVALID_OPTION                 : c_int = (M_rtpLib | 2);
+pub const S_rtpLib_ACCESS_DENIED                  : c_int = (M_rtpLib | 3);
+pub const S_rtpLib_INVALID_RTP_ID                 : c_int = (M_rtpLib | 4);
+pub const S_rtpLib_NO_SYMBOL_TABLE                : c_int = (M_rtpLib | 5);
+pub const S_rtpLib_INVALID_SEGMENT_START_ADDRESS  : c_int = (M_rtpLib | 6);
+pub const S_rtpLib_INVALID_SYMBOL_REGISTR_POLICY  : c_int = (M_rtpLib | 7);
+pub const S_rtpLib_INSTANTIATE_FAILED             : c_int = (M_rtpLib | 8);
+pub const S_rtpLib_INVALID_TASK_OPTION            : c_int = (M_rtpLib | 9);
+pub const S_rtpLib_RTP_NAME_LENGTH_EXCEEDED       : c_int = (M_rtpLib | 10);    // rtpInfoGet
+
+pub const VX_RTP_NAME_LENGTH                      : c_int  = 255;    // max name length for diplay
+
+
+// The 'status' field (32 bit integer) of a RTP holds the RTP state and status.
+//
+// NOTE: RTP_STATE_GET()    : read the RTP state(s)
+//       RTP_STATE_PUT()    : write the RTP state(s)
+//       RTP_STATE_SET()    : set a RTP state
+//       RTP_STATE_UNSET()  : unset a RTP state
+//
+//       RTP_STATUS_GET()   : read the RTP status
+//       RTP_STATUS_PUT()   : write the RTP status
+//       RTP_STATUS_SET()   : set a RTP status
+//       RTP_STATUS_UNSET() : unset a RTP status
+//
+// The PUT/SET/UNSET macros are available only in the kernel headers.
+
+
+// RTP states
+
+pub const RTP_STATE_CREATE           : c_int  = 0x0001; // RrtpStructTP is under construction
+pub const RTP_STATE_NORMAL           : c_int  = 0x0002; // RrtpStructTP is ready
+pub const RTP_STATE_DELETE           : c_int  = 0x0004; // RrtpStructTP is being deleted
+
+pub const RTP_STATUS_STOP            : c_int  = 0x0100; // RTP hrtpStructas recieved stopped signal
+pub const RTP_STATUS_ELECTED_DELETER : c_int  = 0x0200; // RTP drtpStructelete has started
+
+pub const RTP_STATE_MASK             : c_int  = (RTP_STATE_CREATE | RTP_STATE_NORMAL |
+                                                 RTP_STATE_DELETE);
+pub const RTP_STATUS_MASK            : c_int  = (RTP_STATUS_STOP | RTP_STATUS_ELECTED_DELETER);
+
+pub fn RTP_STATE_GET  (value : c_int) -> c_int {
+    value & RTP_STATE_MASK
+}
+pub fn RTP_STATUS_GET (value : c_int) -> c_int {
+    value & RTP_STATUS_MASK
+}
+
+// Indicates that the RTP_ID returned is not valid.
+
+// RTP_ID_ERROR is supposed to be set to -1, but you can't set
+// an unsigned value to a negative without casting, and you
+// can't cast unless the size of the integer types are the same,
+// but the size of RTP_ID may differ between kernel and user space.
+// Bitwise or-ing min and max should get the same result.
+pub const RTP_ID_ERROR : RTP_ID = RTP_ID::min_value() | RTP_ID::max_value();
+
+// IS_RTP_ C macros
+
+pub fn IS_RTP_STATE_NORMAL           (value : c_int) -> bool {
+    (RTP_STATE_GET(value)  & RTP_STATE_NORMAL) == RTP_STATE_NORMAL
+}
+pub fn IS_RTP_STATE_CREATE           (value : c_int) -> bool {
+    (RTP_STATE_GET(value)  & RTP_STATE_CREATE) == RTP_STATE_CREATE
+}
+pub fn IS_RTP_STATE_DELETE           (value : c_int) -> bool {
+    (RTP_STATE_GET(value)  & RTP_STATE_DELETE) == RTP_STATE_DELETE
+}
+pub fn IS_RTP_STATUS_STOP            (value : c_int) -> bool {
+    (RTP_STATUS_GET(value) & RTP_STATUS_STOP ) == RTP_STATUS_STOP
+}
+pub fn IS_RTP_STATUS_ELECTED_DELETER (value : c_int) -> bool {
+    (RTP_STATUS_GET(value) &  RTP_STATUS_ELECTED_DELETER) == RTP_STATUS_ELECTED_DELETER
+}
+
+// **** end of definitions for rtpLibCommon.h ****
+
+
+
+
+// ****    definitions for rtpLib.h     ****
+
+pub fn rtpExit(exitCode : c_int) -> ! {
+    unsafe{ libc::exit (exitCode) }
+}
+
+/* rtpLib.h in the kernel
+pub const RTP_DEL_VIA_TASK_DELETE : c_int  = 0x1;          // rtpDelete() via taskDestroy()
+pub const RTP_DEL_FORCE           : c_int  = 0x2;          // Forceful  rtpDelete()
+pub const RTP_ID_ANY              : RTP_ID = 0;            // used for when a kernel task
+                                                           // wants to wait for the next
+                                                           // RTP to finish
+
+
+// Function pointers
+
+pub type RTP_PRE_CREATE_HOOK    = size_t;
+pub type RTP_POST_CREATE_HOOK   = size_t;
+pub type RTP_INIT_COMPLETE_HOOK = size_t;
+pub type RTP_DELETE_HOOK        = size_t;
+*/
+
+// **** end of definitions for rtpLib.h ****
+
+
+
+
+
+// ****     definitions for signal.h    ****
+pub fn rtpKill(rtpId : RTP_ID, signo : c_int) -> c_int {
+    unsafe{ libc::kill(rtpId as c_int, signo) }
+}
+
+pub fn rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : size_t) -> c_int {
+    unsafe{ libc::sigqueue(rtpId as c_int, signo, value) }
+}
+
+pub fn _rtpSigqueue(rtpId : RTP_ID, signo : c_int, value : *mut size_t, code : c_int) -> c_int {
+    unsafe{ libc::_sigqueue(rtpId, signo, value, code) }
+}
+
+pub fn taskRaise(signo : c_int) -> c_int {
+    unsafe{ libc::taskKill(libc::taskIdSelf(), signo) }
+}
+pub fn rtpRaise(signo : c_int) -> c_int {
+    unsafe{ libc::raise(signo) }
+}
+
+// **** end of definitions for signal.h ****
+
+
+
+// ****     definitions for taskLibCommon.h    ****
+pub const VX_PRIVATE_ENV      : c_int = 0x0080;  // 1 = private environment variables
+pub const VX_NO_STACK_FILL    : c_int = 0x0100;  // 1 = avoid stack fill of 0xee
+pub const VX_PRIVATE_UMASK    : c_int = 0x0400;  // 1 = private file creation mode mask
+pub const VX_TASK_NOACTIVATE  : c_int = 0x2000;  // taskOpen() does not taskActivate()
+pub const VX_NO_STACK_PROTECT : c_int = 0x4000;  // no over/underflow stack protection,
+                                                 // stack space remains executable
+
+// define for all valid user task options
+
+pub const VX_USR_TASK_OPTIONS_BASE: c_int = (VX_PRIVATE_ENV      |
+                                             VX_NO_STACK_FILL    |
+                                             VX_TASK_NOACTIVATE  |
+                                             VX_NO_STACK_PROTECT |
+                                             VX_PRIVATE_UMASK);
+
+// **** end of definitions for taskLibCommon.h ****
+
+
+
+extern "C" {
+// functions in rtpLibCommon.h
+
+// forward declarations
+    pub fn rtpSpawn (
+        pubrtpFileName : *const c_char,
+        argv           : *const *const c_char,
+        envp           : *const *const c_char,
+        priority       : c_int,
+        uStackSize     : size_t,
+        options        : c_int,
+        taskOptions    : c_int,
+    ) -> RTP_ID;
+
+    pub fn rtpInfoGet (
+        rtpId     : RTP_ID,
+        rtpStruct : *mut RTP_DESC,
+    ) -> c_int;
+
+/* functions in rtpLib.h for kernel
+
+
+    // function declarations
+
+    pub fn rtpDelete (
+        id      : RTP_ID,
+        options : c_int,
+        status  : c_int,
+    ) -> c_int;
+
+    pub fn rtpDeleteForce (
+        rtpId : RTP_ID
+    ) -> c_int;
+
+    pub fn rtpShow (
+        rtpNameOrId : *mut c_char,
+        level       : c_int,
+    ) -> BOOL;
+
+    // RTP signals are always present when RTPs are included.  The public RTP
+    // signal APIs are declared here.
+
+
+    pub fn rtpKill (
+        rtpId : RTP_ID,
+        signo : c_int,
+    ) -> c_int;
+
+    pub fn rtpSigqueue (
+        rtpId : RTP_ID,
+        signo : c_int,
+        value : size_t, // Actual type is const union sigval value,
+                        // which is a union of int and void *
+    ) -> c_int;
+
+    pub fn rtpTaskKill (
+        tid   : TASK_ID,
+        signo : c_int,
+    ) -> c_int;
+
+    pub fn rtpTaskSigqueue (
+        tid   : TASK_ID,
+        signo : c_int,
+        value : const size_t, // Actual type is const union sigval,
+                        // which is a union of int and void *
+    ) -> c_int;
+
+    pub fn rtpWait (
+        rtpWaitId : RTP_ID,
+        timeout   : libc::alloc_jemalloc_Vx_ticks_t,
+        pRtpId    : *mut RTP_ID,
+        pStatus   : *mut c_int,
+    ) -> c_int;
+
+                             // Other public functions
+
+
+    pub fn rtpPreCreateHookAdd     (
+        hook      : RTP_PRE_CREATE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpPreCreateHookDelete  (
+        hook      : RTP_POST_CREATE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpPostCreateHookAdd    (
+        hook      : RTP_POST_CREATE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpPostCreateHookDelete (
+        hook      : RTP_POST_CREATE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpInitCompleteHookAdd  (
+        hook      : RTP_INIT_COMPLETE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpInitCompleteHookDelete (
+        hook      : RTP_INIT_COMPLETE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpDeleteHookAdd        (
+        hook      : RTP_DELETE_HOOK,
+        addToHead : BOOL,
+    ) -> c_int;
+
+    pub fn rtpDeleteHookDelete     (
+        hook      : RTP_DELETE_HOOK,
+    ) -> c_int;
+
+    pub fn rtpMemShow              (
+        rtpNameOrId : *mut c_char,
+        level       : c_int,
+    ) -> c_int;
+
+    pub fn rtpHookShow             (
+
+    );
+*/
+}
diff --git a/src/libstd/sys/vxworks/rand.rs b/src/libstd/sys/vxworks/rand.rs
new file mode 100644 (file)
index 0000000..1ec0cbe
--- /dev/null
@@ -0,0 +1,31 @@
+use crate::mem;
+use crate::slice;
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    let mut v = (0, 0);
+    unsafe {
+        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
+                                             mem::size_of_val(&v));
+        imp::fill_bytes(view);
+    }
+    return v
+}
+
+mod imp {
+    use libc;
+    use crate::io;
+
+    extern "C" {
+        fn randBytes (randBuf: *mut libc::c_uchar,
+                      numOfBytes: libc::c_int) -> libc::c_int;
+    }
+
+    pub fn fill_bytes(v: &mut [u8]) {
+        let ret = unsafe {
+            randBytes(v.as_mut_ptr() as *mut libc::c_uchar, v.len() as libc::c_int)
+        };
+        if ret == -1 {
+            panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
+        }
+    }
+}
diff --git a/src/libstd/sys/vxworks/rwlock.rs b/src/libstd/sys/vxworks/rwlock.rs
new file mode 100644 (file)
index 0000000..718f422
--- /dev/null
@@ -0,0 +1,113 @@
+use libc;
+use crate::cell::UnsafeCell;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+pub struct RWLock {
+    inner: UnsafeCell<libc::pthread_rwlock_t>,
+    write_locked: UnsafeCell<bool>,
+    num_readers: AtomicUsize,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock {
+            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
+            write_locked: UnsafeCell::new(false),
+            num_readers: AtomicUsize::new(0),
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        let r = libc::pthread_rwlock_rdlock(self.inner.get());
+        if r == libc::EAGAIN {
+            panic!("rwlock maximum reader count exceeded");
+        } else if r == libc::EDEADLK || *self.write_locked.get() {
+            if r == 0 {
+                self.raw_unlock();
+            }
+        panic!("rwlock read lock would result in deadlock");
+        } else {
+            debug_assert_eq!(r, 0);
+            self.num_readers.fetch_add(1, Ordering::Relaxed);
+        }
+    }
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        let r = libc::pthread_rwlock_tryrdlock(self.inner.get());
+        if r == 0 {
+            if *self.write_locked.get() {
+                self.raw_unlock();
+                false
+            } else {
+                self.num_readers.fetch_add(1, Ordering::Relaxed);
+                true
+            }
+        } else {
+            false
+        }
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        let r = libc::pthread_rwlock_wrlock(self.inner.get());
+        // See comments above for why we check for EDEADLK and write_locked. We
+        // also need to check that num_readers is 0.
+        if r == libc::EDEADLK || *self.write_locked.get() ||
+            self.num_readers.load(Ordering::Relaxed) != 0 {
+            if r == 0 {
+                self.raw_unlock();
+            }
+        panic!("rwlock write lock would result in deadlock");
+        } else {
+            debug_assert_eq!(r, 0);
+        }
+        *self.write_locked.get() = true;
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        let r = libc::pthread_rwlock_trywrlock(self.inner.get());
+        if r == 0 {
+            if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 {
+                self.raw_unlock();
+                false
+            } else {
+                *self.write_locked.get() = true;
+                true
+            }
+            } else {
+                false
+        }
+    }
+
+    #[inline]
+    unsafe fn raw_unlock(&self) {
+        let r = libc::pthread_rwlock_unlock(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        debug_assert!(!*self.write_locked.get());
+        self.num_readers.fetch_sub(1, Ordering::Relaxed);
+        self.raw_unlock();
+    }
+
+     #[inline]
+    pub unsafe fn write_unlock(&self) {
+        debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0);
+        debug_assert!(*self.write_locked.get());
+        *self.write_locked.get() = false;
+        self.raw_unlock();
+    }
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let r = libc::pthread_rwlock_destroy(self.inner.get());
+        debug_assert_eq!(r, 0);
+    }
+}
diff --git a/src/libstd/sys/vxworks/stack_overflow.rs b/src/libstd/sys/vxworks/stack_overflow.rs
new file mode 100644 (file)
index 0000000..561279e
--- /dev/null
@@ -0,0 +1,209 @@
+#![cfg_attr(test, allow(dead_code))]
+
+use self::imp::{make_handler, drop_handler};
+
+pub use self::imp::cleanup;
+pub use self::imp::init;
+
+pub struct Handler {
+    _data: *mut libc::c_void
+}
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        make_handler()
+    }
+}
+
+impl Drop for Handler {
+    fn drop(&mut self) {
+        unsafe {
+            drop_handler(self);
+        }
+    }
+}
+
+#[cfg(any(target_os = "linux",
+          target_os = "macos",
+          target_os = "bitrig",
+          target_os = "dragonfly",
+          target_os = "freebsd",
+          target_os = "solaris",
+          all(target_os = "netbsd", not(target_vendor = "rumprun")),
+          target_os = "openbsd"))]
+mod imp {
+    use super::Handler;
+    use crate::mem;
+    use crate::ptr;
+
+    use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
+    use libc::{sigaction, SIGBUS, SIG_DFL,
+               SA_SIGINFO, SA_ONSTACK, sighandler_t};
+    use libc::{mmap, munmap};
+    use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
+    use libc::MAP_FAILED;
+
+    use crate::sys_common::thread_info;
+
+
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
+        #[repr(C)]
+        struct siginfo_t {
+            a: [libc::c_int; 3], // si_signo, si_errno, si_code
+            si_addr: *mut libc::c_void,
+        }
+
+        (*(info as *const siginfo_t)).si_addr as usize
+    }
+
+    #[cfg(not(any(target_os = "linux", target_os = "android")))]
+    unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
+        (*info).si_addr as usize
+    }
+
+    // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
+    // (unmapped pages) at the end of every thread's stack, so if a thread ends
+    // up running into the guard page it'll trigger this handler. We want to
+    // detect these cases and print out a helpful error saying that the stack
+    // has overflowed. All other signals, however, should go back to what they
+    // were originally supposed to do.
+    //
+    // This handler currently exists purely to print an informative message
+    // whenever a thread overflows its stack. We then abort to exit and
+    // indicate a crash, but to avoid a misleading SIGSEGV that might lead
+    // users to believe that unsafe code has accessed an invalid pointer; the
+    // SIGSEGV encountered when overflowing the stack is expected and
+    // well-defined.
+    //
+    // If this is not a stack overflow, the handler un-registers itself and
+    // then returns (to allow the original signal to be delivered again).
+    // Returning from this kind of signal handler is technically not defined
+    // to work when reading the POSIX spec strictly, but in practice it turns
+    // out many large systems and all implementations allow returning from a
+    // signal handler to work. For a more detailed explanation see the
+    // comments on #26458.
+    unsafe extern fn signal_handler(signum: libc::c_int,
+                                    info: *mut libc::siginfo_t,
+                                    _data: *mut libc::c_void) {
+        use crate::sys_common::util::report_overflow;
+
+        let guard = thread_info::stack_guard().unwrap_or(0..0);
+        let addr = siginfo_si_addr(info);
+
+        // If the faulting address is within the guard page, then we print a
+        // message saying so and abort.
+        if guard.start <= addr && addr < guard.end {
+            report_overflow();
+            rtabort!("stack overflow");
+        } else {
+            // Unregister ourselves by reverting back to the default behavior.
+            let mut action: sigaction = mem::zeroed();
+            action.sa_sigaction = SIG_DFL;
+            sigaction(signum, &action, ptr::null_mut());
+
+            // See comment above for why this function returns.
+        }
+    }
+
+    static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
+
+    pub unsafe fn init() {
+        let mut action: sigaction = mem::zeroed();
+        action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+        action.sa_sigaction = signal_handler as sighandler_t;
+        sigaction(SIGSEGV, &action, ptr::null_mut());
+        sigaction(SIGBUS, &action, ptr::null_mut());
+
+        let handler = make_handler();
+        MAIN_ALTSTACK = handler._data;
+        mem::forget(handler);
+    }
+
+    pub unsafe fn cleanup() {
+        Handler { _data: MAIN_ALTSTACK };
+    }
+
+    unsafe fn get_stackp() -> *mut libc::c_void {
+        let stackp = mmap(ptr::null_mut(),
+                          SIGSTKSZ,
+                          PROT_READ | PROT_WRITE,
+                          MAP_PRIVATE | MAP_ANON,
+                          -1,
+                          0);
+        if stackp == MAP_FAILED {
+            panic!("failed to allocate an alternative stack");
+        }
+        stackp
+    }
+
+    #[cfg(any(target_os = "linux",
+              target_os = "macos",
+              target_os = "bitrig",
+              target_os = "freebsd",
+              target_os = "netbsd",
+              target_os = "openbsd",
+              target_os = "solaris"))]
+    unsafe fn get_stack() -> libc::stack_t {
+        libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
+    }
+
+    #[cfg(target_os = "dragonfly")]
+    unsafe fn get_stack() -> libc::stack_t {
+        libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
+    }
+
+    pub unsafe fn make_handler() -> Handler {
+        let mut stack = mem::zeroed();
+        sigaltstack(ptr::null(), &mut stack);
+        // Configure alternate signal stack, if one is not already set.
+        if stack.ss_flags & SS_DISABLE != 0 {
+            stack = get_stack();
+            sigaltstack(&stack, ptr::null_mut());
+            Handler { _data: stack.ss_sp as *mut libc::c_void }
+        } else {
+            Handler { _data: ptr::null_mut() }
+        }
+    }
+
+    pub unsafe fn drop_handler(handler: &mut Handler) {
+        if !handler._data.is_null() {
+            let stack =  libc::stack_t {
+                ss_sp: ptr::null_mut(),
+                ss_flags: SS_DISABLE,
+                // Workaround for bug in macOS implementation of sigaltstack
+                // UNIX2003 which returns ENOMEM when disabling a stack while
+                // passing ss_size smaller than MINSIGSTKSZ. According to POSIX
+                // both ss_sp and ss_size should be ignored in this case.
+                ss_size: SIGSTKSZ,
+            };
+            sigaltstack(&stack, ptr::null_mut());
+            munmap(handler._data, SIGSTKSZ);
+        }
+    }
+}
+
+#[cfg(not(any(target_os = "linux",
+              target_os = "macos",
+              target_os = "bitrig",
+              target_os = "dragonfly",
+              target_os = "freebsd",
+              target_os = "solaris",
+              all(target_os = "netbsd", not(target_vendor = "rumprun")),
+              target_os = "openbsd")))]
+mod imp {
+    use crate::ptr;
+
+    pub unsafe fn init() {
+    }
+
+    pub unsafe fn cleanup() {
+    }
+
+    pub unsafe fn make_handler() -> super::Handler {
+        super::Handler { _data: ptr::null_mut() }
+    }
+
+    pub unsafe fn drop_handler(_handler: &mut super::Handler) {
+    }
+}
diff --git a/src/libstd/sys/vxworks/stdio.rs b/src/libstd/sys/vxworks/stdio.rs
new file mode 100644 (file)
index 0000000..35f163b
--- /dev/null
@@ -0,0 +1,63 @@
+use crate::io;
+use crate::sys::fd::FileDesc;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+    pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let fd = FileDesc::new(libc::STDIN_FILENO);
+        let ret = fd.read(buf);
+        fd.into_raw(); // do not close this FD
+        ret
+    }
+}
+
+impl Stdout {
+    pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let fd = FileDesc::new(libc::STDOUT_FILENO);
+        let ret = fd.write(buf);
+        fd.into_raw(); // do not close this FD
+        ret
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let fd = FileDesc::new(libc::STDERR_FILENO);
+        let ret = fd.write(buf);
+        fd.into_raw(); // do not close this FD
+        ret
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+    err.raw_os_error() == Some(libc::EBADF as i32)
+}
+
+pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Stderr::new().ok()
+}
diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs
new file mode 100644 (file)
index 0000000..810dbad
--- /dev/null
@@ -0,0 +1,179 @@
+//use crate::boxed::FnBox;
+use crate::cmp;
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::ptr;
+use crate::sys::os;
+use crate::time::Duration;
+
+use crate::sys_common::thread::*;
+
+#[cfg(not(target_os = "l4re"))]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+#[cfg(target_os = "l4re")]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+
+pub struct Thread {
+    id: libc::pthread_t,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc,
+// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS.
+#[cfg(not(target_os = "emscripten"))]
+unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
+                                    stack_size: libc::size_t) -> libc::c_int {
+    libc::pthread_attr_setstacksize(attr, stack_size)
+}
+
+#[cfg(target_os = "emscripten")]
+unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
+                                    _stack_size: libc::size_t) -> libc::c_int {
+    panic!()
+}
+
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>)
+                          -> io::Result<Thread> {
+        let p = box p;
+        let mut native: libc::pthread_t = mem::zeroed();
+        let mut attr: libc::pthread_attr_t = mem::zeroed();
+        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+
+        let stack_size = cmp::max(stack, min_stack_size(&attr));
+
+        match pthread_attr_setstacksize(&mut attr,
+                                        stack_size) {
+            0 => {}
+            n => {
+                assert_eq!(n, libc::EINVAL);
+                // EINVAL means |stack_size| is either too small or not a
+                // multiple of the system page size.  Because it's definitely
+                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+                // Round up to the nearest page and try again.
+                let page_size = os::page_size();
+                let stack_size = (stack_size + page_size - 1) &
+                                 (-(page_size as isize - 1) as usize - 1);
+                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
+                                                           stack_size), 0);
+            }
+        };
+
+        let ret = libc::pthread_create(&mut native, &attr, thread_start,
+                                       &*p as *const _ as *mut _);
+        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+
+        return if ret != 0 {
+            Err(io::Error::from_raw_os_error(ret))
+        } else {
+            mem::forget(p); // ownership passed to pthread_create
+            Ok(Thread { id: native })
+        };
+
+        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+            unsafe { start_thread(main as *mut u8); }
+            ptr::null_mut()
+        }
+    }
+
+    pub fn yield_now() {
+        let ret = unsafe { libc::sched_yield() };
+        debug_assert_eq!(ret, 0);
+    }
+
+    pub fn set_name(_name: &CStr) {
+        assert!(false, "FIXME: set_name");
+    }
+
+    pub fn sleep(dur: Duration) {
+        let mut secs = dur.as_secs();
+        let mut nsecs = dur.subsec_nanos() as _;
+
+        // If we're awoken with a signal then the return value will be -1 and
+        // nanosleep will fill in `ts` with the remaining time.
+        unsafe {
+            while secs > 0 || nsecs > 0 {
+                let mut ts = libc::timespec {
+                    tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
+                    tv_nsec: nsecs,
+                };
+                secs -= ts.tv_sec as u64;
+                if libc::nanosleep(&ts, &mut ts) == -1 {
+                    assert_eq!(os::errno(), libc::EINTR);
+                    secs += ts.tv_sec as u64;
+                    nsecs = ts.tv_nsec;
+                } else {
+                    nsecs = 0;
+                }
+            }
+        }
+    }
+
+    pub fn join(self) {
+        unsafe {
+            let ret = libc::pthread_join(self.id, ptr::null_mut());
+            mem::forget(self);
+            assert!(ret == 0,
+                    "failed to join thread: {}", io::Error::from_raw_os_error(ret));
+        }
+    }
+
+    pub fn id(&self) -> libc::pthread_t { self.id }
+
+    pub fn into_id(self) -> libc::pthread_t {
+        let id = self.id;
+        mem::forget(self);
+        id
+    }
+}
+
+impl Drop for Thread {
+    fn drop(&mut self) {
+        let ret = unsafe { libc::pthread_detach(self.id) };
+        debug_assert_eq!(ret, 0);
+    }
+}
+
+#[cfg_attr(test, allow(dead_code))]
+pub mod guard {
+    use crate::ops::Range;
+    pub type Guard = Range<usize>;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
+    pub unsafe fn deinit() {}
+}
+
+// glibc >= 2.15 has a __pthread_get_minstack() function that returns
+// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
+// storage.  We need that information to avoid blowing up when a small stack
+// is created in an application with big thread-local storage requirements.
+// See #6233 for rationale and details.
+#[cfg(target_os = "linux")]
+#[allow(deprecated)]
+fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
+    weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);
+
+    match __pthread_get_minstack.get() {
+        None => libc::PTHREAD_STACK_MIN,
+        Some(f) => unsafe { f(attr) },
+    }
+}
+
+// No point in looking up __pthread_get_minstack() on non-glibc
+// platforms.
+#[cfg(all(not(target_os = "linux"),
+          not(target_os = "netbsd")))]
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+    libc::PTHREAD_STACK_MIN
+}
+
+#[cfg(target_os = "netbsd")]
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+    2048 // just a guess
+}
diff --git a/src/libstd/sys/vxworks/thread_local.rs b/src/libstd/sys/vxworks/thread_local.rs
new file mode 100644 (file)
index 0000000..ac615b7
--- /dev/null
@@ -0,0 +1,34 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::mem;
+
+pub type Key = libc::pthread_key_t;
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+    let mut key = 0;
+    assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
+    key
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    let r = libc::pthread_setspecific(key, value as *mut _);
+    debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    libc::pthread_getspecific(key) as *mut u8
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    let r = libc::pthread_key_delete(key);
+    debug_assert_eq!(r, 0);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    false
+}
diff --git a/src/libstd/sys/vxworks/time.rs b/src/libstd/sys/vxworks/time.rs
new file mode 100644 (file)
index 0000000..cb3a424
--- /dev/null
@@ -0,0 +1,224 @@
+use crate::cmp::Ordering;
+use libc;
+use crate::time::Duration;
+use ::core::hash::{Hash, Hasher};
+
+pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
+use crate::convert::TryInto;
+
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+
+#[derive(Copy, Clone)]
+struct Timespec {
+    t: libc::timespec,
+}
+
+impl Timespec {
+    const fn zero() -> Timespec {
+        Timespec {
+            t: libc::timespec { tv_sec: 0, tv_nsec: 0 },
+        }
+    }
+    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        if self >= other {
+            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
+                Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
+                                (self.t.tv_nsec - other.t.tv_nsec) as u32)
+                } else {
+                    Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+                        self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+                        other.t.tv_nsec as u32)
+                })
+        } else {
+            match other.sub_timespec(self) {
+                Ok(d) => Err(d),
+                Err(d) => Ok(d),
+            }
+        }
+    }
+
+    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+        let mut secs = other
+            .as_secs()
+            .try_into() // <- target type would be `libc::time_t`
+            .ok()
+            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+
+        // Nano calculations can't overflow because nanos are <1B which fit
+        // in a u32.
+        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+        if nsec >= NSEC_PER_SEC as u32 {
+            nsec -= NSEC_PER_SEC as u32;
+            secs = secs.checked_add(1)?;
+        }
+        Some(Timespec {
+            t: libc::timespec {
+                tv_sec: secs,
+                tv_nsec: nsec as _,
+            },
+        })
+    }
+
+    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+        let mut secs = other
+            .as_secs()
+            .try_into() // <- target type would be `libc::time_t`
+            .ok()
+            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+
+        // Similar to above, nanos can't overflow.
+        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+        if nsec < 0 {
+            nsec += NSEC_PER_SEC as i32;
+            secs = secs.checked_sub(1)?;
+        }
+        Some(Timespec {
+            t: libc::timespec {
+                tv_sec: secs,
+                tv_nsec: nsec as _,
+            },
+        })
+    }
+}
+
+impl PartialEq for Timespec {
+    fn eq(&self, other: &Timespec) -> bool {
+        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
+    }
+}
+
+impl Eq for Timespec {}
+
+impl PartialOrd for Timespec {
+    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Timespec {
+    fn cmp(&self, other: &Timespec) -> Ordering {
+        let me = (self.t.tv_sec, self.t.tv_nsec);
+        let other = (other.t.tv_sec, other.t.tv_nsec);
+        me.cmp(&other)
+    }
+}
+
+impl Hash for Timespec {
+    fn hash<H : Hasher>(&self, state: &mut H) {
+        self.t.tv_sec.hash(state);
+        self.t.tv_nsec.hash(state);
+    }
+}
+mod inner {
+    use crate::fmt;
+    use libc;
+    use crate::sys::cvt;
+    use crate::time::Duration;
+
+    use super::Timespec;
+
+    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+    pub struct Instant {
+        t: Timespec,
+    }
+
+    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+    pub struct SystemTime {
+        t: Timespec,
+    }
+
+    pub const UNIX_EPOCH: SystemTime = SystemTime {
+        t: Timespec {
+            t: libc::timespec {
+                tv_sec: 0,
+                tv_nsec: 0,
+            },
+        },
+    };
+
+    impl Instant {
+        pub fn now() -> Instant {
+            Instant { t: now(libc::CLOCK_MONOTONIC) }
+        }
+
+        pub const fn zero() -> Instant {
+            Instant {
+                t: Timespec::zero(),
+            }
+        }
+
+        pub fn actually_monotonic() -> bool {
+            true
+        }
+
+        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+            self.t.sub_timespec(&other.t).ok()
+        }
+
+        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+            Some(Instant { t: self.t.checked_add_duration(other)? })
+        }
+
+        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+            Some(Instant { t: self.t.checked_sub_duration(other)? })
+        }
+    }
+
+    impl fmt::Debug for Instant {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.debug_struct("Instant")
+             .field("tv_sec", &self.t.t.tv_sec)
+             .field("tv_nsec", &self.t.t.tv_nsec)
+             .finish()
+        }
+    }
+
+    impl SystemTime {
+        pub fn now() -> SystemTime {
+            SystemTime { t: now(libc::CLOCK_REALTIME) }
+        }
+
+        pub fn sub_time(&self, other: &SystemTime)
+                        -> Result<Duration, Duration> {
+            self.t.sub_timespec(&other.t)
+        }
+
+        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+            Some(SystemTime { t: self.t.checked_add_duration(other)? })
+        }
+
+        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+        }
+    }
+
+    impl From<libc::timespec> for SystemTime {
+        fn from(t: libc::timespec) -> SystemTime {
+            SystemTime { t: Timespec { t: t } }
+        }
+    }
+
+    impl fmt::Debug for SystemTime {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.debug_struct("SystemTime")
+             .field("tv_sec", &self.t.t.tv_sec)
+             .field("tv_nsec", &self.t.t.tv_nsec)
+             .finish()
+        }
+    }
+
+    pub type clock_t = libc::c_int;
+
+    fn now(clock: clock_t) -> Timespec {
+        let mut t = Timespec {
+            t: libc::timespec {
+                tv_sec: 0,
+                tv_nsec: 0,
+            }
+        };
+        cvt(unsafe {
+            libc::clock_gettime(clock, &mut t.t)
+        }).unwrap();
+        t
+    }
+}
diff --git a/src/libstd/sys/vxworks/weak.rs b/src/libstd/sys/vxworks/weak.rs
new file mode 100644 (file)
index 0000000..284f211
--- /dev/null
@@ -0,0 +1,60 @@
+//! Support for "weak linkage" to symbols on Unix
+//!
+//! Some I/O operations we do in libstd require newer versions of OSes but we
+//! need to maintain binary compatibility with older releases for now. In order
+//! to use the new functionality when available we use this module for
+//! detection.
+//!
+//! One option to use here is weak linkage, but that is unfortunately only
+//! really workable on Linux. Hence, use dlsym to get the symbol value at
+//! runtime. This is also done for compatibility with older versions of glibc,
+//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
+//! we've been dynamically linked to the library the symbol comes from, but that
+//! is currently always the case for things like libpthread/libc.
+//!
+//! A long time ago this used weak linkage for the __pthread_get_minstack
+//! symbol, but that caused Debian to detect an unnecessarily strict versioned
+//! dependency on libc6 (#23628).
+
+use crate::ffi::CStr;
+use crate::marker;
+use crate::mem;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+pub struct Weak<F> {
+    name: &'static str,
+    addr: AtomicUsize,
+    _marker: marker::PhantomData<F>,
+}
+
+impl<F> Weak<F> {
+    pub const fn new(name: &'static str) -> Weak<F> {
+        Weak {
+            name,
+            addr: AtomicUsize::new(1),
+            _marker: marker::PhantomData,
+        }
+    }
+
+    pub fn get(&self) -> Option<F> {
+        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+        unsafe {
+            if self.addr.load(Ordering::SeqCst) == 1 {
+                self.addr.store(fetch(self.name), Ordering::SeqCst);
+            }
+            match self.addr.load(Ordering::SeqCst) {
+                0 => None,
+                addr => Some(mem::transmute_copy::<usize, F>(&addr)),
+            }
+        }
+    }
+}
+
+unsafe fn fetch(name: &str) -> usize {
+    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
+        Ok(cstr) => cstr,
+        Err(..) => return 0,
+    };
+    assert!(false, "FIXME: fetch");
+   libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
+}
index 53bf67bdf671f181db9378d731fa0990a0403ead..fa45c9d7d9d796a81369a1d1f3ea7c482fc52909 100644 (file)
@@ -1263,6 +1263,12 @@ fn num_cpus() -> usize {
         1
     }
 
+    #[cfg(target_os = "vxworks")]
+    fn num_cpus() -> usize {
+        // FIXME: Implement num_cpus on vxWorks
+        1
+    }
+
     #[cfg(any(
         all(target_arch = "wasm32", not(target_os = "emscripten")),
         all(target_vendor = "fortanix", target_env = "sgx")
index 35caf82dd71287fcf65e17d335cdd2329dc71150..66fbe3c7037a7ee8834ea258185d0f30f94dc509 100644 (file)
@@ -1653,6 +1653,18 @@ fn exec_compiled_test(&self) -> ProcRes {
                     None,
                 )
             }
+            _ if self.config.target.contains("vxworks") => {
+                let aux_dir = self.aux_output_dir_name();
+                let ProcArgs { prog, args } = self.make_run_args();
+                let mut vx_run = Command::new("vx-run");
+                vx_run.args(&[&prog]).args(args).envs(env.clone());
+                self.compose_and_run(
+                    vx_run,
+                    self.config.run_lib_path.to_str().unwrap(),
+                    Some(aux_dir.to_str().unwrap()),
+                    None,
+                )
+            }
             _ => {
                 let aux_dir = self.aux_output_dir_name();
                 let ProcArgs { prog, args } = self.make_run_args();
index 8caf5ca00f5053638f6ded0bfcdf298c814d325f..76099b950b0b08d77d0a27f0ce9e55769b9ffa9d 100644 (file)
@@ -30,6 +30,7 @@
     ("solaris", "solaris"),
     ("win32", "windows"),
     ("windows", "windows"),
+    ("vxworks", "vxworks"),
 ];
 
 const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[