actix-rt-2.8.0/CHANGES.md000064400000000000000000000146501046102023000127660ustar 00000000000000# Changes ## Unreleased - 2022-xx-xx ## 2.8.0 - 2022-12-21 - Add `#[track_caller]` attribute to `spawn` functions and methods. [#454] - Update `tokio-uring` dependency to `0.4`. [#473] - Minimum supported Rust version (MSRV) is now 1.59. [#454]: https://github.com/actix/actix-net/pull/454 [#473]: https://github.com/actix/actix-net/pull/473 ## 2.7.0 - 2022-03-08 - Update `tokio-uring` dependency to `0.3`. [#448] - Minimum supported Rust version (MSRV) is now 1.49. [#448]: https://github.com/actix/actix-net/pull/448 ## 2.6.0 - 2022-01-12 - Update `tokio-uring` dependency to `0.2`. [#436] [#436]: https://github.com/actix/actix-net/pull/436 ## 2.5.1 - 2021-12-31 - Expose `System::with_tokio_rt` and `Arbiter::with_tokio_rt`. [#430] [#430]: https://github.com/actix/actix-net/pull/430 ## 2.5.0 - 2021-11-22 - Add `System::run_with_code` to allow retrieving the exit code on stop. [#411] [#411]: https://github.com/actix/actix-net/pull/411 ## 2.4.0 - 2021-11-05 - Add `Arbiter::try_current` for situations where thread may or may not have Arbiter context. [#408] - Start io-uring with `System::new` when feature is enabled. [#395] [#395]: https://github.com/actix/actix-net/pull/395 [#408]: https://github.com/actix/actix-net/pull/408 ## 2.3.0 - 2021-10-11 - The `spawn` method can now resolve with non-unit outputs. [#369] - Add experimental (semver-exempt) `io-uring` feature for enabling async file I/O on linux. [#374] [#369]: https://github.com/actix/actix-net/pull/369 [#374]: https://github.com/actix/actix-net/pull/374 ## 2.2.0 - 2021-03-29 - **BREAKING** `ActixStream::{poll_read_ready, poll_write_ready}` methods now return `Ready` object in ok variant. [#293] * Breakage is acceptable since `ActixStream` was not intended to be public. [#293]: https://github.com/actix/actix-net/pull/293 ## 2.1.0 - 2021-02-24 - Add `ActixStream` extension trait to include readiness methods. [#276] - Re-export `tokio::net::TcpSocket` in `net` module [#282] [#276]: https://github.com/actix/actix-net/pull/276 [#282]: https://github.com/actix/actix-net/pull/282 ## 2.0.2 - 2021-02-06 - Add `Arbiter::handle` to get a handle of an owned Arbiter. [#274] - Add `System::try_current` for situations where actix may or may not be running a System. [#275] [#274]: https://github.com/actix/actix-net/pull/274 [#275]: https://github.com/actix/actix-net/pull/275 ## 2.0.1 - 2021-02-06 - Expose `JoinError` from Tokio. [#271] [#271]: https://github.com/actix/actix-net/pull/271 ## 2.0.0 - 2021-02-02 - Remove all Arbiter-local storage methods. [#262] - Re-export `tokio::pin`. [#262] [#262]: https://github.com/actix/actix-net/pull/262 ## 2.0.0-beta.3 - 2021-01-31 - Remove `run_in_tokio`, `attach_to_tokio` and `AsyncSystemRunner`. [#253] - Return `JoinHandle` from `actix_rt::spawn`. [#253] - Remove old `Arbiter::spawn`. Implementation is now inlined into `actix_rt::spawn`. [#253] - Rename `Arbiter::{send => spawn}` and `Arbiter::{exec_fn => spawn_fn}`. [#253] - Remove `Arbiter::exec`. [#253] - Remove deprecated `Arbiter::local_join` and `Arbiter::is_running`. [#253] - `Arbiter::spawn` now accepts !Unpin futures. [#256] - `System::new` no longer takes arguments. [#257] - Remove `System::with_current`. [#257] - Remove `Builder`. [#257] - Add `System::with_init` as replacement for `Builder::run`. [#257] - Rename `System::{is_set => is_registered}`. [#257] - Add `ArbiterHandle` for sending messages to non-current-thread arbiters. [#257]. - `System::arbiter` now returns an `&ArbiterHandle`. [#257] - `Arbiter::current` now returns an `ArbiterHandle` instead. [#257] - `Arbiter::join` now takes self by value. [#257] [#253]: https://github.com/actix/actix-net/pull/253 [#254]: https://github.com/actix/actix-net/pull/254 [#256]: https://github.com/actix/actix-net/pull/256 [#257]: https://github.com/actix/actix-net/pull/257 ## 2.0.0-beta.2 - 2021-01-09 - Add `task` mod with re-export of `tokio::task::{spawn_blocking, yield_now, JoinHandle}` [#245] - Add default "macros" feature to allow faster compile times when using `default-features=false`. [#245]: https://github.com/actix/actix-net/pull/245 ## 2.0.0-beta.1 - 2020-12-28 - Add `System::attach_to_tokio` method. [#173] - Update `tokio` dependency to `1.0`. [#236] - Rename `time` module `delay_for` to `sleep`, `delay_until` to `sleep_until`, `Delay` to `Sleep` to stay aligned with Tokio's naming. [#236] - Remove `'static` lifetime requirement for `Runtime::block_on` and `SystemRunner::block_on`. * These methods now accept `&self` when calling. [#236] - Remove `'static` lifetime requirement for `System::run` and `Builder::run`. [#236] - `Arbiter::spawn` now panics when `System` is not in scope. [#207] - Fix work load issue by removing `PENDING` thread local. [#207] [#207]: https://github.com/actix/actix-net/pull/207 [#236]: https://github.com/actix/actix-net/pull/236 ## 1.1.1 - 2020-04-30 - Fix memory leak due to [#94] (see [#129] for more detail) [#129]: https://github.com/actix/actix-net/issues/129 ## 1.1.0 - 2020-04-08 _(YANKED)_ - Expose `System::is_set` to check if current system has ben started [#99] - Add `Arbiter::is_running` to check if event loop is running [#124] - Add `Arbiter::local_join` associated function to get be able to `await` for spawned futures [#94] [#94]: https://github.com/actix/actix-net/pull/94 [#99]: https://github.com/actix/actix-net/pull/99 [#124]: https://github.com/actix/actix-net/pull/124 ## 1.0.0 - 2019-12-11 - Update dependencies ## 1.0.0-alpha.3 - 2019-12-07 - Migrate to tokio 0.2 - Fix compilation on non-unix platforms ## 1.0.0-alpha.2 - 2019-12-02 - Export `main` and `test` attribute macros - Export `time` module (re-export of tokio-timer) - Export `net` module (re-export of tokio-net) ## 1.0.0-alpha.1 - 2019-11-22 - Migrate to std::future and tokio 0.2 ## 0.2.6 - 2019-11-14 - Allow to join arbiter's thread. #60 - Fix arbiter's thread panic message. ## 0.2.5 - 2019-09-02 - Add arbiter specific storage ## 0.2.4 - 2019-07-17 - Avoid a copy of the Future when initializing the Box. #29 ## 0.2.3 - 2019-06-22 - Allow to start System using existing CurrentThread Handle #22 ## 0.2.2 - 2019-03-28 - Moved `blocking` module to `actix-threadpool` crate ## 0.2.1 - 2019-03-11 - Added `blocking` module - Added `Arbiter::exec_fn` - execute fn on the arbiter's thread - Added `Arbiter::exec` - execute fn on the arbiter's thread and wait result ## 0.2.0 - 2019-03-06 - `run` method returns `io::Result<()>` - Removed `Handle` ## 0.1.0 - 2018-12-09 - Initial release actix-rt-2.8.0/Cargo.lock0000644000000211250000000000100105520ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "actix-macros" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ "quote", "syn", ] [[package]] name = "actix-rt" version = "2.8.0" dependencies = [ "actix-macros", "futures-core", "tokio", "tokio-uring", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "futures-core" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "io-uring" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41c85eff7f7c8d3ab8c7ec87313c0c194bbaf4371bb7d40f80293ba01bce8264" dependencies = [ "bitflags", "libc", ] [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "lock_api" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] [[package]] name = "mio" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi", "windows-sys", ] [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-sys", ] [[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.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "scoped-tls" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "signal-hook-registry" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] [[package]] name = "slab" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "socket2" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", ] [[package]] name = "syn" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "tokio" version = "1.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" dependencies = [ "autocfg", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "windows-sys", ] [[package]] name = "tokio-uring" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d5e02bb137e030b3a547c65a3bd2f1836d66a97369fdcc69034002b10e155ef" dependencies = [ "io-uring", "libc", "scoped-tls", "slab", "socket2", "tokio", ] [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" actix-rt-2.8.0/Cargo.toml0000644000000026700000000000100106010ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "actix-rt" version = "2.8.0" authors = [ "Nikolay Kim ", "Rob Ede ", ] description = "Tokio-based single-threaded async runtime for the Actix ecosystem" homepage = "https://actix.rs" readme = "README.md" keywords = [ "async", "futures", "io", "runtime", ] categories = [ "network-programming", "asynchronous", ] license = "MIT OR Apache-2.0" repository = "https://github.com/actix/actix-net.git" [lib] name = "actix_rt" path = "src/lib.rs" [dependencies.actix-macros] version = "0.2.3" optional = true [dependencies.futures-core] version = "0.3" default-features = false [dependencies.tokio] version = "1.18.4" features = [ "rt", "net", "parking_lot", "signal", "sync", "time", ] [features] default = ["macros"] io-uring = ["tokio-uring"] macros = ["actix-macros"] [target."cfg(target_os = \"linux\")".dependencies.tokio-uring] version = "0.4" optional = true actix-rt-2.8.0/Cargo.toml.orig0000644000000016630000000000100115410ustar [package] name = "actix-rt" version = "2.8.0" authors = [ "Nikolay Kim ", "Rob Ede ", ] description = "Tokio-based single-threaded async runtime for the Actix ecosystem" keywords = ["async", "futures", "io", "runtime"] homepage = "https://actix.rs" repository = "https://github.com/actix/actix-net.git" categories = ["network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2018" [lib] name = "actix_rt" path = "src/lib.rs" [features] default = ["macros"] macros = ["actix-macros"] io-uring = ["tokio-uring"] [dependencies] actix-macros = { version = "0.2.3", optional = true } futures-core = { version = "0.3", default-features = false } tokio = { version = "1.18.4", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] } # runtime for `io-uring` feature [target.'cfg(target_os = "linux")'.dependencies] tokio-uring = { version = "0.4", optional = true } actix-rt-2.8.0/Cargo.toml.orig000064400000000000000000000016631046102023000142630ustar 00000000000000[package] name = "actix-rt" version = "2.8.0" authors = [ "Nikolay Kim ", "Rob Ede ", ] description = "Tokio-based single-threaded async runtime for the Actix ecosystem" keywords = ["async", "futures", "io", "runtime"] homepage = "https://actix.rs" repository = "https://github.com/actix/actix-net.git" categories = ["network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2018" [lib] name = "actix_rt" path = "src/lib.rs" [features] default = ["macros"] macros = ["actix-macros"] io-uring = ["tokio-uring"] [dependencies] actix-macros = { version = "0.2.3", optional = true } futures-core = { version = "0.3", default-features = false } tokio = { version = "1.18.4", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] } # runtime for `io-uring` feature [target.'cfg(target_os = "linux")'.dependencies] tokio-uring = { version = "0.4", optional = true } actix-rt-2.8.0/LICENSE-APACHE000064400000000000000000000261201046102023000133130ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2017-NOW Actix Team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. actix-rt-2.8.0/LICENSE-MIT000064400000000000000000000020421046102023000130200ustar 00000000000000Copyright (c) 2017-NOW Actix Team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. actix-rt-2.8.0/README.md000064400000000000000000000015171046102023000126510ustar 00000000000000# actix-rt > Tokio-based single-threaded async runtime for the Actix ecosystem. [![crates.io](https://img.shields.io/crates/v/actix-rt?label=latest)](https://crates.io/crates/actix-rt) [![Documentation](https://docs.rs/actix-rt/badge.svg?version=2.8.0)](https://docs.rs/actix-rt/2.8.0) [![Version](https://img.shields.io/badge/rustc-1.46+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-rt.svg)
[![dependency status](https://deps.rs/crate/actix-rt/2.8.0/status.svg)](https://deps.rs/crate/actix-rt/2.8.0) ![Download](https://img.shields.io/crates/d/actix-rt.svg) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/WghFtEH6Hb) See crate documentation for more: https://docs.rs/actix-rt. actix-rt-2.8.0/src/arbiter.rs000064400000000000000000000241211046102023000141530ustar 00000000000000use std::{ cell::RefCell, fmt, future::Future, pin::Pin, sync::atomic::{AtomicUsize, Ordering}, task::{Context, Poll}, thread, }; use futures_core::ready; use tokio::sync::mpsc; use crate::system::{System, SystemCommand}; pub(crate) static COUNT: AtomicUsize = AtomicUsize::new(0); thread_local!( static HANDLE: RefCell> = RefCell::new(None); ); pub(crate) enum ArbiterCommand { Stop, Execute(Pin + Send>>), } impl fmt::Debug for ArbiterCommand { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ArbiterCommand::Stop => write!(f, "ArbiterCommand::Stop"), ArbiterCommand::Execute(_) => write!(f, "ArbiterCommand::Execute"), } } } /// A handle for sending spawn and stop messages to an [Arbiter]. #[derive(Debug, Clone)] pub struct ArbiterHandle { tx: mpsc::UnboundedSender, } impl ArbiterHandle { pub(crate) fn new(tx: mpsc::UnboundedSender) -> Self { Self { tx } } /// Send a future to the [Arbiter]'s thread and spawn it. /// /// If you require a result, include a response channel in the future. /// /// Returns true if future was sent successfully and false if the [Arbiter] has died. pub fn spawn(&self, future: Fut) -> bool where Fut: Future + Send + 'static, { self.tx .send(ArbiterCommand::Execute(Box::pin(future))) .is_ok() } /// Send a function to the [Arbiter]'s thread and execute it. /// /// Any result from the function is discarded. If you require a result, include a response /// channel in the function. /// /// Returns true if function was sent successfully and false if the [Arbiter] has died. pub fn spawn_fn(&self, f: F) -> bool where F: FnOnce() + Send + 'static, { self.spawn(async { f() }) } /// Instruct [Arbiter] to stop processing it's event loop. /// /// Returns true if stop message was sent successfully and false if the [Arbiter] has /// been dropped. pub fn stop(&self) -> bool { self.tx.send(ArbiterCommand::Stop).is_ok() } } /// An Arbiter represents a thread that provides an asynchronous execution environment for futures /// and functions. /// /// When an arbiter is created, it spawns a new [OS thread](thread), and hosts an event loop. #[derive(Debug)] pub struct Arbiter { tx: mpsc::UnboundedSender, thread_handle: thread::JoinHandle<()>, } impl Arbiter { /// Spawn a new Arbiter thread and start its event loop. /// /// # Panics /// Panics if a [System] is not registered on the current thread. #[cfg(not(all(target_os = "linux", feature = "io-uring")))] #[allow(clippy::new_without_default)] pub fn new() -> Arbiter { Self::with_tokio_rt(|| { crate::runtime::default_tokio_runtime() .expect("Cannot create new Arbiter's Runtime.") }) } /// Spawn a new Arbiter using the [Tokio Runtime](tokio-runtime) returned from a closure. /// /// [tokio-runtime]: tokio::runtime::Runtime #[cfg(not(all(target_os = "linux", feature = "io-uring")))] pub fn with_tokio_rt(runtime_factory: F) -> Arbiter where F: Fn() -> tokio::runtime::Runtime + Send + 'static, { let sys = System::current(); let system_id = sys.id(); let arb_id = COUNT.fetch_add(1, Ordering::Relaxed); let name = format!("actix-rt|system:{}|arbiter:{}", system_id, arb_id); let (tx, rx) = mpsc::unbounded_channel(); let (ready_tx, ready_rx) = std::sync::mpsc::channel::<()>(); let thread_handle = thread::Builder::new() .name(name.clone()) .spawn({ let tx = tx.clone(); move || { let rt = crate::runtime::Runtime::from(runtime_factory()); let hnd = ArbiterHandle::new(tx); System::set_current(sys); HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone())); // register arbiter let _ = System::current() .tx() .send(SystemCommand::RegisterArbiter(arb_id, hnd)); ready_tx.send(()).unwrap(); // run arbiter event processing loop rt.block_on(ArbiterRunner { rx }); // deregister arbiter let _ = System::current() .tx() .send(SystemCommand::DeregisterArbiter(arb_id)); } }) .unwrap_or_else(|err| { panic!("Cannot spawn Arbiter's thread: {:?}. {:?}", &name, err) }); ready_rx.recv().unwrap(); Arbiter { tx, thread_handle } } /// Spawn a new Arbiter thread and start its event loop with `tokio-uring` runtime. /// /// # Panics /// Panics if a [System] is not registered on the current thread. #[cfg(all(target_os = "linux", feature = "io-uring"))] #[allow(clippy::new_without_default)] pub fn new() -> Arbiter { let sys = System::current(); let system_id = sys.id(); let arb_id = COUNT.fetch_add(1, Ordering::Relaxed); let name = format!("actix-rt|system:{}|arbiter:{}", system_id, arb_id); let (tx, rx) = mpsc::unbounded_channel(); let (ready_tx, ready_rx) = std::sync::mpsc::channel::<()>(); let thread_handle = thread::Builder::new() .name(name.clone()) .spawn({ let tx = tx.clone(); move || { let hnd = ArbiterHandle::new(tx); System::set_current(sys); HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone())); // register arbiter let _ = System::current() .tx() .send(SystemCommand::RegisterArbiter(arb_id, hnd)); ready_tx.send(()).unwrap(); // run arbiter event processing loop tokio_uring::start(ArbiterRunner { rx }); // deregister arbiter let _ = System::current() .tx() .send(SystemCommand::DeregisterArbiter(arb_id)); } }) .unwrap_or_else(|err| { panic!("Cannot spawn Arbiter's thread: {:?}. {:?}", &name, err) }); ready_rx.recv().unwrap(); Arbiter { tx, thread_handle } } /// Sets up an Arbiter runner in a new System using the environment's local set. pub(crate) fn in_new_system() -> ArbiterHandle { let (tx, rx) = mpsc::unbounded_channel(); let hnd = ArbiterHandle::new(tx); HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone())); crate::spawn(ArbiterRunner { rx }); hnd } /// Return a handle to the this Arbiter's message sender. pub fn handle(&self) -> ArbiterHandle { ArbiterHandle::new(self.tx.clone()) } /// Return a handle to the current thread's Arbiter's message sender. /// /// # Panics /// Panics if no Arbiter is running on the current thread. pub fn current() -> ArbiterHandle { HANDLE.with(|cell| match *cell.borrow() { Some(ref hnd) => hnd.clone(), None => panic!("Arbiter is not running."), }) } /// Try to get current running arbiter handle. /// /// Returns `None` if no Arbiter has been started. /// /// Unlike [`current`](Self::current), this never panics. pub fn try_current() -> Option { HANDLE.with(|cell| cell.borrow().clone()) } /// Stop Arbiter from continuing it's event loop. /// /// Returns true if stop message was sent successfully and false if the Arbiter has been dropped. pub fn stop(&self) -> bool { self.tx.send(ArbiterCommand::Stop).is_ok() } /// Send a future to the Arbiter's thread and spawn it. /// /// If you require a result, include a response channel in the future. /// /// Returns true if future was sent successfully and false if the Arbiter has died. #[track_caller] pub fn spawn(&self, future: Fut) -> bool where Fut: Future + Send + 'static, { self.tx .send(ArbiterCommand::Execute(Box::pin(future))) .is_ok() } /// Send a function to the Arbiter's thread and execute it. /// /// Any result from the function is discarded. If you require a result, include a response /// channel in the function. /// /// Returns true if function was sent successfully and false if the Arbiter has died. #[track_caller] pub fn spawn_fn(&self, f: F) -> bool where F: FnOnce() + Send + 'static, { self.spawn(async { f() }) } /// Wait for Arbiter's event loop to complete. /// /// Joins the underlying OS thread handle. See [`JoinHandle::join`](thread::JoinHandle::join). pub fn join(self) -> thread::Result<()> { self.thread_handle.join() } } /// A persistent future that processes [Arbiter] commands. struct ArbiterRunner { rx: mpsc::UnboundedReceiver, } impl Future for ArbiterRunner { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // process all items currently buffered in channel loop { match ready!(self.rx.poll_recv(cx)) { // channel closed; no more messages can be received None => return Poll::Ready(()), // process arbiter command Some(item) => match item { ArbiterCommand::Stop => { return Poll::Ready(()); } ArbiterCommand::Execute(task_fut) => { tokio::task::spawn_local(task_fut); } }, } } } } actix-rt-2.8.0/src/lib.rs000064400000000000000000000150151046102023000132730ustar 00000000000000//! Tokio-based single-threaded async runtime for the Actix ecosystem. //! //! In most parts of the the Actix ecosystem, it has been chosen to use !Send futures. For this //! reason, a single-threaded runtime is appropriate since it is guaranteed that futures will not //! be moved between threads. This can result in small performance improvements over cases where //! atomics would otherwise be needed. //! //! To achieve similar performance to multi-threaded, work-stealing runtimes, applications //! using `actix-rt` will create multiple, mostly disconnected, single-threaded runtimes. //! This approach has good performance characteristics for workloads where the majority of tasks //! have similar runtime expense. //! //! The disadvantage is that idle threads will not steal work from very busy, stuck or otherwise //! backlogged threads. Tasks that are disproportionately expensive should be offloaded to the //! blocking task thread-pool using [`task::spawn_blocking`]. //! //! # Examples //! ```no_run //! use std::sync::mpsc; //! use actix_rt::{Arbiter, System}; //! //! let _ = System::new(); //! //! let (tx, rx) = mpsc::channel::(); //! //! let arbiter = Arbiter::new(); //! arbiter.spawn_fn(move || tx.send(42).unwrap()); //! //! let num = rx.recv().unwrap(); //! assert_eq!(num, 42); //! //! arbiter.stop(); //! arbiter.join().unwrap(); //! ``` //! //! # `io-uring` Support //! There is experimental support for using io-uring with this crate by enabling the //! `io-uring` feature. For now, it is semver exempt. //! //! Note that there are currently some unimplemented parts of using `actix-rt` with `io-uring`. //! In particular, when running a `System`, only `System::block_on` is supported. #![deny(rust_2018_idioms, nonstandard_style)] #![warn(future_incompatible, missing_docs)] #![allow(clippy::type_complexity)] #![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")] #[cfg(all(not(target_os = "linux"), feature = "io-uring"))] compile_error!("io_uring is a linux only feature."); use std::future::Future; // Cannot define a main macro when compiled into test harness. // Workaround for https://github.com/rust-lang/rust/issues/62127. #[cfg(all(feature = "macros", not(test)))] pub use actix_macros::main; #[cfg(feature = "macros")] pub use actix_macros::test; mod arbiter; mod runtime; mod system; pub use tokio::pin; use tokio::task::JoinHandle; pub use self::arbiter::{Arbiter, ArbiterHandle}; pub use self::runtime::Runtime; pub use self::system::{System, SystemRunner}; pub mod signal { //! Asynchronous signal handling (Tokio re-exports). #[cfg(unix)] pub mod unix { //! Unix specific signals (Tokio re-exports). pub use tokio::signal::unix::*; } pub use tokio::signal::ctrl_c; } pub mod net { //! TCP/UDP/Unix bindings (mostly Tokio re-exports). use std::{ future::Future, io, task::{Context, Poll}, }; pub use tokio::io::Ready; use tokio::io::{AsyncRead, AsyncWrite, Interest}; pub use tokio::net::UdpSocket; pub use tokio::net::{TcpListener, TcpSocket, TcpStream}; #[cfg(unix)] pub use tokio::net::{UnixDatagram, UnixListener, UnixStream}; /// Extension trait over async read+write types that can also signal readiness. #[doc(hidden)] pub trait ActixStream: AsyncRead + AsyncWrite + Unpin { /// Poll stream and check read readiness of Self. /// /// See [tokio::net::TcpStream::poll_read_ready] for detail on intended use. fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll>; /// Poll stream and check write readiness of Self. /// /// See [tokio::net::TcpStream::poll_write_ready] for detail on intended use. fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll>; } impl ActixStream for TcpStream { fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> { let ready = self.ready(Interest::READABLE); tokio::pin!(ready); ready.poll(cx) } fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> { let ready = self.ready(Interest::WRITABLE); tokio::pin!(ready); ready.poll(cx) } } #[cfg(unix)] impl ActixStream for UnixStream { fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> { let ready = self.ready(Interest::READABLE); tokio::pin!(ready); ready.poll(cx) } fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> { let ready = self.ready(Interest::WRITABLE); tokio::pin!(ready); ready.poll(cx) } } impl ActixStream for Box { fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll> { (**self).poll_read_ready(cx) } fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll> { (**self).poll_write_ready(cx) } } } pub mod time { //! Utilities for tracking time (Tokio re-exports). pub use tokio::time::Instant; pub use tokio::time::{interval, interval_at, Interval}; pub use tokio::time::{sleep, sleep_until, Sleep}; pub use tokio::time::{timeout, Timeout}; } pub mod task { //! Task management (Tokio re-exports). pub use tokio::task::{spawn_blocking, yield_now, JoinError, JoinHandle}; } /// Spawns a future on the current thread as a new task. /// /// If not immediately awaited, the task can be cancelled using [`JoinHandle::abort`]. /// /// The provided future is spawned as a new task; therefore, panics are caught. /// /// # Panics /// Panics if Actix system is not running. /// /// # Examples /// ``` /// # use std::time::Duration; /// # actix_rt::Runtime::new().unwrap().block_on(async { /// // task resolves successfully /// assert_eq!(actix_rt::spawn(async { 1 }).await.unwrap(), 1); /// /// // task panics /// assert!(actix_rt::spawn(async { /// panic!("panic is caught at task boundary"); /// }) /// .await /// .unwrap_err() /// .is_panic()); /// /// // task is cancelled before completion /// let handle = actix_rt::spawn(actix_rt::time::sleep(Duration::from_secs(100))); /// handle.abort(); /// assert!(handle.await.unwrap_err().is_cancelled()); /// # }); /// ``` #[track_caller] #[inline] pub fn spawn(f: Fut) -> JoinHandle where Fut: Future + 'static, Fut::Output: 'static, { tokio::task::spawn_local(f) } actix-rt-2.8.0/src/runtime.rs000064400000000000000000000055161046102023000142150ustar 00000000000000use std::{future::Future, io}; use tokio::task::{JoinHandle, LocalSet}; /// A Tokio-based runtime proxy. /// /// All spawned futures will be executed on the current thread. Therefore, there is no `Send` bound /// on submitted futures. #[derive(Debug)] pub struct Runtime { local: LocalSet, rt: tokio::runtime::Runtime, } pub(crate) fn default_tokio_runtime() -> io::Result { tokio::runtime::Builder::new_current_thread() .enable_io() .enable_time() .build() } impl Runtime { /// Returns a new runtime initialized with default configuration values. #[allow(clippy::new_ret_no_self)] pub fn new() -> io::Result { let rt = default_tokio_runtime()?; Ok(Runtime { rt, local: LocalSet::new(), }) } /// Offload a future onto the single-threaded runtime. /// /// The returned join handle can be used to await the future's result. /// /// See [crate root][crate] documentation for more details. /// /// # Examples /// ``` /// let rt = actix_rt::Runtime::new().unwrap(); /// /// // Spawn a future onto the runtime /// let handle = rt.spawn(async { /// println!("running on the runtime"); /// 42 /// }); /// /// assert_eq!(rt.block_on(handle).unwrap(), 42); /// ``` /// /// # Panics /// This function panics if the spawn fails. Failure occurs if the executor is currently at /// capacity and is unable to spawn a new future. #[track_caller] pub fn spawn(&self, future: F) -> JoinHandle where F: Future + 'static, { self.local.spawn_local(future) } /// Runs the provided future, blocking the current thread until the future completes. /// /// This function can be used to synchronously block the current thread until the provided /// `future` has resolved either successfully or with an error. The result of the future is /// then returned from this function call. /// /// Note that this function will also execute any spawned futures on the current thread, but /// will not block until these other spawned futures have completed. Once the function returns, /// any uncompleted futures remain pending in the `Runtime` instance. These futures will not run /// until `block_on` or `run` is called again. /// /// The caller is responsible for ensuring that other spawned futures complete execution by /// calling `block_on` or `run`. #[track_caller] pub fn block_on(&self, f: F) -> F::Output where F: Future, { self.local.block_on(&self.rt, f) } } impl From for Runtime { fn from(rt: tokio::runtime::Runtime) -> Self { Self { local: LocalSet::new(), rt, } } } actix-rt-2.8.0/src/system.rs000064400000000000000000000230051046102023000140470ustar 00000000000000use std::{ cell::RefCell, collections::HashMap, future::Future, io, pin::Pin, sync::atomic::{AtomicUsize, Ordering}, task::{Context, Poll}, }; use futures_core::ready; use tokio::sync::{mpsc, oneshot}; use crate::{arbiter::ArbiterHandle, Arbiter}; static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0); thread_local!( static CURRENT: RefCell> = RefCell::new(None); ); /// A manager for a per-thread distributed async runtime. #[derive(Clone, Debug)] pub struct System { id: usize, sys_tx: mpsc::UnboundedSender, /// Handle to the first [Arbiter] that is created with the System. arbiter_handle: ArbiterHandle, } #[cfg(not(feature = "io-uring"))] impl System { /// Create a new system. /// /// # Panics /// Panics if underlying Tokio runtime can not be created. #[allow(clippy::new_ret_no_self)] pub fn new() -> SystemRunner { Self::with_tokio_rt(|| { crate::runtime::default_tokio_runtime() .expect("Default Actix (Tokio) runtime could not be created.") }) } /// Create a new System using the [Tokio Runtime](tokio-runtime) returned from a closure. /// /// [tokio-runtime]: tokio::runtime::Runtime pub fn with_tokio_rt(runtime_factory: F) -> SystemRunner where F: Fn() -> tokio::runtime::Runtime, { let (stop_tx, stop_rx) = oneshot::channel(); let (sys_tx, sys_rx) = mpsc::unbounded_channel(); let rt = crate::runtime::Runtime::from(runtime_factory()); let sys_arbiter = rt.block_on(async { Arbiter::in_new_system() }); let system = System::construct(sys_tx, sys_arbiter.clone()); system .tx() .send(SystemCommand::RegisterArbiter(usize::MAX, sys_arbiter)) .unwrap(); // init background system arbiter let sys_ctrl = SystemController::new(sys_rx, stop_tx); rt.spawn(sys_ctrl); SystemRunner { rt, stop_rx } } } #[cfg(feature = "io-uring")] impl System { /// Create a new system. /// /// # Panics /// Panics if underlying Tokio runtime can not be created. #[allow(clippy::new_ret_no_self)] pub fn new() -> SystemRunner { SystemRunner } /// Create a new System using the [Tokio Runtime](tokio-runtime) returned from a closure. /// /// [tokio-runtime]: tokio::runtime::Runtime #[doc(hidden)] pub fn with_tokio_rt(_: F) -> SystemRunner where F: Fn() -> tokio::runtime::Runtime, { unimplemented!("System::with_tokio_rt is not implemented for io-uring feature yet") } } impl System { /// Constructs new system and registers it on the current thread. pub(crate) fn construct( sys_tx: mpsc::UnboundedSender, arbiter_handle: ArbiterHandle, ) -> Self { let sys = System { sys_tx, arbiter_handle, id: SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst), }; System::set_current(sys.clone()); sys } /// Get current running system. /// /// # Panics /// Panics if no system is registered on the current thread. pub fn current() -> System { CURRENT.with(|cell| match *cell.borrow() { Some(ref sys) => sys.clone(), None => panic!("System is not running"), }) } /// Try to get current running system. /// /// Returns `None` if no System has been started. /// /// Unlike [`current`](Self::current), this never panics. pub fn try_current() -> Option { CURRENT.with(|cell| cell.borrow().clone()) } /// Get handle to a the System's initial [Arbiter]. pub fn arbiter(&self) -> &ArbiterHandle { &self.arbiter_handle } /// Check if there is a System registered on the current thread. pub fn is_registered() -> bool { CURRENT.with(|sys| sys.borrow().is_some()) } /// Register given system on current thread. #[doc(hidden)] pub fn set_current(sys: System) { CURRENT.with(|cell| { *cell.borrow_mut() = Some(sys); }) } /// Numeric system identifier. /// /// Useful when using multiple Systems. pub fn id(&self) -> usize { self.id } /// Stop the system (with code 0). pub fn stop(&self) { self.stop_with_code(0) } /// Stop the system with a given exit code. pub fn stop_with_code(&self, code: i32) { let _ = self.sys_tx.send(SystemCommand::Exit(code)); } pub(crate) fn tx(&self) -> &mpsc::UnboundedSender { &self.sys_tx } } /// Runner that keeps a [System]'s event loop alive until stop message is received. #[cfg(not(feature = "io-uring"))] #[must_use = "A SystemRunner does nothing unless `run` is called."] #[derive(Debug)] pub struct SystemRunner { rt: crate::runtime::Runtime, stop_rx: oneshot::Receiver, } #[cfg(not(feature = "io-uring"))] impl SystemRunner { /// Starts event loop and will return once [System] is [stopped](System::stop). pub fn run(self) -> io::Result<()> { let exit_code = self.run_with_code()?; match exit_code { 0 => Ok(()), nonzero => Err(io::Error::new( io::ErrorKind::Other, format!("Non-zero exit code: {}", nonzero), )), } } /// Runs the event loop until [stopped](System::stop_with_code), returning the exit code. pub fn run_with_code(self) -> io::Result { let SystemRunner { rt, stop_rx, .. } = self; // run loop rt.block_on(stop_rx) .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) } /// Runs the provided future, blocking the current thread until the future completes. #[track_caller] #[inline] pub fn block_on(&self, fut: F) -> F::Output { self.rt.block_on(fut) } } /// Runner that keeps a [System]'s event loop alive until stop message is received. #[cfg(feature = "io-uring")] #[must_use = "A SystemRunner does nothing unless `run` is called."] #[derive(Debug)] pub struct SystemRunner; #[cfg(feature = "io-uring")] impl SystemRunner { /// Starts event loop and will return once [System] is [stopped](System::stop). pub fn run(self) -> io::Result<()> { unimplemented!("SystemRunner::run is not implemented for io-uring feature yet"); } /// Runs the event loop until [stopped](System::stop_with_code), returning the exit code. pub fn run_with_code(self) -> io::Result { unimplemented!( "SystemRunner::run_with_code is not implemented for io-uring feature yet" ); } /// Runs the provided future, blocking the current thread until the future completes. #[inline] pub fn block_on(&self, fut: F) -> F::Output { tokio_uring::start(async move { let (stop_tx, stop_rx) = oneshot::channel(); let (sys_tx, sys_rx) = mpsc::unbounded_channel(); let sys_arbiter = Arbiter::in_new_system(); let system = System::construct(sys_tx, sys_arbiter.clone()); system .tx() .send(SystemCommand::RegisterArbiter(usize::MAX, sys_arbiter)) .unwrap(); // init background system arbiter let sys_ctrl = SystemController::new(sys_rx, stop_tx); tokio_uring::spawn(sys_ctrl); let res = fut.await; drop(stop_rx); res }) } } #[derive(Debug)] pub(crate) enum SystemCommand { Exit(i32), RegisterArbiter(usize, ArbiterHandle), DeregisterArbiter(usize), } /// There is one `SystemController` per [System]. It runs in the background, keeping track of /// [Arbiter]s and is able to distribute a system-wide stop command. #[derive(Debug)] pub(crate) struct SystemController { stop_tx: Option>, cmd_rx: mpsc::UnboundedReceiver, arbiters: HashMap, } impl SystemController { pub(crate) fn new( cmd_rx: mpsc::UnboundedReceiver, stop_tx: oneshot::Sender, ) -> Self { SystemController { cmd_rx, stop_tx: Some(stop_tx), arbiters: HashMap::with_capacity(4), } } } impl Future for SystemController { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // process all items currently buffered in channel loop { match ready!(self.cmd_rx.poll_recv(cx)) { // channel closed; no more messages can be received None => return Poll::Ready(()), // process system command Some(cmd) => match cmd { SystemCommand::Exit(code) => { // stop all arbiters for arb in self.arbiters.values() { arb.stop(); } // stop event loop // will only fire once if let Some(stop_tx) = self.stop_tx.take() { let _ = stop_tx.send(code); } } SystemCommand::RegisterArbiter(id, arb) => { self.arbiters.insert(id, arb); } SystemCommand::DeregisterArbiter(id) => { self.arbiters.remove(&id); } }, } } } } actix-rt-2.8.0/tests/test-macro-import-conflict.rs000064400000000000000000000011731046102023000202650ustar 00000000000000//! Checks that test macro does not cause problems in the presence of imports named "test" that //! could be either a module with test items or the "test with runtime" macro itself. //! //! Before actix/actix-net#399 was implemented, this macro was running twice. The first run output //! `#[test]` and it got run again and since it was in scope. //! //! Prevented by using the fully-qualified test marker (`#[::core::prelude::v1::test]`). #![cfg(feature = "macros")] use actix_rt::time as test; #[actix_rt::test] async fn test_naming_conflict() { use test as time; time::sleep(std::time::Duration::from_millis(2)).await; } actix-rt-2.8.0/tests/tests.rs000064400000000000000000000221041046102023000142370ustar 00000000000000use std::{ future::Future, time::{Duration, Instant}, }; use actix_rt::{task::JoinError, Arbiter, System}; #[cfg(not(feature = "io-uring"))] use { std::{sync::mpsc::channel, thread}, tokio::sync::oneshot, }; #[test] fn await_for_timer() { let time = Duration::from_secs(1); let instant = Instant::now(); System::new().block_on(async move { tokio::time::sleep(time).await; }); assert!( instant.elapsed() >= time, "Block on should poll awaited future to completion" ); } #[cfg(not(feature = "io-uring"))] #[test] fn run_with_code() { let sys = System::new(); System::current().stop_with_code(42); let exit_code = sys.run_with_code().expect("system stop should not error"); assert_eq!(exit_code, 42); } #[test] fn join_another_arbiter() { let time = Duration::from_secs(1); let instant = Instant::now(); System::new().block_on(async move { let arbiter = Arbiter::new(); arbiter.spawn(Box::pin(async move { tokio::time::sleep(time).await; Arbiter::current().stop(); })); arbiter.join().unwrap(); }); assert!( instant.elapsed() >= time, "Join on another arbiter should complete only when it calls stop" ); let instant = Instant::now(); System::new().block_on(async move { let arbiter = Arbiter::new(); arbiter.spawn_fn(move || { actix_rt::spawn(async move { tokio::time::sleep(time).await; Arbiter::current().stop(); }); }); arbiter.join().unwrap(); }); assert!( instant.elapsed() >= time, "Join on an arbiter that has used actix_rt::spawn should wait for said future" ); let instant = Instant::now(); System::new().block_on(async move { let arbiter = Arbiter::new(); arbiter.spawn(Box::pin(async move { tokio::time::sleep(time).await; Arbiter::current().stop(); })); arbiter.stop(); arbiter.join().unwrap(); }); assert!( instant.elapsed() < time, "Premature stop of arbiter should conclude regardless of it's current state" ); } #[test] fn non_static_block_on() { let string = String::from("test_str"); let string = string.as_str(); let sys = System::new(); sys.block_on(async { actix_rt::time::sleep(Duration::from_millis(1)).await; assert_eq!("test_str", string); }); let rt = actix_rt::Runtime::new().unwrap(); rt.block_on(async { actix_rt::time::sleep(Duration::from_millis(1)).await; assert_eq!("test_str", string); }); } #[test] fn wait_for_spawns() { let rt = actix_rt::Runtime::new().unwrap(); let handle = rt.spawn(async { println!("running on the runtime"); // panic is caught at task boundary panic!("intentional test panic"); }); assert!(rt.block_on(handle).is_err()); } // Temporary disabled tests for io-uring feature. // They should be enabled when possible. #[cfg(not(feature = "io-uring"))] #[test] fn arbiter_spawn_fn_runs() { let _ = System::new(); let (tx, rx) = channel::(); let arbiter = Arbiter::new(); arbiter.spawn_fn(move || tx.send(42).unwrap()); let num = rx.recv().unwrap(); assert_eq!(num, 42); arbiter.stop(); arbiter.join().unwrap(); } #[cfg(not(feature = "io-uring"))] #[test] fn arbiter_handle_spawn_fn_runs() { let sys = System::new(); let (tx, rx) = channel::(); let arbiter = Arbiter::new(); let handle = arbiter.handle(); drop(arbiter); handle.spawn_fn(move || { tx.send(42).unwrap(); System::current().stop() }); let num = rx.recv_timeout(Duration::from_secs(2)).unwrap(); assert_eq!(num, 42); handle.stop(); sys.run().unwrap(); } #[cfg(not(feature = "io-uring"))] #[test] fn arbiter_drop_no_panic_fn() { let _ = System::new(); let arbiter = Arbiter::new(); arbiter.spawn_fn(|| panic!("test")); arbiter.stop(); arbiter.join().unwrap(); } #[cfg(not(feature = "io-uring"))] #[test] fn arbiter_drop_no_panic_fut() { let _ = System::new(); let arbiter = Arbiter::new(); arbiter.spawn(async { panic!("test") }); arbiter.stop(); arbiter.join().unwrap(); } #[cfg(not(feature = "io-uring"))] #[test] fn system_arbiter_spawn() { let runner = System::new(); let (tx, rx) = oneshot::channel(); let sys = System::current(); thread::spawn(|| { // this thread will have no arbiter in it's thread local so call will panic Arbiter::current(); }) .join() .unwrap_err(); let thread = thread::spawn(|| { // this thread will have no arbiter in it's thread local so use the system handle instead System::set_current(sys); let sys = System::current(); let arb = sys.arbiter(); arb.spawn(async move { tx.send(42u32).unwrap(); System::current().stop(); }); }); assert_eq!(runner.block_on(rx).unwrap(), 42); thread.join().unwrap(); } #[cfg(not(feature = "io-uring"))] #[test] fn system_stop_stops_arbiters() { let sys = System::new(); let arb = Arbiter::new(); // arbiter should be alive to receive spawn msg assert!(Arbiter::current().spawn_fn(|| {})); assert!(arb.spawn_fn(|| {})); System::current().stop(); sys.run().unwrap(); // account for slightly slow thread de-spawns thread::sleep(Duration::from_millis(500)); // arbiter should be dead and return false assert!(!Arbiter::current().spawn_fn(|| {})); assert!(!arb.spawn_fn(|| {})); arb.join().unwrap(); } #[cfg(not(feature = "io-uring"))] #[test] fn new_system_with_tokio() { let (tx, rx) = channel(); let res = System::with_tokio_rt(move || { tokio::runtime::Builder::new_multi_thread() .enable_io() .enable_time() .thread_keep_alive(Duration::from_millis(1000)) .worker_threads(2) .max_blocking_threads(2) .on_thread_start(|| {}) .on_thread_stop(|| {}) .build() .unwrap() }) .block_on(async { actix_rt::time::sleep(Duration::from_millis(1)).await; tokio::task::spawn(async move { tx.send(42).unwrap(); }) .await .unwrap(); 123usize }); assert_eq!(res, 123); assert_eq!(rx.recv().unwrap(), 42); } #[cfg(not(feature = "io-uring"))] #[test] fn new_arbiter_with_tokio() { use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, }; let _ = System::new(); let arb = Arbiter::with_tokio_rt(|| { tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap() }); let counter = Arc::new(AtomicBool::new(true)); let counter1 = counter.clone(); let did_spawn = arb.spawn(async move { actix_rt::time::sleep(Duration::from_millis(1)).await; counter1.store(false, Ordering::SeqCst); Arbiter::current().stop(); }); assert!(did_spawn); arb.join().unwrap(); assert!(!counter.load(Ordering::SeqCst)); } #[test] #[should_panic] fn no_system_current_panic() { System::current(); } #[test] #[should_panic] fn no_system_arbiter_new_panic() { Arbiter::new(); } #[test] fn try_current_no_system() { assert!(System::try_current().is_none()) } #[test] fn try_current_with_system() { System::new().block_on(async { assert!(System::try_current().is_some()) }); } #[allow(clippy::unit_cmp)] #[test] fn spawn_local() { System::new().block_on(async { // demonstrate that spawn -> R is strictly more capable than spawn -> () assert_eq!(actix_rt::spawn(async {}).await.unwrap(), ()); assert_eq!(actix_rt::spawn(async { 1 }).await.unwrap(), 1); assert!(actix_rt::spawn(async { panic!("") }).await.is_err()); actix_rt::spawn(async { tokio::time::sleep(Duration::from_millis(50)).await }) .await .unwrap(); fn g>>(_f: F) {} g(actix_rt::spawn(async {})); // g(actix_rt::spawn(async { 1 })); // compile err fn h>, R>(_f: F) {} h(actix_rt::spawn(async {})); h(actix_rt::spawn(async { 1 })); }) } #[cfg(all(target_os = "linux", feature = "io-uring"))] #[test] fn tokio_uring_arbiter() { System::new().block_on(async { let (tx, rx) = std::sync::mpsc::channel(); Arbiter::new().spawn(async move { let handle = actix_rt::spawn(async move { let f = tokio_uring::fs::File::create("test.txt").await.unwrap(); let buf = b"Hello World!"; let (res, _) = f.write_at(&buf[..], 0).await; assert!(res.is_ok()); f.sync_all().await.unwrap(); f.close().await.unwrap(); std::fs::remove_file("test.txt").unwrap(); }); handle.await.unwrap(); tx.send(true).unwrap(); }); assert!(rx.recv().unwrap()); }) }