Make mio optional in ethcore-io (#8537)
* Make mio optional in ethcore-io * Add some annotations, plus a check for features * Increase timer for test
This commit is contained in:
parent
6e2e08628a
commit
1b8f299df2
46
Cargo.lock
generated
46
Cargo.lock
generated
@ -209,6 +209,16 @@ dependencies = [
|
|||||||
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cid"
|
name = "cid"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -542,7 +552,7 @@ dependencies = [
|
|||||||
"memory-cache 0.1.0",
|
"memory-cache 0.1.0",
|
||||||
"memorydb 0.1.1",
|
"memorydb 0.1.1",
|
||||||
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-machine 0.1.0",
|
"parity-machine 0.1.0",
|
||||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"patricia-trie 0.1.0",
|
"patricia-trie 0.1.0",
|
||||||
@ -597,10 +607,14 @@ name = "ethcore-io"
|
|||||||
version = "1.12.0"
|
version = "1.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -991,7 +1005,7 @@ dependencies = [
|
|||||||
"dir 0.1.0",
|
"dir 0.1.0",
|
||||||
"docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethstore 0.2.0",
|
"ethstore 0.2.0",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"panic_hook 0.1.0",
|
"panic_hook 0.1.0",
|
||||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1117,7 +1131,7 @@ version = "0.1.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1483,7 +1497,7 @@ dependencies = [
|
|||||||
"interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"kvdb 0.1.0",
|
"kvdb 0.1.0",
|
||||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)",
|
"rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)",
|
||||||
@ -1888,7 +1902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1981,7 +1995,7 @@ dependencies = [
|
|||||||
"migration-rocksdb 0.1.0",
|
"migration-rocksdb 0.1.0",
|
||||||
"node-filter 1.12.0",
|
"node-filter 1.12.0",
|
||||||
"node-health 0.1.0",
|
"node-health 0.1.0",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"panic_hook 0.1.0",
|
"panic_hook 0.1.0",
|
||||||
"parity-dapps 1.12.0",
|
"parity-dapps 1.12.0",
|
||||||
@ -2680,7 +2694,7 @@ dependencies = [
|
|||||||
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3183,7 +3197,7 @@ name = "threadpool"
|
|||||||
version = "1.7.1"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3197,6 +3211,14 @@ dependencies = [
|
|||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "timer"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiny-keccak"
|
name = "tiny-keccak"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -3350,7 +3372,7 @@ dependencies = [
|
|||||||
"crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -3795,6 +3817,7 @@ dependencies = [
|
|||||||
"checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9"
|
"checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9"
|
||||||
"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0"
|
"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0"
|
||||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||||
|
"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
|
||||||
"checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6"
|
"checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6"
|
||||||
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
|
"checksum clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f4a2b3bb7ef3c672d7c13d15613211d5a6976b6892c598b0fcb5d40765f19c2"
|
||||||
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
|
||||||
@ -3903,7 +3926,7 @@ dependencies = [
|
|||||||
"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593"
|
"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593"
|
||||||
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||||
"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
|
"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
|
||||||
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
|
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||||
"checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902"
|
"checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902"
|
||||||
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
|
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
|
||||||
"checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb"
|
"checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb"
|
||||||
@ -4001,6 +4024,7 @@ dependencies = [
|
|||||||
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
|
||||||
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
|
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
|
||||||
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
|
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
|
||||||
|
"checksum timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b"
|
||||||
"checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01"
|
"checksum tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "58911ed5eb275a8fd2f1f0418ed360a42f59329864b64e1e95377a9024498c01"
|
||||||
"checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922"
|
"checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922"
|
||||||
"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
|
"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
|
||||||
|
@ -34,6 +34,7 @@ trace-time = { path = "../../util/trace-time" }
|
|||||||
ipnetwork = "0.12.6"
|
ipnetwork = "0.12.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
ethcore-io = { path = "../../util/io", features = ["mio"] }
|
||||||
ethkey = { path = "../../ethkey" }
|
ethkey = { path = "../../ethkey" }
|
||||||
kvdb-memorydb = { path = "../../util/kvdb-memorydb" }
|
kvdb-memorydb = { path = "../../util/kvdb-memorydb" }
|
||||||
ethcore-private-tx = { path = "../private-tx" }
|
ethcore-private-tx = { path = "../private-tx" }
|
||||||
|
2
test.sh
2
test.sh
@ -33,6 +33,8 @@ if [ "$VALIDATE" -eq "1" ]; then
|
|||||||
# Validate --no-default-features build
|
# Validate --no-default-features build
|
||||||
echo "________Validate build________"
|
echo "________Validate build________"
|
||||||
cargo check --no-default-features
|
cargo check --no-default-features
|
||||||
|
cargo check --manifest-path util/io/Cargo.toml --no-default-features
|
||||||
|
cargo check --manifest-path util/io/Cargo.toml --features "mio"
|
||||||
|
|
||||||
# Validate chainspecs
|
# Validate chainspecs
|
||||||
echo "________Validate chainspecs________"
|
echo "________Validate chainspecs________"
|
||||||
|
@ -7,9 +7,12 @@ version = "1.12.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
mio = "0.6.8"
|
fnv = "1.0"
|
||||||
|
mio = { version = "0.6.8", optional = true }
|
||||||
crossbeam = "0.3"
|
crossbeam = "0.3"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.5"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
slab = "0.2"
|
slab = "0.4"
|
||||||
|
num_cpus = "1.8"
|
||||||
|
timer = "0.2"
|
||||||
|
time = "0.1"
|
||||||
|
@ -54,30 +54,59 @@
|
|||||||
//! // Drop the service
|
//! // Drop the service
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Mio vs non-mio
|
||||||
|
//!
|
||||||
|
//! This library has two modes: mio and not mio. The `mio` feature can be activated or deactivated
|
||||||
|
//! when compiling or depending on the library.
|
||||||
|
//!
|
||||||
|
//! Without mio, only timers and message-passing are available. With mio, you can also use
|
||||||
|
//! low-level sockets provided by mio.
|
||||||
|
//!
|
||||||
|
//! The non-mio mode exists because the `mio` library doesn't compile on platforms such as
|
||||||
|
//! emscripten.
|
||||||
|
|
||||||
//TODO: use Poll from mio
|
//TODO: use Poll from mio
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
extern crate mio;
|
extern crate mio;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log as rlog;
|
extern crate log as rlog;
|
||||||
extern crate slab;
|
extern crate slab;
|
||||||
extern crate crossbeam;
|
extern crate crossbeam;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
|
extern crate num_cpus;
|
||||||
|
extern crate timer;
|
||||||
|
extern crate fnv;
|
||||||
|
extern crate time;
|
||||||
|
|
||||||
mod service;
|
#[cfg(feature = "mio")]
|
||||||
|
mod service_mio;
|
||||||
|
#[cfg(not(feature = "mio"))]
|
||||||
|
mod service_non_mio;
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
mod worker;
|
mod worker;
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
use std::{fmt, error};
|
use std::{fmt, error};
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
use mio::deprecated::{EventLoop, NotifyError};
|
use mio::deprecated::{EventLoop, NotifyError};
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
use mio::Token;
|
use mio::Token;
|
||||||
|
|
||||||
pub use worker::LOCAL_STACK_SIZE;
|
thread_local! {
|
||||||
|
/// Stack size
|
||||||
|
/// Should be modified if it is changed in Rust since it is no way
|
||||||
|
/// to know or get it
|
||||||
|
pub static LOCAL_STACK_SIZE: Cell<usize> = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// IO Error
|
/// IO Error
|
||||||
pub enum IoError {
|
pub enum IoError {
|
||||||
/// Low level error from mio crate
|
/// Low level error from mio crate
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
Mio(::std::io::Error),
|
Mio(::std::io::Error),
|
||||||
/// Error concerning the Rust standard library's IO subsystem.
|
/// Error concerning the Rust standard library's IO subsystem.
|
||||||
StdIo(::std::io::Error),
|
StdIo(::std::io::Error),
|
||||||
@ -88,6 +117,7 @@ impl fmt::Display for IoError {
|
|||||||
// just defer to the std implementation for now.
|
// just defer to the std implementation for now.
|
||||||
// we can refine the formatting when more variants are added.
|
// we can refine the formatting when more variants are added.
|
||||||
match *self {
|
match *self {
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
IoError::Mio(ref std_err) => std_err.fmt(f),
|
IoError::Mio(ref std_err) => std_err.fmt(f),
|
||||||
IoError::StdIo(ref std_err) => std_err.fmt(f),
|
IoError::StdIo(ref std_err) => std_err.fmt(f),
|
||||||
}
|
}
|
||||||
@ -106,8 +136,9 @@ impl From<::std::io::Error> for IoError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> From<NotifyError<service::IoMessage<Message>>> for IoError where Message: Send {
|
#[cfg(feature = "mio")]
|
||||||
fn from(_err: NotifyError<service::IoMessage<Message>>) -> IoError {
|
impl<Message> From<NotifyError<service_mio::IoMessage<Message>>> for IoError where Message: Send {
|
||||||
|
fn from(_err: NotifyError<service_mio::IoMessage<Message>>) -> IoError {
|
||||||
IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error"))
|
IoError::Mio(::std::io::Error::new(::std::io::ErrorKind::ConnectionAborted, "Network IO notification error"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,58 +154,120 @@ pub trait IoHandler<Message>: Send + Sync where Message: Send + Sync + 'static {
|
|||||||
/// Called when a broadcasted message is received. The message can only be sent from a different IO handler.
|
/// Called when a broadcasted message is received. The message can only be sent from a different IO handler.
|
||||||
fn message(&self, _io: &IoContext<Message>, _message: &Message) {}
|
fn message(&self, _io: &IoContext<Message>, _message: &Message) {}
|
||||||
/// Called when an IO stream gets closed
|
/// Called when an IO stream gets closed
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
fn stream_hup(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
fn stream_hup(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
||||||
/// Called when an IO stream can be read from
|
/// Called when an IO stream can be read from
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
fn stream_readable(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
fn stream_readable(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
||||||
/// Called when an IO stream can be written to
|
/// Called when an IO stream can be written to
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
fn stream_writable(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
fn stream_writable(&self, _io: &IoContext<Message>, _stream: StreamToken) {}
|
||||||
/// Register a new stream with the event loop
|
/// Register a new stream with the event loop
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
fn register_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
fn register_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
||||||
/// Re-register a stream with the event loop
|
/// Re-register a stream with the event loop
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
fn update_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
fn update_stream(&self, _stream: StreamToken, _reg: Token, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
||||||
/// Deregister a stream. Called whenstream is removed from event loop
|
/// Deregister a stream. Called whenstream is removed from event loop
|
||||||
|
#[cfg(feature = "mio")]
|
||||||
fn deregister_stream(&self, _stream: StreamToken, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
fn deregister_stream(&self, _stream: StreamToken, _event_loop: &mut EventLoop<IoManager<Message>>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use service::TimerToken;
|
#[cfg(feature = "mio")]
|
||||||
pub use service::StreamToken;
|
pub use service_mio::{TimerToken, StreamToken, IoContext, IoService, IoChannel, IoManager, TOKENS_PER_HANDLER};
|
||||||
pub use service::IoContext;
|
#[cfg(not(feature = "mio"))]
|
||||||
pub use service::IoService;
|
pub use service_non_mio::{TimerToken, IoContext, IoService, IoChannel, TOKENS_PER_HANDLER};
|
||||||
pub use service::IoChannel;
|
|
||||||
pub use service::IoManager;
|
|
||||||
pub use service::TOKENS_PER_HANDLER;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic;
|
||||||
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
struct MyHandler;
|
#[test]
|
||||||
|
fn send_message_to_handler() {
|
||||||
|
struct MyHandler(atomic::AtomicBool);
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct MyMessage {
|
struct MyMessage {
|
||||||
data: u32
|
data: u32
|
||||||
}
|
|
||||||
|
|
||||||
impl IoHandler<MyMessage> for MyHandler {
|
|
||||||
fn initialize(&self, io: &IoContext<MyMessage>) {
|
|
||||||
io.register_timer(0, Duration::from_secs(1)).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timeout(&self, _io: &IoContext<MyMessage>, timer: TimerToken) {
|
impl IoHandler<MyMessage> for MyHandler {
|
||||||
println!("Timeout {}", timer);
|
fn message(&self, _io: &IoContext<MyMessage>, message: &MyMessage) {
|
||||||
|
assert_eq!(message.data, 5);
|
||||||
|
self.0.store(true, atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn message(&self, _io: &IoContext<MyMessage>, message: &MyMessage) {
|
let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false)));
|
||||||
println!("Message {}", message.data);
|
|
||||||
}
|
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
||||||
|
service.register_handler(handler.clone()).unwrap();
|
||||||
|
|
||||||
|
service.send_message(MyMessage { data: 5 }).unwrap();
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_secs(5));
|
||||||
|
assert!(handler.0.load(atomic::Ordering::SeqCst));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_service_register_handler () {
|
fn timeout_working() {
|
||||||
|
struct MyHandler(atomic::AtomicBool);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyMessage {
|
||||||
|
data: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoHandler<MyMessage> for MyHandler {
|
||||||
|
fn initialize(&self, io: &IoContext<MyMessage>) {
|
||||||
|
io.register_timer_once(1234, Duration::from_millis(500)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timeout(&self, _io: &IoContext<MyMessage>, timer: TimerToken) {
|
||||||
|
assert_eq!(timer, 1234);
|
||||||
|
assert!(!self.0.swap(true, atomic::Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = Arc::new(MyHandler(atomic::AtomicBool::new(false)));
|
||||||
|
|
||||||
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
||||||
service.register_handler(Arc::new(MyHandler)).unwrap();
|
service.register_handler(handler.clone()).unwrap();
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_secs(2));
|
||||||
|
assert!(handler.0.load(atomic::Ordering::SeqCst));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn multi_timeout_working() {
|
||||||
|
struct MyHandler(atomic::AtomicUsize);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct MyMessage {
|
||||||
|
data: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoHandler<MyMessage> for MyHandler {
|
||||||
|
fn initialize(&self, io: &IoContext<MyMessage>) {
|
||||||
|
io.register_timer(1234, Duration::from_millis(500)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timeout(&self, _io: &IoContext<MyMessage>, timer: TimerToken) {
|
||||||
|
assert_eq!(timer, 1234);
|
||||||
|
self.0.fetch_add(1, atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = Arc::new(MyHandler(atomic::AtomicUsize::new(0)));
|
||||||
|
|
||||||
|
let service = IoService::<MyMessage>::start().expect("Error creating network service");
|
||||||
|
service.register_handler(handler.clone()).unwrap();
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_secs(2));
|
||||||
|
assert!(handler.0.load(atomic::Ordering::SeqCst) >= 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ struct UserTimer {
|
|||||||
/// Root IO handler. Manages user handlers, messages and IO timers.
|
/// Root IO handler. Manages user handlers, messages and IO timers.
|
||||||
pub struct IoManager<Message> where Message: Send + Sync {
|
pub struct IoManager<Message> where Message: Send + Sync {
|
||||||
timers: Arc<RwLock<HashMap<HandlerId, UserTimer>>>,
|
timers: Arc<RwLock<HashMap<HandlerId, UserTimer>>>,
|
||||||
handlers: Arc<RwLock<Slab<Arc<IoHandler<Message>>, HandlerId>>>,
|
handlers: Arc<RwLock<Slab<Arc<IoHandler<Message>>>>>,
|
||||||
workers: Vec<Worker>,
|
workers: Vec<Worker>,
|
||||||
worker_channel: chase_lev::Worker<Work<Message>>,
|
worker_channel: chase_lev::Worker<Work<Message>>,
|
||||||
work_ready: Arc<SCondvar>,
|
work_ready: Arc<SCondvar>,
|
||||||
@ -191,7 +191,7 @@ impl<Message> IoManager<Message> where Message: Send + Sync + 'static {
|
|||||||
/// Creates a new instance and registers it with the event loop.
|
/// Creates a new instance and registers it with the event loop.
|
||||||
pub fn start(
|
pub fn start(
|
||||||
event_loop: &mut EventLoop<IoManager<Message>>,
|
event_loop: &mut EventLoop<IoManager<Message>>,
|
||||||
handlers: Arc<RwLock<Slab<Arc<IoHandler<Message>>, HandlerId>>>
|
handlers: Arc<RwLock<Slab<Arc<IoHandler<Message>>>>>
|
||||||
) -> Result<(), IoError> {
|
) -> Result<(), IoError> {
|
||||||
let (worker, stealer) = chase_lev::deque();
|
let (worker, stealer) = chase_lev::deque();
|
||||||
let num_workers = 4;
|
let num_workers = 4;
|
||||||
@ -267,7 +267,8 @@ impl<Message> Handler for IoManager<Message> where Message: Send + Sync + 'stati
|
|||||||
event_loop.shutdown();
|
event_loop.shutdown();
|
||||||
},
|
},
|
||||||
IoMessage::AddHandler { handler } => {
|
IoMessage::AddHandler { handler } => {
|
||||||
let handler_id = self.handlers.write().insert(handler.clone()).unwrap_or_else(|_| panic!("Too many handlers registered"));
|
let handler_id = self.handlers.write().insert(handler.clone());
|
||||||
|
assert!(handler_id <= MAX_HANDLERS, "Too many handlers registered");
|
||||||
handler.initialize(&IoContext::new(IoChannel::new(event_loop.channel(), Arc::downgrade(&self.handlers)), handler_id));
|
handler.initialize(&IoContext::new(IoChannel::new(event_loop.channel(), Arc::downgrade(&self.handlers)), handler_id));
|
||||||
},
|
},
|
||||||
IoMessage::RemoveHandler { handler_id } => {
|
IoMessage::RemoveHandler { handler_id } => {
|
||||||
@ -332,7 +333,7 @@ impl<Message> Handler for IoManager<Message> where Message: Send + Sync + 'stati
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Handlers<Message> where Message: Send {
|
enum Handlers<Message> where Message: Send {
|
||||||
SharedCollection(Weak<RwLock<Slab<Arc<IoHandler<Message>>, HandlerId>>>),
|
SharedCollection(Weak<RwLock<Slab<Arc<IoHandler<Message>>>>>),
|
||||||
Single(Weak<IoHandler<Message>>),
|
Single(Weak<IoHandler<Message>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +418,7 @@ impl<Message> IoChannel<Message> where Message: Send + Sync + 'static {
|
|||||||
handlers: Handlers::Single(handler),
|
handlers: Handlers::Single(handler),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn new(channel: Sender<IoMessage<Message>>, handlers: Weak<RwLock<Slab<Arc<IoHandler<Message>>, HandlerId>>>) -> IoChannel<Message> {
|
fn new(channel: Sender<IoMessage<Message>>, handlers: Weak<RwLock<Slab<Arc<IoHandler<Message>>>>>) -> IoChannel<Message> {
|
||||||
IoChannel {
|
IoChannel {
|
||||||
channel: Some(channel),
|
channel: Some(channel),
|
||||||
handlers: Handlers::SharedCollection(handlers),
|
handlers: Handlers::SharedCollection(handlers),
|
||||||
@ -430,7 +431,7 @@ impl<Message> IoChannel<Message> where Message: Send + Sync + 'static {
|
|||||||
pub struct IoService<Message> where Message: Send + Sync + 'static {
|
pub struct IoService<Message> where Message: Send + Sync + 'static {
|
||||||
thread: Mutex<Option<JoinHandle<()>>>,
|
thread: Mutex<Option<JoinHandle<()>>>,
|
||||||
host_channel: Mutex<Sender<IoMessage<Message>>>,
|
host_channel: Mutex<Sender<IoMessage<Message>>>,
|
||||||
handlers: Arc<RwLock<Slab<Arc<IoHandler<Message>>, HandlerId>>>,
|
handlers: Arc<RwLock<Slab<Arc<IoHandler<Message>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> IoService<Message> where Message: Send + Sync + 'static {
|
impl<Message> IoService<Message> where Message: Send + Sync + 'static {
|
||||||
@ -440,7 +441,7 @@ impl<Message> IoService<Message> where Message: Send + Sync + 'static {
|
|||||||
config.messages_per_tick(1024);
|
config.messages_per_tick(1024);
|
||||||
let mut event_loop = config.build().expect("Error creating event loop");
|
let mut event_loop = config.build().expect("Error creating event loop");
|
||||||
let channel = event_loop.channel();
|
let channel = event_loop.channel();
|
||||||
let handlers = Arc::new(RwLock::new(Slab::new(MAX_HANDLERS)));
|
let handlers = Arc::new(RwLock::new(Slab::with_capacity(MAX_HANDLERS)));
|
||||||
let h = handlers.clone();
|
let h = handlers.clone();
|
||||||
let thread = thread::spawn(move || {
|
let thread = thread::spawn(move || {
|
||||||
IoManager::<Message>::start(&mut event_loop, h).expect("Error starting IO service");
|
IoManager::<Message>::start(&mut event_loop, h).expect("Error starting IO service");
|
||||||
@ -491,4 +492,3 @@ impl<Message> Drop for IoService<Message> where Message: Send + Sync {
|
|||||||
self.stop()
|
self.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
334
util/io/src/service_non_mio.rs
Normal file
334
util/io/src/service_non_mio.rs
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use std::thread;
|
||||||
|
use crossbeam::sync::chase_lev;
|
||||||
|
use slab::Slab;
|
||||||
|
use fnv::FnvHashMap;
|
||||||
|
use {IoError, IoHandler};
|
||||||
|
use parking_lot::{RwLock, Mutex};
|
||||||
|
use num_cpus;
|
||||||
|
use std::time::Duration;
|
||||||
|
use timer::{Timer, Guard as TimerGuard};
|
||||||
|
use time::Duration as TimeDuration;
|
||||||
|
|
||||||
|
/// Timer ID
|
||||||
|
pub type TimerToken = usize;
|
||||||
|
/// IO Handler ID
|
||||||
|
pub type HandlerId = usize;
|
||||||
|
|
||||||
|
/// Maximum number of tokens a handler can use
|
||||||
|
pub const TOKENS_PER_HANDLER: usize = 16384;
|
||||||
|
const MAX_HANDLERS: usize = 8;
|
||||||
|
|
||||||
|
/// IO access point. This is passed to all IO handlers and provides an interface to the IO subsystem.
|
||||||
|
pub struct IoContext<Message> where Message: Send + Sync + 'static {
|
||||||
|
handler: HandlerId,
|
||||||
|
shared: Arc<Shared<Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> IoContext<Message> where Message: Send + Sync + 'static {
|
||||||
|
/// Register a new recurring IO timer. 'IoHandler::timeout' will be called with the token.
|
||||||
|
pub fn register_timer(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> {
|
||||||
|
let channel = self.channel();
|
||||||
|
|
||||||
|
let msg = WorkTask::TimerTrigger {
|
||||||
|
handler_id: self.handler,
|
||||||
|
token: token,
|
||||||
|
};
|
||||||
|
|
||||||
|
let delay = TimeDuration::from_std(delay)
|
||||||
|
.map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::Other, e))?;
|
||||||
|
let guard = self.shared.timer.lock().schedule_repeating(delay, move || {
|
||||||
|
channel.send_raw(msg.clone());
|
||||||
|
});
|
||||||
|
|
||||||
|
self.shared.timers.lock().insert(token, guard);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a new IO timer once. 'IoHandler::timeout' will be called with the token.
|
||||||
|
pub fn register_timer_once(&self, token: TimerToken, delay: Duration) -> Result<(), IoError> {
|
||||||
|
let channel = self.channel();
|
||||||
|
|
||||||
|
let msg = WorkTask::TimerTrigger {
|
||||||
|
handler_id: self.handler,
|
||||||
|
token: token,
|
||||||
|
};
|
||||||
|
|
||||||
|
let delay = TimeDuration::from_std(delay)
|
||||||
|
.map_err(|e| ::std::io::Error::new(::std::io::ErrorKind::Other, e))?;
|
||||||
|
let guard = self.shared.timer.lock().schedule_with_delay(delay, move || {
|
||||||
|
channel.send_raw(msg.clone());
|
||||||
|
});
|
||||||
|
|
||||||
|
self.shared.timers.lock().insert(token, guard);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete a timer.
|
||||||
|
pub fn clear_timer(&self, token: TimerToken) -> Result<(), IoError> {
|
||||||
|
self.shared.timers.lock().remove(&token);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Broadcast a message to other IO clients
|
||||||
|
pub fn message(&self, message: Message) -> Result<(), IoError> {
|
||||||
|
if let Some(ref channel) = *self.shared.channel.lock() {
|
||||||
|
channel.push(WorkTask::UserMessage(Arc::new(message)));
|
||||||
|
}
|
||||||
|
for thread in self.shared.threads.read().iter() {
|
||||||
|
thread.unpark();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get message channel
|
||||||
|
pub fn channel(&self) -> IoChannel<Message> {
|
||||||
|
IoChannel { shared: Arc::downgrade(&self.shared) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unregister current IO handler.
|
||||||
|
pub fn unregister_handler(&self) -> Result<(), IoError> {
|
||||||
|
self.shared.handlers.write().remove(self.handler);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows sending messages into the event loop. All the IO handlers will get the message
|
||||||
|
/// in the `message` callback.
|
||||||
|
pub struct IoChannel<Message> where Message: Send + Sync + 'static {
|
||||||
|
shared: Weak<Shared<Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Clone for IoChannel<Message> where Message: Send + Sync + 'static {
|
||||||
|
fn clone(&self) -> IoChannel<Message> {
|
||||||
|
IoChannel {
|
||||||
|
shared: self.shared.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> IoChannel<Message> where Message: Send + Sync + 'static {
|
||||||
|
/// Send a message through the channel
|
||||||
|
pub fn send(&self, message: Message) -> Result<(), IoError> {
|
||||||
|
if let Some(shared) = self.shared.upgrade() {
|
||||||
|
match *shared.channel.lock() {
|
||||||
|
Some(ref channel) => channel.push(WorkTask::UserMessage(Arc::new(message))),
|
||||||
|
None => self.send_sync(message)?
|
||||||
|
};
|
||||||
|
|
||||||
|
for thread in shared.threads.read().iter() {
|
||||||
|
thread.unpark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a message through the channel and handle it synchronously
|
||||||
|
pub fn send_sync(&self, message: Message) -> Result<(), IoError> {
|
||||||
|
if let Some(shared) = self.shared.upgrade() {
|
||||||
|
for id in 0 .. MAX_HANDLERS {
|
||||||
|
if let Some(h) = shared.handlers.read().get(id) {
|
||||||
|
let handler = h.clone();
|
||||||
|
let ctxt = IoContext { handler: id, shared: shared.clone() };
|
||||||
|
handler.message(&ctxt, &message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send low level io message
|
||||||
|
fn send_raw(&self, message: WorkTask<Message>) {
|
||||||
|
if let Some(shared) = self.shared.upgrade() {
|
||||||
|
if let Some(ref channel) = *shared.channel.lock() {
|
||||||
|
channel.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
for thread in shared.threads.read().iter() {
|
||||||
|
thread.unpark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new channel disconnected from an event loop.
|
||||||
|
pub fn disconnected() -> IoChannel<Message> {
|
||||||
|
IoChannel {
|
||||||
|
shared: Weak::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// General IO Service. Starts an event loop and dispatches IO requests.
|
||||||
|
/// 'Message' is a notification message type
|
||||||
|
pub struct IoService<Message> where Message: Send + Sync + 'static {
|
||||||
|
thread_joins: Mutex<Vec<thread::JoinHandle<()>>>,
|
||||||
|
shared: Arc<Shared<Message>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct shared throughout the whole implementation.
|
||||||
|
struct Shared<Message> where Message: Send + Sync + 'static {
|
||||||
|
// All the I/O handlers that have been registered.
|
||||||
|
handlers: RwLock<Slab<Arc<IoHandler<Message>>>>,
|
||||||
|
// All the background threads, so that we can unpark them.
|
||||||
|
threads: RwLock<Vec<thread::Thread>>,
|
||||||
|
// Used to create timeouts.
|
||||||
|
timer: Mutex<Timer>,
|
||||||
|
// List of created timers. We need to keep them in a data struct so that we can cancel them if
|
||||||
|
// necessary.
|
||||||
|
timers: Mutex<FnvHashMap<TimerToken, TimerGuard>>,
|
||||||
|
// Channel used to send work to the worker threads.
|
||||||
|
channel: Mutex<Option<chase_lev::Worker<WorkTask<Message>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messages used to communicate with the event loop from other threads.
|
||||||
|
enum WorkTask<Message> where Message: Send + Sized {
|
||||||
|
Shutdown,
|
||||||
|
TimerTrigger {
|
||||||
|
handler_id: HandlerId,
|
||||||
|
token: TimerToken,
|
||||||
|
},
|
||||||
|
UserMessage(Arc<Message>)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Clone for WorkTask<Message> where Message: Send + Sized {
|
||||||
|
fn clone(&self) -> WorkTask<Message> {
|
||||||
|
match *self {
|
||||||
|
WorkTask::Shutdown => WorkTask::Shutdown,
|
||||||
|
WorkTask::TimerTrigger { handler_id, token } => WorkTask::TimerTrigger { handler_id, token },
|
||||||
|
WorkTask::UserMessage(ref msg) => WorkTask::UserMessage(msg.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> IoService<Message> where Message: Send + Sync + 'static {
|
||||||
|
/// Starts IO event loop
|
||||||
|
pub fn start() -> Result<IoService<Message>, IoError> {
|
||||||
|
let (tx, rx) = chase_lev::deque();
|
||||||
|
|
||||||
|
let shared = Arc::new(Shared {
|
||||||
|
handlers: RwLock::new(Slab::with_capacity(MAX_HANDLERS)),
|
||||||
|
threads: RwLock::new(Vec::new()),
|
||||||
|
timer: Mutex::new(Timer::new()),
|
||||||
|
timers: Mutex::new(FnvHashMap::default()),
|
||||||
|
channel: Mutex::new(Some(tx)),
|
||||||
|
});
|
||||||
|
|
||||||
|
let thread_joins = (0 .. num_cpus::get()).map(|_| {
|
||||||
|
let rx = rx.clone();
|
||||||
|
let shared = shared.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
do_work(&shared, rx)
|
||||||
|
})
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
*shared.threads.write() = thread_joins.iter().map(|t| t.thread().clone()).collect();
|
||||||
|
|
||||||
|
Ok(IoService {
|
||||||
|
thread_joins: Mutex::new(thread_joins),
|
||||||
|
shared,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stops the IO service.
|
||||||
|
pub fn stop(&self) {
|
||||||
|
trace!(target: "shutdown", "[IoService] Closing...");
|
||||||
|
// Clear handlers so that shared pointers are not stuck on stack
|
||||||
|
// in Channel::send_sync
|
||||||
|
self.shared.handlers.write().clear();
|
||||||
|
let channel = self.shared.channel.lock().take();
|
||||||
|
let mut thread_joins = self.thread_joins.lock();
|
||||||
|
if let Some(channel) = channel {
|
||||||
|
for _ in 0 .. thread_joins.len() {
|
||||||
|
channel.push(WorkTask::Shutdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for thread in thread_joins.drain(..) {
|
||||||
|
thread.thread().unpark();
|
||||||
|
thread.join().unwrap_or_else(|e| {
|
||||||
|
debug!(target: "shutdown", "Error joining IO service worker thread: {:?}", e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
trace!(target: "shutdown", "[IoService] Closed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register an IO handler with the event loop.
|
||||||
|
pub fn register_handler(&self, handler: Arc<IoHandler<Message>+Send>) -> Result<(), IoError> {
|
||||||
|
let id = self.shared.handlers.write().insert(handler.clone());
|
||||||
|
assert!(id <= MAX_HANDLERS, "Too many handlers registered");
|
||||||
|
let ctxt = IoContext { handler: id, shared: self.shared.clone() };
|
||||||
|
handler.initialize(&ctxt);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a message over the network. Normaly `HostIo::send` should be used. This can be used from non-io threads.
|
||||||
|
pub fn send_message(&self, message: Message) -> Result<(), IoError> {
|
||||||
|
if let Some(ref channel) = *self.shared.channel.lock() {
|
||||||
|
channel.push(WorkTask::UserMessage(Arc::new(message)));
|
||||||
|
}
|
||||||
|
for thread in self.shared.threads.read().iter() {
|
||||||
|
thread.unpark();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new message channel
|
||||||
|
#[inline]
|
||||||
|
pub fn channel(&self) -> IoChannel<Message> {
|
||||||
|
IoChannel {
|
||||||
|
shared: Arc::downgrade(&self.shared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Drop for IoService<Message> where Message: Send + Sync {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_work<Message>(shared: &Arc<Shared<Message>>, rx: chase_lev::Stealer<WorkTask<Message>>)
|
||||||
|
where Message: Send + Sync + 'static
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
match rx.steal() {
|
||||||
|
chase_lev::Steal::Abort => continue,
|
||||||
|
chase_lev::Steal::Empty => thread::park(),
|
||||||
|
chase_lev::Steal::Data(WorkTask::Shutdown) => break,
|
||||||
|
chase_lev::Steal::Data(WorkTask::UserMessage(message)) => {
|
||||||
|
for id in 0 .. MAX_HANDLERS {
|
||||||
|
if let Some(handler) = shared.handlers.read().get(id) {
|
||||||
|
let ctxt = IoContext { handler: id, shared: shared.clone() };
|
||||||
|
handler.message(&ctxt, &message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chase_lev::Steal::Data(WorkTask::TimerTrigger { handler_id, token }) => {
|
||||||
|
if let Some(handler) = shared.handlers.read().get(handler_id) {
|
||||||
|
let ctxt = IoContext { handler: handler_id, shared: shared.clone() };
|
||||||
|
handler.timeout(&ctxt, token);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,21 +18,14 @@ use std::sync::Arc;
|
|||||||
use std::thread::{JoinHandle, self};
|
use std::thread::{JoinHandle, self};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||||
use crossbeam::sync::chase_lev;
|
use crossbeam::sync::chase_lev;
|
||||||
use service::{HandlerId, IoChannel, IoContext};
|
use service_mio::{HandlerId, IoChannel, IoContext};
|
||||||
use IoHandler;
|
use IoHandler;
|
||||||
use std::cell::Cell;
|
use LOCAL_STACK_SIZE;
|
||||||
|
|
||||||
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
|
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
|
||||||
|
|
||||||
const STACK_SIZE: usize = 16*1024*1024;
|
const STACK_SIZE: usize = 16*1024*1024;
|
||||||
|
|
||||||
thread_local! {
|
|
||||||
/// Stack size
|
|
||||||
/// Should be modified if it is changed in Rust since it is no way
|
|
||||||
/// to know or get it
|
|
||||||
pub static LOCAL_STACK_SIZE: Cell<usize> = Cell::new(::std::env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok()).unwrap_or(2 * 1024 * 1024));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum WorkType<Message> {
|
pub enum WorkType<Message> {
|
||||||
Readable,
|
Readable,
|
||||||
Writable,
|
Writable,
|
||||||
|
@ -19,7 +19,7 @@ libc = "0.2.7"
|
|||||||
parking_lot = "0.5"
|
parking_lot = "0.5"
|
||||||
ansi_term = "0.10"
|
ansi_term = "0.10"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
ethcore-io = { path = "../io" }
|
ethcore-io = { path = "../io", features = ["mio"] }
|
||||||
ethcore-bytes = { path = "../bytes" }
|
ethcore-bytes = { path = "../bytes" }
|
||||||
ethcore-crypto = { path = "../../ethcore/crypto" }
|
ethcore-crypto = { path = "../../ethcore/crypto" }
|
||||||
ethcore-logger = { path ="../../logger" }
|
ethcore-logger = { path ="../../logger" }
|
||||||
|
Loading…
Reference in New Issue
Block a user