├── .clang-format ├── .clang-tidy ├── .envrc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── junction-ctl ├── .gitignore ├── CMakeLists.txt ├── Cargo.toml └── src │ ├── control_request_generated.rs │ ├── control_response_generated.rs │ └── main.rs ├── junction ├── CMakeLists.txt ├── base │ ├── CMakeLists.txt │ ├── arch.cc │ ├── arch.h │ ├── bitmap.h │ ├── bits.h │ ├── byte_channel.h │ ├── compiler.h │ ├── error.cc │ ├── error.h │ ├── finally.h │ ├── intrusive_list.h │ ├── io.cc │ ├── io.h │ ├── io_test.cc │ ├── slab_list.h │ ├── slab_list_test.cc │ ├── string.h │ ├── time.cc │ ├── time.h │ └── uid.h ├── bindings │ ├── CMakeLists.txt │ ├── log.cc │ ├── log.h │ ├── net.h │ ├── rcu.h │ ├── runtime.cc │ ├── runtime.h │ ├── stack.h │ ├── storage.h │ ├── switch.S │ ├── sync.cc │ ├── sync.h │ ├── test.cc │ ├── thread.cc │ ├── thread.h │ ├── timer.cc │ └── timer.h ├── control │ ├── CMakeLists.txt │ ├── control_request.fbs │ ├── control_response.fbs │ ├── ctl_conn.h │ └── webctl.cc ├── fs │ ├── CMakeLists.txt │ ├── core.cc │ ├── dev.cc │ ├── dev.h │ ├── file.cc │ ├── file.h │ ├── fs.h │ ├── linuxfs │ │ ├── dir.cc │ │ ├── linuxfile.cc │ │ ├── linuxfile.h │ │ ├── linuxfs.cc │ │ └── linuxfs.h │ ├── memfs │ │ ├── dir.cc │ │ ├── memfs.cc │ │ ├── memfs.h │ │ ├── memfs_test.cc │ │ └── memfsfile.h │ └── procfs │ │ ├── procfs.cc │ │ ├── procfs.h │ │ └── seqfile.h ├── junction.cc ├── junction.h ├── kernel │ ├── CMakeLists.txt │ ├── elf.cc │ ├── elf.h │ ├── eventfd.cc │ ├── exec.cc │ ├── exec.h │ ├── futex.cc │ ├── futex.h │ ├── itimer.cc │ ├── itimer.h │ ├── ksys.S │ ├── ksys.h │ ├── misc.cc │ ├── mm.cc │ ├── mm.h │ ├── pipe.cc │ ├── poll.cc │ ├── poll.h │ ├── proc.cc │ ├── proc.h │ ├── random.cc │ ├── sched.cc │ ├── sigframe.cc │ ├── sigframe.h │ ├── signal.cc │ ├── signal.h │ ├── stdiofile.cc │ ├── stdiofile.h │ ├── time.cc │ ├── trapframe.cc │ ├── trapframe.h │ └── usys.h ├── libc_override.cc ├── limits.h ├── net │ ├── CMakeLists.txt │ ├── caladan_poll.cc │ ├── caladan_poll.h │ ├── net.cc │ ├── socket.h │ ├── tcp_bench_test.cc │ ├── tcp_socket.h │ ├── udp_bench_test.cc │ └── udp_socket.h ├── new_override.cc ├── run.cc ├── run.h ├── samples │ ├── CMakeLists.txt │ ├── cereal │ │ ├── CMakeLists.txt │ │ ├── dumb.h │ │ ├── polymorph.cc │ │ ├── polymorph.h │ │ └── smart.cc │ ├── filesystem │ │ ├── CMakeLists.txt │ │ ├── create_files │ │ │ ├── CMakeLists.txt │ │ │ ├── README.md │ │ │ └── create_files.cc │ │ └── getdents │ │ │ ├── CMakeLists.txt │ │ │ └── getdents.cc │ ├── hello_world │ │ ├── CMakeLists.txt │ │ └── hello_world.cc │ ├── netbench_udp │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── fake_worker.cc │ │ ├── fake_worker.h │ │ ├── netbench_udp.cc │ │ ├── proto.h │ │ ├── timing.cc │ │ └── timing.h │ ├── netperf_tcp │ │ ├── CMakeLists.txt │ │ └── server.cc │ ├── snapshots │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── c │ │ │ ├── CMakeLists.txt │ │ │ ├── mt_simple.cc │ │ │ ├── st_catch_all.cc │ │ │ ├── st_empty.cc │ │ │ ├── st_epoll.cc │ │ │ ├── st_linux_file.cc │ │ │ ├── st_memfs_file.cc │ │ │ ├── st_pipe.cc │ │ │ ├── st_socketpair.cc │ │ │ ├── st_stdio_file.cc │ │ │ └── yes.cc │ │ ├── go │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── hello.go │ │ │ ├── images │ │ │ │ ├── AIMG_4087.jpg │ │ │ │ ├── IMG_4011.jpg │ │ │ │ └── almost_dayrise_house.jpg │ │ │ └── resizer.go │ │ ├── node │ │ │ ├── CMakeLists.txt │ │ │ └── hello.js │ │ ├── python │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── README.md │ │ │ ├── hello.py │ │ │ ├── images │ │ │ │ ├── AIMG_4087.jpg │ │ │ │ ├── IMG_4011.jpg │ │ │ │ └── almost_dayrise_house.jpg │ │ │ ├── numpy_test.py │ │ │ └── python_resizer.py │ │ └── rust │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ └── resize-rs │ │ │ ├── Cargo.toml │ │ │ ├── images │ │ │ ├── AIMG_4087.jpg │ │ │ ├── IMG_4011.jpg │ │ │ └── almost_dayrise_house.jpg │ │ │ └── src │ │ │ └── main.rs │ ├── tcp │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── client.cc │ │ └── server.cc │ └── udp │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── client.cc │ │ └── server.cc ├── shim │ ├── CMakeLists.txt │ ├── backend │ │ ├── init.cc │ │ ├── init.h │ │ ├── sem.cc │ │ └── sync.cc │ ├── child_test.cc │ ├── frontend.cc │ ├── functions.txt │ ├── shim.h │ ├── shimjmp_tbl.py │ ├── sync.h │ └── tbench_test.cc ├── snapshot │ ├── CMakeLists.txt │ ├── cereal.h │ ├── pod.h │ ├── snapshot.cc │ └── snapshot.h └── syscall │ ├── CMakeLists.txt │ ├── entry.S │ ├── entry.h │ ├── seccomp.cc │ ├── seccomp.h │ ├── seccomp_bpf.h │ ├── strace.cc │ ├── strace.h │ ├── syscall.cc │ ├── syscall.h │ ├── syscall_testenv.cc │ ├── systbl.h │ ├── systbl.py │ └── usys.txt ├── lib ├── CMakeLists.txt └── patches │ ├── caladan │ ├── 0001-no-op-pthread_mutex_destroy-to-let-libc-exit-handler.patch │ ├── 0002-set-config-options.patch │ ├── 0003-runtime-allow-uthreads-to-set-their-own-fsbase-value.patch │ ├── 0004-runtime-add-thread_create_nostack.patch │ ├── 0005-base-runtime-make-all-runtime-syscalls-from-a-set-in.patch │ ├── 0006-base-don-t-track-physical-page-numbers.patch │ ├── 0007-base-some-tweaks-to-make-things-easier-in-junction.patch │ ├── 0008-base-provide-sigaction-functionality-for-runtime-jun.patch │ ├── 0009-base-use-write-syscall-directly-for-logging.patch │ ├── 0010-remove-shim-tls-implementation.patch │ ├── 0011-tcp-increase-window-size.patch │ ├── 0012-report-transactions-second-as-well.patch │ ├── 0013-Do-not-call-mbind-in-__mem_map_anom.patch │ ├── 0014-support-external-polling-for-tcp-udp-sockets.patch │ ├── 0015-expose-thread-struct.patch │ ├── 0016-enlarge-stacks.patch │ ├── 0017-extend-struct-thread-to-support-extended-register-sa.patch │ ├── 0018-add-space-for-Thread-class-in-struct-thread.patch │ ├── 0019-add-support-for-alternate-syscall-stacks.patch │ ├── 0020-syscall-nits.patch │ ├── 0021-thread-nit.patch │ ├── 0022-preemption-and-signal-updates.patch │ ├── 0023-disable-stack-protector.patch │ ├── 0024-recurring-timers.patch │ ├── 0025-copy-small-mbufs.patch │ ├── 0026-latency-tuning.patch │ ├── 0027-split-tx-buffer-pool.patch │ ├── 0028-add-const-alias-for-thread_self.patch │ ├── 0029-make-logging-safe.patch │ ├── 0030-add-support-for-interruptible-waiting.patch │ ├── 0031-make-TCP-UDP-sockets-interruptible.patch │ ├── 0032-uintr.patch │ ├── 0033-uintr-xsave-area.patch │ ├── 0034-sched-mark-newly-created-threads.patch │ ├── 0035-use-hint-for-stack-mapping.patch │ ├── 0036-support-MSG_PEEK.patch │ ├── 0037-collect-thread-cpu-times.patch │ └── 0038-bump-tstate-buf.patch │ └── glibc │ ├── 0001-Not-building-binaries-that-are-not-required.patch │ ├── 0002-junction-syscall-hooks.patch │ ├── 0003-glibc-hook-some-more-syscalls.patch │ ├── 0005-cancel-cancellation.patch │ ├── 0006-patch-rt_sigreturn.patch │ └── 0007-switch-syscall-format.patch └── scripts ├── build.sh ├── install.sh ├── install_caladan.sh ├── install_cereal.sh ├── install_cmake.sh ├── install_flatbuffers.sh ├── install_glibc.sh ├── run_clang_format.sh ├── run_clang_tidy.sh ├── snapshot_test.sh ├── submodule_check.sh ├── test.sh ├── tools ├── create_image.py ├── debug.sh ├── gdb_find_symbols.py ├── generate_flamegraph.sh └── run.sh └── viz ├── Makefile ├── plot_timings.py ├── requirements.txt └── timings.awk /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | ... 5 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # Based on: https://github.com/googleapis/google-cloud-cpp/blob/main/.clang-tidy 2 | 3 | Checks: > 4 | -*, 5 | bugprone-*, 6 | google-*, 7 | misc-*, 8 | modernize-*, 9 | performance-*, 10 | portability-*, 11 | readability-*, 12 | -google-readability-braces-around-statements, 13 | -google-readability-namespace-comments, 14 | -google-runtime-references, 15 | -misc-non-private-member-variables-in-classes, 16 | -misc-const-correctness, 17 | -modernize-return-braced-init-list, 18 | -modernize-use-trailing-return-type, 19 | -modernize-avoid-c-arrays, 20 | -performance-move-const-arg, 21 | -readability-braces-around-statements, 22 | -readability-identifier-length, 23 | -readability-magic-numbers, 24 | -readability-named-parameter, 25 | -readability-redundant-declaration, 26 | -readability-function-cognitive-complexity, 27 | -readability-identifier-naming, #broken by some bug 28 | -bugprone-narrowing-conversions, 29 | -bugprone-easily-swappable-parameters, 30 | -bugprone-implicit-widening-of-multiplication-result 31 | 32 | CheckOptions: 33 | - { key: readability-identifier-naming.NamespaceCase, value: lower_case } 34 | - { key: readability-identifier-naming.ClassCase, value: CamelCase } 35 | - { key: readability-identifier-naming.StructCase, value: CamelCase } 36 | - { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase } 37 | - { key: readability-identifier-naming.FunctionCase, value: aNy_CasE } 38 | - { key: readability-identifier-naming.VariableCase, value: lower_case } 39 | - { key: readability-identifier-naming.ClassMemberCase, value: lower_case } 40 | - { key: readability-identifier-naming.ClassMemberSuffix, value: _ } 41 | - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } 42 | - { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ } 43 | - { key: readability-identifier-naming.EnumConstantCase, value: CamelCase } 44 | - { key: readability-identifier-naming.EnumConstantPrefix, value: k } 45 | - { key: readability-identifier-naming.ConstexprVariableCase, value: CamelCase } 46 | - { key: readability-identifier-naming.ConstexprVariablePrefix, value: k } 47 | - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } 48 | - { key: readability-identifier-naming.GlobalConstantPrefix, value: k } 49 | - { key: readability-identifier-naming.MemberConstantCase, value: CamelCase } 50 | - { key: readability-identifier-naming.MemberConstantPrefix, value: k } 51 | - { key: readability-identifier-naming.StaticConstantCase, value: CamelCase } 52 | - { key: readability-identifier-naming.StaticConstantPrefix, value: k } 53 | - { key: readability-implicit-bool-conversion.AllowIntegerConditions, value: 1 } 54 | - { key: readability-implicit-bool-conversion.AllowPointerConditions, value: 1 } 55 | - { key: readability-function-cognitive-complexity.IgnoreMacros, value: 1 } 56 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | export JUNCTION_HOME=$(pwd) 2 | export CALADAN_HOME=${JUNCTION_HOME}/lib/caladan 3 | export DEFAULT_CONFIG_PATH=${JUNCTION_HOME}/build/junction/caladan_test.config 4 | 5 | export JUNCTION_RUN=${JUNCTION_HOME}/build/junction/junction_run 6 | export JUNCTION_RUN_DEBUG=${JUNCTION_HOME}/build-debug/junction/junction_run 7 | export IOKERNELD=${CALADAN_HOME}/iokerneld 8 | 9 | export PATH=${PATH}:$(pwd)/scripts 10 | export PATH=${PATH}:$(pwd)/scripts/viz 11 | 12 | # add junction-ctl 13 | export PATH=$(pwd)/build/junction-ctl:$(pwd)/build-debug/junction-ctl:${PATH} 14 | 15 | export CC=gcc 16 | export CXX=g++ 17 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Junction CI Pipeline 2 | 3 | name: Junction 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the $default-branch branch 8 | push: 9 | branches: [ $default-branch ] 10 | pull_request: 11 | branches: [ $default-branch ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | build: 20 | # The type of runner that the job will run on 21 | runs-on: self-hosted 22 | 23 | # Steps represent a sequence of tasks that will be executed as part of the job 24 | steps: 25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 26 | - uses: actions/checkout@v3 27 | 28 | - name: Install 29 | run: | 30 | git config --global user.email "abelay@mit.edu" 31 | git config --global user.name "Adam Belay" 32 | sudo apt-get update 33 | sudo apt-get install -y gcc-12 g++-12 34 | sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 10 35 | sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 10 36 | ./scripts/install.sh 37 | 38 | - name: Build 39 | run: | 40 | ./scripts/build.sh 41 | 42 | - name: Test 43 | run: ./scripts/test.sh 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/** 2 | build-debug/** 3 | bin/** 4 | perf_*/** 5 | Testing/** 6 | *.d 7 | *.o 8 | *.a 9 | [._]*.sw[a-p] 10 | *~ 11 | .cproject 12 | .project 13 | .vscode 14 | **/*.DS_Store 15 | lib/.caladan_installed_ver 16 | lib/.glibc_installed_ver 17 | *.snapshot 18 | *.elf 19 | *.metadata 20 | 21 | junction/control/control_request_generated.h 22 | junction/control/control_response_generated.h 23 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/shenango"] 2 | path = lib/caladan 3 | url = https://github.com/shenango/caladan.git 4 | ignore = dirty 5 | [submodule "lib/glibc"] 6 | path = lib/glibc 7 | url = https://sourceware.org/git/glibc.git 8 | ignore = dirty 9 | [submodule "lib/FlameGraph"] 10 | path = lib/FlameGraph 11 | url = https://github.com/brendangregg/FlameGraph.git 12 | ignore = dirty 13 | [submodule "lib/cereal"] 14 | path = lib/cereal 15 | url = https://github.com/USCiLab/cereal.git 16 | [submodule "lib/flatbuffers"] 17 | path = lib/flatbuffers 18 | url = https://github.com/google/flatbuffers 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | project(junction C CXX ASM) 3 | 4 | message(STATUS "Building junction") 5 | 6 | set(CMAKE_VERBOSE_MAKEFILE ON) 7 | set(CMAKE_COLOR_MAKEFILE ON) 8 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | 11 | set(CMAKE_CXX_STANDARD 23) 12 | set(CMAKE_ENABLE_EXPORTS ON) 13 | set(THREADS_PREFER_PTHREAD_FLAG ON) 14 | SET(ASM_OPTIONS "-x assembler-with-cpp") 15 | SET(CMAKE_ASM_FLAGS "${CFLAGS} ${ASM_OPTIONS}") 16 | 17 | if(NOT CMAKE_BUILD_TYPE) 18 | set(CMAKE_BUILD_TYPE Release) 19 | endif() 20 | 21 | set(CMAKE_CXX_FLAGS "-Wall -g -fno-stack-protector -march=native -m64 -muintr -mxsavec") 22 | set(CMAKE_CXX_FLAGS_DEBUG "-DDEBUG") 23 | set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -flto=auto -ffast-math -fconcepts-diagnostics-depth=100") 24 | 25 | # Add corrosion: a way to build rust code in Cmake 26 | include(FetchContent) 27 | 28 | FetchContent_Declare( 29 | Corrosion 30 | GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git 31 | GIT_TAG v0.4 # Optionally specify a commit hash, version tag or branch here 32 | ) 33 | # Set any global configuration variables such as `Rust_TOOLCHAIN` before this line! 34 | FetchContent_MakeAvailable(Corrosion) 35 | 36 | include_directories( 37 | ${CMAKE_SOURCE_DIR} 38 | SYSTEM ${CMAKE_SOURCE_DIR}/lib/caladan/inc 39 | SYSTEM ${CMAKE_SOURCE_DIR}/lib/cereal/include 40 | SYSTEM ${CMAKE_SOURCE_DIR}/lib/flatbuffers/include 41 | ) 42 | 43 | add_subdirectory(lib) 44 | add_subdirectory(junction) 45 | add_subdirectory(junction-ctl) 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Massachusetts Institute of Technology 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /junction-ctl/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | -------------------------------------------------------------------------------- /junction-ctl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | message(STATUS "Building junction-ctl") 2 | 3 | corrosion_import_crate(MANIFEST_PATH Cargo.toml) 4 | -------------------------------------------------------------------------------- /junction-ctl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "junction-ctl" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0.81" 10 | clap = { version = "4.5.4", features = ["derive"] } 11 | easy-repl = "0.2.1" 12 | 13 | flatbuffers = { path = "../lib/flatbuffers/rust/flatbuffers" } 14 | -------------------------------------------------------------------------------- /junction/base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | message(STATUS "Building junction base") 2 | 3 | add_library(base 4 | arch.cc 5 | error.cc 6 | io.cc 7 | time.cc 8 | ) 9 | 10 | add_executable(slab_list_test 11 | slab_list_test.cc 12 | ) 13 | target_link_libraries(slab_list_test 14 | "$" 15 | ) 16 | 17 | add_test( 18 | NAME slab_list_test 19 | COMMAND sh -c "$" 20 | ) 21 | 22 | add_executable(io_test 23 | io_test.cc 24 | ) 25 | 26 | target_link_libraries(io_test 27 | "$" 28 | base 29 | bindings 30 | caladan_runtime 31 | ) 32 | 33 | add_test( 34 | NAME io_test 35 | COMMAND sh -c "$" 36 | ) -------------------------------------------------------------------------------- /junction/base/arch.cc: -------------------------------------------------------------------------------- 1 | // arch.cc - support for x86_64 CPU features 2 | // 3 | // TODO(amb): Do misaligned reads still work with RDRAND/RDSEED? 4 | 5 | #include "junction/base/arch.h" 6 | 7 | #include 8 | 9 | namespace junction { 10 | namespace { 11 | 12 | bool ReadRandomWord(uint64_t *val) { 13 | // The number of retries before giving up. Intel suggests this is a HW error. 14 | static constexpr int kRetries = 10; 15 | bool ok; 16 | 17 | for (int i = 0; i < kRetries; ++i) { 18 | asm volatile("rdrand %0" : "=r"(*val), "=@ccc"(ok)); 19 | if (ok) return true; 20 | } 21 | return false; 22 | } 23 | 24 | bool ReadSeedWord(uint64_t *val, bool blocking) { 25 | bool ok; 26 | 27 | while (true) { 28 | asm volatile("rdseed %0" : "=r"(*val), "=@ccc"(ok)); 29 | if (!blocking || ok) break; 30 | CPURelax(); 31 | } 32 | 33 | return ok; 34 | } 35 | 36 | } // namespace 37 | 38 | Status ReadRandom(std::span buf) { 39 | size_t n = 0; 40 | while (n < buf.size()) { 41 | // Copy if less than 8 bytes. 42 | if (buf.size() - n < sizeof(uint64_t)) { 43 | uint64_t val; 44 | if (!ReadRandomWord(&val)) return MakeError(EIO); 45 | std::memcpy(buf.data() + n, &val, buf.size() - n); 46 | break; 47 | } 48 | 49 | // Otherwise no need to copy. 50 | if (!ReadRandomWord(reinterpret_cast(buf.data() + n))) 51 | return MakeError(EIO); 52 | n += sizeof(uint64_t); 53 | } 54 | 55 | return buf.size(); 56 | } 57 | 58 | Status ReadEntropy(std::span buf, bool blocking) { 59 | size_t n = 0; 60 | while (n < buf.size()) { 61 | // Copy if less than 8 bytes. 62 | if (buf.size() - n < sizeof(uint64_t)) { 63 | uint64_t val; 64 | if (!ReadSeedWord(&val, blocking)) break; 65 | std::memcpy(buf.data() + n, &val, buf.size() - n); 66 | break; 67 | } 68 | 69 | // Otherwise no need to copy. 70 | if (!ReadSeedWord(reinterpret_cast(buf.data() + n), blocking)) 71 | break; 72 | n += sizeof(uint64_t); 73 | } 74 | 75 | if (!buf.empty() && n == 0) return MakeError(EAGAIN); 76 | return buf.size(); 77 | } 78 | 79 | } // namespace junction 80 | -------------------------------------------------------------------------------- /junction/base/bits.h: -------------------------------------------------------------------------------- 1 | // bits.h - useful bit tricks 2 | 3 | #pragma once 4 | 5 | extern "C" { 6 | #include 7 | } 8 | 9 | #include 10 | #include 11 | 12 | namespace junction { 13 | 14 | inline constexpr size_t kBitsPerByte = 8; 15 | 16 | // AlignUp aligns the value up to a power of two alignment 17 | template 18 | __always_inline __nofp constexpr T AlignUp(T val, size_t align) noexcept 19 | requires std::is_unsigned_v 20 | { 21 | assert(std::has_single_bit(align)); 22 | return T((val + (T(align) - 1)) & ~T(align - 1)); 23 | } 24 | 25 | // AlignDown aligns the value down to a power of two alignment 26 | template 27 | __always_inline __nofp constexpr T AlignDown(T val, size_t align) noexcept 28 | requires std::is_unsigned_v 29 | { 30 | assert(std::has_single_bit(align)); 31 | return T(val & ~T(align - 1)); 32 | } 33 | 34 | // DivideUp divides a dividend by a divisor, but rounds up to the next integer 35 | template 36 | constexpr T DivideUp(T dividend, T divisor) noexcept 37 | requires std::is_integral_v 38 | { 39 | return (dividend + divisor - 1) / divisor; 40 | } 41 | 42 | } // namespace junction 43 | -------------------------------------------------------------------------------- /junction/base/compiler.h: -------------------------------------------------------------------------------- 1 | // compiler.h - compiler tricks 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace junction { 11 | 12 | constexpr bool is_debug_build() { 13 | #ifndef NDEBUG 14 | return true; 15 | #else 16 | return false; 17 | #endif 18 | } 19 | 20 | // Force the compiler to access a memory location. 21 | template 22 | T volatile &access_once(T &t) 23 | requires std::is_integral_v 24 | { 25 | return static_cast(t); 26 | } 27 | 28 | // Force the compiler to read a memory location. 29 | template 30 | T read_once(const T &p) 31 | requires std::is_integral_v 32 | { 33 | return static_cast(p); 34 | } 35 | 36 | // Force the compiler to write a memory location. 37 | template 38 | void write_once(T &p, const T &val) 39 | requires std::is_integral_v 40 | { 41 | static_cast(p) = val; 42 | } 43 | 44 | // Calculate the maximum number of elements that can be contained in an array. 45 | template 46 | constexpr size_t ArrayMaxElements() { 47 | return std::numeric_limits::max() / sizeof(T); 48 | } 49 | 50 | template 51 | constexpr bool is_most_derived(const T &x) { 52 | return (typeid(x) == typeid(NewT)); 53 | } 54 | 55 | // most_derived_cast casts to the most derived type of a base type if possible, 56 | // or returns nullptr if not. It is faster than dynamic_cast and does not use 57 | // RTTI, but only works with the most derived type (i.e., not with intermediate 58 | // types and multiple inheritance). 59 | template 60 | NewT *most_derived_cast(T *x) { 61 | if (is_most_derived(*x)) return static_cast(x); 62 | return nullptr; 63 | } 64 | 65 | namespace detail { 66 | template typename> 67 | struct is_instantiation_impl : public std::false_type {}; 68 | 69 | template