diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 000000000..624b848a5 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,25 @@ +name: Clippy + +on: + push: + branches: + - master + - staging + - trying + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Rustup (apply rust-toolchain.toml) + run: rustup show + - name: Clippy + run: cargo clippy --all-targets -- -D warnings diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index a57e6a4ce..88c7105af 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -1,36 +1,23 @@ -name: Format check +name: Format on: - pull_request: push: branches: - master - staging - trying + pull_request: + +env: + CARGO_TERM_COLOR: always jobs: - check: - name: Format check + format: + name: Format runs-on: ubuntu-latest - - strategy: - matrix: - os: [ubuntu-latest] - rust: [nightly] - include: - - os: ubuntu-latest - rust: 'nightly' - components: 'rustfmt' - targets: 'x86_64-unknown-linux-gnu' - - steps: - - uses: hecrj/setup-rust-action@v1 - with: - rust-version: ${{ matrix.rust }} - components: ${{ matrix.components || '' }} - targets: ${{ matrix.targets || '' }} - - name: Checkout - uses: actions/checkout@v2 - - name: Check Formatting + - uses: actions/checkout@v2 + - name: Rustup (apply rust-toolchain.toml) + run: rustup show + - name: Format run: cargo fmt -- --check diff --git a/.github/workflows/kvm_test.yml b/.github/workflows/kvm_test.yml new file mode 100644 index 000000000..b67b809a4 --- /dev/null +++ b/.github/workflows/kvm_test.yml @@ -0,0 +1,43 @@ +name: KVM Test + +on: + push: + branches: + - master + - staging + - trying + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + kvm_test: + name: KVM Test + runs-on: [self-hosted] + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Rustup (apply rust-toolchain.toml) + run: rustup show + - name: Build dev profile + run: cargo build --package rusty_demo + - name: Install uhyve + run: cargo install uhyve --locked + - name: Check KVM availability + shell: bash + run: | + lscpu + kvm-ok + - name: Test debug version + run: uhyve --verbose --cpus 1 target/x86_64-unknown-hermit/debug/rusty_demo + env: + RUST_LOG: debug + - name: Build release profile + run: cargo build --package rusty_demo --release + - name: Test release version + run: uhyve --verbose --cpus 1 target/x86_64-unknown-hermit/release/rusty_demo + env: + RUST_LOG: debug diff --git a/.github/workflows/publish.yml b/.github/workflows/publish_docs.yml similarity index 67% rename from .github/workflows/publish.yml rename to .github/workflows/publish_docs.yml index f2cfd9c21..ec5440d32 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish_docs.yml @@ -1,26 +1,25 @@ -name: Build docs +name: Publish Docs on: push: branches: - master -jobs: - publish: - runs-on: ubuntu-18.04 # linux required if you want to use docker - container: - image: registry.git.rwth-aachen.de/acs/public/hermitcore/hermitrust +env: + CARGO_TERM_COLOR: always +jobs: + publish_docs: + runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 with: - submodules: true + submodules: true + - name: Rustup (apply rust-toolchain.toml) + run: rustup show - name: Generate documentation - uses: actions-rs/cargo@v1 - with: - command: doc - args: --workspace -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit + run: cargo doc - name: Generate index.html run: | cat > target/x86_64-unknown-hermit/doc/index.html <> $GITHUB_PATH + echo "C:\Program Files\NASM" >> $GITHUB_PATH + - name: Build loader + run: | + sed -i.old 's/OBJCOPY := $(shell find $(SYSROOT) -name llvm-objcopy)/OBJCOPY := $(shell find $(SYSROOT) -name llvm-objcopy -o -name llvm-objcopy.exe)/g' loader/Makefile + make -C loader release=1 + - name: Test dev profile + run: | + qemu-system-x86_64 -display none -smp 1 -m 128M -serial stdio \ + -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand \ + -kernel loader/target/x86_64-unknown-hermit-loader/release/rusty-loader \ + -initrd target/x86_64-unknown-hermit/debug/rusty_demo + - name: Build release profile + run: + cargo build --package rusty_demo --release + - name: Test release profile + run: | + qemu-system-x86_64 -display none -smp 1 -m 128M -serial stdio \ + -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand \ + -kernel loader/target/x86_64-unknown-hermit-loader/release/rusty-loader \ + -initrd target/x86_64-unknown-hermit/release/rusty_demo + - name: Build httpd with DHCP support + run: + cargo build --package httpd --features dhcpv4 + - name: Build httpd without DHCP support + run: + cargo build --package httpd diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0c5d99955..01b813474 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,10 +17,6 @@ variables: stage: prepare image: name: docker - variables: - _BUILDAH_STARTED_IN_USERNS: "" - BUILDAH_ISOLATION: chroot - BUILDAH_LAYERS: "true" before_script: - docker version - docker login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" @@ -36,22 +32,36 @@ prepare:docker: build:demo: stage: build image: ${CI_REGISTRY_IMAGE} + before_script: + - rustup update script: - cargo build -p rusty_demo - - RUSTFLAGS="-Clinker-plugin-lto" cargo build -p rusty_demo --release + - cargo build -p rusty_demo --release + - cd loader + - make + - make release=1 + - cd .. artifacts: paths: - target/x86_64-unknown-hermit/debug/rusty_demo - target/x86_64-unknown-hermit/release/rusty_demo + - loader/target/x86_64-unknown-hermit-loader/debug/rusty-loader + - loader/target/x86_64-unknown-hermit-loader/release/rusty-loader build:httpd: stage: build image: ${CI_REGISTRY_IMAGE} + before_script: + - rustup update script: - - RUSTFLAGS="-Clinker-plugin-lto" cargo build --manifest-path examples/httpd/Cargo.toml --no-default-features --features pci,acpi,smoltcp,vga,dhcpv4 --release + - cargo build --manifest-path examples/httpd/Cargo.toml --no-default-features --features pci,acpi,smoltcp,vga,dhcpv4 --release + - cd loader + - make release=1 + - cd .. artifacts: paths: - target/x86_64-unknown-hermit/release/httpd + - loader/target/x86_64-unknown-hermit-loader/release/rusty-loader test:uhyve: stage: test @@ -61,7 +71,7 @@ test:uhyve: script: - lscpu - kvm-ok - - cargo install uhyve + - cargo install uhyve --locked - uhyve -v -c 1 target/x86_64-unknown-hermit/debug/rusty_demo - uhyve -v -c 2 target/x86_64-unknown-hermit/debug/rusty_demo - uhyve -v -c 1 target/x86_64-unknown-hermit/release/rusty_demo @@ -77,26 +87,19 @@ test:qemu: script: - lscpu - kvm-ok - - cd loader - - make - - make release=1 - - cd .. - - qemu-system-x86_64 -display none -smp 1 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/debug/rusty-loader -initrd target/x86_64-unknown-hermit/debug/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,fxsr,rdrand -enable-kvm - - qemu-system-x86_64 -display none -smp 2 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/debug/rusty-loader -initrd target/x86_64-unknown-hermit/debug/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,fxsr,rdrand -enable-kvm - - qemu-system-x86_64 -display none -smp 1 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/release/rusty-loader -initrd target/x86_64-unknown-hermit/release/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,fxsr,rdrand -enable-kvm - - qemu-system-x86_64 -display none -smp 2 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/release/rusty-loader -initrd target/x86_64-unknown-hermit/release/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,fxsr,rdrand -enable-kvm + - qemu-system-x86_64 -display none -smp 1 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/debug/rusty-loader -initrd target/x86_64-unknown-hermit/debug/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand -enable-kvm + - qemu-system-x86_64 -display none -smp 2 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/debug/rusty-loader -initrd target/x86_64-unknown-hermit/debug/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand -enable-kvm + - qemu-system-x86_64 -display none -smp 1 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/release/rusty-loader -initrd target/x86_64-unknown-hermit/release/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand -enable-kvm + - qemu-system-x86_64 -display none -smp 2 -m 64M -serial stdio -kernel loader/target/x86_64-unknown-hermit-loader/release/rusty-loader -initrd target/x86_64-unknown-hermit/release/rusty_demo -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand -enable-kvm tags: - privileged -test:image: +test:httpd_image: stage: test dependencies: - build:httpd image: ${CI_REGISTRY_IMAGE} script: - - cd loader - - make release=1 - - cd .. - dd if=/dev/zero of=disk.img bs=1k count=1M - echo ',,,*;' | sfdisk disk.img - mkfs.ext2 -F -E offset=1048576 disk.img @@ -129,39 +132,63 @@ test:image: refs: - master -deploy:docker: +.deploy:httpd_docker: &deploy_httpd_docker stage: predeploy dependencies: - - test:image + - test:httpd_image image: - name: quay.io/buildah/stable - variables: - _BUILDAH_STARTED_IN_USERNS: "" - BUILDAH_ISOLATION: chroot - BUILDAH_LAYERS: "true" + name: docker before_script: - - buildah version - - buildah login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" + - docker version + - docker login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" script: - | cat << END > ${DOCKER_FILE} FROM scratch ADD disk.qcow2 /disk/ END - - buildah bud -f ${DOCKER_FILE} -t ${DOCKER_IMAGE}/httpd:latest . - - buildah push ${DOCKER_IMAGE}/httpd:latest docker://${DOCKER_IMAGE}/httpd:latest - after_script: - - buildah logout "${CI_REGISTRY}" + - docker build -f ${DOCKER_FILE} -t ${DOCKER_IMAGE}/httpd:latest . + - docker push ${DOCKER_IMAGE}/httpd:latest tags: - - builder + - docker only: refs: - master +deploy:httpd_docker: + <<: *deploy_httpd_docker + +.deploy:demo_docker: &deploy_demo_docker + stage: predeploy + dependencies: + - build:demo + image: + name: docker + before_script: + - docker version + - docker login --username "${CI_REGISTRY_USER}" --password "${CI_REGISTRY_PASSWORD}" "${CI_REGISTRY}" + script: + - | + cat << END > ${DOCKER_FILE} + FROM registry.git.rwth-aachen.de/acs/public/hermitcore/rusty-loader/loader:latest + ADD target/x86_64-unknown-hermit/release/rusty_demo /hermit/ + ENTRYPOINT ["/hermit/rusty_demo"] + END + - docker build -f ${DOCKER_FILE} -t ${DOCKER_IMAGE}/demo:latest . + - docker push ${DOCKER_IMAGE}/demo:latest + tags: + - docker + only: + refs: + - master + +deploy:demo_docker: + <<: *deploy_demo_docker + deploy:httpd: stage: deploy dependencies: - - deploy:docker + - deploy:httpd_docker variables: KUBECONFIG: /root/.kube/config KUBEVIRT_VERSION: v0.36.0 diff --git a/Cargo.lock b/Cargo.lock index ebe4ea7de..e27e6e956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,12 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aarch64" -version = "0.0.4" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f59a84cc62bda7593f3c5c57f32a89492d6f4cbd9ad462019ac7c46f66c9606" +checksum = "4fb59c3a5adf5ce5807ba9e635a0874c7c4136e07208caafeb4e2b0ecf0764cb" dependencies = [ "cortex-a", ] @@ -24,13 +26,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109" +[[package]] +name = "async-task" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.17", + "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "libc", "winapi 0.3.9", ] @@ -55,33 +63,33 @@ checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1f8e949d755f9d79112b5bb46938e0ef9d3804a0b16dfab13aafcaa5f0fa72" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] -name = "cc" -version = "1.0.66" +name = "cache-padded" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] -name = "cfg-if" -version = "0.1.10" +name = "cc" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" [[package]] name = "cfg-if" @@ -101,9 +109,9 @@ dependencies = [ [[package]] name = "chunked_transfer" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" [[package]] name = "clap" @@ -131,18 +139,21 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.38" +version = "0.1.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475f939b731d862c8efe7001757c5d7c80978e00ef2923d60d90a6f0cb184c6b" +checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2" dependencies = [ "rustc-std-workspace-core", ] [[package]] -name = "const_fn" -version = "0.4.4" +name = "concurrent-queue" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] [[package]] name = "core_affinity" @@ -158,42 +169,41 @@ dependencies = [ [[package]] name = "cortex-a" -version = "3.0.5" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad53da88d3deae442c1d6d3d7f3c1ba101520736e01ddb12acb17783b745aff5" +checksum = "509fc35485a2b4ddbacabe0bf2212cdfff88da93658608e5cc651afcb75b7733" dependencies = [ - "register", + "tock-registers", ] [[package]] name = "crossbeam-channel" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ - "cfg-if 1.0.0", - "const_fn", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", @@ -202,20 +212,19 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg 1.0.1", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] [[package]] name = "dtoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "either" @@ -223,11 +232,20 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "fastrand" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +dependencies = [ + "instant", +] + [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding", @@ -239,6 +257,33 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "futures-core" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" + +[[package]] +name = "futures-io" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "hdrhist" version = "0.5.0" @@ -254,27 +299,30 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +version = "0.1.19" dependencies = [ + "compiler_builtins", "libc", + "rustc-std-workspace-core", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "compiler_builtins", "libc", - "rustc-std-workspace-core", ] [[package]] name = "hermit-sys" -version = "0.1.20" +version = "0.1.24" dependencies = [ "aarch64", + "async-task", + "concurrent-queue", + "futures-lite", "lazy_static", "libm", "llvm-tools", @@ -297,15 +345,24 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", "unicode-normalization", ] +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "0.3.4" @@ -330,9 +387,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" dependencies = [ "rustc-std-workspace-core", ] @@ -351,11 +408,11 @@ checksum = "955be5d0ca0465caf127165acb47964f911e2bc26073e865deb8be7189302faf" [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -366,15 +423,21 @@ checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577" [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] name = "memoffset" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" dependencies = [ "autocfg 1.0.1", ] @@ -423,10 +486,16 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "hermit-abi 0.1.17", + "hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "libc", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -471,20 +540,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -597,20 +672,18 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "8.1.2" +version = "10.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fdf7d9dbd43f3d81d94a49c1c3df73cc2b3827995147e6cf7f89d4ec5483e73" +checksum = "929f54e29691d4e6a9cc558479de70db7aa3d98cd6fe7ab86d7507aa2886b9d2" dependencies = [ "bitflags", - "cc", - "rustc_version", ] [[package]] name = "rayon" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" dependencies = [ "autocfg 1.0.1", "crossbeam-deque", @@ -620,9 +693,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -640,15 +713,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "register" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deaba5b0e477d21f61a57504bb5cef4a1e86de30300b457d38971c1cfc98b815" -dependencies = [ - "tock-registers", -] - [[package]] name = "rftrace" version = "0.1.0" @@ -672,15 +736,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1956f5517128a2b6f23ab2dadf1a976f4f5b27962e7724c2bf3d45e539ec098c" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - [[package]] name = "rusty_demo" version = "0.1.0" @@ -707,21 +762,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "0.9.15" @@ -730,18 +770,18 @@ checksum = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" [[package]] name = "serde" -version = "1.0.118" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" dependencies = [ "proc-macro2", "quote", @@ -762,9 +802,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76" +checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" dependencies = [ "proc-macro2", "quote", @@ -779,9 +819,9 @@ checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" [[package]] name = "smoltcp" -version = "0.7.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab527c390c7e107f687bd92a886a083fde61b8cdc700b37f3d7e4346ffd8fae1" +checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3" dependencies = [ "bitflags", "byteorder", @@ -796,9 +836,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.57" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" dependencies = [ "proc-macro2", "quote", @@ -812,7 +852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c15c969e3531d0506b248a095423c3a37b734cb8a214c100f7e86addec515c5" dependencies = [ "cc", - "serde 1.0.118", + "serde 1.0.127", "serde_repr", ] @@ -850,9 +890,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" dependencies = [ "tinyvec_macros", ] @@ -865,24 +905,21 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tock-registers" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70323afdb8082186c0986da0e10f6e4ed103d681c921c00597e98d9806dac20f" +checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] @@ -895,15 +932,15 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "url" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -917,11 +954,17 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", "winapi 0.3.9", @@ -973,9 +1016,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "x86" -version = "0.34.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c146cbc47471e076987378c159a7aa8fa434680c6fbddca59fe6f40f1591c819" +checksum = "edcf43654d533a571fe7f7116373098a95ebc01279efdc5038fc45d3b220cb5a" dependencies = [ "bit_field", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index e5121bea3..895cc41ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,10 @@ members = [ exclude = ["target", "loader", "libhermit-rs"] [profile.release] -opt-level = 3 +opt-level = 2 debug = false rpath = false -lto = "thin" +lto = false debug-assertions = false [profile.dev] diff --git a/README.md b/README.md index 338e36172..4e0cc80d7 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Afterwards, the loader is stored in `target/x86_64-unknown-hermit-loader/debug/` As final step, the unikernel application `app` can be booted with following command: ```bash -qemu-system-x86_64 -display none -smp 1 -m 64M -serial stdio -kernel path_to_loader/rusty-loader -initrd path_to_app/app -cpu qemu64,apic,fsgsbase,rdtscp,xsave,fxsr +qemu-system-x86_64 -display none -smp 1 -m 64M -serial stdio -kernel path_to_loader/rusty-loader -initrd path_to_app/app -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr ``` It is important to enable the processor features _fsgsbase_ and _rdtscp_ because it is a prerequisite to boot RustyHermit. @@ -152,24 +152,6 @@ qemu-system-x86_64 ... -append "kernel-arguments -- application-arguments" You are not happy with `Hello World` yet? -### Link Time Optimization (LTO) - -To enable *Link Time Optimization* (LTO), please extend the release configuration in *Cargo.toml* as follows: - -```toml -# Cargo.toml -[profile.release] -opt-level = 3 -lto = "thin" -``` - -In addition, the [Linker-plugin LTO](https://doc.rust-lang.org/rustc/linker-plugin-lto.html) have to be enabled by setting the compiler flag `linker-plugin-lto`. -In this case, the release version have to build as follows: - -```sh -RUSTFLAGS="-Clinker-plugin-lto" cargo build -Z build-std=std,core,alloc,panic_abort --target x86_64-unknown-hermit --release -``` - ### Controlling kernel message verbosity RustyHermit uses the lightweight logging crate [log](https://github.com/rust-lang/log) to print kernel messages. @@ -220,7 +202,7 @@ Currently, RustyHermit does only support network interfaces through [virtio](htt To use it, you have to start RustyHermit in Qemu with following command: ```bash -$ qemu-system-x86_64 -cpu qemu64,apic,fsgsbase,rdtscp,xsave,fxsr \ +$ qemu-system-x86_64 -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr \ -enable-kvm -display none -smp 1 -m 1G -serial stdio \ -kernel path_to_loader/rusty-loader \ -initrd path_to_app/app \ @@ -232,11 +214,11 @@ You can now access the files in SHARED_DIRECTORY under the virtiofs tag like `/m ## Use RustyHermit for C/C++, Go, and Fortran applications -If you are interested to build C/C++, Go, and Fortran applications on top of a Rust-based library operating systen, please take a look at [https://github.com/hermitcore/hermit-playground](https://github.com/hermitcore/hermit-playground). +If you are interested to build C/C++, Go, and Fortran applications on top of a Rust-based library operating system, please take a look at [https://github.com/hermitcore/hermit-playground](https://github.com/hermitcore/hermit-playground). ## Missing features -* Multikernel support (might be comming) +* Multikernel support (might be coming) * Virtio support (partly available) * Network support (partly available) diff --git a/benches/micro/Cargo.toml b/benches/micro/Cargo.toml index 24f63dd62..7b6287af5 100644 --- a/benches/micro/Cargo.toml +++ b/benches/micro/Cargo.toml @@ -33,7 +33,7 @@ instrument = ["hermit-sys/instrument"] opt-level = 3 debug = false rpath = false -lto = true +lto = false debug-assertions = false [profile.dev] diff --git a/benches/micro/rust-toolchain b/benches/micro/rust-toolchain deleted file mode 100644 index bf867e0ae..000000000 --- a/benches/micro/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly diff --git a/benches/micro/src/main.rs b/benches/micro/src/main.rs index 61baf9f48..13a06eec4 100644 --- a/benches/micro/src/main.rs +++ b/benches/micro/src/main.rs @@ -8,6 +8,7 @@ #![allow(dead_code)] #![allow(unused_imports)] #![feature(test)] +#![feature(bench_black_box)] #[cfg(target_os = "hermit")] extern crate hermit_sys; diff --git a/benches/netbench/Cargo.toml b/benches/netbench/Cargo.toml index 27ed16e1b..b18d73ae6 100644 --- a/benches/netbench/Cargo.toml +++ b/benches/netbench/Cargo.toml @@ -3,6 +3,7 @@ name = "rust-tcp-io-perf" version = "0.0.0" authors = ["Lorenzo Martini "] +edition = "2018" readme = "README.md" description = "A Rust program to measure bandwidth or latency over a Rust TCP connection" @@ -49,7 +50,7 @@ path = "src/rust-tcp-latency/client.rs" opt-level = 3 debug = false rpath = false -lto = true +lto = false debug-assertions = false [profile.dev] diff --git a/benches/netbench/README.md b/benches/netbench/README.md index 340a6ee45..f32d115ef 100644 --- a/benches/netbench/README.md +++ b/benches/netbench/README.md @@ -28,13 +28,13 @@ For both programs, you can run them the same way. We will use `bw` as example. T #### Instructions 1) Run server -- Go on the machine where you wanna launch the server (or ssh into it) +- Go on the machine where you want to launch the server (or ssh into it) - Open a terminal - `cd` into the inner `code` folder -- Run `cargo run --bin server-bw --release` (or compile and run, meaning `cargo build --bin server-bw --release` and once compiled `./target/release/server-bw`). You can specify the port you wanna listen on with `-p `. +- Run `cargo run --bin server-bw --release` (or compile and run, meaning `cargo build --bin server-bw --release` and once compiled `./target/release/server-bw`). You can specify the port you want to listen on with `-p `. 2) Run client -- Go on the machine where you wanna launch the client (or ssh into it) +- Go on the machine where you want to launch the client (or ssh into it) - Open a terminal - `cd` into the inner `code` folder - Run `cargo run --bin client-bw --release` (or compile and run, meaning `cargo build --bin client-bw --release` and once compiled `./target/release/client-bw`). You can specify a bunch of parameters. Run the program with the `-h` option to see available params. Make sure you specify the right address and port to connect to the server, using parameters `-a
-p `. @@ -52,7 +52,7 @@ The config file is important because it will contain a bunch of things like mach #### Prerequisites -- Make sure you can ssh into the machines you wanna use for your benchmark +- Make sure you can ssh into the machines you want to use for your benchmark. - Make sure you have set up the ssh connections correctly and have the machines in your known host and have the ssh keys somewhere in your pc (or the machine you will start the script from). #### Instructions diff --git a/benches/netbench/run.sh b/benches/netbench/run.sh new file mode 100755 index 000000000..43405bdd8 --- /dev/null +++ b/benches/netbench/run.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +# Usage: run.sh TARGET BIN +# Example: run.sh linux server-bw +# run.sh hermit client-bw + +set -o errexit + +netbench_dir="${0%/*}" +root_dir="$netbench_dir"/../.. +rusty_loader_dir="$root_dir"/loader + +bin=$2 +args="--bytes 1048576 --rounds 1000" + +hermit() { + echo "Building rusty-loader" + + make -C "$rusty_loader_dir" release=1 + + echo "Building $bin image" + + cargo build --manifest-path "$netbench_dir"/Cargo.toml --bin $bin \ + --release + + echo "Launching $bin image on QEMU" + + qemu-system-x86_64 -cpu host \ + -enable-kvm -display none -smp 1 -m 1G -serial stdio \ + -kernel "$rusty_loader_dir"/target/x86_64-unknown-hermit-loader/release/rusty-loader \ + -initrd "$root_dir"/target/x86_64-unknown-hermit/release/$bin \ + -netdev tap,id=net0,ifname=tap10,script=no,downscript=no,vhost=on \ + -device virtio-net-pci,netdev=net0,disable-legacy=on \ + -append "-- --nonblocking 0 --address 10.0.5.1 $args" +} + +linux() { + echo "Launching $bin on linux" + + cargo run --manifest-path "$netbench_dir"/Cargo.toml --bin $bin \ + --release \ + --target x86_64-unknown-linux-gnu \ + -- \ + --nonblocking 0 --address 10.0.5.3 $args +} + +$1 diff --git a/benches/netbench/src/config.rs b/benches/netbench/src/config.rs index 5800efe52..5ea92957f 100644 --- a/benches/netbench/src/config.rs +++ b/benches/netbench/src/config.rs @@ -32,7 +32,7 @@ pub fn parse_config() -> Config { .short("p") .long("port") .value_name("port") - .help("port to connect to, like port 7878 if you wanna connect to 127.0.0.1:7878") + .help("port to connect to, like port 7878 if you want to connect to 127.0.0.1:7878") .takes_value(true) .default_value("7878"), ) @@ -113,14 +113,14 @@ pub fn parse_config() -> Config { // Don't kill machines if n_bytes > 100_000_000 { panic!( - "More than 100 MB per round is probably too much data you wanna send, \ + "More than 100 MB per round is probably too much data you want to send, \ you may kill one of the machines. Try with maybe 100MB but more rounds" ) } // Very improbable case error handling if (n_bytes * 1000000) as u128 * n_rounds as u128 > u64::max_value().into() { - panic!("There's gonna be too much data. Make sure n_bytes * n_rounds is < u128::MAX") + panic!("There's going to be too much data. Make sure n_bytes * n_rounds is < u128::MAX") } Config { diff --git a/benches/netbench/src/connection.rs b/benches/netbench/src/connection.rs index ec5e6de01..187de4410 100644 --- a/benches/netbench/src/connection.rs +++ b/benches/netbench/src/connection.rs @@ -1,6 +1,6 @@ extern crate core_affinity; -use config::Config; +use crate::config::Config; use std::io; use std::io::ErrorKind::WouldBlock; use std::io::{Read, Write}; diff --git a/benches/netbench/src/threading.rs b/benches/netbench/src/threading.rs index 230c96b9b..daa9c5346 100644 --- a/benches/netbench/src/threading.rs +++ b/benches/netbench/src/threading.rs @@ -1,4 +1,4 @@ -use config::Config; +use crate::config::Config; pub fn setup(config: &Config) { if config.p_id >= 0 { diff --git a/bors.toml b/bors.toml index 9165a035b..23792800d 100644 --- a/bors.toml +++ b/bors.toml @@ -1,9 +1,10 @@ status = [ - "Test (macOS-latest, nightly)", - "Test (windows-latest, nightly)", - "Test (ubuntu-latest, nightly)", - "Format check (ubuntu-latest, nightly)", - "ci/gitlab/git.rwth-aachen.de", + "Test (ubuntu-latest)", + "Test (macos-latest)", + "Test (windows-latest)", + "Format", + "Clippy", + "KVM Test", ] delete_merged_branches = true timeout_sec = 7200 diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml index 19ab1dadd..e5fd9cd46 100644 --- a/examples/demo/Cargo.toml +++ b/examples/demo/Cargo.toml @@ -46,7 +46,7 @@ instrument = ["hermit-sys/instrument"] opt-level = 3 debug = false rpath = false -lto = true +lto = false debug-assertions = false [profile.dev] diff --git a/examples/demo/src/tests/matmul.rs b/examples/demo/src/tests/matmul.rs index 338818291..bc076d6be 100644 --- a/examples/demo/src/tests/matmul.rs +++ b/examples/demo/src/tests/matmul.rs @@ -1,3 +1,6 @@ +#![allow(clippy::many_single_char_names)] +#![allow(clippy::too_many_arguments)] + use std::time::Instant; /// Code is derived Rayon's matmul example diff --git a/examples/demo/src/tests/mod.rs b/examples/demo/src/tests/mod.rs index b270d9cac..e7b6da732 100644 --- a/examples/demo/src/tests/mod.rs +++ b/examples/demo/src/tests/mod.rs @@ -155,7 +155,7 @@ pub fn hello() -> Result<(), ()> { println!("你好,世界"); println!("สวัสดีชาวโลก"); println!("Chào thế giới"); - let crab = vec![0xF0 as u8, 0x9F as u8, 0xA6 as u8, 0x80 as u8]; + let crab = vec![0xF0_u8, 0x9F_u8, 0xA6_u8, 0x80_u8]; println!( "Crab emoji: {}", String::from_utf8(crab).unwrap_or_default() diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml index 67fbb1281..01244730f 100644 --- a/examples/hello_world/Cargo.toml +++ b/examples/hello_world/Cargo.toml @@ -23,7 +23,7 @@ instrument = ["hermit-sys/instrument"] opt-level = 3 debug = false rpath = false -lto = true +lto = false debug-assertions = false [profile.dev] diff --git a/examples/httpd/Cargo.toml b/examples/httpd/Cargo.toml index bae1b4240..7ad601c85 100644 --- a/examples/httpd/Cargo.toml +++ b/examples/httpd/Cargo.toml @@ -29,7 +29,7 @@ instrument = ["hermit-sys/instrument"] opt-level = 3 debug = false rpath = false -lto = true +lto = false debug-assertions = false [profile.dev] diff --git a/examples/httpd/src/main.rs b/examples/httpd/src/main.rs index 4fafe0aa4..48ae88886 100644 --- a/examples/httpd/src/main.rs +++ b/examples/httpd/src/main.rs @@ -6,7 +6,7 @@ extern crate hermit_sys; extern crate tiny_http; fn main() { - let crab = vec![0xF0 as u8, 0x9F as u8, 0xA6 as u8, 0x80 as u8]; + let crab = vec![0xF0_u8, 0x9F_u8, 0xA6_u8, 0x80_u8]; let text = format!( "Hello from RustyHermit {}", String::from_utf8(crab).unwrap_or_default() diff --git a/hermit-abi/Cargo.toml b/hermit-abi/Cargo.toml index e520847ee..baa693072 100644 --- a/hermit-abi/Cargo.toml +++ b/hermit-abi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" authors = ["Stefan Lankes"] license = "MIT/Apache-2.0" readme = "README.md" @@ -9,14 +9,14 @@ description = """ hermit-abi is small interface to call functions from the unikernel RustyHermit. It is used to build the target `x86_64-unknown-hermit`. """ -repository = "https://github.com/hermitcore/libhermit-rs" +repository = "https://github.com/hermitcore/rusty-hermit" keywords = ["unikernel", "libos"] categories = ["os"] documentation = "https://hermitcore.github.io/rusty-hermit/hermit_abi" [dependencies] core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } -compiler_builtins = { version = "0.1.0", optional = true } +compiler_builtins = { version = "0.1", optional = true } libc = { version = "0.2.51", default-features = false } [features] diff --git a/hermit-abi/rust-toolchain b/hermit-abi/rust-toolchain deleted file mode 100644 index bf867e0ae..000000000 --- a/hermit-abi/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly diff --git a/hermit-abi/src/lib.rs b/hermit-abi/src/lib.rs index 0b8c5b44b..7bb4a4cb0 100644 --- a/hermit-abi/src/lib.rs +++ b/hermit-abi/src/lib.rs @@ -2,6 +2,9 @@ //! [RustyHermit](https://github.com/hermitcore/libhermit-rs). #![no_std] +#![allow(clippy::missing_safety_doc)] +#![allow(clippy::result_unit_err)] + extern crate libc; pub mod tcplistener; @@ -116,7 +119,7 @@ pub fn isatty(_fd: libc::c_int) -> bool { false } -/// intialize the network stack +/// initialize the network stack pub fn network_init() -> i32 { unsafe { sys_network_init() } } diff --git a/hermit-sys/Cargo.toml b/hermit-sys/Cargo.toml index ed3475ee2..24ce83695 100644 --- a/hermit-sys/Cargo.toml +++ b/hermit-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hermit-sys" -version = "0.1.20" +version = "0.1.24" authors = ["Stefan Lankes"] license = "MIT/Apache-2.0" description = "FFI bindings to HermitCore" @@ -15,7 +15,7 @@ documentation = "https://hermitcore.github.io/rusty-hermit/hermit_sys" [features] default = ["pci", "acpi", "smp", "fsgsbase"] -# controlls whether RustyHermit is build with -Z instrument-mcount +# controls whether RustyHermit is build with -Z instrument-mcount instrument = ["rftrace"] trace = [] fsgsbase = [] @@ -34,8 +34,11 @@ llvm-tools = { version = "0.1" } [dependencies] log = { version = "0.4", default-features = false } -lazy_static = "1.4.0" libm = { version = "0.2.1", default-features = false } +async-task = "4.0" +concurrent-queue = "1.2" +futures-lite = "1.11" +lazy_static = "1.4" [target.'cfg(target_arch = "x86_64")'.dependencies.x86] version = "0.*" @@ -49,9 +52,9 @@ default-features = false version = "0.7.0" optional = true default-features = false -features = ["std", "ethernet", "socket-udp", "socket-tcp", "proto-ipv4", "proto-ipv6"] +features = ["std", "ethernet", "socket-udp", "socket-tcp", "proto-ipv4", "proto-ipv6", "async"] # to increase the output the features log and verbose should be enabled -#features = ["log", "verbose", "std", "ethernet", "socket-udp", "socket-tcp", "proto-ipv4", "proto-ipv6"] +#features = ["log", "verbose", "std", "ethernet", "socket-udp", "socket-tcp", "proto-ipv4", "proto-ipv6", "async"] [dependencies.rftrace] version = "0.1.0" diff --git a/hermit-sys/build.rs b/hermit-sys/build.rs index b3b293fa6..457890c6f 100644 --- a/hermit-sys/build.rs +++ b/hermit-sys/build.rs @@ -3,19 +3,26 @@ extern crate target_build_utils; extern crate walkdir; use std::env; +use std::ffi::OsStr; +use std::ffi::OsString; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf}; -#[cfg(feature = "mem")] use std::process; use std::process::Command; use target_build_utils::TargetInfo; use walkdir::{DirEntry, WalkDir}; fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) { + assert!( + src_dir.exists(), + "rusty_hermit source folder does not exist" + ); let target = TargetInfo::new().expect("Could not get target info"); let profile = env::var("PROFILE").expect("PROFILE was not set"); - let mut cmd = Command::new("cargo"); + let mut cmd = Command::new(env!("CARGO")); + + cmd.env("CARGO_TERM_COLOR", "always"); if target.target_arch() == "x86_64" { cmd.current_dir(src_dir) @@ -50,6 +57,11 @@ fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) { // disable all default features cmd.arg("--no-default-features"); + if target.target_arch() == "aarch64" { + cmd.arg("--features"); + cmd.arg("aarch64-qemu-stdout"); + } + // do we have to enable PCI support? #[cfg(feature = "pci")] { @@ -85,26 +97,33 @@ fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) { cmd.arg("vga"); } + let mut rustflags = vec!["-Zmutable-noalias=no".to_string()]; + let outer_rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(); + #[cfg(feature = "instrument")] { - cmd.env("RUSTFLAGS", "-Z instrument-mcount"); - // if instrument is not set, ensure that instrument is not in environment variables! - cmd.env( - "RUSTFLAGS", - env::var("RUSTFLAGS") - .unwrap_or_else(|_| "".into()) - .replace("-Z instrument-mcount", ""), - ); + rustflags.push("-Zinstrument-mcount".to_string()); + // Add outer rustflags to command + rustflags.push(outer_rustflags); + } + + #[cfg(not(feature = "instrument"))] + { + // If the `instrument` feature feature is not enabled, + // filter it from outer rustflags before adding them to the command. + if !outer_rustflags.is_empty() { + let flags = outer_rustflags + .split('\x1f') + .filter(|&flag| !flag.contains("instrument-mcount")) + .map(String::from); + rustflags.extend(flags); + } } - let output = cmd.output().expect("Unable to build kernel"); - let stdout = std::string::String::from_utf8(output.stdout); - let stderr = std::string::String::from_utf8(output.stderr); + cmd.env("CARGO_ENCODED_RUSTFLAGS", rustflags.join("\x1f")); - println!("Build libhermit-rs output-status: {}", output.status); - println!("Build libhermit-rs output-stdout: {}", stdout.unwrap()); - println!("Build libhermit-rs output-stderr: {}", stderr.unwrap()); - assert!(output.status.success()); + let status = cmd.status().expect("failed to start kernel build"); + assert!(status.success()); let lib_location = if target.target_arch() == "x86_64" { target_dir @@ -123,61 +142,62 @@ fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) { }; println!("Lib location: {}", lib_location.display()); + let lib = lib_location.join("libhermit.a"); + + rename_symbol("rust_begin_unwind", &lib); + rename_symbol("rust_oom", &lib); + #[cfg(feature = "mem")] { - // Kernel and user space has its own versions of memcpy, memset, etc, - // Consequently, we rename the functions in the libos to avoid collisions. - // In addition, it provides us the offer to create a optimized version of memcpy - // in user space. - - // get access to llvm tools shipped in the llvm-tools-preview rustup component - let llvm_tools = match llvm_tools::LlvmTools::new() { - Ok(tools) => tools, - Err(llvm_tools::Error::NotFound) => { - eprintln!("Error: llvm-tools not found"); - eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?"); - eprintln!(" Install it through: `rustup component add llvm-tools-preview`"); - process::exit(1); - } - Err(err) => { - eprintln!("Failed to retrieve llvm-tools component: {:?}", err); - process::exit(1); - } - }; - - let lib = lib_location.join("libhermit.a"); - - let symbols: [&str; 5] = ["memcpy", "memmove", "memset", "memcmp", "bcmp"]; - for symbol in symbols.iter() { - // determine llvm_objcopy - let llvm_objcopy = llvm_tools - .tool(&llvm_tools::exe("llvm-objcopy")) - .expect("llvm_objcopy not found in llvm-tools"); - - // rename symbols - let mut cmd = Command::new(llvm_objcopy); - cmd.arg("--redefine-sym") - .arg(String::from(*symbol) + &String::from("=kernel") + &String::from(*symbol)) - .arg(lib.display().to_string()); - - println!("cmd {:?}", cmd); - let output = cmd.output().expect("Unable to rename symbols"); - let stdout = std::string::String::from_utf8(output.stdout); - let stderr = std::string::String::from_utf8(output.stderr); - println!("Rename symbols output-status: {}", output.status); - println!("Rename symbols output-stdout: {}", stdout.unwrap()); - println!("Rename symbols output-stderr: {}", stderr.unwrap()); + for symbol in ["memcpy", "memmove", "memset", "memcmp", "bcmp"] { + rename_symbol(symbol, &lib); } } println!("cargo:rustc-link-search=native={}", lib_location.display()); println!("cargo:rustc-link-lib=static=hermit"); - //HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time - // Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306 + // HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER"); } +/// Kernel and user space has its own versions of panic handler, oom handler, memcpy, memset, etc, +/// Consequently, we rename the functions in the libos to avoid collisions. +/// In addition, it provides us the offer to create a optimized version of memcpy +/// in user space. +fn rename_symbol(symbol: impl AsRef, lib: impl AsRef) { + // Get access to llvm tools shipped in the llvm-tools-preview rustup component + let llvm_tools = match llvm_tools::LlvmTools::new() { + Ok(tools) => tools, + Err(llvm_tools::Error::NotFound) => { + eprintln!("Error: llvm-tools not found"); + eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?"); + eprintln!(" Install it through: `rustup component add llvm-tools-preview`"); + process::exit(1); + } + Err(err) => { + eprintln!("Failed to retrieve llvm-tools component: {:?}", err); + process::exit(1); + } + }; + + // Retrieve path of llvm-objcopy + let llvm_objcopy = llvm_tools + .tool(&llvm_tools::exe("llvm-objcopy")) + .expect("llvm-objcopy not found in llvm-tools"); + + // Rename symbols + let arg = IntoIterator::into_iter([symbol.as_ref(), "=kernel-".as_ref(), symbol.as_ref()]) + .collect::(); + let status = Command::new(llvm_objcopy) + .arg("--redefine-sym") + .arg(arg) + .arg(lib.as_ref()) + .status() + .expect("failed to execute llvm-objcopy"); + assert!(status.success(), "llvm-objcopy was not successful"); +} + #[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))] fn build() { #[cfg(windows)] @@ -186,15 +206,21 @@ fn build() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let src_dir = out_dir.join("rusty-hermit"); - let _output = Command::new("cargo") - .current_dir(out_dir) - .arg("download") - .arg("--output") - .arg(src_dir.clone().into_os_string()) - .arg("--extract") - .arg("rusty-hermit") - .output() - .expect("Unable to download rusty-hermit. Please install `cargo-download`."); + if !src_dir.as_path().exists() { + let status = Command::new(env!("CARGO")) + .current_dir(out_dir) + .arg("download") + .arg("--output") + .arg(src_dir.clone().into_os_string()) + .arg("--extract") + .arg("rusty-hermit") + .status() + .expect("failed to start kernel download"); + assert!( + status.success(), + "Unable to download rusty-hermit. Is cargo-download installed?" + ); + } build_hermit(src_dir.as_ref(), None); } @@ -202,7 +228,7 @@ fn build() { #[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))] fn build() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let target_dir = out_dir.clone().join("target"); + let target_dir = out_dir.join("target"); let src_dir = env::current_dir() .unwrap() .parent() diff --git a/hermit-sys/rust-toolchain b/hermit-sys/rust-toolchain deleted file mode 100644 index bf867e0ae..000000000 --- a/hermit-sys/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly diff --git a/hermit-sys/src/lib.rs b/hermit-sys/src/lib.rs index 7390ca317..812fd4952 100644 --- a/hermit-sys/src/lib.rs +++ b/hermit-sys/src/lib.rs @@ -1,3 +1,6 @@ +#![allow(clippy::large_enum_variant)] +#![allow(clippy::new_ret_no_self)] + #[cfg(target_arch = "aarch64")] extern crate aarch64; #[macro_use] diff --git a/hermit-sys/src/net/device.rs b/hermit-sys/src/net/device.rs index 6a6b8db32..6edcbd613 100644 --- a/hermit-sys/src/net/device.rs +++ b/hermit-sys/src/net/device.rs @@ -24,7 +24,8 @@ use smoltcp::wire::IpAddress; use smoltcp::wire::Ipv4Cidr; use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address}; -use crate::net::NetworkInterface; +use crate::net::waker::WakerRegistration; +use crate::net::{NetworkInterface, NetworkState}; extern "Rust" { fn sys_get_mac_address() -> Result<[u8; 6], ()>; @@ -39,23 +40,23 @@ extern "Rust" { /// Data type to determine the mac address #[derive(Debug, Copy, Clone)] #[repr(C)] -pub struct HermitNet { +pub(crate) struct HermitNet { pub mtu: u16, } impl HermitNet { - pub fn new(mtu: u16) -> Self { + pub(crate) const fn new(mtu: u16) -> Self { Self { mtu } } } impl NetworkInterface { #[cfg(feature = "dhcpv4")] - pub fn new() -> Option { + pub(crate) fn new() -> NetworkState { let mtu = match unsafe { sys_get_mtu() } { Ok(mtu) => mtu, Err(_) => { - return None; + return NetworkState::InitializationFailed; } }; let device = HermitNet::new(mtu); @@ -67,7 +68,7 @@ impl NetworkInterface { let mac: [u8; 6] = match unsafe { sys_get_mac_address() } { Ok(mac) => mac, Err(_) => { - return None; + return NetworkState::InitializationFailed; } }; @@ -92,21 +93,21 @@ impl NetworkInterface { .routes(routes) .finalize(); - Some(Self { + NetworkState::Initialized(Self { iface, - sockets: sockets, - wait_for: BTreeMap::new(), + sockets, dhcp, prev_cidr, + waker: WakerRegistration::new(), }) } #[cfg(not(feature = "dhcpv4"))] - pub fn new() -> Option { + pub(crate) fn new() -> NetworkState { let mtu = match unsafe { sys_get_mtu() } { Ok(mtu) => mtu, Err(_) => { - return None; + return NetworkState::InitializationFailed; } }; let device = HermitNet::new(mtu); @@ -118,7 +119,7 @@ impl NetworkInterface { let mac: [u8; 6] = match unsafe { sys_get_mac_address() } { Ok(mac) => mac, Err(_) => { - return None; + return NetworkState::InitializationFailed; } }; let myip: Ipv4Addr = HERMIT_IP.parse().expect("Unable to parse IPv4 address"); @@ -166,10 +167,10 @@ impl NetworkInterface { .routes(routes) .finalize(); - Some(Self { + NetworkState::Initialized(Self { iface, sockets: SocketSet::new(vec![]), - wait_for: BTreeMap::new(), + waker: WakerRegistration::new(), }) } } @@ -198,13 +199,13 @@ impl<'a> Device<'a> for HermitNet { } #[doc(hidden)] -pub struct RxToken { +pub(crate) struct RxToken { buffer: &'static mut [u8], handle: usize, } impl RxToken { - pub fn new(buffer: &'static mut [u8], handle: usize) -> Self { + pub(crate) fn new(buffer: &'static mut [u8], handle: usize) -> Self { Self { buffer, handle } } } @@ -225,10 +226,10 @@ impl phy::RxToken for RxToken { } #[doc(hidden)] -pub struct TxToken; +pub(crate) struct TxToken; impl TxToken { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self {} } } diff --git a/hermit-sys/src/net/executor.rs b/hermit-sys/src/net/executor.rs new file mode 100644 index 000000000..9b4f494eb --- /dev/null +++ b/hermit-sys/src/net/executor.rs @@ -0,0 +1,168 @@ +/// An executor, which is run when idling on network I/O. +use crate::net::network_delay; +use async_task::{Runnable, Task}; +use concurrent_queue::ConcurrentQueue; +use futures_lite::pin; +use smoltcp::time::{Duration, Instant}; +use std::sync::atomic::Ordering; +use std::{ + future::Future, + sync::{atomic::AtomicBool, Arc}, + task::{Context, Poll, Wake}, +}; + +/// A thread handle type +type Tid = u32; + +extern "C" { + fn sys_getpid() -> Tid; + fn sys_yield(); + fn sys_wakeup_task(tid: Tid); + fn sys_set_network_polling_mode(value: bool); + fn sys_block_current_task_with_timeout(timeout: u64); + fn sys_block_current_task(); +} + +lazy_static! { + static ref QUEUE: ConcurrentQueue = ConcurrentQueue::unbounded(); +} + +fn run_executor() { + while let Ok(runnable) = QUEUE.pop() { + runnable.run(); + } +} + +/// Spawns a future on the executor. +pub fn spawn(future: F) -> Task +where + F: Future + Send + 'static, + T: Send + 'static, +{ + let schedule = |runnable| QUEUE.push(runnable).unwrap(); + let (runnable, task) = async_task::spawn(future, schedule); + runnable.schedule(); + task +} + +struct ThreadNotify { + /// The (single) executor thread. + thread: Tid, + /// A flag to ensure a wakeup is not "forgotten" before the next `block_current_task` + unparked: AtomicBool, +} + +impl ThreadNotify { + pub fn new() -> Self { + Self { + thread: unsafe { sys_getpid() }, + unparked: AtomicBool::new(false), + } + } +} + +impl Drop for ThreadNotify { + fn drop(&mut self) { + println!("Dropping ThreadNotify!"); + } +} + +impl Wake for ThreadNotify { + fn wake(self: Arc) { + self.wake_by_ref() + } + + fn wake_by_ref(self: &Arc) { + // Make sure the wakeup is remembered until the next `park()`. + let unparked = self.unparked.swap(true, Ordering::Relaxed); + if !unparked { + unsafe { + sys_wakeup_task(self.thread); + } + } + } +} + +thread_local! { + static CURRENT_THREAD_NOTIFY: Arc = Arc::new(ThreadNotify::new()); +} + +pub fn poll_on(future: F, timeout: Option) -> Result +where + F: Future, +{ + CURRENT_THREAD_NOTIFY.with(|thread_notify| { + unsafe { + sys_set_network_polling_mode(true); + } + + let start = Instant::now(); + let waker = thread_notify.clone().into(); + let mut cx = Context::from_waker(&waker); + pin!(future); + + loop { + if let Poll::Ready(t) = future.as_mut().poll(&mut cx) { + unsafe { + sys_set_network_polling_mode(false); + } + return Ok(t); + } + + if let Some(duration) = timeout { + if Instant::now() >= start + duration { + unsafe { + sys_set_network_polling_mode(false); + } + return Err(()); + } + } + + run_executor() + } + }) +} + +/// Blocks the current thread on `f`, running the executor when idling. +pub fn block_on(future: F, timeout: Option) -> Result +where + F: Future, +{ + CURRENT_THREAD_NOTIFY.with(|thread_notify| { + let start = Instant::now(); + let waker = thread_notify.clone().into(); + let mut cx = Context::from_waker(&waker); + pin!(future); + + loop { + if let Poll::Ready(t) = future.as_mut().poll(&mut cx) { + return Ok(t); + } + + if let Some(duration) = timeout { + if Instant::now() >= start + duration { + return Err(()); + } + } + + let delay = network_delay(Instant::now()).map(|d| d.total_millis()); + + if delay.is_none() || delay.unwrap() > 100 { + let unparked = thread_notify.unparked.swap(false, Ordering::Acquire); + if !unparked { + unsafe { + match delay { + Some(d) => sys_block_current_task_with_timeout(d), + None => sys_block_current_task(), + }; + sys_yield(); + } + thread_notify.unparked.store(false, Ordering::Release); + run_executor() + } + } else { + run_executor() + } + } + }) +} diff --git a/hermit-sys/src/net/mod.rs b/hermit-sys/src/net/mod.rs index 0da9f0c62..fa3965e17 100644 --- a/hermit-sys/src/net/mod.rs +++ b/hermit-sys/src/net/mod.rs @@ -1,12 +1,13 @@ +pub mod device; +mod executor; +mod waker; + #[cfg(target_arch = "aarch64")] use aarch64::regs::*; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::_rdtsc; -use std::collections::BTreeMap; use std::convert::TryInto; -use std::future::Future; -use std::mem::MaybeUninit; -use std::pin::Pin; +use std::ops::DerefMut; use std::str::FromStr; use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::Mutex; @@ -24,19 +25,31 @@ use smoltcp::time::{Duration, Instant}; use smoltcp::wire::IpAddress; #[cfg(feature = "dhcpv4")] use smoltcp::wire::{IpCidr, Ipv4Address, Ipv4Cidr}; +use smoltcp::Error; + +use futures_lite::future; use crate::net::device::HermitNet; +use crate::net::executor::{block_on, poll_on, spawn}; +use crate::net::waker::WakerRegistration; -pub mod device; +pub(crate) enum NetworkState { + Missing, + InitializationFailed, + Initialized(NetworkInterface), +} -lazy_static! { - static ref NIC: Mutex>> = - Mutex::new(NetworkInterface::::new()); +impl NetworkState { + fn as_nic_mut(&mut self) -> Result<&mut NetworkInterface, &'static str> { + match self { + NetworkState::Initialized(nic) => Ok(nic), + _ => Err("Network is not initialized!"), + } + } } -extern "Rust" { - fn sys_netwait(handle: Handle, millis: Option); - fn sys_netwait_and_wakeup(handles: &[Handle], millis: Option); +lazy_static! { + static ref NIC: Mutex = Mutex::new(NetworkState::Missing); } extern "C" { @@ -48,6 +61,7 @@ extern "C" { prio: u8, selector: isize, ) -> i32; + fn sys_netwait(); } pub type Handle = SocketHandle; @@ -58,52 +72,37 @@ const DEFAULT_KEEP_ALIVE_INTERVAL: u64 = 75000; static LOCAL_ENDPOINT: AtomicU16 = AtomicU16::new(0); -#[derive(Debug, PartialEq, Eq)] -pub enum WriteFailed { - CanSendFailed, - InternalError, -} - -#[derive(Debug, PartialEq, Eq)] -pub enum ReadFailed { - CanRecvFailed, - InternalError, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum WaitFor { - Establish, - IsActive, - Read, - Write, - Close, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum WaitForResult { - Ok, - Failed, -} - -pub struct NetworkInterface Device<'a>> { +pub(crate) struct NetworkInterface Device<'a>> { #[cfg(feature = "trace")] pub iface: smoltcp::iface::EthernetInterface<'static, EthernetTracer>, #[cfg(not(feature = "trace"))] pub iface: smoltcp::iface::EthernetInterface<'static, T>, pub sockets: SocketSet<'static>, - pub wait_for: BTreeMap, #[cfg(feature = "dhcpv4")] dhcp: Dhcpv4Client, #[cfg(feature = "dhcpv4")] prev_cidr: Ipv4Cidr, + waker: WakerRegistration, } impl NetworkInterface where T: for<'a> Device<'a>, { - pub fn poll(&mut self) -> (std::option::Option, Vec) { - let timestamp = Instant::now(); + pub(crate) fn create_handle(&mut self) -> Result { + let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 65535]); + let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 65535]); + let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer); + let tcp_handle = self.sockets.add(tcp_socket); + + Ok(tcp_handle) + } + + pub(crate) fn wake(&mut self) { + self.waker.wake() + } + + pub(crate) fn poll_common(&mut self, timestamp: Instant) { while self .iface .poll(&mut self.sockets, timestamp) @@ -130,7 +129,7 @@ where }); }); self.prev_cidr = cidr; - info!("Assigned a new IPv4 address: {}", cidr); + debug!("Assigned a new IPv4 address: {}", cidr); } } @@ -144,267 +143,198 @@ where routes_map .get(&IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)) .map(|default_route| { - info!("Default gateway: {}", default_route.via_router); + debug!("Default gateway: {}", default_route.via_router); }); }); if config.dns_servers.iter().any(|s| s.is_some()) { - info!("DNS servers:"); + debug!("DNS servers:"); for dns_server in config.dns_servers.iter().filter_map(|s| *s) { - info!("- {}", dns_server); + debug!("- {}", dns_server); } } }); + } - let mut vec = Vec::new(); - let values: Vec<(Handle, WaitFor)> = self - .wait_for - .iter() - .map(|(handle, wait)| (*handle, *wait)) - .collect(); - for (handle, wait) in values { - if self.check_handle(handle, wait).is_some() { - vec.push(handle); - } - } - - let delay = self.iface.poll_delay(&self.sockets, timestamp); + pub(crate) fn poll(&mut self, cx: &mut Context<'_>, timestamp: Instant) { + self.waker.register(cx.waker()); + self.poll_common(timestamp); + } - (delay, vec) + pub(crate) fn poll_delay(&mut self, timestamp: Instant) -> Option { + self.iface.poll_delay(&self.sockets, timestamp) } +} - pub fn poll_handle(&mut self, handle: Handle) -> Option { - let timestamp = Instant::now(); - while self - .iface - .poll(&mut self.sockets, timestamp) - .unwrap_or(true) - { - // just to make progress - } +pub(crate) struct AsyncSocket(Handle); - if let Some(wait) = self.wait_for.get(&handle) { - let wait = *wait; - self.check_handle(handle, wait) - } else { - None - } +impl AsyncSocket { + pub(crate) fn new() -> Self { + let handle = NIC + .lock() + .unwrap() + .as_nic_mut() + .unwrap() + .create_handle() + .unwrap(); + Self(handle) } - fn check_handle(&mut self, handle: Handle, wait: WaitFor) -> Option { - let socket = self.sockets.get::(handle); - match wait { - // a thread is trying to establish a connection - WaitFor::Establish => match socket.state() { - TcpState::Established => Some(WaitForResult::Ok), - TcpState::FinWait1 - | TcpState::FinWait2 - | TcpState::Closing - | TcpState::TimeWait - | TcpState::LastAck - | TcpState::Closed => Some(WaitForResult::Failed), - _ => None, - }, - // a thread wants to read data - WaitFor::Read => { - if socket.can_recv() { - Some(WaitForResult::Ok) - } else if !socket.may_recv() { - Some(WaitForResult::Failed) - } else { - match socket.state() { - TcpState::FinWait1 - | TcpState::FinWait2 - | TcpState::Closing - | TcpState::Closed => Some(WaitForResult::Failed), - _ => None, - } - } - } - // a thread wants to write data - WaitFor::Write => { - if socket.can_send() { - Some(WaitForResult::Ok) - } else { - match socket.state() { - TcpState::FinWait1 - | TcpState::FinWait2 - | TcpState::Closing - | TcpState::Closed => Some(WaitForResult::Failed), - _ => None, - } - } - } - // a thread is waiting for acknowledge - WaitFor::Close => match socket.state() { - TcpState::FinWait1 - | TcpState::FinWait2 - | TcpState::Closed - | TcpState::Closing - | TcpState::TimeWait => Some(WaitForResult::Ok), - _ => None, - }, - // a thread is waiting for an active connection - WaitFor::IsActive => { - if socket.is_active() { - Some(WaitForResult::Ok) - } else { - match socket.state() { - TcpState::FinWait1 - | TcpState::FinWait2 - | TcpState::Closing - | TcpState::Closed => Some(WaitForResult::Failed), - _ => None, - } - } - } - } + fn with(&self, f: impl FnOnce(&mut TcpSocket) -> R) -> R { + let mut guard = NIC.lock().unwrap(); + let nic = guard.as_nic_mut().unwrap(); + let res = { + let mut s = nic.sockets.get::(self.0); + f(&mut *s) + }; + nic.wake(); + res } - pub fn connect(&mut self, ip: &[u8], port: u16) -> Result { - let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 65535]); - let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 65535]); - let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer); - let tcp_handle = self.sockets.add(tcp_socket); - let address = - IpAddress::from_str(std::str::from_utf8(ip).map_err(|_| ())?).map_err(|_| ())?; + pub(crate) async fn connect(&self, ip: &[u8], port: u16) -> Result { + let address = IpAddress::from_str(std::str::from_utf8(ip).map_err(|_| Error::Illegal)?) + .map_err(|_| Error::Illegal)?; - // request a connection - let mut socket = self.sockets.get::(tcp_handle); - socket - .connect( + self.with(|s| { + s.connect( (address, port), LOCAL_ENDPOINT.fetch_add(1, Ordering::SeqCst), ) - .map_err(|_| ())?; - - Ok(tcp_handle) - } - - pub fn accept(&mut self, port: u16) -> Result { - let tcp_rx_buffer = TcpSocketBuffer::new(vec![0; 65535]); - let tcp_tx_buffer = TcpSocketBuffer::new(vec![0; 65535]); - let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer); - let tcp_handle = self.sockets.add(tcp_socket); - - // request a connection - let mut socket = self.sockets.get::(tcp_handle); - socket.listen(port).map_err(|_| ())?; - - Ok(tcp_handle) + }) + .map_err(|_| Error::Illegal)?; + + future::poll_fn(|cx| { + self.with(|s| match s.state() { + TcpState::Closed | TcpState::TimeWait => Poll::Ready(Err(Error::Unaddressable)), + TcpState::Listen => Poll::Ready(Err(Error::Illegal)), + TcpState::SynSent | TcpState::SynReceived => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + _ => Poll::Ready(Ok(self.0)), + }) + }) + .await } - pub fn close(&mut self, handle: Handle) -> Result<(), ()> { - let timestamp = Instant::now(); - while self - .iface - .poll(&mut self.sockets, timestamp) - .unwrap_or(true) - { - // just to be sure that everything is sent - } - - let mut socket = self.sockets.get::(handle); - socket.close(); + pub(crate) async fn accept(&self, port: u16) -> Result<(IpAddress, u16), Error> { + self.with(|s| s.listen(port).map_err(|_| Error::Illegal))?; - Ok(()) - } + future::poll_fn(|cx| { + self.with(|s| { + if s.is_active() { + Poll::Ready(Ok(())) + } else { + match s.state() { + TcpState::Closed + | TcpState::Closing + | TcpState::FinWait1 + | TcpState::FinWait2 => Poll::Ready(Err(Error::Illegal)), + _ => { + s.register_recv_waker(cx.waker()); + Poll::Pending + } + } + } + }) + }) + .await?; - pub fn read(&mut self, handle: Handle, buffer: &mut [u8]) -> Result { - let mut socket = self.sockets.get::(handle); - if socket.can_recv() { - let len = socket - .recv_slice(buffer) - .map_err(|_| ReadFailed::InternalError)?; + let mut guard = NIC.lock().unwrap(); + let nic = guard.as_nic_mut().map_err(|_| Error::Illegal)?; + let mut socket = nic.sockets.get::(self.0); + socket.set_keep_alive(Some(Duration::from_millis(DEFAULT_KEEP_ALIVE_INTERVAL))); + let endpoint = socket.remote_endpoint(); - Ok(len) - } else { - Err(ReadFailed::CanRecvFailed) - } + Ok((endpoint.addr, endpoint.port)) } - pub fn write(&mut self, handle: Handle, buffer: &[u8]) -> Result { - let mut socket = self.sockets.get::(handle); - if !socket.may_recv() { - return Ok(0); - } else if !socket.can_send() { - return Err(WriteFailed::CanSendFailed); - } - - socket - .send_slice(buffer) - .map_err(|_| WriteFailed::InternalError) + pub(crate) async fn read(&self, buffer: &mut [u8]) -> Result { + future::poll_fn(|cx| { + self.with(|s| match s.state() { + TcpState::FinWait1 + | TcpState::FinWait2 + | TcpState::Closed + | TcpState::Closing + | TcpState::TimeWait => Poll::Ready(Err(Error::Illegal)), + _ => { + if s.may_recv() { + Poll::Ready(s.recv_slice(buffer)) + } else { + s.register_recv_waker(cx.waker()); + Poll::Pending + } + } + }) + }) + .await + .map_err(|_| Error::Illegal) } -} - -struct AsyncSocket(Handle); - -impl Future for AsyncSocket { - type Output = WaitForResult; - - fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll { - let mut guard = NIC.lock().unwrap(); - let nic = guard.as_mut().unwrap(); - if let Some(result) = nic.poll_handle(self.0) { - Poll::Ready(result) - } else { - Poll::Pending - } + pub(crate) async fn write(&self, buffer: &[u8]) -> Result { + future::poll_fn(|cx| { + self.with(|s| match s.state() { + TcpState::FinWait1 + | TcpState::FinWait2 + | TcpState::Closed + | TcpState::Closing + | TcpState::TimeWait => Poll::Ready(Err(Error::Illegal)), + _ => { + if !s.may_recv() { + Poll::Ready(Ok(0)) + } else if s.can_send() { + Poll::Ready(s.send_slice(buffer).map_err(|_| Error::Illegal)) + } else { + s.register_send_waker(cx.waker()); + Poll::Pending + } + } + }) + }) + .await } -} - -async fn socket_wait(handle: Handle) -> WaitForResult { - AsyncSocket(handle).await -} - -fn wait_for_result(handle: Handle, timeout: Option, polling: bool) -> WaitForResult { - let start = std::time::Instant::now(); - let mut task = Box::pin(socket_wait(handle)); - // I can do this because I know that the AsyncSocket primitive and - // never use the context argument. - // Fixme: This is UB - let v = MaybeUninit::uninit(); - let mut ctx: Context = unsafe { v.assume_init() }; - - loop { - match task.as_mut().poll(&mut ctx) { - Poll::Ready(res) => { - return res; - } - Poll::Pending => { - if let Some(t) = timeout { - if u128::from(t) < std::time::Instant::now().duration_since(start).as_millis() { - return WaitForResult::Failed; + pub(crate) async fn close(&self) -> Result<(), Error> { + future::poll_fn(|cx| { + self.with(|s| match s.state() { + TcpState::FinWait1 + | TcpState::FinWait2 + | TcpState::Closed + | TcpState::Closing + | TcpState::TimeWait => Poll::Ready(Err(Error::Illegal)), + _ => { + if s.send_queue() > 0 { + s.register_send_waker(cx.waker()); + Poll::Pending + } else { + s.close(); + Poll::Ready(Ok(())) } } + }) + }) + .await?; - let new_timeout = if polling { Some(0) } else { timeout }; - unsafe { - sys_netwait(handle, new_timeout); + future::poll_fn(|cx| { + self.with(|s| match s.state() { + TcpState::FinWait1 + | TcpState::FinWait2 + | TcpState::Closed + | TcpState::Closing + | TcpState::TimeWait => Poll::Ready(Ok(())), + _ => { + s.register_send_waker(cx.waker()); + Poll::Pending } - } - } + }) + }) + .await } } -#[no_mangle] -extern "C" fn uhyve_thread(_: usize) { - loop { - let mut guard = NIC.lock().unwrap(); - if let Some(iface) = guard.as_mut() { - let (delay, handles) = iface.poll(); - // release lock - drop(guard); - - unsafe { - sys_netwait_and_wakeup(handles.as_slice(), delay.map(|s| s.millis())); - } - } else { - warn!("Ethernet interface not available"); - return; - } +impl From for AsyncSocket { + fn from(handle: Handle) -> Self { + AsyncSocket(handle) } } @@ -420,148 +350,83 @@ fn start_endpoint() -> u16 { (CNTPCT_EL0.get() % (u16::MAX as u64)).try_into().unwrap() } -pub fn network_init() -> Result<(), ()> { - // initialize variable, which contains the next local endpoint - LOCAL_ENDPOINT.store(start_endpoint(), Ordering::SeqCst); +pub(crate) fn network_delay(timestamp: Instant) -> Option { + NIC.lock().unwrap().as_nic_mut().ok()?.poll_delay(timestamp) +} - // create thread, which manages the network stack - // use a higher priority to reduce the network latency - let mut tid: Tid = 0; - let ret = unsafe { sys_spawn(&mut tid, uhyve_thread, 0, 3, 0) }; - if ret >= 0 { - info!("Spawn network thread with id {}", tid); - } +pub(crate) async fn network_run() { + future::poll_fn(|cx| match NIC.lock().unwrap().deref_mut() { + NetworkState::Initialized(nic) => { + nic.poll(cx, Instant::now()); + Poll::Pending + } + _ => Poll::Ready(()), + }) + .await +} - // switch to - unsafe { - sys_yield(); - } +extern "C" fn nic_thread(_: usize) { + loop { + unsafe { sys_netwait() }; - Ok(()) -} + trace!("Network thread checks the devices"); -#[no_mangle] -pub fn sys_tcp_stream_connect(ip: &[u8], port: u16, timeout: Option) -> Result { - let limit = match timeout { - Some(t) => t, - _ => 5000, - }; - let handle = { - let mut guard = NIC.lock().map_err(|_| ())?; - let nic = guard.as_mut().ok_or(())?; - let handle = nic.connect(ip, port)?; - nic.wait_for.insert(handle, WaitFor::Establish); - - handle - }; - - let result = wait_for_result(handle, Some(limit), false); - match result { - WaitForResult::Ok => { - let mut guard = NIC.lock().map_err(|_| ())?; - let nic = guard.as_mut().ok_or(())?; - let mut socket = nic.sockets.get::(handle); - socket.set_keep_alive(Some(Duration::from_millis(DEFAULT_KEEP_ALIVE_INTERVAL))); - - Ok(handle) + if let NetworkState::Initialized(nic) = NIC.lock().unwrap().deref_mut() { + nic.poll_common(Instant::now()); } - _ => Err(()), } } -fn tcp_stream_try_read(handle: Handle, buffer: &mut [u8]) -> Result { - let mut guard = NIC.lock().map_err(|_| ReadFailed::InternalError)?; - let nic = guard.as_mut().ok_or(ReadFailed::InternalError)?; +pub(crate) fn network_init() -> Result<(), ()> { + // initialize variable, which contains the next local endpoint + LOCAL_ENDPOINT.store(start_endpoint(), Ordering::SeqCst); - nic.read(handle, buffer).map_err(|err| { - if let ReadFailed::CanRecvFailed = err { - *nic.wait_for - .get_mut(&handle) - .expect("Unable to find handle") = WaitFor::Read; - } + let mut guard = NIC.lock().unwrap(); - err - }) -} + *guard = NetworkInterface::::new(); -#[no_mangle] -pub fn sys_tcp_stream_read(handle: Handle, buffer: &mut [u8]) -> Result { - loop { - let result = tcp_stream_try_read(handle, buffer); + if let NetworkState::Initialized(nic) = guard.deref_mut() { + nic.poll_common(Instant::now()); - match result { - Ok(len) => { - return Ok(len); - } - Err(ReadFailed::CanRecvFailed) => { - // wait for tx buffers and try the send operation - // ToDo: Is the != here correct? seems unintuitive to return ok if result is not okay - // Additionally timeout of None seems like a bad idea - if wait_for_result(handle, None, false) != WaitForResult::Ok { - return Ok(0); - } - } - _ => { - return Err(()); - } + // create thread, which manages the network stack + // use a higher priority to reduce the network latency + let mut tid: Tid = 0; + let ret = unsafe { sys_spawn(&mut tid, nic_thread, 0, 3, 0) }; + if ret >= 0 { + debug!("Spawn network thread with id {}", tid); } - } -} -fn tcp_stream_try_write(handle: Handle, buffer: &[u8]) -> Result { - let mut guard = NIC.lock().map_err(|_| WriteFailed::InternalError)?; - let nic = guard.as_mut().ok_or(WriteFailed::InternalError)?; + spawn(network_run()).detach(); - let len = nic.write(handle, buffer).map_err(|err| { - if let WriteFailed::CanSendFailed = err { - *nic.wait_for - .get_mut(&handle) - .expect("Unable to find handle") = WaitFor::Write; - } + // switch to network thread + unsafe { sys_yield() }; + } - err - })?; + Ok(()) +} - Ok(len) +#[no_mangle] +pub fn sys_tcp_stream_connect(ip: &[u8], port: u16, timeout: Option) -> Result { + let socket = AsyncSocket::new(); + block_on(socket.connect(ip, port), timeout.map(Duration::from_millis))?.map_err(|_| ()) } #[no_mangle] -pub fn sys_tcp_stream_write(handle: Handle, buffer: &[u8]) -> Result { - loop { - let result = tcp_stream_try_write(handle, buffer); +pub fn sys_tcp_stream_read(handle: Handle, buffer: &mut [u8]) -> Result { + let socket = AsyncSocket::from(handle); + poll_on(socket.read(buffer), None)?.map_err(|_| ()) +} - match result { - Ok(len) => { - return Ok(len); - } - Err(WriteFailed::CanSendFailed) => { - // wait for tx buffers and try the send operation - if wait_for_result(handle, None, true) != WaitForResult::Ok { - return Err(()); - } - } - _ => { - return Err(()); - } - } - } +#[no_mangle] +pub fn sys_tcp_stream_write(handle: Handle, buffer: &[u8]) -> Result { + let socket = AsyncSocket::from(handle); + poll_on(socket.write(buffer), None)?.map_err(|_| ()) } #[no_mangle] pub fn sys_tcp_stream_close(handle: Handle) -> Result<(), ()> { - { - // close connection - let mut guard = NIC.lock().map_err(|_| ())?; - let nic = guard.as_mut().ok_or(())?; - nic.close(handle)?; - *nic.wait_for - .get_mut(&handle) - .expect("Unable to find handle") = WaitFor::Close; - } - - wait_for_result(handle, None, false); - - Ok(()) + let socket = AsyncSocket::from(handle); + block_on(socket.close(), None)?.map_err(|_| ()) } //ToDo: an enum, or at least constants would be better @@ -569,7 +434,7 @@ pub fn sys_tcp_stream_close(handle: Handle) -> Result<(), ()> { pub fn sys_tcp_stream_shutdown(handle: Handle, how: i32) -> Result<(), ()> { match how { 0 /* Read */ => { - debug!("Shutdown::Read is not implemented"); + trace!("Shutdown::Read is not implemented"); Ok(()) }, 1 /* Write */ => { @@ -632,8 +497,8 @@ pub fn sys_tcp_stream_get_tll(_handle: Handle) -> Result { #[no_mangle] pub fn sys_tcp_stream_peer_addr(handle: Handle) -> Result<(IpAddress, u16), ()> { - let mut guard = NIC.lock().map_err(|_| ())?; - let nic = guard.as_mut().ok_or(())?; + let mut guard = NIC.lock().unwrap(); + let nic = guard.as_nic_mut().map_err(drop)?; let mut socket = nic.sockets.get::(handle); socket.set_keep_alive(Some(Duration::from_millis(DEFAULT_KEEP_ALIVE_INTERVAL))); let endpoint = socket.remote_endpoint(); @@ -643,26 +508,8 @@ pub fn sys_tcp_stream_peer_addr(handle: Handle) -> Result<(IpAddress, u16), ()> #[no_mangle] pub fn sys_tcp_listener_accept(port: u16) -> Result<(Handle, IpAddress, u16), ()> { - let handle = { - let mut guard = NIC.lock().map_err(|_| ())?; - let nic = guard.as_mut().ok_or(())?; - let handle = nic.accept(port)?; - nic.wait_for.insert(handle, WaitFor::IsActive); - - handle - }; - - let result = wait_for_result(handle, None, false); - match result { - WaitForResult::Ok => { - let mut guard = NIC.lock().map_err(|_| ())?; - let nic = guard.as_mut().ok_or(())?; - let mut socket = nic.sockets.get::(handle); - socket.set_keep_alive(Some(Duration::from_millis(DEFAULT_KEEP_ALIVE_INTERVAL))); - let endpoint = socket.remote_endpoint(); - - Ok((handle, endpoint.addr, endpoint.port)) - } - _ => Err(()), - } + let socket = AsyncSocket::new(); + let (addr, port) = block_on(socket.accept(port), None)?.map_err(|_| ())?; + + Ok((socket.0, addr, port)) } diff --git a/hermit-sys/src/net/waker.rs b/hermit-sys/src/net/waker.rs new file mode 100644 index 000000000..8b77808c3 --- /dev/null +++ b/hermit-sys/src/net/waker.rs @@ -0,0 +1,46 @@ +/// The waker registration is derived from smoltcp waker registration +use core::task::Waker; + +/// Utility struct to register and wake a waker. +#[derive(Debug)] +pub(crate) struct WakerRegistration { + waker: Option, +} + +impl WakerRegistration { + pub(crate) const fn new() -> Self { + Self { waker: None } + } + + /// Register a waker. Overwrites the previous waker, if any. + pub(crate) fn register(&mut self, w: &Waker) { + match self.waker { + // Optimization: If both the old and new Wakers wake the same task, we can simply + // keep the old waker, skipping the clone. (In most executor implementations, + // cloning a waker is somewhat expensive, comparable to cloning an Arc). + Some(ref w2) if (w2.will_wake(w)) => {} + _ => { + // clone the new waker and store it + if let Some(old_waker) = std::mem::replace(&mut self.waker, Some(w.clone())) { + // We had a waker registered for another task. Wake it, so the other task can + // reregister itself if it's still interested. + // + // If two tasks are waiting on the same thing concurrently, this will cause them + // to wake each other in a loop fighting over this WakerRegistration. This wastes + // CPU but things will still work. + // + // If the user wants to have two tasks waiting on the same thing they should use + // a more appropriate primitive that can store multiple wakers. + old_waker.wake() + } + } + } + } + + /// Wake the registered waker, if any. + pub(crate) fn wake(&mut self) { + if let Some(w) = self.waker.take() { + w.wake(); + } + } +} diff --git a/libhermit-rs b/libhermit-rs index eefecbb4e..a5a5744b0 160000 --- a/libhermit-rs +++ b/libhermit-rs @@ -1 +1 @@ -Subproject commit eefecbb4ed9487b199af4cf1bf05ec9dbb7d0e01 +Subproject commit a5a5744b0290bab1eecd04af7487d28d90d90ca0 diff --git a/loader b/loader index c649f4cbd..2cf63cb33 160000 --- a/loader +++ b/loader @@ -1 +1 @@ -Subproject commit c649f4cbd3d7039d0d649a2bfd7b005778c990b4 +Subproject commit 2cf63cb339e4d4f05114bdda2fa2b0776bf7c391 diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index fb3723262..000000000 --- a/rust-toolchain +++ /dev/null @@ -1,4 +0,0 @@ -[toolchain] -channel = "nightly-2021-04-20" -components = [ "rustfmt", "rust-src", "llvm-tools-preview"] -targets = [ "x86_64-unknown-hermit" ] diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..2a3300bc4 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,9 @@ +[toolchain] +channel = "nightly-2021-08-31" +components = [ + "rust-src", + "llvm-tools-preview", + "rustfmt", + "clippy", +] +targets = [ "x86_64-unknown-hermit" ]