diff --git a/Cargo.lock b/Cargo.lock index 88c61c19de3940..a27257bbad0879 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,11 +103,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9021768bcce77296b64648cc7a7460e3df99979b97ed5c925c38d1cc83778d98" dependencies = [ "brotli", - "bytes", + "bytes 0.5.6", "flate2", "futures-core", "memchr", - "pin-project-lite", + "pin-project-lite 0.1.7", ] [[package]] @@ -242,6 +242,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +[[package]] +name = "bytes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16" + [[package]] name = "cargo_gn" version = "0.0.15" @@ -260,6 +266,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" version = "0.4.15" @@ -295,6 +307,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cloudabi" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" +dependencies = [ + "bitflags", +] + [[package]] name = "const-random" version = "0.1.8" @@ -336,7 +357,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -356,7 +377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg 1.0.1", - "cfg-if", + "cfg-if 0.1.10", "lazy_static", ] @@ -402,7 +423,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f260e2fc850179ef410018660006951c1b55b79e8087e87111a2c388994b9b5" dependencies = [ "ahash", - "cfg-if", + "cfg-if 0.1.10", "num_cpus", ] @@ -413,7 +434,7 @@ dependencies = [ "atty", "base64 0.12.3", "byteorder", - "bytes", + "bytes 0.5.6", "chrono", "clap", "deno_core", @@ -453,7 +474,7 @@ dependencies = [ "tempfile", "termcolor", "test_util", - "tokio", + "tokio 0.2.22", "tokio-rustls", "tokio-tungstenite", "uuid", @@ -479,7 +500,7 @@ dependencies = [ "serde", "serde_json", "smallvec", - "tokio", + "tokio 0.3.4", "url", ] @@ -640,7 +661,7 @@ version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a51b8cf747471cb9499b6d59e59b0444f4c90eba8968c4e44874e92b5b64ace2" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -691,7 +712,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi 0.3.9", @@ -709,7 +730,7 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crc32fast", "libc", "miniz_oxide", @@ -913,7 +934,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -924,7 +945,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "futures-sink", @@ -932,7 +953,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio", + "tokio 0.2.22", "tokio-util", "tracing", ] @@ -951,7 +972,7 @@ checksum = "ed18eb2459bf1a09ad2d6b1547840c3e5e62882fa09b9a6a20b1de8e3228848f" dependencies = [ "base64 0.12.3", "bitflags", - "bytes", + "bytes 0.5.6", "headers-core", "http", "mime", @@ -983,7 +1004,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "itoa", ] @@ -994,7 +1015,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" dependencies = [ - "bytes", + "bytes 0.5.6", "http", ] @@ -1019,7 +1040,7 @@ version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-channel", "futures-core", "futures-util", @@ -1031,7 +1052,7 @@ dependencies = [ "pin-project 0.4.23", "socket2", "time", - "tokio", + "tokio 0.2.22", "tower-service", "tracing", "want", @@ -1043,12 +1064,12 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37743cc83e8ee85eacfce90f2f4102030d9ff0a95244098d781e9bee4a90abb6" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-util", "hyper", "log", "rustls", - "tokio", + "tokio 0.2.22", "tokio-rustls", "webpki", ] @@ -1112,7 +1133,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" dependencies = [ - "bytes", + "bytes 0.5.6", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] @@ -1206,7 +1236,7 @@ checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" dependencies = [ "arrayvec", "bitflags", - "cfg-if", + "cfg-if 0.1.10", "ryu", "static_assertions", ] @@ -1217,13 +1247,22 @@ version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -1276,7 +1315,7 @@ version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", @@ -1289,6 +1328,19 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f33bc887064ef1fd66020c9adfc45bb9f33d75a42096c81e7c56c65b75dd1a8b" +dependencies = [ + "libc", + "log", + "miow 0.3.6", + "ntapi", + "winapi 0.3.9", +] + [[package]] name = "mio-extras" version = "2.0.6" @@ -1297,7 +1349,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ "lazycell", "log", - "mio", + "mio 0.6.22", "slab", ] @@ -1308,8 +1360,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656" dependencies = [ "log", - "mio", - "miow 0.3.5", + "mio 0.6.22", + "miow 0.3.6", "winapi 0.3.9", ] @@ -1321,7 +1373,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio", + "mio 0.6.22", ] [[package]] @@ -1338,9 +1390,9 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2", "winapi 0.3.9", @@ -1370,7 +1422,7 @@ version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "winapi 0.3.9", ] @@ -1389,7 +1441,7 @@ checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" dependencies = [ "bitflags", "cc", - "cfg-if", + "cfg-if 0.1.10", "libc", ] @@ -1418,12 +1470,21 @@ dependencies = [ "fsevent-sys", "inotify", "libc", - "mio", + "mio 0.6.22", "mio-extras", "walkdir", "winapi 0.3.9", ] +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "num-bigint" version = "0.2.6" @@ -1511,6 +1572,32 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" +dependencies = [ + "cfg-if 0.1.10", + "cloudabi 0.1.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.9", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1617,6 +1704,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" +[[package]] +name = "pin-project-lite" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" + [[package]] name = "pin-utils" version = "0.1.0" @@ -1837,7 +1930,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi", + "cloudabi 0.0.3", "fuchsia-cprng", "libc", "rand_core 0.4.2", @@ -1929,7 +2022,7 @@ checksum = "e9eaa17ac5d7b838b7503d118fa16ad88f440498bf9ffe5424e621f93190d61e" dependencies = [ "async-compression", "base64 0.12.3", - "bytes", + "bytes 0.5.6", "encoding_rs", "futures-core", "futures-util", @@ -1944,11 +2037,11 @@ dependencies = [ "mime", "mime_guess", "percent-encoding", - "pin-project-lite", + "pin-project-lite 0.1.7", "rustls", "serde", "serde_urlencoded", - "tokio", + "tokio 0.2.22", "tokio-rustls", "url", "wasm-bindgen", @@ -2020,7 +2113,7 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "log", "memchr", @@ -2169,7 +2262,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 0.1.10", "cpuid-bool", "digest 0.9.0", "opaque-debug 0.3.0", @@ -2211,11 +2304,11 @@ checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" [[package]] name = "socket2" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" +checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "winapi 0.3.9", @@ -2348,7 +2441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd78e25ecc138a4667f5e5ea4d1a1c35d424477882b549d4fc011062eecd50e" dependencies = [ "ast_node", - "cfg-if", + "cfg-if 0.1.10", "either", "from_variant", "fxhash", @@ -2616,7 +2709,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand 0.7.3", "redox_syscall", @@ -2646,14 +2739,14 @@ dependencies = [ name = "test_util" version = "0.1.0" dependencies = [ - "bytes", + "bytes 0.5.6", "futures", "lazy_static", "os_pipe", "pty", "regex", "tempfile", - "tokio", + "tokio 0.2.22", "warp", ] @@ -2718,21 +2811,43 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd" dependencies = [ - "bytes", + "bytes 0.5.6", "fnv", "futures-core", "iovec", "lazy_static", "libc", "memchr", - "mio", + "mio 0.6.22", "mio-named-pipes", "mio-uds", "num_cpus", - "pin-project-lite", + "pin-project-lite 0.1.7", + "signal-hook-registry", + "slab", + "tokio-macros 0.2.5", + "winapi 0.3.9", +] + +[[package]] +name = "tokio" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfe2523e6fa84ddf5e688151d4e5fddc51678de9752c6512a24714c23818d61" +dependencies = [ + "autocfg 1.0.1", + "bytes 0.6.0", + "futures-core", + "lazy_static", + "libc", + "memchr", + "mio 0.7.6", + "num_cpus", + "parking_lot", + "pin-project-lite 0.2.0", "signal-hook-registry", "slab", - "tokio-macros", + "tokio-macros 0.3.1", "winapi 0.3.9", ] @@ -2747,6 +2862,17 @@ dependencies = [ "syn 1.0.48", ] +[[package]] +name = "tokio-macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d30fdbb5dc2d8f91049691aa1a9d4d4ae422a21c334ce8936e5886d30c5c45" +dependencies = [ + "proc-macro2 1.0.24", + "quote 1.0.7", + "syn 1.0.48", +] + [[package]] name = "tokio-rustls" version = "0.14.1" @@ -2755,7 +2881,7 @@ checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" dependencies = [ "futures-core", "rustls", - "tokio", + "tokio 0.2.22", "webpki", ] @@ -2768,7 +2894,7 @@ dependencies = [ "futures-util", "log", "pin-project 0.4.23", - "tokio", + "tokio 0.2.22", "tungstenite", ] @@ -2778,12 +2904,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" dependencies = [ - "bytes", + "bytes 0.5.6", "futures-core", "futures-sink", "log", - "pin-project-lite", - "tokio", + "pin-project-lite 0.1.7", + "tokio 0.2.22", ] [[package]] @@ -2807,7 +2933,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "log", "tracing-core", ] @@ -2845,7 +2971,7 @@ checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23" dependencies = [ "base64 0.12.3", "byteorder", - "bytes", + "bytes 0.5.6", "http", "httparse", "input_buffer", @@ -3006,7 +3132,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f41be6df54c97904af01aa23e613d4521eed7ab23537cede692d4058f6449407" dependencies = [ - "bytes", + "bytes 0.5.6", "futures", "headers", "http", @@ -3020,7 +3146,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "tokio", + "tokio 0.2.22", "tokio-rustls", "tokio-tungstenite", "tower-service", @@ -3047,7 +3173,7 @@ version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "serde", "serde_json", "wasm-bindgen-macro", @@ -3074,7 +3200,7 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "js-sys", "wasm-bindgen", "web-sys", diff --git a/core/Cargo.toml b/core/Cargo.toml index 84a14f73d1170e..ed1f71c75d493e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,7 +14,7 @@ path = "lib.rs" [dependencies] anyhow = "1.0.32" -futures = "0.3.5" +futures = "0.3.8" indexmap = "1.6.0" lazy_static = "1.4.0" libc = "0.2.77" @@ -35,4 +35,4 @@ path = "examples/http_bench_json_ops.rs" # These dependendencies are only used for the 'http_bench_*_ops' examples. [dev-dependencies] -tokio = { version = "0.2.22", features = ["full"] } +tokio = { version = "0.3.4", features = ["full"] } diff --git a/core/async_cell.rs b/core/async_cell.rs new file mode 100644 index 00000000000000..a140dceb19ffb8 --- /dev/null +++ b/core/async_cell.rs @@ -0,0 +1,713 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use std::any::Any; +use std::borrow::Borrow; +use std::cell::Cell; +use std::cell::UnsafeCell; +use std::collections::VecDeque; +use std::ops::Deref; +use std::rc::Rc; + +use self::internal as i; + +pub type AsyncRef = i::AsyncBorrowImpl; +pub type AsyncMut = i::AsyncBorrowImpl; + +pub type AsyncRefFuture = i::AsyncBorrowFutureImpl; +pub type AsyncMutFuture = i::AsyncBorrowFutureImpl; + +pub struct AsyncRefCell { + value: UnsafeCell, + borrow_count: Cell, + waiters: Cell>>, + turn: Cell, +} + +impl AsyncRefCell { + /// Create a new `AsyncRefCell` that encapsulates the specified value. + /// Note that in order to borrow the inner value, the `AsyncRefCell` + /// needs to be wrapped in an `Rc` or an `RcRef`. These can be created + /// either manually, or by using the convenience method + /// `AsyncRefCell::new_rc()`. + pub fn new(value: T) -> Self { + Self { + value: UnsafeCell::new(value), + borrow_count: Default::default(), + waiters: Default::default(), + turn: Default::default(), + } + } + + pub fn new_rc(value: T) -> Rc { + Rc::new(Self::new(value)) + } + + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } +} + +impl Default for AsyncRefCell { + fn default() -> Self { + Self::new(Default::default()) + } +} + +impl AsyncRefCell { + pub fn default_rc() -> Rc { + Rc::new(Default::default()) + } +} + +impl From for AsyncRefCell { + fn from(value: T) -> Self { + Self::new(value) + } +} + +impl AsyncRefCell { + pub fn borrow(self: &Rc) -> AsyncRefFuture { + AsyncRefFuture::new(self) + } + + pub fn borrow_mut(self: &Rc) -> AsyncMutFuture { + AsyncMutFuture::new(self) + } + + pub fn try_borrow(self: &Rc) -> Option> { + Self::borrow_sync(self) + } + + pub fn try_borrow_mut(self: &Rc) -> Option> { + Self::borrow_sync(self) + } +} + +impl RcRef> { + pub fn borrow(&self) -> AsyncRefFuture { + AsyncRefFuture::new(self) + } + + pub fn borrow_mut(&self) -> AsyncMutFuture { + AsyncMutFuture::new(self) + } + + pub fn try_borrow(&self) -> Option> { + AsyncRefCell::::borrow_sync(self) + } + + pub fn try_borrow_mut(&self) -> Option> { + AsyncRefCell::::borrow_sync(self) + } +} + +/// An `RcRef` encapsulates a reference counted pointer, just like a regular +/// `std::rc::Rc`. However, unlike a regular `Rc`, it can be remapped so that +/// it dereferences to any value that's reachable through the reference-counted +/// pointer. This is achieved through the associated method, `RcRef::map()`, +/// similar to how `std::cell::Ref::map()` works. Example: +/// +/// ```rust +/// # use std::rc::Rc; +/// # use deno_core::async_cell::RcRef; +/// +/// struct Stuff { +/// foo: u32, +/// bar: String, +/// } +/// +/// let stuff_rc = Rc::new(Stuff { +/// foo: 42, +/// bar: "hello".to_owned(), +/// }); +/// +/// // `foo_rc` and `bar_rc` dereference to different types, however +/// // they share a reference count. +/// let foo_rc: RcRef = RcRef::map(stuff_rc.clone(), |v| &v.foo); +/// let bar_rc: RcRef = RcRef::map(stuff_rc, |v| &v.bar); +/// ``` +pub struct RcRef { + rc: Rc, + value: *const T, +} + +impl RcRef { + pub fn new(value: T) -> Self { + Self::from(Rc::new(value)) + } + + pub fn map, F: FnOnce(&S) -> &T>( + source: R, + map_fn: F, + ) -> RcRef { + let RcRef:: { rc, value } = source.into(); + let value = map_fn(unsafe { &*value }); + RcRef { rc, value } + } +} + +impl Default for RcRef { + fn default() -> Self { + Self::new(Default::default()) + } +} + +impl From> for RcRef { + fn from(rc: Rc) -> Self { + Self { + value: &*rc, + rc: rc as Rc<_>, + } + } +} + +impl Clone for RcRef { + fn clone(&self) -> Self { + Self { + rc: self.rc.clone(), + value: self.value, + } + } +} + +impl Deref for RcRef { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { &*self.value } + } +} + +impl Borrow for RcRef { + fn borrow(&self) -> &T { + &**self + } +} + +impl AsRef for RcRef { + fn as_ref(&self) -> &T { + &**self + } +} + +mod internal { + use super::AsyncRefCell; + use super::RcRef; + use futures::future::Future; + use futures::ready; + use futures::task::Context; + use futures::task::Poll; + use futures::task::Waker; + use std::borrow::Borrow; + use std::borrow::BorrowMut; + use std::fmt::Debug; + use std::marker::PhantomData; + use std::ops::Deref; + use std::ops::DerefMut; + use std::pin::Pin; + use std::rc::Rc; + + impl AsyncRefCell { + /// Borrow the cell's contents synchronouslym without creating an + /// intermediate future. If the cell has already been borrowed and either + /// the existing or the requested borrow is exclusive, this function returns + /// `None`. + pub(super) fn borrow_sync< + M: BorrowModeTrait, + R: RcLike>, + >( + cell: &R, + ) -> Option> { + // Don't allow synchronous borrows to cut in line; if there are any + // enqueued waiters, return `None`, even if the current borrow is a shared + // one and the requested borrow is too. + let waiters = unsafe { &mut *cell.waiters.as_ptr() }; + if waiters.is_empty() { + // There are no enqueued waiters, but it is still possible that the cell + // is currently borrowed. If there are no current borrows, or both the + // existing and requested ones are shared, `try_add()` returns the + // adjusted borrow count. + let new_borrow_count = + cell.borrow_count.get().try_add(M::borrow_mode())?; + cell.borrow_count.set(new_borrow_count); + Some(AsyncBorrowImpl::::new(cell.clone().into())) + } else { + None + } + } + + fn drop_borrow(&self) { + let new_borrow_count = self.borrow_count.get().remove(M::borrow_mode()); + self.borrow_count.set(new_borrow_count); + + if new_borrow_count.is_empty() { + self.wake_waiters() + } + } + + fn create_waiter(&self) -> usize { + let waiter = Waiter::new(M::borrow_mode()); + let turn = self.turn.get(); + let index = { + let waiters = unsafe { &mut *self.waiters.as_ptr() }; + waiters.push_back(Some(waiter)); + waiters.len() - 1 + }; + if index == 0 { + // SAFETY: the `waiters` reference used above *must* be dropped here. + self.wake_waiters() + } + // Return the new waiter's id. + turn + index + } + + fn poll_waiter( + &self, + id: usize, + cx: &mut Context, + ) -> Poll<()> { + let borrow_count = self.borrow_count.get(); + let turn = self.turn.get(); + if id < turn { + // This waiter made it to the front of the line; we reserved a borrow + // for it, woke its Waker, and removed the waiter from the queue. + // Assertion: BorrowCount::remove() will panic if `mode` is incorrect. + let _ = borrow_count.remove(M::borrow_mode()); + Poll::Ready(()) + } else { + // This waiter is still in line and has not yet been woken. + let waiters = unsafe { &mut *self.waiters.as_ptr() }; + // Sanity check: id cannot be higher than the last queue element. + assert!(id < turn + waiters.len()); + // Sanity check: since we always call wake_waiters() when the queue head + // is updated, it should be impossible to add it to the current borrow. + assert!(id > turn || borrow_count.try_add(M::borrow_mode()).is_none()); + // Save or update the waiter's Waker. + // TODO(piscisaureus): Use will_wake() to make this more efficient. + let waiter_mut = waiters[id - turn].as_mut().unwrap(); + waiter_mut.set_waker(cx.waker().clone()); + Poll::Pending + } + } + + fn wake_waiters(&self) { + let mut borrow_count = self.borrow_count.get(); + let waiters = unsafe { &mut *self.waiters.as_ptr() }; + let mut turn = self.turn.get(); + + loop { + let waiter_entry = match waiters.front().map(Option::as_ref) { + None => break, // Queue empty. + Some(w) => w, + }; + let borrow_mode = match waiter_entry { + None => { + // Queue contains a hole. This happens when a Waiter is dropped + // before it makes it to the front of the queue. + waiters.pop_front(); + turn += 1; + continue; + } + Some(waiter) => waiter.borrow_mode(), + }; + // See if the waiter at the front of the queue can borrow the cell's + // value now. If it does, `try_add()` returns the new borrow count, + // effectively "reserving" the borrow until the associated + // AsyncBorrowFutureImpl future gets polled and produces the actual + // borrow. + borrow_count = match borrow_count.try_add(borrow_mode) { + None => break, // Can't borrow yet. + Some(b) => b, + }; + // Drop from queue. + let mut waiter = waiters.pop_front().unwrap().unwrap(); + turn += 1; + // Wake this waiter, so the AsyncBorrowFutureImpl future gets polled. + if let Some(waker) = waiter.take_waker() { + waker.wake() + } + } + // Save updated counters. + self.borrow_count.set(borrow_count); + self.turn.set(turn); + } + + fn drop_waiter(&self, id: usize) { + let turn = self.turn.get(); + if id < turn { + // We already made a borrow count reservation for this waiter but the + // borrow will never be picked up and removesequently, never dropped. + // Therefore, call the borrow drop handler here. + self.drop_borrow::(); + } else { + // This waiter is still in the queue, take it out and leave a "hole". + let waiters = unsafe { &mut *self.waiters.as_ptr() }; + waiters[id - turn].take().unwrap(); + } + + if id == turn { + // Since the first entry in the waiter queue was touched we have to + // reprocess the waiter queue. + self.wake_waiters() + } + } + } + + pub struct AsyncBorrowFutureImpl { + cell: Option>>, + id: usize, + _phantom: PhantomData, + } + + impl AsyncBorrowFutureImpl { + pub fn new>>(cell: &R) -> Self { + Self { + cell: Some(cell.clone().into()), + id: cell.create_waiter::(), + _phantom: PhantomData, + } + } + } + + impl Future for AsyncBorrowFutureImpl { + type Output = AsyncBorrowImpl; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + ready!(self.cell.as_ref().unwrap().poll_waiter::(self.id, cx)); + let self_mut = unsafe { Pin::get_unchecked_mut(self) }; + let cell = self_mut.cell.take().unwrap(); + Poll::Ready(AsyncBorrowImpl::::new(cell)) + } + } + + impl Drop for AsyncBorrowFutureImpl { + fn drop(&mut self) { + // The expected mode of operation is that this future gets polled until it + // is ready and yields a value of type `AsyncBorrowImpl`, which has a drop + // handler that adjusts the `AsyncRefCell` borrow counter. However if the + // `cell` field still holds a value at this point, it means that the + // future was never polled to completion and no `AsyncBorrowImpl` was ever + // created, so we have to adjust the borrow count here. + if let Some(cell) = self.cell.take() { + cell.drop_waiter::(self.id) + } + } + } + + pub struct AsyncBorrowImpl { + cell: RcRef>, + _phantom: PhantomData, + } + + impl AsyncBorrowImpl { + fn new(cell: RcRef>) -> Self { + Self { + cell, + _phantom: PhantomData, + } + } + } + + impl Deref for AsyncBorrowImpl { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { &*self.cell.as_ptr() } + } + } + + impl Borrow for AsyncBorrowImpl { + fn borrow(&self) -> &T { + &**self + } + } + + impl AsRef for AsyncBorrowImpl { + fn as_ref(&self) -> &T { + &**self + } + } + + impl DerefMut for AsyncBorrowImpl { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.cell.as_ptr() } + } + } + + impl BorrowMut for AsyncBorrowImpl { + fn borrow_mut(&mut self) -> &mut T { + &mut **self + } + } + + impl AsMut for AsyncBorrowImpl { + fn as_mut(&mut self) -> &mut T { + &mut **self + } + } + + impl Drop for AsyncBorrowImpl { + fn drop(&mut self) { + self.cell.drop_borrow::() + } + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum BorrowMode { + Shared, + Exclusive, + } + + pub trait BorrowModeTrait: Copy { + fn borrow_mode() -> BorrowMode; + } + + #[derive(Copy, Clone, Debug)] + pub struct Shared; + + impl BorrowModeTrait for Shared { + fn borrow_mode() -> BorrowMode { + BorrowMode::Shared + } + } + + #[derive(Copy, Clone, Debug)] + pub struct Exclusive; + + impl BorrowModeTrait for Exclusive { + fn borrow_mode() -> BorrowMode { + BorrowMode::Exclusive + } + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum BorrowCount { + Shared(usize), + Exclusive, + } + + impl Default for BorrowCount { + fn default() -> Self { + Self::Shared(0) + } + } + + impl BorrowCount { + pub fn is_empty(self) -> bool { + matches!(self, BorrowCount::Shared(0)) + } + + pub fn try_add(self, mode: BorrowMode) -> Option { + match (self, mode) { + (BorrowCount::Shared(refs), BorrowMode::Shared) => { + Some(BorrowCount::Shared(refs + 1)) + } + (BorrowCount::Shared(0), BorrowMode::Exclusive) => { + Some(BorrowCount::Exclusive) + } + _ => None, + } + } + + #[allow(dead_code)] + pub fn add(self, mode: BorrowMode) -> BorrowCount { + match self.try_add(mode) { + Some(value) => value, + None => panic!("Can't add {:?} to {:?}", mode, self), + } + } + + pub fn try_remove(self, mode: BorrowMode) -> Option { + match (self, mode) { + (BorrowCount::Shared(refs), BorrowMode::Shared) if refs > 0 => { + Some(BorrowCount::Shared(refs - 1)) + } + (BorrowCount::Exclusive, BorrowMode::Exclusive) => { + Some(BorrowCount::Shared(0)) + } + _ => None, + } + } + + pub fn remove(self, mode: BorrowMode) -> BorrowCount { + match self.try_remove(mode) { + Some(value) => value, + None => panic!("Can't remove {:?} from {:?}", mode, self), + } + } + } + + /// The `waiters` queue that is associated with an individual `AsyncRefCell` + /// contains elements of the `Waiter` type. + pub struct Waiter { + borrow_mode: BorrowMode, + waker: Option, + } + + impl Waiter { + pub fn new(borrow_mode: BorrowMode) -> Self { + Self { + borrow_mode, + waker: None, + } + } + + pub fn borrow_mode(&self) -> BorrowMode { + self.borrow_mode + } + + pub fn set_waker(&mut self, waker: Waker) { + self.waker.replace(waker); + } + + pub fn take_waker(&mut self) -> Option { + self.waker.take() + } + } + + /// The `RcLike` trait provides an abstraction over `std::rc::Rc` and `RcRef`, + /// so that applicable methods can operate on either type. + pub trait RcLike: Clone + Deref + Into> {} + + impl RcLike for Rc {} + impl RcLike for RcRef {} +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Default)] + struct Thing { + touch_count: usize, + _private: (), + } + + impl Thing { + pub fn look(&self) -> usize { + self.touch_count + } + + pub fn touch(&mut self) -> usize { + self.touch_count += 1; + self.touch_count + } + } + + #[tokio::test] + async fn async_ref_cell_borrow() { + let cell = AsyncRefCell::::default_rc(); + + let fut1 = cell.borrow(); + let fut2 = cell.borrow_mut(); + let fut3 = cell.borrow(); + let fut4 = cell.borrow(); + let fut5 = cell.borrow(); + let fut6 = cell.borrow(); + let fut7 = cell.borrow_mut(); + let fut8 = cell.borrow(); + + // The `try_borrow` and `try_borrow_mut` methods should always return `None` + // if there's a queue of async borrowers. + assert!(cell.try_borrow().is_none()); + assert!(cell.try_borrow_mut().is_none()); + + assert_eq!(fut1.await.look(), 0); + + assert_eq!(fut2.await.touch(), 1); + + { + let ref5 = fut5.await; + let ref4 = fut4.await; + let ref3 = fut3.await; + let ref6 = fut6.await; + assert_eq!(ref3.look(), 1); + assert_eq!(ref4.look(), 1); + assert_eq!(ref5.look(), 1); + assert_eq!(ref6.look(), 1); + } + + { + let mut ref7 = fut7.await; + assert_eq!(ref7.look(), 1); + assert_eq!(ref7.touch(), 2); + } + + { + let ref8 = fut8.await; + assert_eq!(ref8.look(), 2); + } + } + + #[test] + fn async_ref_cell_try_borrow() { + let cell = AsyncRefCell::::default_rc(); + + { + let ref1 = cell.try_borrow().unwrap(); + assert_eq!(ref1.look(), 0); + assert!(cell.try_borrow_mut().is_none()); + } + + { + let mut ref2 = cell.try_borrow_mut().unwrap(); + assert_eq!(ref2.touch(), 1); + assert!(cell.try_borrow().is_none()); + assert!(cell.try_borrow_mut().is_none()); + } + + { + let ref3 = cell.try_borrow().unwrap(); + let ref4 = cell.try_borrow().unwrap(); + let ref5 = cell.try_borrow().unwrap(); + let ref6 = cell.try_borrow().unwrap(); + assert_eq!(ref3.look(), 1); + assert_eq!(ref4.look(), 1); + assert_eq!(ref5.look(), 1); + assert_eq!(ref6.look(), 1); + assert!(cell.try_borrow_mut().is_none()); + } + + { + let mut ref7 = cell.try_borrow_mut().unwrap(); + assert_eq!(ref7.look(), 1); + assert_eq!(ref7.touch(), 2); + assert!(cell.try_borrow().is_none()); + assert!(cell.try_borrow_mut().is_none()); + } + + { + let ref8 = cell.try_borrow().unwrap(); + assert_eq!(ref8.look(), 2); + assert!(cell.try_borrow_mut().is_none()); + assert!(cell.try_borrow().is_some()); + } + } + + #[derive(Default)] + struct ThreeThings { + pub thing1: AsyncRefCell, + pub thing2: AsyncRefCell, + pub thing3: AsyncRefCell, + } + + #[tokio::test] + async fn rc_ref_map() { + let three_cells = Rc::new(ThreeThings::default()); + + let rc1 = RcRef::map(three_cells.clone(), |things| &things.thing1); + let rc2 = RcRef::map(three_cells.clone(), |things| &things.thing2); + let rc3 = RcRef::map(three_cells, |things| &things.thing3); + + let mut ref1 = rc1.borrow_mut().await; + let ref2 = rc2.borrow().await; + let mut ref3 = rc3.borrow_mut().await; + + assert_eq!(ref1.look(), 0); + assert_eq!(ref3.touch(), 1); + assert_eq!(ref1.touch(), 1); + assert_eq!(ref2.look(), 0); + assert_eq!(ref3.touch(), 2); + assert_eq!(ref1.look(), 1); + assert_eq!(ref1.touch(), 2); + assert_eq!(ref3.touch(), 3); + assert_eq!(ref1.touch(), 3); + } +} diff --git a/core/examples/http_bench_bin_ops.js b/core/examples/http_bench_bin_ops.js index 066d5bf5822b9d..a90be70c03ae80 100644 --- a/core/examples/http_bench_bin_ops.js +++ b/core/examples/http_bench_bin_ops.js @@ -134,7 +134,6 @@ async function main() { for (;;) { const rid = await accept(listenerRid); - // Deno.core.print(`accepted ${rid}`); if (rid < 0) { Deno.core.print(`accept error ${rid}`); return; diff --git a/core/examples/http_bench_bin_ops.rs b/core/examples/http_bench_bin_ops.rs index 7335b86703cb71..9af74d98006c04 100644 --- a/core/examples/http_bench_bin_ops.rs +++ b/core/examples/http_bench_bin_ops.rs @@ -3,16 +3,21 @@ #[macro_use] extern crate log; +use deno_core::AsyncMutFuture; +use deno_core::AsyncRefCell; +use deno_core::AsyncRefFuture; use deno_core::BufVec; use deno_core::JsRuntime; use deno_core::Op; use deno_core::OpState; +use deno_core::RcRef; +use deno_core::Resource; use deno_core::ZeroCopyBuf; -use futures::future::poll_fn; use futures::future::FutureExt; use futures::future::TryFuture; use futures::future::TryFutureExt; use std::cell::RefCell; +use std::convert::TryFrom; use std::convert::TryInto; use std::env; use std::fmt::Debug; @@ -20,14 +25,10 @@ use std::io::Error; use std::io::ErrorKind; use std::mem::size_of; use std::net::SocketAddr; -use std::pin::Pin; use std::ptr; use std::rc::Rc; -use tokio::io::AsyncRead; -use tokio::io::AsyncWrite; -use tokio::net::TcpListener; -use tokio::net::TcpStream; -use tokio::runtime; +use tokio::io::AsyncReadExt; +use tokio::io::AsyncWriteExt; struct Logger; @@ -45,6 +46,64 @@ impl log::Log for Logger { fn flush(&self) {} } +// Note: it isn't actually necessary to wrap the `tokio::net::TcpListener` in +// a cell, because it only supports one op (`accept`) which does not require +// a mutable reference to the listener. +struct TcpListener(AsyncRefCell); + +impl Resource for TcpListener {} + +impl TcpListener { + /// Returns a future that yields a shared borrow of the TCP listener. + fn borrow(self: Rc) -> AsyncRefFuture { + RcRef::map(self, |r| &r.0).borrow() + } +} + +impl TryFrom for TcpListener { + type Error = Error; + fn try_from(l: std::net::TcpListener) -> Result { + tokio::net::TcpListener::try_from(l) + .map(AsyncRefCell::new) + .map(Self) + } +} + +struct TcpStream { + rd: AsyncRefCell, + wr: AsyncRefCell, +} + +impl Resource for TcpStream {} + +impl TcpStream { + /// Returns a future that yields an exclusive borrow of the read end of the + /// tcp stream. + fn rd_borrow_mut( + self: Rc, + ) -> AsyncMutFuture { + RcRef::map(self, |r| &r.rd).borrow_mut() + } + + /// Returns a future that yields an exclusive borrow of the write end of the + /// tcp stream. + fn wr_borrow_mut( + self: Rc, + ) -> AsyncMutFuture { + RcRef::map(self, |r| &r.wr).borrow_mut() + } +} + +impl From for TcpStream { + fn from(s: tokio::net::TcpStream) -> Self { + let (rd, wr) = s.into_split(); + Self { + rd: rd.into(), + wr: wr.into(), + } + } +} + #[derive(Copy, Clone, Debug, PartialEq)] struct Record { promise_id: u32, @@ -94,8 +153,9 @@ fn op_listen( debug!("listen"); let addr = "127.0.0.1:4544".parse::().unwrap(); let std_listener = std::net::TcpListener::bind(&addr)?; - let listener = TcpListener::from_std(std_listener)?; - let rid = state.resource_table.add("tcpListener", Box::new(listener)); + std_listener.set_nonblocking(true)?; + let listener = TcpListener::try_from(std_listener)?; + let rid = state.resource_table_2.add(listener); Ok(rid) } @@ -106,7 +166,7 @@ fn op_close( ) -> Result { debug!("close rid={}", rid); state - .resource_table + .resource_table_2 .close(rid) .map(|_| 0) .ok_or_else(bad_resource_id) @@ -119,56 +179,52 @@ async fn op_accept( ) -> Result { debug!("accept rid={}", rid); - poll_fn(move |cx| { - let resource_table = &mut state.borrow_mut().resource_table; - - let listener = resource_table - .get_mut::(rid) - .ok_or_else(bad_resource_id)?; - listener.poll_accept(cx).map_ok(|(stream, _addr)| { - resource_table.add("tcpStream", Box::new(stream)) - }) - }) - .await + let listener_rc = state + .borrow() + .resource_table_2 + .get::(rid) + .ok_or_else(bad_resource_id)?; + let listener_ref = listener_rc.borrow().await; + + let stream: TcpStream = listener_ref.accept().await?.0.into(); + let rid = state.borrow_mut().resource_table_2.add(stream); + Ok(rid) } -fn op_read( +async fn op_read( state: Rc>, rid: u32, - bufs: BufVec, -) -> impl TryFuture { + mut bufs: BufVec, +) -> Result { assert_eq!(bufs.len(), 1, "Invalid number of arguments"); - let mut buf = bufs[0].clone(); - debug!("read rid={}", rid); - poll_fn(move |cx| { - let resource_table = &mut state.borrow_mut().resource_table; + let stream_rc = state + .borrow() + .resource_table_2 + .get::(rid) + .ok_or_else(bad_resource_id)?; + let mut rd_stream_mut = stream_rc.rd_borrow_mut().await; - let stream = resource_table - .get_mut::(rid) - .ok_or_else(bad_resource_id)?; - Pin::new(stream).poll_read(cx, &mut buf) - }) + rd_stream_mut.read(&mut bufs[0]).await } -fn op_write( +async fn op_write( state: Rc>, rid: u32, bufs: BufVec, -) -> impl TryFuture { +) -> Result { assert_eq!(bufs.len(), 1, "Invalid number of arguments"); - let buf = bufs[0].clone(); debug!("write rid={}", rid); - poll_fn(move |cx| { - let resource_table = &mut state.borrow_mut().resource_table; + let stream_rc = state + .borrow() + .resource_table_2 + .get::(rid) + .ok_or_else(bad_resource_id)?; + let mut wr_stream_mut = stream_rc.wr_borrow_mut().await; - let stream = resource_table - .get_mut::(rid) - .ok_or_else(bad_resource_id)?; - Pin::new(stream).poll_write(cx, &buf) - }) + wr_stream_mut.write(&bufs[0]).await } fn register_op_bin_sync( @@ -247,8 +303,7 @@ fn main() { deno_core::v8_set_flags(env::args().collect()); let mut js_runtime = create_js_runtime(); - let mut runtime = runtime::Builder::new() - .basic_scheduler() + let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs index 2cf3d09e339b2d..830da14cd8f682 100644 --- a/core/examples/http_bench_json_ops.rs +++ b/core/examples/http_bench_json_ops.rs @@ -21,9 +21,9 @@ use std::rc::Rc; use std::task::Poll; use tokio::io::AsyncRead; use tokio::io::AsyncWrite; +use tokio::io::ReadBuf; use tokio::net::TcpListener; use tokio::net::TcpStream; -use tokio::runtime; struct Logger; @@ -133,8 +133,9 @@ fn op_read( let stream = resource_table .get_mut::(rid) .ok_or_else(bad_resource_id)?; + let mut read_buf = ReadBuf::new(&mut bufs[0]); Pin::new(stream) - .poll_read(cx, &mut bufs[0])? + .poll_read(cx, &mut read_buf)? .map(|nread| Ok(serde_json::json!({ "nread": nread }))) }) } @@ -180,8 +181,7 @@ fn main() { deno_core::v8_set_flags(env::args().collect()); let mut js_runtime = create_js_runtime(); - let mut runtime = runtime::Builder::new() - .basic_scheduler() + let runtime = tokio::runtime::Builder::new_current_thread() .enable_all() .build() .unwrap(); diff --git a/core/lib.rs b/core/lib.rs index 48968fa97d3324..34bd25bcb3ee57 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -5,6 +5,7 @@ extern crate lazy_static; #[macro_use] extern crate log; +mod async_cell; mod bindings; pub mod error; mod flags; @@ -15,6 +16,7 @@ mod normalize_path; mod ops; pub mod plugin_api; mod resources; +mod resources2; mod runtime; mod shared_queue; mod zero_copy_buf; @@ -26,6 +28,12 @@ pub use serde; pub use serde_json; pub use url; +pub use crate::async_cell::AsyncMut; +pub use crate::async_cell::AsyncMutFuture; +pub use crate::async_cell::AsyncRef; +pub use crate::async_cell::AsyncRefCell; +pub use crate::async_cell::AsyncRefFuture; +pub use crate::async_cell::RcRef; pub use crate::flags::v8_set_flags; pub use crate::module_specifier::ModuleResolutionError; pub use crate::module_specifier::ModuleSpecifier; @@ -47,6 +55,9 @@ pub use crate::ops::OpId; pub use crate::ops::OpState; pub use crate::ops::OpTable; pub use crate::resources::ResourceTable; +pub use crate::resources2::Resource; +pub use crate::resources2::ResourceId; +pub use crate::resources2::ResourceTable2; pub use crate::runtime::GetErrorClassFn; pub use crate::runtime::JsRuntime; pub use crate::runtime::RuntimeOptions; diff --git a/core/ops.rs b/core/ops.rs index ed74ce873995fa..bf10d3d86e919b 100644 --- a/core/ops.rs +++ b/core/ops.rs @@ -34,6 +34,7 @@ pub enum Op { /// Maintains the resources and ops inside a JS runtime. pub struct OpState { pub resource_table: crate::ResourceTable, + pub resource_table_2: crate::resources2::ResourceTable, pub op_table: OpTable, pub get_error_class_fn: crate::runtime::GetErrorClassFn, gotham_state: GothamState, @@ -45,10 +46,11 @@ impl Default for OpState { // pub(crate) fn new() -> OpState fn default() -> OpState { OpState { - resource_table: crate::ResourceTable::default(), + resource_table: Default::default(), + resource_table_2: Default::default(), op_table: OpTable::default(), get_error_class_fn: &|_| "Error", - gotham_state: GothamState::default(), + gotham_state: Default::default(), } } } diff --git a/core/resources.rs b/core/resources.rs index 25ea95f41efe79..753fa97139a294 100644 --- a/core/resources.rs +++ b/core/resources.rs @@ -6,13 +6,10 @@ // Resources may or may not correspond to a real operating system file // descriptor (hence the different name). +use crate::resources2::ResourceId; use std::any::Any; use std::collections::HashMap; -/// ResourceId is Deno's version of a file descriptor. ResourceId is also referred -/// to as `rid` in the code base. -pub type ResourceId = u32; - /// These store Deno's file descriptors. These are not necessarily the operating /// system ones. type ResourceMap = HashMap)>; diff --git a/core/resources2.rs b/core/resources2.rs new file mode 100644 index 00000000000000..52bd4f3e7741d8 --- /dev/null +++ b/core/resources2.rs @@ -0,0 +1,140 @@ +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +// Think of Resources as File Descriptors. They are integers that are allocated +// by the privileged side of Deno which refer to various rust objects that need +// to be persisted between various ops. For example, network sockets are +// resources. Resources may or may not correspond to a real operating system +// file descriptor (hence the different name). + +use std::any::type_name; +use std::any::Any; +use std::any::TypeId; +use std::borrow::Cow; +use std::collections::HashMap; +use std::iter::Iterator; +use std::rc::Rc; + +/// All objects that can be store in the resource table should implement the +/// `Resource` trait. +pub trait Resource: Any + 'static { + /// Returns a string representation of the resource which is made available + /// to JavaScript code through `op_resources`. The default implementation + /// returns the Rust type name, but specific resource types may override this + /// trait method. + fn name(&self) -> Cow { + type_name::().into() + } +} + +impl dyn Resource { + #[inline(always)] + fn is(&self) -> bool { + self.type_id() == TypeId::of::() + } + + #[inline(always)] + fn downcast_rc<'a, T: Resource>(self: &'a Rc) -> Option<&'a Rc> { + if self.is::() { + let ptr = self as *const Rc<_> as *const Rc; + Some(unsafe { &*ptr }) + } else { + None + } + } +} + +/// A `ResourceId` is an integer value referencing a resource. It could be +/// considered to be the Deno equivalent of a `file descriptor` in POSIX like +/// operating systems. Elsewhere in the code base it is commonly abbreviated +/// to `rid`. +// TODO: use `u64` instead? +pub type ResourceId = u32; + +/// Temporary alias for `crate::resources2::ResourceTable`. +// TODO: remove this when the old `ResourceTable` is obsolete. +pub type ResourceTable2 = ResourceTable; + +/// Map-like data structure storing Deno's resources (equivalent to file +/// descriptors). +/// +/// Provides basic methods for element access. A resource can be of any type. +/// Different types of resources can be stored in the same map, and provided +/// with a name for description. +/// +/// Each resource is identified through a _resource ID (rid)_, which acts as +/// the key in the map. +#[derive(Default)] +pub struct ResourceTable { + index: HashMap>, + next_rid: ResourceId, +} + +impl ResourceTable { + /// Returns true if any resource with the given `rid` is exists. + pub fn has(&self, rid: ResourceId) -> bool { + self.index.contains_key(&rid) + } + + /// Returns a reference counted pointer to the resource of type `T` with the + /// given `rid`. If `rid` is not present or has a type different than `T`, + /// this function returns `None`. + pub fn get(&self, rid: ResourceId) -> Option> { + self + .index + .get(&rid) + .and_then(|resource| resource.downcast_rc::()) + .map(Clone::clone) + } + + /// Inserts resource into the resource table, which takes ownership of it. + /// + /// The resource type is erased at runtime and must be statically known + /// when retrieving it through `get()`. + /// + /// Returns a unique resource ID, which acts as a key for this resource. + pub fn add(&mut self, resource: T) -> ResourceId { + self.add_rc(Rc::new(resource)) + } + + /// Inserts a `Rc`-wrapped resource into the resource table. + /// + /// The resource type is erased at runtime and must be statically known + /// when retrieving it through `get()`. + /// + /// Returns a unique resource ID, which acts as a key for this resource. + pub fn add_rc(&mut self, resource: Rc) -> ResourceId { + let resource = resource as Rc; + let rid = self.next_rid; + let removed_resource = self.index.insert(rid, resource); + assert!(removed_resource.is_none()); + self.next_rid += 1; + rid + } + + /// Removes the resource with the given `rid` from the resource table. If the + /// only reference to this resource existed in the resource table, this will + /// cause the resource to be dropped. However, since resources are reference + /// counted, therefore pending ops are not automatically cancelled. + pub fn close(&mut self, rid: ResourceId) -> Option<()> { + self.index.remove(&rid).map(|_| ()) + } + + /// Returns an iterator that yields a `(id, name)` pair for every resource + /// that's currently in the resource table. This can be used for debugging + /// purposes or to implement the `op_resources` op. Note that the order in + /// which items appear is not specified. + /// + /// # Example + /// + /// ``` + /// # use deno_core::resources2::ResourceTable; + /// # let resource_table = ResourceTable::default(); + /// let resource_names = resource_table.names().collect::>(); + /// ``` + pub fn names(&self) -> impl Iterator)> { + self + .index + .iter() + .map(|(&id, resource)| (id, resource.name())) + } +} diff --git a/op_crates/web/Cargo.toml b/op_crates/web/Cargo.toml index 1ade1d6d0e8a4a..9e03cac7b889e7 100644 --- a/op_crates/web/Cargo.toml +++ b/op_crates/web/Cargo.toml @@ -19,4 +19,4 @@ idna = "0.2.0" serde = { version = "1.0.116", features = ["derive"] } [dev-dependencies] -futures = "0.3.5" +futures = "0.3.8" diff --git a/test_plugin/Cargo.toml b/test_plugin/Cargo.toml index b9be58dade0a80..e7eb3932cddb68 100644 --- a/test_plugin/Cargo.toml +++ b/test_plugin/Cargo.toml @@ -11,7 +11,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -futures = "0.3.5" +futures = "0.3.8" deno_core = { path = "../core" } [dev-dependencies] diff --git a/test_util/Cargo.toml b/test_util/Cargo.toml index cf450e36040280..fefe7f3d8ebaf1 100644 --- a/test_util/Cargo.toml +++ b/test_util/Cargo.toml @@ -13,7 +13,7 @@ path = "src/test_server.rs" [dependencies] tokio = { version = "0.2.22", features = ["full"] } -futures = "0.3.5" +futures = "0.3.8" bytes = "0.5.6" lazy_static = "1.4.0" os_pipe = "0.9.2"