diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d60a3b63f..abbd6a18f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: cmake --build . --config Release - name: Run rust tests - run: cargo test --verbose --release --features=logger-autoinit --features=shared-memory + run: cargo test --verbose --release --features=logger-autoinit - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/CMakeLists.txt b/CMakeLists.txt index cb9000cf5..dff87d445 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ enable_testing() # declare_cache_var_true_if_vscode(ZENOHC_BUILD_IN_SOURCE_TREE "Do build inside source tree") declare_cache_var(ZENOHC_BUILD_WITH_LOGGER_AUTOINIT TRUE BOOL "Enable logger-autoinit zenoh-c feature") -declare_cache_var(ZENOHC_BUILD_WITH_SHARED_MEMORY TRUE BOOL "Enable shared-memory zenoh-c feature") +declare_cache_var(ZENOHC_BUILD_WITH_SHARED_MEMORY FALSE BOOL "Enable shared-memory zenoh-c feature") declare_cache_var(ZENOHC_CUSTOM_TARGET "" STRING "Rust target for cross compilation, 'aarch64-unknown-linux-gnu' for example") declare_cache_var(ZENOHC_CARGO_CHANNEL "" STRING "Cargo channel parameter. Should be '+stable', '+nightly' or empty value") declare_cache_var(ZENOHC_CARGO_FLAGS "" STRING "Additional cargo flags") diff --git a/Cargo.lock b/Cargo.lock index a87099c8a..0fd1a01fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3904,4 +3904,4 @@ dependencies = [ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index af800bf08..8b9e9bdcd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,9 @@ build = "build.rs" [features] logger-autoinit = [] -shared-memory = ["zenoh/shared-memory"] -default = ["zenoh/default"] +shared-memory = ["zenoh/shared-memory", "zenoh-ext/shared-memory", "zenoh-protocol/shared-memory"] +unstable = ["zenoh/unstable", "zenoh-ext/unstable"] +default = ["zenoh/default", "unstable"] [badges] maintenance = { status = "actively-developed" } @@ -52,11 +53,10 @@ rand = "0.8.5" spin = "0.9.5" unwrap-infallible = "0.1.5" const_format = "0.2.32" -# shared-memory enabled for zenoh even if zenoh-c "shared-memory" feature is disabled. This is to make "std::mem::transmute" work for `ZSLice` -zenoh = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["shared-memory", "unstable"], default-features = false } -zenoh-protocol = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["shared-memory"] } +zenoh = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", default-features = false } +zenoh-protocol = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } zenoh-util = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } -zenoh-ext = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["unstable"] } +zenoh-ext = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } flume = "*" [build-dependencies] @@ -68,7 +68,7 @@ fs_extra = "1.3.0" [lib] path="src/lib.rs" -name = "zenohc" +name = "zenohcd" crate-type = ["cdylib", "staticlib"] doctest = false diff --git a/Cargo.toml.in b/Cargo.toml.in index 160298690..1b11c5d9b 100644 --- a/Cargo.toml.in +++ b/Cargo.toml.in @@ -32,8 +32,9 @@ build = "@CARGO_PROJECT_DIR@build.rs" [features] logger-autoinit = [] -shared-memory = ["zenoh/shared-memory"] -default = ["zenoh/default"] +shared-memory = ["zenoh/shared-memory", "zenoh-ext/shared-memory", "zenoh-protocol/shared-memory"] +unstable = ["zenoh/unstable", "zenoh-ext/unstable"] +default = ["zenoh/default", "unstable"] [badges] maintenance = { status = "actively-developed" } @@ -52,11 +53,10 @@ rand = "0.8.5" spin = "0.9.5" unwrap-infallible = "0.1.5" const_format = "0.2.32" -# shared-memory enabled for zenoh even if zenoh-c "shared-memory" feature is disabled. This is to make "std::mem::transmute" work for `ZSLice` -zenoh = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["shared-memory", "unstable"], default-features = false } -zenoh-protocol = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["shared-memory"] } +zenoh = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", default-features = false } +zenoh-protocol = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } zenoh-util = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } -zenoh-ext = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["unstable"] } +zenoh-ext = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } flume = "*" [build-dependencies] diff --git a/build-resources/opaque-types/Cargo.lock b/build-resources/opaque-types/Cargo.lock index a1561915d..32a17410e 100644 --- a/build-resources/opaque-types/Cargo.lock +++ b/build-resources/opaque-types/Cargo.lock @@ -291,6 +291,18 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bincode" version = "1.3.3" @@ -392,6 +404,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const_format" version = "0.2.32" @@ -412,6 +430,22 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -452,6 +486,23 @@ dependencies = [ "typenum", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -459,6 +510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -585,9 +637,15 @@ dependencies = [ "futures-core", "futures-sink", "nanorand", - "spin", + "spin 0.9.8", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -824,12 +882,39 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -942,6 +1027,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" @@ -959,6 +1047,12 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.1.3" @@ -1084,6 +1178,17 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "libc", +] + [[package]] name = "no-std-net" version = "0.6.0" @@ -1110,6 +1215,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -1119,6 +1241,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1126,6 +1259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1164,6 +1298,12 @@ dependencies = [ "zenoh-protocol", ] +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "option-ext" version = "0.2.0" @@ -1203,6 +1343,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1329,6 +1478,27 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pnet_base" version = "0.34.0" @@ -1416,6 +1586,54 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.21.12", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand", + "ring 0.16.20", + "rustc-hash", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2 0.5.7", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -1510,6 +1728,21 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -1520,8 +1753,8 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -1541,18 +1774,44 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", + "base64 0.21.7", "bitflags 2.5.0", "serde", "serde_derive", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1589,6 +1848,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.22.4" @@ -1596,28 +1867,82 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.4", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "rustls-webpki" version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -1632,6 +1957,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "schemars" version = "0.8.21" @@ -1662,6 +1996,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -1672,6 +2016,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.23" @@ -1756,6 +2123,17 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1800,7 +2178,7 @@ checksum = "ba8593196da75d9dc4f69349682bd4c2099f8cde114257d1ef7ef1b33d1aba54" dependencies = [ "cfg-if", "libc", - "nix", + "nix 0.23.2", "rand", "win-sys", ] @@ -1823,6 +2201,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "siphasher" version = "0.3.11" @@ -1864,6 +2252,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -1873,6 +2267,16 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stabby" version = "5.0.1" @@ -1999,6 +2403,21 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "token-cell" version = "1.5.0" @@ -2036,6 +2455,39 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -2074,6 +2526,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2142,6 +2595,25 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -2175,15 +2647,30 @@ dependencies = [ "log", "rand", "serde", - "spin", + "spin 0.9.8", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.4" @@ -2196,6 +2683,12 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -2219,6 +2712,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "uuid" version = "1.8.0" @@ -2364,6 +2874,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c452ad30530b54a4d8e71952716a212b08efd0f3562baa66c29a618b07da7c3" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "win-sys" version = "0.3.1" @@ -2593,7 +3112,7 @@ source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa6 dependencies = [ "ahash", "async-trait", - "base64", + "base64 0.21.7", "const_format", "event-listener 4.0.3", "flume", @@ -2754,6 +3273,12 @@ dependencies = [ "async-trait", "zenoh-config", "zenoh-link-commons", + "zenoh-link-quic", + "zenoh-link-tcp", + "zenoh-link-tls", + "zenoh-link-udp", + "zenoh-link-unixsock_stream", + "zenoh-link-ws", "zenoh-protocol", "zenoh-result", ] @@ -2766,8 +3291,8 @@ dependencies = [ "async-trait", "flume", "futures", - "rustls", - "rustls-webpki", + "rustls 0.22.4", + "rustls-webpki 0.102.4", "serde", "tokio", "tokio-util", @@ -2782,6 +3307,146 @@ dependencies = [ "zenoh-util", ] +[[package]] +name = "zenoh-link-quic" +version = "0.11.0-dev" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa626afc47296eaa0d569166ce035a0ab0ce6" +dependencies = [ + "async-trait", + "base64 0.21.7", + "futures", + "quinn", + "rustls 0.21.12", + "rustls-native-certs 0.7.0", + "rustls-pemfile 1.0.4", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "secrecy", + "tokio", + "tokio-rustls 0.24.1", + "tokio-util", + "tracing", + "webpki-roots", + "zenoh-collections", + "zenoh-config", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-tcp" +version = "0.11.0-dev" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa626afc47296eaa0d569166ce035a0ab0ce6" +dependencies = [ + "async-trait", + "tokio", + "tokio-util", + "tracing", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-tls" +version = "0.11.0-dev" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa626afc47296eaa0d569166ce035a0ab0ce6" +dependencies = [ + "async-trait", + "base64 0.21.7", + "futures", + "rustls 0.22.4", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "secrecy", + "tokio", + "tokio-rustls 0.25.0", + "tokio-util", + "tracing", + "webpki-roots", + "zenoh-collections", + "zenoh-config", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-udp" +version = "0.11.0-dev" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa626afc47296eaa0d569166ce035a0ab0ce6" +dependencies = [ + "async-trait", + "socket2 0.5.7", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-collections", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-unixsock_stream" +version = "0.11.0-dev" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa626afc47296eaa0d569166ce035a0ab0ce6" +dependencies = [ + "async-trait", + "futures", + "nix 0.27.1", + "tokio", + "tokio-util", + "tracing", + "uuid", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", +] + +[[package]] +name = "zenoh-link-ws" +version = "0.11.0-dev" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=dev/1.0.0#2d9fa626afc47296eaa0d569166ce035a0ab0ce6" +dependencies = [ + "async-trait", + "futures-util", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tracing", + "url", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-util", +] + [[package]] name = "zenoh-macros" version = "0.11.0-dev" @@ -2909,6 +3574,7 @@ dependencies = [ "paste", "rand", "ringbuffer-spsc", + "rsa", "serde", "sha3", "tokio", diff --git a/build-resources/opaque-types/Cargo.toml b/build-resources/opaque-types/Cargo.toml index 65205bbf9..e75615862 100644 --- a/build-resources/opaque-types/Cargo.toml +++ b/build-resources/opaque-types/Cargo.toml @@ -5,10 +5,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +shared-memory = ["zenoh/shared-memory", "zenoh-ext/shared-memory", "zenoh-protocol/shared-memory"] +unstable = ["zenoh/unstable", "zenoh-ext/unstable"] +default = ["zenoh/default", "unstable"] + [dependencies] -# shared-memory enabled for zenoh even if zenoh-c "shared-memory" feature is disabled. This is to make "std::mem::transmute" work for `ZSLice` -zenoh = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["shared-memory", "unstable"], default-features = false } -zenoh-ext = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["unstable"] } -zenoh-protocol = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", features = ["shared-memory"] } +zenoh = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0", default-features = false } +zenoh-ext = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } +zenoh-protocol = { version = "0.11.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "dev/1.0.0" } const_format = "0.2.32" flume = "*" \ No newline at end of file diff --git a/build-resources/opaque-types/src/lib.rs b/build-resources/opaque-types/src/lib.rs index eec95a368..0ad8c6095 100644 --- a/build-resources/opaque-types/src/lib.rs +++ b/build-resources/opaque-types/src/lib.rs @@ -29,6 +29,15 @@ use zenoh::time::Timestamp; use zenoh::value::Value; use zenoh_protocol::core::EntityGlobalId; +use core::ffi::c_void; + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +use zenoh::shm::{ + SharedMemoryClient, ProtocolID, SharedMemoryClientStorage, AllocLayout,DynamicProtocolID, BufAllocResult, + ChunkAllocResult, MemoryLayout, ZShmMut, ZShm, zshm, zshmmut, SharedMemoryProvider, ChunkDescriptor, + SharedMemoryProviderBackend, PosixSharedMemoryProviderBackend, StaticProtocolID, POSIX_PROTOCOL_ID +}; + #[macro_export] macro_rules! get_opaque_type_data { ($src_type:ty, $name:ident) => { @@ -48,7 +57,7 @@ macro_rules! get_opaque_type_data { /// A serialized Zenoh data. /// /// To minimize copies and reallocations, Zenoh may provide data in several separate buffers. -get_opaque_type_data!(Option, z_owned_bytes_t); +get_opaque_type_data!(ZBytes, z_owned_bytes_t); /// A loaned serialized Zenoh data. get_opaque_type_data!(ZBytes, z_loaned_bytes_t); @@ -245,6 +254,149 @@ get_opaque_type_data!(Option, z_owned_hello_t); /// A loaned hello message. get_opaque_type_data!(Hello, z_loaned_hello_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned SHM Client +get_opaque_type_data!(Option>, z_owned_shared_memory_client_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned list of SHM Clients +get_opaque_type_data!(Option)>>, zc_owned_shared_memory_client_list_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned list of SHM Clients +get_opaque_type_data!(Vec<(ProtocolID, Arc)>, zc_loaned_shared_memory_client_list_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned SHM Client Storage +get_opaque_type_data!(Option>, z_owned_shared_memory_client_storage_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned SHM Client Storage +get_opaque_type_data!(Arc, z_loaned_shared_memory_client_storage_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned MemoryLayout +get_opaque_type_data!(Option, z_owned_memory_layout_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned MemoryLayout +get_opaque_type_data!(MemoryLayout, z_loaned_memory_layout_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned ChunkAllocResult +get_opaque_type_data!(Option, z_owned_chunk_alloc_result_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned ChunkAllocResult +get_opaque_type_data!(ChunkAllocResult, z_loaned_chunk_alloc_result_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned BufAllocResult +get_opaque_type_data!(Option, z_owned_buf_alloc_result_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned BufAllocResult +get_opaque_type_data!(BufAllocResult, z_loaned_buf_alloc_result_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned ZShm slice +get_opaque_type_data!(Option, z_owned_shm_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned ZShm slice +get_opaque_type_data!(zshm, z_loaned_shm_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned ZShmMut slice +get_opaque_type_data!(Option, z_owned_shm_mut_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned ZShmMut slice +get_opaque_type_data!(zshmmut, z_loaned_shm_mut_t); + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +#[derive(Debug)] +#[repr(C)] +struct DummyCallbacks { + alloc_fn: unsafe extern "C" fn(), + free_fn: unsafe extern "C" fn(), + defragment_fn: unsafe extern "C" fn() -> usize, + available_fn: unsafe extern "C" fn() -> usize, + layout_for_fn: unsafe extern "C" fn(), +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +#[derive(Debug)] +#[repr(C)] +struct DummyContext { + context: *mut c_void, + delete_fn: unsafe extern "C" fn(*mut c_void), +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +#[derive(Debug)] +struct DummySHMProviderBackend { + context: DummyContext, + callbacks: DummyCallbacks, +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +impl SharedMemoryProviderBackend for DummySHMProviderBackend { + fn alloc(&self, layout: &MemoryLayout) -> ChunkAllocResult { + todo!() + } + + fn free(&self, chunk: &ChunkDescriptor) { + todo!() + } + + fn defragment(&self) -> usize { + todo!() + } + + fn available(&self) -> usize { + todo!() + } + + fn layout_for(&self, layout: MemoryLayout) -> zenoh::core::Result { + todo!() + } +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +type DummySHMProvider = SharedMemoryProvider; + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +type PosixSHMProvider = + SharedMemoryProvider, PosixSharedMemoryProviderBackend>; + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +enum CDummySHMProvider { + Posix(PosixSHMProvider), + Dynamic(DummySHMProvider), +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned SharedMemoryProvider +get_opaque_type_data!(Option, z_owned_shared_memory_provider_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned SharedMemoryProvider +get_opaque_type_data!(CDummySHMProvider, z_loaned_shared_memory_provider_t); + + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +type PosixAllocLayout = AllocLayout<'static, StaticProtocolID, PosixSharedMemoryProviderBackend>; + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +type DummyDynamicAllocLayout = AllocLayout<'static, DynamicProtocolID, DummySHMProviderBackend>; + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +enum CSHMLayout { + Posix(PosixAllocLayout), + Dynamic(DummyDynamicAllocLayout), +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// An owned SharedMemoryProvider's AllocLayout +get_opaque_type_data!(Option, z_owned_alloc_layout_t); +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// A loaned SharedMemoryProvider's AllocLayout +get_opaque_type_data!(CSHMLayout, z_loaned_alloc_layout_t); + /// An owned Zenoh fifo sample handler. get_opaque_type_data!(Option>, z_owned_fifo_handler_sample_t); /// An loaned Zenoh fifo sample handler. diff --git a/build.rs b/build.rs index d4cdfc41e..0b74f2629 100644 --- a/build.rs +++ b/build.rs @@ -2,6 +2,7 @@ use fs2::FileExt; use regex::Regex; use std::collections::HashSet; use std::env; +use std::fs::File; use std::io::{Read, Write}; use std::process::{Command, Stdio}; use std::{ @@ -12,6 +13,7 @@ use std::{ }; const GENERATION_PATH: &str = "include/zenoh-gen.h"; +const PREPROCESS_PATH: &str = "include/zenoh-cpp.h"; const SPLITGUIDE_PATH: &str = "splitguide.yaml"; const HEADER: &str = r"// // Copyright (c) 2022 ZettaScale Technology @@ -32,13 +34,52 @@ const HEADER: &str = r"// #endif "; +fn preprocess_header(input: &str, output: &str) { + let mut feature_args: Vec<&str> = vec![]; + #[cfg(feature = "shared-memory")] + { + feature_args.push("-DSHARED_MEMORY"); + } + #[cfg(feature = "unstable")] + { + feature_args.push("-DUNSTABLE"); + } + + let cpp = Command::new("cpp") + .arg("-E") + .arg("-DZENOHC_API= ") + .arg("-D_Bool=bool") + .arg("-D__const=const") + .args(feature_args) + .arg(input) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + let sed = Command::new("sed") + .arg("/^#/d") + .stdin(Stdio::from(cpp.stdout.unwrap())) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + let sed_out = sed.wait_with_output().unwrap(); + assert!(!sed_out.stdout.is_empty()); + + let mut out = File::create(output).expect("failed to open output"); + out.write_all(&sed_out.stdout).unwrap(); +} + fn main() { generate_opaque_types(); cbindgen::generate(std::env::var("CARGO_MANIFEST_DIR").unwrap()) .expect("Unable to generate bindings") .write_to_file(GENERATION_PATH); - create_generics_header(GENERATION_PATH, "include/zenoh_macros.h"); + preprocess_header(GENERATION_PATH, PREPROCESS_PATH); + create_generics_header(PREPROCESS_PATH, "include/zenoh_macros.h"); + std::fs::remove_file(PREPROCESS_PATH).unwrap(); + configure(); let split_guide = SplitGuide::from_yaml(SPLITGUIDE_PATH); split_bindings(&split_guide).unwrap(); @@ -73,8 +114,22 @@ fn produce_opaque_types_data() -> PathBuf { let output_file_path = current_folder.join("./.build_resources_opaque_types.txt"); let out_file = std::fs::File::create(output_file_path.clone()).unwrap(); let stdio = Stdio::from(out_file); + + let mut feature_args: Vec<&str> = vec![]; + #[cfg(feature = "shared-memory")] + { + feature_args.push("-F"); + feature_args.push("shared-memory"); + } + #[cfg(feature = "unstable")] + { + feature_args.push("-F"); + feature_args.push("unstable"); + } + let _ = Command::new("cargo") .arg("build") + .args(feature_args) .arg("--target") .arg(target) .arg("--manifest-path") @@ -116,9 +171,11 @@ pub struct {type_name} {{ } data_out += &s; } - for d in docs.keys() { - panic!("Failed to find type information for opaque type: {d}"); - } + // todo: in order to support rust features in opaque_types, we should respect features here. + // I will remove it for a while, maybe we'll implement this later + //for d in docs.keys() { + // panic!("Failed to find type information for opaque type: {d}"); + //} std::fs::write(path_out, data_out).unwrap(); } @@ -182,6 +239,11 @@ fn configure() { .unwrap(); file.lock_exclusive().unwrap(); file.write_all(content.as_bytes()).unwrap(); + #[cfg(feature = "shared-memory")] + file.write_all("#define SHARED_MEMORY\n".as_bytes()) + .unwrap(); + #[cfg(feature = "unstable")] + file.write_all("#define UNSTABLE\n".as_bytes()).unwrap(); file.unlock().unwrap(); } @@ -296,6 +358,16 @@ impl SplitGuide { name, rules .into_iter() + .filter_map(|s| { + let mut split = s.split('#'); + let val = split.next().unwrap(); + for feature in split { + if !Self::test_feature(feature) { + return None; + } + } + Some(val.to_owned()) + }) .map(|mut s| match s.as_str() { ":functions" => SplitRule::Brand(RecordType::Function), ":typedefs" => SplitRule::Brand(RecordType::Typedef), @@ -344,6 +416,15 @@ impl SplitGuide { }) }) } + fn test_feature(feature: &str) -> bool { + match feature { + #[cfg(feature = "shared-memory")] + "shared-memory" => true, + #[cfg(feature = "unstable")] + "unstable" => true, + _ => false, + } + } } fn group_tokens(stream: Tokenizer) -> Result, String> { diff --git a/cbindgen.toml b/cbindgen.toml index f0704fe81..0bf296444 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -57,6 +57,10 @@ usize_is_size_t = true "target_arch = aarch64" = "TARGET_ARCH_AARCH64" "target_arch = x86_64" = "TARGET_ARCH_X86_64" "target_arch = arm" = "TARGET_ARCH_ARM" +"target_os = windows" = "_WIN32" +"target_os = linux" = "__unix__" +"feature = shared-memory" = "SHARED_MEMORY" +"feature = unstable" = "UNSTABLE" [export] include = [] diff --git a/docs/api.rst b/docs/api.rst index 133f5a497..7db3cf24a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -51,8 +51,8 @@ String ------ Types ^^^^^ -.. doxygenstruct:: z_owned_str_t -.. doxygenstruct:: z_view_str_t +.. doxygenstruct:: z_owned_string_t +.. doxygenstruct:: z_view_string_t .. doxygenstruct:: z_loaned_str_t Functions diff --git a/docs/examples.rst b/docs/examples.rst index 7c6819f89..4bd6a85f4 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -53,9 +53,9 @@ Subscribe #include "zenoh.h" void data_handler(const z_loaned_sample_t *sample, const void *arg) { - z_view_str_t key_string; - z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_string); - z_owned_str_t payload_string; + z_view_string_t key_string; + z_keyexpr_to_string(z_sample_keyexpr(sample), &key_string); + z_owned_string_t payload_string; z_bytes_decode_into_string(z_sample_payload(sample), &payload_string); printf(">> Received (%.*s, %.*s)\n", (int)z_str_len(z_loan(key_string)), z_str_data(z_loan(key_string)), @@ -126,9 +126,9 @@ Query for (z_recv(z_loan(handler), &reply); z_check(reply); z_recv(z_loan(handler), &reply)) { if (z_reply_is_ok(&reply)) { const z_loaned_sample_t* sample = z_reply_ok(&reply); - z_view_str_t key_string; - z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_string); - z_owned_str_t payload_string; + z_view_string_t key_string; + z_keyexpr_to_string(z_sample_keyexpr(sample), &key_string); + z_owned_string_t payload_string; z_bytes_decode_into_string(z_sample_payload(sample), &payload_string); printf(">> Received (%.*s, %.*s)\n", (int)z_str_len(z_loan(key_string)), z_str_data(z_loan(key_string)), @@ -154,12 +154,12 @@ Queryable #include "zenoh.h" void query_handler(const z_loaned_query_t *query, void *context) { - z_view_str_t key_string; - z_keyexpr_as_view_string(z_query_keyexpr(query), &key_string); + z_view_string_t key_string; + z_keyexpr_to_string(z_query_keyexpr(query), &key_string); const z_loaned_bytes_t* payload = z_value_payload(z_query_value(query)); if (z_bytes_len(payload) > 0) { - z_owned_str_t payload_string; + z_owned_string_t payload_string; z_bytes_decode_into_string(payload, &payload_string); printf(">> [Queryable ] Received Query '%.*s' with value '%.*s'\n", diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ad0fec92f..87e36a1d3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -17,6 +17,13 @@ file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c") foreach(file ${files}) get_filename_component(target ${file} NAME_WE) + # Exclude SHM examples if SHM feature is disabled + if(NOT(ZENOHC_BUILD_WITH_SHARED_MEMORY)) + if(${target} MATCHES "^.*_shm.*$") + continue() + endif() + endif() + # FIXME: remove once zenoh time primitives are available and examples updated if(NOT(UNIX) AND(${target} STREQUAL "z_ping" OR ${target} STREQUAL "z_pong" OR ${target} STREQUAL "z_sub_thr")) continue() diff --git a/examples/z_get_shm.c b/examples/z_get_shm.c new file mode 100644 index 000000000..e226f26a2 --- /dev/null +++ b/examples/z_get_shm.c @@ -0,0 +1,127 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, + +#include +#include + +#include "zenoh.h" + +int main(int argc, char** argv) { + char* expr = "demo/example/**"; + char* value = NULL; + switch (argc) { + default: + case 3: + value = argv[2]; + case 2: + expr = argv[1]; + break; + case 1: + value = "Test Value"; + break; + } + size_t value_len = value ? strlen(value) : 0; + + z_view_keyexpr_t keyexpr; + if (z_view_keyexpr_from_string(&keyexpr, expr) < 0) { + printf("%s is not a valid key expression", expr); + exit(-1); + } + z_owned_config_t config; + z_config_default(&config); + if (argc > 3) { + if (zc_config_insert_json(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, argv[3]) < 0) { + printf( + "Couldn't insert value `%s` in configuration at `%s`. This is likely because `%s` expects a " + "JSON-serialized list of strings\n", + argv[3], Z_CONFIG_CONNECT_KEY, Z_CONFIG_CONNECT_KEY); + exit(-1); + } + } + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config))) { + printf("Unable to open session!\n"); + exit(-1); + } + + // Create SHM Provider + z_alloc_alignment_t alignment = {0}; + z_owned_memory_layout_t layout; + z_memory_layout_new(&layout, value_len, alignment); + z_owned_shared_memory_provider_t provider; + z_posix_shared_memory_provider_new(&provider, z_loan(layout)); + z_owned_buf_alloc_result_t alloc; + z_shared_memory_provider_alloc(&alloc, z_loan(provider), value_len, alignment); + + // Allocate SHM Buffer + z_owned_shm_mut_t shm_mut; + z_alloc_error_t shm_error; + z_buf_alloc_result_unwrap(z_move(alloc), &shm_mut, &shm_error); + if (!z_check(shm_mut)) { + printf("Unexpected failure during SHM buffer allocation..."); + return -1; + } + // Fill SHM Buffer with data + uint8_t* data = z_shm_mut_data_mut(z_loan_mut(shm_mut)); + memcpy(data, value, value_len); + // Convert mutable SHM Buffer into immutable one (to be able to make it's ref copies) + z_owned_shm_t shm; + z_shm_from_mut(&shm, z_move(shm_mut)); + const z_loaned_shm_t* loaned_shm = z_loan(shm); + + printf("Sending Query '%s'...\n", expr); + z_owned_fifo_handler_reply_t handler; + z_owned_closure_reply_t closure; + z_fifo_channel_reply_new(&closure, &handler, 16); + + z_get_options_t opts; + z_get_options_default(&opts); + + z_owned_bytes_t payload; + if (value != NULL) { + z_bytes_encode_from_shm_copy(&payload, z_loan(shm)); + opts.payload = &payload; + } + z_get(z_loan(s), z_loan(keyexpr), "", z_move(closure), + z_move(opts)); // here, the send is moved and will be dropped by zenoh when adequate + z_owned_reply_t reply; + + for (z_recv(z_loan(handler), &reply); z_check(reply); z_recv(z_loan(handler), &reply)) { + if (z_reply_is_ok(z_loan(reply))) { + const z_loaned_sample_t* sample = z_reply_ok(z_loan(reply)); + + z_view_string_t key_str; + z_keyexpr_as_view_string(z_sample_keyexpr(sample), &key_str); + + z_owned_string_t reply_str; + z_bytes_decode_into_string(z_sample_payload(sample), &reply_str); + + printf(">> Received ('%.*s': '%.*s')\n", (int)z_string_len(z_loan(key_str)), z_string_data(z_loan(key_str)), + (int)z_string_len(z_loan(reply_str)), z_string_data(z_loan(reply_str))); + z_drop(z_move(reply_str)); + } else { + printf("Received an error\n"); + } + z_drop(z_move(reply)); + } + + z_drop(z_move(handler)); + z_close(z_move(s)); + + z_drop(z_move(shm)); + z_drop(z_move(provider)); + z_drop(z_move(layout)); + return 0; +} \ No newline at end of file diff --git a/examples/z_ping_shm.c b/examples/z_ping_shm.c new file mode 100644 index 000000000..35f12647c --- /dev/null +++ b/examples/z_ping_shm.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include + +#include "zenoh.h" + +#define DEFAULT_PKT_SIZE 8 +#define DEFAULT_PING_NB 100 +#define DEFAULT_WARMUP_MS 1000 +#define PING_TIMEOUT_SEC 1 + +#define handle_error_en(en, msg) \ + do { \ + errno = en; \ + perror(msg); \ + exit(EXIT_FAILURE); \ + } while (0) + +z_owned_condvar_t cond; +z_owned_mutex_t mutex; + +void callback(const z_loaned_sample_t* sample, void* context) { z_condvar_signal(z_loan(cond)); } +void drop(void* context) { z_drop(z_move(cond)); } + +struct args_t { + unsigned int size; // -s + unsigned int number_of_pings; // -n + unsigned int warmup_ms; // -w + char* config_path; // -c + uint8_t help_requested; // -h +}; +struct args_t parse_args(int argc, char** argv); + +int main(int argc, char** argv) { + struct args_t args = parse_args(argc, argv); + if (args.help_requested) { + printf( + "\ + -n (optional, int, default=%d): the number of pings to be attempted\n\ + -s (optional, int, default=%d): the size of the payload embedded in the ping and repeated by the pong\n\ + -w (optional, int, default=%d): the warmup time in ms during which pings will be emitted but not measured\n\ + -c (optional, string): the path to a configuration file for the session. If this option isn't passed, the default configuration will be used.\n\ + ", + DEFAULT_PKT_SIZE, DEFAULT_PING_NB, DEFAULT_WARMUP_MS); + return 1; + } + z_mutex_init(&mutex); + z_condvar_init(&cond); + z_owned_config_t config; + if (args.config_path) { + zc_config_from_file(&config, args.config_path); + } else { + z_config_default(&config); + } + z_owned_session_t session; + z_open(&session, z_move(config)); + z_view_keyexpr_t ping; + z_view_keyexpr_from_string_unchecked(&ping, "test/ping"); + z_view_keyexpr_t pong; + z_view_keyexpr_from_string_unchecked(&pong, "test/pong"); + z_owned_publisher_t pub; + z_declare_publisher(&pub, z_loan(session), z_loan(ping), NULL); + z_owned_closure_sample_t respond; + z_closure(&respond, callback, drop, (void*)(&pub)); + z_owned_subscriber_t sub; + z_declare_subscriber(&sub, z_loan(session), z_loan(pong), z_move(respond), NULL); + + // Create SHM Provider + z_alloc_alignment_t alignment = {0}; + z_owned_memory_layout_t layout; + z_memory_layout_new(&layout, args.size, alignment); + z_owned_shared_memory_provider_t provider; + z_posix_shared_memory_provider_new(&provider, z_loan(layout)); + z_owned_buf_alloc_result_t alloc; + z_shared_memory_provider_alloc(&alloc, z_loan(provider), args.size, alignment); + + // Allocate SHM Buffer + z_owned_shm_mut_t shm_mut; + z_alloc_error_t shm_error; + z_buf_alloc_result_unwrap(z_move(alloc), &shm_mut, &shm_error); + if (!z_check(shm_mut)) { + printf("Unexpected failure during SHM buffer allocation..."); + return -1; + } + // Fill SHM Buffer with data + uint8_t* data = z_shm_mut_data_mut(z_loan_mut(shm_mut)); + for (int i = 0; i < args.size; i++) { + data[i] = i % 10; + } + // Convert mutable SHM Buffer into immutable one (to be able to make it's ref copies) + z_owned_shm_t shm; + z_shm_from_mut(&shm, z_move(shm_mut)); + const z_loaned_shm_t* loaned_shm = z_loan(shm); + + z_owned_bytes_t payload; + + z_mutex_lock(z_loan_mut(mutex)); + if (args.warmup_ms) { + printf("Warming up for %dms...\n", args.warmup_ms); + z_clock_t warmup_start = z_clock_now(); + + unsigned long elapsed_us = 0; + while (elapsed_us < args.warmup_ms * 1000) { + z_bytes_encode_from_shm_copy(&payload, loaned_shm); + z_publisher_put(z_loan(pub), z_move(payload), NULL); + int s = z_condvar_wait(z_loan(cond), z_loan_mut(mutex)); + if (s != 0) { + handle_error_en(s, "z_condvar_wait"); + } + elapsed_us = z_clock_elapsed_us(&warmup_start); + } + } + unsigned long* results = z_malloc(sizeof(unsigned long) * args.number_of_pings); + for (int i = 0; i < args.number_of_pings; i++) { + z_clock_t measure_start = z_clock_now(); + z_publisher_put(z_loan(pub), z_move(payload), NULL); + int s = z_condvar_wait(z_loan(cond), z_loan_mut(mutex)); + if (s != 0) { + handle_error_en(s, "z_condvar_wait"); + } + results[i] = z_clock_elapsed_us(&measure_start); + } + for (int i = 0; i < args.number_of_pings; i++) { + printf("%d bytes: seq=%d rtt=%luµs, lat=%luµs\n", args.size, i, results[i], results[i] / 2); + } + z_mutex_unlock(z_loan_mut(mutex)); + z_free(results); + z_free(data); + z_undeclare_subscriber(z_move(sub)); + z_undeclare_publisher(z_move(pub)); + z_drop(z_move(mutex)); + z_close(z_move(session)); + + z_drop(z_move(shm)); + z_drop(z_move(provider)); + z_drop(z_move(layout)); +} + +char* getopt(int argc, char** argv, char option) { + for (int i = 0; i < argc; i++) { + size_t len = strlen(argv[i]); + if (len >= 2 && argv[i][0] == '-' && argv[i][1] == option) { + if (len > 2 && argv[i][2] == '=') { + return argv[i] + 3; + } else if (i + 1 < argc) { + return argv[i + 1]; + } + } + } + return NULL; +} + +struct args_t parse_args(int argc, char** argv) { + for (int i = 0; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0) { + return (struct args_t){.help_requested = 1}; + } + } + char* arg = getopt(argc, argv, 's'); + unsigned int size = DEFAULT_PKT_SIZE; + if (arg) { + size = atoi(arg); + } + arg = getopt(argc, argv, 'n'); + unsigned int number_of_pings = DEFAULT_PING_NB; + if (arg) { + number_of_pings = atoi(arg); + } + arg = getopt(argc, argv, 'w'); + unsigned int warmup_ms = DEFAULT_WARMUP_MS; + if (arg) { + warmup_ms = atoi(arg); + } + return (struct args_t){.help_requested = 0, + .size = size, + .number_of_pings = number_of_pings, + .warmup_ms = warmup_ms, + .config_path = getopt(argc, argv, 'c')}; +} \ No newline at end of file diff --git a/examples/z_pub_attachment.c b/examples/z_pub_attachment.c index 32ca37468..9b9be7a4f 100644 --- a/examples/z_pub_attachment.c +++ b/examples/z_pub_attachment.c @@ -27,16 +27,17 @@ typedef struct kv_pairs_t { size_t current_idx; } kv_pairs_t; -void create_attachment_iter(z_owned_bytes_t* kv_pair, void* context) { +bool create_attachment_iter(z_owned_bytes_t* kv_pair, void* context) { kv_pairs_t *kvs = (kv_pairs_t*)(context); z_owned_bytes_t k, v; if (kvs->current_idx >= kvs->len) { - z_null(kv_pair); + return false; } else { z_bytes_encode_from_string(&k, kvs->data[kvs->current_idx].key); z_bytes_encode_from_string(&v, kvs->data[kvs->current_idx].value); z_bytes_encode_from_pair(kv_pair, z_move(k), z_move(v)); kvs->current_idx++; + return true; } }; diff --git a/examples/z_pub_shm.c b/examples/z_pub_shm.c new file mode 100644 index 000000000..e8962fb35 --- /dev/null +++ b/examples/z_pub_shm.c @@ -0,0 +1,118 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +#include +#include + +#include "zenoh.h" + +void matching_status_handler(const zcu_matching_status_t *matching_status, void *arg) { + if (matching_status->matching) { + printf("Subscriber matched\n"); + } else { + printf("No Subscribers matched\n"); + } +} + +int main(int argc, char **argv) { + char *keyexpr = "demo/example/zenoh-c-pub"; + char *value = "Pub from C!"; + bool add_matching_listener = false; + + if (argc > 1) keyexpr = argv[1]; + if (argc > 2) value = argv[2]; + if (argc > 3) add_matching_listener = atoi(argv[3]); + + z_owned_config_t config; + z_config_default(&config); + if (argc > 4) { + if (zc_config_insert_json(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, argv[4]) < 0) { + printf( + "Couldn't insert value `%s` in configuration at `%s`. This is likely because `%s` expects a " + "JSON-serialized list of strings\n", + argv[4], Z_CONFIG_CONNECT_KEY, Z_CONFIG_CONNECT_KEY); + exit(-1); + } + } + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config)) < 0) { + printf("Unable to open session!\n"); + exit(-1); + } + + printf("Declaring Publisher on '%s'...\n", keyexpr); + z_owned_publisher_t pub; + z_view_keyexpr_t ke; + z_view_keyexpr_from_string(&ke, keyexpr); + if (z_declare_publisher(&pub, z_loan(s), z_loan(ke), NULL) < 0) { + printf("Unable to declare Publisher for key expression!\n"); + exit(-1); + } + + zcu_owned_matching_listener_t listener; + if (add_matching_listener) { + zcu_owned_closure_matching_status_t callback; + z_closure(&callback, matching_status_handler, NULL, NULL); + zcu_publisher_matching_listener_callback(&listener, z_loan(pub), z_move(callback)); + } + + printf("Creating POSIX SHM Provider...\n"); + const size_t total_size = 4096; + const size_t buf_ok_size = total_size / 4; + + z_alloc_alignment_t alignment = {0}; + z_owned_memory_layout_t layout; + z_memory_layout_new(&layout, total_size, alignment); + + z_owned_shared_memory_provider_t provider; + z_posix_shared_memory_provider_new(&provider, z_loan(layout)); + + for (int idx = 0; 1; ++idx) { + z_sleep_s(1); + + z_owned_buf_alloc_result_t alloc; + z_shared_memory_provider_alloc_gc_defrag_blocking(&alloc, z_loan(provider), buf_ok_size, alignment); + + z_owned_shm_mut_t shm_buf; + z_alloc_error_t shm_error; + z_buf_alloc_result_unwrap(z_move(alloc), &shm_buf, &shm_error); + if (z_check(shm_buf)) { + { + uint8_t *buf = z_shm_mut_data_mut(z_loan_mut(shm_buf)); + sprintf(buf, "SHM [%4d] %s", idx, value); + printf("Putting Data ('%s': '%s')...\n", keyexpr, buf); + } + + z_publisher_put_options_t options; + z_publisher_put_options_default(&options); + + z_owned_bytes_t payload; + z_bytes_encode_from_shm_mut(&payload, &shm_buf); + + z_publisher_put(z_loan(pub), z_move(payload), &options); + } else { + printf("Unexpected failure during SHM buffer allocation..."); + break; + } + } + + z_undeclare_publisher(z_move(pub)); + z_close(z_move(s)); + + z_drop(z_move(provider)); + z_drop(z_move(layout)); + + return 0; +} diff --git a/examples/z_pub_shm_thr.c b/examples/z_pub_shm_thr.c new file mode 100644 index 000000000..e6c5ccb42 --- /dev/null +++ b/examples/z_pub_shm_thr.c @@ -0,0 +1,92 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +#include +#include + +#include "zenoh.h" + +int main(int argc, char **argv) { + if (argc < 2) { + printf("USAGE:\n\tz_pub_thr []\n\n"); + exit(-1); + } + + char *keyexpr = "test/thr"; + size_t len = atoi(argv[1]); + + z_owned_config_t config; + z_config_default(&config); + if (argc > 2) { + if (zc_config_insert_json(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, argv[2]) < 0) { + printf( + "Couldn't insert value `%s` in configuration at `%s`. This is likely because `%s` expects a " + "JSON-serialized list of strings\n", + argv[2], Z_CONFIG_CONNECT_KEY, Z_CONFIG_CONNECT_KEY); + exit(-1); + } + } + + z_owned_session_t s; + if (z_open(&s, z_move(config)) < 0) { + printf("Unable to open session!\n"); + exit(-1); + } + + z_publisher_options_t options; + z_publisher_options_default(&options); + options.congestion_control = Z_CONGESTION_CONTROL_BLOCK; + + z_owned_publisher_t pub; + z_view_keyexpr_t ke; + z_view_keyexpr_from_string(&ke, keyexpr); + if (z_declare_publisher(&pub, z_loan(s), z_loan(ke), &options)) { + printf("Unable to declare publisher for key expression!\n"); + exit(-1); + } + + printf("Creating POSIX SHM Provider...\n"); + z_alloc_alignment_t alignment = {0}; + z_owned_memory_layout_t layout; + z_memory_layout_new(&layout, len, alignment); + z_owned_shared_memory_provider_t provider; + z_posix_shared_memory_provider_new(&provider, z_loan(layout)); + z_owned_buf_alloc_result_t alloc; + z_shared_memory_provider_alloc(&alloc, z_loan(provider), len, alignment); + + printf("Allocating single SHM buffer\n"); + z_owned_shm_mut_t shm_mut; + z_alloc_error_t shm_error; + z_buf_alloc_result_unwrap(z_move(alloc), &shm_mut, &shm_error); + if (!z_check(shm_mut)) { + printf("Unexpected failure during SHM buffer allocation..."); + return -1; + } + memset(z_shm_mut_data_mut(z_loan_mut(shm_mut)), 1, len); + z_owned_shm_t shm; + z_shm_from_mut(&shm, z_move(shm_mut)); + const z_loaned_shm_t *loaned_shm = z_loan(shm); + + z_owned_bytes_t payload; + while (1) { + z_bytes_encode_from_shm_copy(&payload, loaned_shm); + z_publisher_put(z_loan(pub), z_move(payload), NULL); + } + + z_undeclare_publisher(z_move(pub)); + z_close(z_move(s)); + + z_drop(z_move(shm)); + z_drop(z_move(provider)); + z_drop(z_move(layout)); +} diff --git a/include/zenoh.h b/include/zenoh.h index 95843bded..5a7845b57 100644 --- a/include/zenoh.h +++ b/include/zenoh.h @@ -28,8 +28,6 @@ extern "C" { #define ZENOHC_API #endif -#include "zenoh_configure.h" - // clang-format off // include order is important #include "zenoh_concrete.h" diff --git a/include/zenoh_commons.h b/include/zenoh_commons.h index 985a8cec2..898323e4b 100644 --- a/include/zenoh_commons.h +++ b/include/zenoh_commons.h @@ -15,6 +15,26 @@ #define ALIGN(n) #define ZENOHC_API #endif +/** + * Allocation errors + * + * - **NEED_DEFRAGMENT**: defragmentation needed + * - **OUT_OF_MEMORY**: the provider is out of memory + * - **OTHER**: other error + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef enum z_alloc_error_t { +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) + Z_ALLOC_ERROR_NEED_DEFRAGMENT, +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) + Z_ALLOC_ERROR_OUT_OF_MEMORY, +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) + Z_ALLOC_ERROR_OTHER, +#endif +} z_alloc_error_t; +#endif typedef enum z_congestion_control_t { /** * Messages are not dropped in case of congestion. @@ -186,6 +206,68 @@ typedef enum zcu_reply_keyexpr_t { ZCU_REPLY_KEYEXPR_MATCHING_QUERY = 1, } zcu_reply_keyexpr_t; typedef int8_t z_error_t; +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct z_alloc_alignment_t { + uint8_t pow; +} z_alloc_alignment_t; +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct zc_threadsafe_context_data_t { + void *ptr; +} zc_threadsafe_context_data_t; +#endif +/** + * A tread-safe droppable context. + * Contexts are idiomatically used in C together with callback interfaces to deliver associated state + * information to each callback. + * + * This is a thread-safe context - the associated callbacks may be executed concurrently with the same + * zc_context_t instance. In other words, all the callbacks associated with this context data MUST be + * thread-safe. + * + * Once moved to zenoh-c ownership, this context is guaranteed to execute delete_fn when deleted.The + * delete_fn is guaranteed to be executed only once at some point of time after the last associated + * callback call returns. + * NOTE: if user doesn't pass the instance of this context to zenoh-c, the delete_fn callback won't + * be executed. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct zc_threadsafe_context_t { + struct zc_threadsafe_context_data_t context; + void (*delete_fn)(void*); +} zc_threadsafe_context_t; +#endif +/** + * Unique segment identifier + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef uint32_t z_segment_id_t; +#endif +/** + * Chunk id within it's segment + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef uint32_t z_chunk_id_t; +#endif +/** + * A ChunkDescriptor + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct z_chunk_descriptor_t { + z_segment_id_t segment; + z_chunk_id_t chunk; + size_t len; +} z_chunk_descriptor_t; +#endif +/** + * An AllocatedChunk + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct z_allocated_chunk_t { + struct z_chunk_descriptor_t descriptpr; + void *data; +} z_allocated_chunk_t; +#endif /** * Monotonic clock */ @@ -538,6 +620,81 @@ typedef struct z_scout_options_t { */ enum z_whatami_t zc_what; } z_scout_options_t; +/** + * A callbacks for SharedMemorySegment + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct zc_shared_memory_segment_callbacks_t { + uint8_t *(*map_fn)(z_chunk_id_t chunk_id, void *context); +} zc_shared_memory_segment_callbacks_t; +#endif +/** + * A SharedMemorySegment + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct z_shared_memory_segment_t { + struct zc_threadsafe_context_t context; + struct zc_shared_memory_segment_callbacks_t callbacks; +} z_shared_memory_segment_t; +#endif +/** + * A callbacks for SharedMemoryClient + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct zc_shared_memory_client_callbacks_t { + bool (*attach_fn)(struct z_shared_memory_segment_t *out_segment, + z_segment_id_t segment_id, + void *context); +} zc_shared_memory_client_callbacks_t; +#endif +/** + * Unique protocol identifier. + * Here is a contract: it is up to user to make sure that incompatible SharedMemoryClient + * and SharedMemoryProviderBackend implementations will never use the same ProtocolID + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef uint32_t z_protocol_id_t; +#endif +/** + * A non-tread-safe droppable context. + * Contexts are idiomatically used in C together with callback interfaces to deliver associated state + * information to each callback. + * + * This is a non-thread-safe context - zenoh-c guarantees that associated callbacks that share the same + * zc_context_t instance will never be executed concurrently. In other words, all the callbacks associated + * with this context data are not required to be thread-safe. + * + * NOTE: Remember that the same callback interfaces associated with different zc_context_t instances can + * still be executed concurrently. The exact behavior depends on user's application, but we strongly + * discourage our users from pinning to some specific behavior unless they _really_ understand what they + * are doing. + * + * Once moved to zenoh-c ownership, this context is guaranteed to execute delete_fn when deleted. The + * delete_fn is guaranteed to be executed only once at some point of time after the last associated + * callback call returns. + * NOTE: if user doesn't pass the instance of this context to zenoh-c, the delete_fn callback won't + * be executed. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct zc_context_t { + void *context; + void (*delete_fn)(void*); +} zc_context_t; +#endif +/** + * A callbacks for SharedMemoryProviderBackend + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +typedef struct zc_shared_memory_provider_backend_callbacks_t { + void (*alloc_fn)(z_owned_chunk_alloc_result_t *out_result, + const z_loaned_memory_layout_t *layout, + void *context); + void (*free_fn)(const struct z_chunk_descriptor_t *chunk, void *context); + size_t (*defragment_fn)(void *context); + size_t (*available_fn)(void *context); + void (*layout_for_fn)(z_owned_memory_layout_t *layout, void *context); +} zc_shared_memory_provider_backend_callbacks_t; +#endif typedef struct z_task_attr_t { size_t _0; } z_task_attr_t; @@ -672,6 +829,105 @@ ZENOHC_API extern const char *Z_CONFIG_MULTICAST_IPV4_ADDRESS_KEY; ZENOHC_API extern const char *Z_CONFIG_SCOUTING_TIMEOUT_KEY; ZENOHC_API extern const char *Z_CONFIG_SCOUTING_DELAY_KEY; ZENOHC_API extern const char *Z_CONFIG_ADD_TIMESTAMP_KEY; +ZENOHC_API extern const unsigned int Z_SHM_POSIX_PROTOCOL_ID; +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_alloc_layout_alloc(z_owned_buf_alloc_result_t *out_result, + const z_loaned_alloc_layout_t *layout); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_alloc_layout_alloc_gc(z_owned_buf_alloc_result_t *out_result, + const z_loaned_alloc_layout_t *layout); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_alloc_layout_alloc_gc_defrag(z_owned_buf_alloc_result_t *out_result, + const z_loaned_alloc_layout_t *layout); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_alloc_layout_alloc_gc_defrag_blocking(z_owned_buf_alloc_result_t *out_result, + const z_loaned_alloc_layout_t *layout); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_alloc_layout_alloc_gc_defrag_dealloc(z_owned_buf_alloc_result_t *out_result, + const z_loaned_alloc_layout_t *layout); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_alloc_layout_check(const z_owned_alloc_layout_t *this_); +#endif +/** + * Deletes Alloc Layout + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_alloc_layout_drop(z_owned_alloc_layout_t *this_); +#endif +/** + * Borrows Alloc Layout + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API const z_loaned_alloc_layout_t *z_alloc_layout_loan(const z_owned_alloc_layout_t *this_); +#endif +/** + * Creates a new Alloc Layout for SHM Provider + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_alloc_layout_new(z_owned_alloc_layout_t *this_, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +/** + * Constructs Alloc Layout in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_alloc_layout_null(z_owned_alloc_layout_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_alloc_layout_threadsafe_alloc_gc_defrag_async(z_owned_buf_alloc_result_t *out_result, + const z_loaned_alloc_layout_t *layout, + struct zc_threadsafe_context_t result_context, + void (*result_callback)(void*, + z_owned_buf_alloc_result_t*)); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_buf_alloc_result_check(const z_owned_buf_alloc_result_t *this_); +#endif +/** + * Deletes Buf Alloc Result + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_buf_alloc_result_drop(z_owned_buf_alloc_result_t *this_); +#endif +/** + * Borrows Buf Alloc Result + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +const z_loaned_buf_alloc_result_t *z_buf_alloc_result_loan(const z_owned_buf_alloc_result_t *this_); +#endif +/** + * Constructs Buf Alloc Result in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_buf_alloc_result_null(z_owned_buf_alloc_result_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_buf_alloc_result_unwrap(z_owned_buf_alloc_result_t *alloc_result, + z_owned_shm_mut_t *out_buf, + enum z_alloc_error_t *out_error); +#endif /** * Returns ``true`` if `this_` is in a valid state, ``false`` if it is in a gravestone state. */ @@ -710,6 +966,39 @@ ZENOHC_API z_error_t z_bytes_decode_into_int64(const struct z_loaned_bytes_t *th * @return 0 in case of success, negative error code otherwise. */ ZENOHC_API z_error_t z_bytes_decode_into_int8(const struct z_loaned_bytes_t *this_, int8_t *dst); +/** + * Decodes data into a loaned SHM buffer + * + * @param this_: Data to decode. + * @param dst: An unitialized memory location where to construct a decoded string. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_bytes_decode_into_loaned_shm(const struct z_loaned_bytes_t *this_, + const z_loaned_shm_t **dst); +#endif +/** + * Decodes data into a mutably loaned SHM buffer + * + * @param this_: Data to decode. + * @param dst: An unitialized memory location where to construct a decoded string. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_bytes_decode_into_mut_loaned_shm(struct z_loaned_bytes_t *this_, + z_loaned_shm_t **dst); +#endif +/** + * Decodes data into an owned SHM buffer by copying it's shared reference + * + * @param this_: Data to decode. + * @param dst: An unitialized memory location where to construct a decoded string. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_bytes_decode_into_owned_shm(const struct z_loaned_bytes_t *this_, + z_owned_shm_t *dst); +#endif /** * Decodes into a pair of `z_owned_bytes` objects. * @return 0 in case of success, negative error code otherwise. @@ -807,13 +1096,13 @@ ZENOHC_API void z_bytes_encode_from_int8(struct z_owned_bytes_t *this_, int8_t v /** * Constructs payload from an iterator to `z_owned_bytes_t`. * @param this_: An uninitialized location in memery for `z_owned_bytes_t` will be constructed. - * @param iterator_body: Iterator body function, providing data items. Returning NULL + * @param iterator_body: Iterator body function, providing data items. Returning false is treated as iteration end. * @param context: Arbitrary context that will be passed to iterator_body. * @return 0 in case of success, negative error code otherwise. */ ZENOHC_API z_error_t z_bytes_encode_from_iter(struct z_owned_bytes_t *this_, - void (*iterator_body)(struct z_owned_bytes_t *data, void *context), + bool (*iterator_body)(struct z_owned_bytes_t *data, void *context), void *context); /** * Encodes a pair of `z_owned_bytes` objects which are consumed in the process. @@ -823,6 +1112,28 @@ ZENOHC_API z_error_t z_bytes_encode_from_pair(struct z_owned_bytes_t *this_, struct z_owned_bytes_t *first, struct z_owned_bytes_t *second); +/** + * Encodes from an immutable SHM buffer consuming it + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_error_t z_bytes_encode_from_shm(struct z_owned_bytes_t *this_, z_owned_shm_t *shm); +#endif +/** + * Encodes from an immutable SHM buffer copying it + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_bytes_encode_from_shm_copy(struct z_owned_bytes_t *this_, + const z_loaned_shm_t *shm); +#endif +/** + * Encodes from a mutable SHM buffer consuming it + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_bytes_encode_from_shm_mut(struct z_owned_bytes_t *this_, + z_owned_shm_mut_t *shm); +#endif /** * Encodes a slice by aliasing. */ @@ -906,7 +1217,7 @@ z_error_t z_bytes_iter(const struct z_loaned_bytes_t *this_, /** * Constructs `z_owned_bytes` object corresponding to the next element of encoded data. * - * Will construct `z_owned_bytes` when iterator reaches the end. + * Will construct null-state `z_owned_bytes` when iterator reaches the end. * @return ``false`` when iterator reaches the end, ``true`` otherwise */ ZENOHC_API bool z_bytes_iterator_next(struct z_bytes_iterator_t *iter, struct z_owned_bytes_t *out); @@ -984,6 +1295,47 @@ ZENOHC_API z_error_t z_bytes_writer_write(struct z_loaned_bytes_writer_t *this_, const uint8_t *src, size_t len); +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_chunk_alloc_result_check(const z_owned_chunk_alloc_result_t *this_); +#endif +/** + * Deletes Chunk Alloc Result + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_chunk_alloc_result_drop(z_owned_chunk_alloc_result_t *this_); +#endif +/** + * Borrows Chunk Alloc Result + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +const z_loaned_chunk_alloc_result_t *z_chunk_alloc_result_loan(const z_owned_chunk_alloc_result_t *this_); +#endif +/** + * Creates a new Chunk Alloc Result with Error value + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_chunk_alloc_result_new_error(z_owned_chunk_alloc_result_t *this_, + enum z_alloc_error_t alloc_error); +#endif +/** + * Creates a new Chunk Alloc Result with Ok value + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_chunk_alloc_result_new_ok(z_owned_chunk_alloc_result_t *this_, + struct z_allocated_chunk_t allocated_chunk); +#endif +/** + * Constructs Chunk Alloc Result in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_chunk_alloc_result_null(z_owned_chunk_alloc_result_t *this_); +#endif /** * Get number of milliseconds passed since creation of `time`. */ @@ -1702,6 +2054,49 @@ ZENOHC_API void z_keyexpr_null(struct z_owned_keyexpr_t *this_); ZENOHC_API enum z_keyexpr_intersection_level_t z_keyexpr_relation_to(const struct z_loaned_keyexpr_t *left, const struct z_loaned_keyexpr_t *right); +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_memory_layout_check(const z_owned_memory_layout_t *this_); +#endif +/** + * Deletes Memory Layout + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_memory_layout_drop(z_owned_memory_layout_t *this_); +#endif +/** + * Deletes Memory Layout + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_memory_layout_get_data(size_t *out_size, + struct z_alloc_alignment_t *out_alignment, + const z_loaned_memory_layout_t *this_); +#endif +/** + * Borrows Memory Layout + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +const z_loaned_memory_layout_t *z_memory_layout_loan(const z_owned_memory_layout_t *this_); +#endif +/** + * Creates a new Memory Layout + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_memory_layout_new(z_owned_memory_layout_t *this_, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +/** + * Constructs Memory Layout in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_memory_layout_null(z_owned_memory_layout_t *this_); +#endif /** * Returns ``true`` if mutex is valid, ``false`` otherwise. */ @@ -1747,6 +2142,31 @@ z_error_t z_mutex_unlock(struct z_loaned_mutex_t *this_); ZENOHC_API z_error_t z_open(struct z_owned_session_t *this_, struct z_owned_config_t *config); +/** + * Constructs and opens a new Zenoh session with specified client storage. + * + * @return 0 in case of success, negative error code otherwise (in this case the session will be in its gravestone state). + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_open_with_custom_shm_clients(struct z_owned_session_t *this_, + struct z_owned_config_t *config, + const z_loaned_shared_memory_client_storage_t *shm_clients); +#endif +/** + * Creates a new POSIX SHM Client + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_error_t z_posix_shared_memory_client_new(z_owned_shared_memory_client_t *this_); +#endif +/** + * Creates a new threadsafe SHM Provider + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_posix_shared_memory_provider_new(z_owned_shared_memory_provider_t *this_, + const z_loaned_memory_layout_t *layout); +#endif /** * Returns the default value of #z_priority_t. */ @@ -1997,6 +2417,10 @@ ZENOHC_API uint64_t z_random_u64(void); * Generates random `uint8_t`. */ ZENOHC_API uint8_t z_random_u8(void); +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_ref_shared_memory_client_storage_global(z_owned_shared_memory_client_storage_t *this_); +#endif /** * Returns ``true`` if `reply` is valid, ``false`` otherwise. */ @@ -2256,6 +2680,287 @@ ZENOHC_API const struct z_loaned_session_t *z_session_loan(const struct z_owned_ * Constructs a Zenoh session in its gravestone state. */ ZENOHC_API void z_session_null(struct z_owned_session_t *this_); +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_shared_memory_client_check(const z_owned_shared_memory_client_t *this_); +#endif +/** + * Deletes SHM Client + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shared_memory_client_drop(z_owned_shared_memory_client_t *this_); +#endif +/** + * Creates a new SHM Client + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_client_new(z_owned_shared_memory_client_t *this_, + struct zc_threadsafe_context_t context, + struct zc_shared_memory_client_callbacks_t callbacks); +#endif +/** + * Constructs SHM client in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shared_memory_client_null(z_owned_shared_memory_client_t *this_); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +bool z_shared_memory_client_storage_check(const z_owned_shared_memory_client_storage_t *this_); +#endif +/** + * Derefs SHM Client Storage + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shared_memory_client_storage_drop(z_owned_shared_memory_client_storage_t *this_); +#endif +/** + * Borrows SHM Client Storage + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +const z_loaned_shared_memory_client_storage_t *z_shared_memory_client_storage_loan(const z_owned_shared_memory_client_storage_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_client_storage_new(z_owned_shared_memory_client_storage_t *this_, + const zc_loaned_shared_memory_client_list_t *clients, + bool add_default_client_set); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_client_storage_new_default(z_owned_shared_memory_client_storage_t *this_); +#endif +/** + * Constructs SHM Client Storage in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shared_memory_client_storage_null(z_owned_shared_memory_client_storage_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_provider_alloc(z_owned_buf_alloc_result_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_provider_alloc_gc(z_owned_buf_alloc_result_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_provider_alloc_gc_defrag(z_owned_buf_alloc_result_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_provider_alloc_gc_defrag_async(z_owned_buf_alloc_result_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment, + struct zc_threadsafe_context_t result_context, + void (*result_callback)(void*, + z_error_t, + z_owned_buf_alloc_result_t*)); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_provider_alloc_gc_defrag_blocking(z_owned_buf_alloc_result_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t z_shared_memory_provider_alloc_gc_defrag_dealloc(z_owned_buf_alloc_result_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + size_t size, + struct z_alloc_alignment_t alignment); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +size_t z_shared_memory_provider_available(const z_loaned_shared_memory_provider_t *provider); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_shared_memory_provider_check(const z_owned_shared_memory_provider_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_shared_memory_provider_defragment(const z_loaned_shared_memory_provider_t *provider); +#endif +/** + * Deletes SHM Provider + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shared_memory_provider_drop(z_owned_shared_memory_provider_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_shared_memory_provider_garbage_collect(const z_loaned_shared_memory_provider_t *provider); +#endif +/** + * Borrows SHM Provider + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +const z_loaned_shared_memory_provider_t *z_shared_memory_provider_loan(const z_owned_shared_memory_provider_t *this_); +#endif +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_shared_memory_provider_map(z_owned_shm_mut_t *out_result, + const z_loaned_shared_memory_provider_t *provider, + struct z_allocated_chunk_t allocated_chunk, + size_t len); +#endif +/** + * Creates a new SHM Provider + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_shared_memory_provider_new(z_owned_shared_memory_provider_t *this_, + z_protocol_id_t id, + struct zc_context_t context, + struct zc_shared_memory_provider_backend_callbacks_t callbacks); +#endif +/** + * Constructs SHM Provider in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shared_memory_provider_null(z_owned_shared_memory_provider_t *this_); +#endif +/** + * Creates a new threadsafe SHM Provider + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +void z_shared_memory_provider_threadsafe_new(z_owned_shared_memory_provider_t *this_, + z_protocol_id_t id, + struct zc_threadsafe_context_t context, + struct zc_shared_memory_provider_backend_callbacks_t callbacks); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_shm_check(const z_owned_shm_t *this_); +#endif +/** + * Converts borrowed ZShm slice to owned ZShm slice by performing a shallow SHM reference copy + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_clone(const z_loaned_shm_t *this_, z_owned_shm_t *out); +#endif +/** + * @return the pointer of the ZShm slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API const unsigned char *z_shm_data(const z_loaned_shm_t *this_); +#endif +/** + * Deletes ZShm slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_drop(z_owned_shm_t *this_); +#endif +/** + * Constructs ZShm slice from ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_from_mut(z_owned_shm_t *this_, z_owned_shm_mut_t *that); +#endif +/** + * @return the length of the ZShm slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API size_t z_shm_len(const z_loaned_shm_t *this_); +#endif +/** + * Borrows ZShm slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API const z_loaned_shm_t *z_shm_loan(const z_owned_shm_t *this_); +#endif +/** + * Mutably borrows ZShm slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_loaned_shm_t *z_shm_loan_mut(z_owned_shm_t *this_); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API bool z_shm_mut_check(const z_owned_shm_mut_t *this_); +#endif +/** + * @return the mutable pointer of the ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API unsigned char *z_shm_mut_data_mut(z_loaned_shm_mut_t *this_); +#endif +/** + * Deletes ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_mut_drop(z_owned_shm_mut_t *this_); +#endif +/** + * @return the length of the ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API size_t z_shm_mut_len(const z_loaned_shm_mut_t *this_); +#endif +/** + * Borrows ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_loaned_shm_mut_t *z_shm_mut_loan_mut(z_owned_shm_mut_t *this_); +#endif +/** + * Constructs ZShmMut slice in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_mut_null(z_owned_shm_mut_t *this_); +#endif +/** + * Tries to construct ZShmMut slice from ZShm slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_mut_try_from_immut(z_owned_shm_mut_t *this_, z_owned_shm_t *that); +#endif +/** + * Constructs ZShm slice in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void z_shm_null(z_owned_shm_t *this_); +#endif +/** + * Mutably borrows ZShm slice as borrowed ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_loaned_shm_mut_t *z_shm_try_mut(z_owned_shm_t *this_); +#endif +/** + * Tries to reborrow mutably-borrowed ZShm slice as borrowed ZShmMut slice + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_loaned_shm_mut_t *z_shm_try_reloan_mut(z_loaned_shm_t *this_); +#endif /** * Puts current thread to sleep for specified amount of milliseconds. */ @@ -2968,6 +3673,51 @@ ZENOHC_API z_error_t zc_liveliness_undeclare_token(struct zc_owned_liveliness_to ZENOHC_API void zc_session_clone(const struct z_loaned_session_t *this_, struct z_owned_session_t *dst); +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +z_error_t zc_shared_memory_client_list_add_client(z_protocol_id_t id, + z_owned_shared_memory_client_t *client, + zc_loaned_shared_memory_client_list_t *list); +#endif +/** + * Returns ``true`` if `this` is valid. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +bool zc_shared_memory_client_list_check(const zc_owned_shared_memory_client_list_t *this_); +#endif +/** + * Deletes list of SHM Clients + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void zc_shared_memory_client_list_drop(zc_owned_shared_memory_client_list_t *this_); +#endif +/** + * Borrows list of SHM Clients + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +const zc_loaned_shared_memory_client_list_t *zc_shared_memory_client_list_loan(const zc_owned_shared_memory_client_list_t *this_); +#endif +/** + * Mutably borrows list of SHM Clients + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API +zc_loaned_shared_memory_client_list_t *zc_shared_memory_client_list_loan_mut(zc_owned_shared_memory_client_list_t *this_); +#endif +/** + * Creates a new empty list of SHM Clients + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API z_error_t zc_shared_memory_client_list_new(zc_owned_shared_memory_client_list_t *this_); +#endif +/** + * Constructs SHM client list in its gravestone value. + */ +#if (defined(SHARED_MEMORY) && defined(UNSTABLE)) +ZENOHC_API void zc_shared_memory_client_list_null(zc_owned_shared_memory_client_list_t *this_); +#endif /** * Calls the closure. Calling an uninitialized closure is a no-op. */ diff --git a/splitguide.yaml b/splitguide.yaml index f422c8c89..9d1b664fb 100644 --- a/splitguide.yaml +++ b/splitguide.yaml @@ -67,6 +67,25 @@ zenoh_opaque.h: - z_loaned_closure_sample_t! - z_loaned_closure_zid_t! - zcu_loaned_closure_matching_status_t! + - z_owned_shared_memory_client_t!#shared-memory#unstable + - zc_owned_shared_memory_client_list_t!#shared-memory#unstable + - zc_loaned_shared_memory_client_list_t!#shared-memory#unstable + - z_owned_shared_memory_client_storage_t!#shared-memory#unstable + - z_loaned_shared_memory_client_storage_t!#shared-memory#unstable + - z_owned_memory_layout_t!#shared-memory#unstable + - z_loaned_memory_layout_t!#shared-memory#unstable + - z_owned_chunk_alloc_result_t!#shared-memory#unstable + - z_loaned_chunk_alloc_result_t!#shared-memory#unstable + - z_owned_buf_alloc_result_t!#shared-memory#unstable + - z_loaned_buf_alloc_result_t!#shared-memory#unstable + - z_owned_shm_t!#shared-memory#unstable + - z_loaned_shm_t!#shared-memory#unstable + - z_owned_shm_mut_t!#shared-memory#unstable + - z_loaned_shm_mut_t!#shared-memory#unstable + - z_owned_shared_memory_provider_t!#shared-memory#unstable + - z_loaned_shared_memory_provider_t!#shared-memory#unstable + - z_owned_alloc_layout_t!#shared-memory#unstable + - z_loaned_alloc_layout_t!#shared-memory#unstable - z_owned_fifo_handler_sample_t! - z_loaned_fifo_handler_sample_t! - z_owned_ring_handler_sample_t! diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 000000000..ee2a10e45 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,118 @@ +// +// Copyright (c) 2017, 2022 ZettaScale Technology. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh team, +// + +use libc::c_void; +use std::fmt::Debug; + +/// A trait for implementing droppable contexts +pub trait DroppableContext: Debug { + fn get(&self) -> *mut c_void; +} + +/// A non-tread-safe droppable context. +/// Contexts are idiomatically used in C together with callback interfaces to deliver associated state +/// information to each callback. +/// +/// This is a non-thread-safe context - zenoh-c guarantees that associated callbacks that share the same +/// zc_context_t instance will never be executed concurrently. In other words, all the callbacks associated +/// with this context data are not required to be thread-safe. +/// +/// NOTE: Remember that the same callback interfaces associated with different zc_context_t instances can +/// still be executed concurrently. The exact behavior depends on user's application, but we strongly +/// discourage our users from pinning to some specific behavior unless they _really_ understand what they +/// are doing. +/// +/// Once moved to zenoh-c ownership, this context is guaranteed to execute delete_fn when deleted. The +/// delete_fn is guaranteed to be executed only once at some point of time after the last associated +/// callback call returns. +/// NOTE: if user doesn't pass the instance of this context to zenoh-c, the delete_fn callback won't +/// be executed. +#[derive(Debug)] +#[repr(C)] +pub struct zc_context_t { + context: *mut c_void, + delete_fn: unsafe extern "C" fn(*mut c_void), +} + +impl From for Context { + fn from(value: zc_context_t) -> Self { + Self(value) + } +} + +#[derive(Debug)] +#[repr(transparent)] +pub struct Context(zc_context_t); +impl DroppableContext for Context { + fn get(&self) -> *mut c_void { + self.0.context + } +} +impl Drop for Context { + fn drop(&mut self) { + unsafe { + (self.0.delete_fn)(self.0.context); + } + } +} + +/// A tread-safe droppable context. +/// Contexts are idiomatically used in C together with callback interfaces to deliver associated state +/// information to each callback. +/// +/// This is a thread-safe context - the associated callbacks may be executed concurrently with the same +/// zc_context_t instance. In other words, all the callbacks associated with this context data MUST be +/// thread-safe. +/// +/// Once moved to zenoh-c ownership, this context is guaranteed to execute delete_fn when deleted.The +/// delete_fn is guaranteed to be executed only once at some point of time after the last associated +/// callback call returns. +/// NOTE: if user doesn't pass the instance of this context to zenoh-c, the delete_fn callback won't +/// be executed. +#[derive(Debug)] +#[repr(C)] +pub struct zc_threadsafe_context_t { + context: zc_threadsafe_context_data_t, + delete_fn: unsafe extern "C" fn(*mut c_void), +} + +impl From for ThreadsafeContext { + fn from(value: zc_threadsafe_context_t) -> Self { + Self(value) + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct zc_threadsafe_context_data_t { + ptr: *mut c_void, +} +unsafe impl Send for zc_threadsafe_context_data_t {} +unsafe impl Sync for zc_threadsafe_context_data_t {} + +#[derive(Debug)] +#[repr(transparent)] +pub struct ThreadsafeContext(zc_threadsafe_context_t); +impl DroppableContext for ThreadsafeContext { + fn get(&self) -> *mut c_void { + self.0.context.ptr + } +} +impl Drop for ThreadsafeContext { + fn drop(&mut self) { + unsafe { + (self.0.delete_fn)(self.0.context.ptr); + } + } +} diff --git a/src/get.rs b/src/get.rs index 4686cb3ed..6fa5b510b 100644 --- a/src/get.rs +++ b/src/get.rs @@ -156,20 +156,12 @@ pub unsafe extern "C" fn z_get( let key_expr = key_expr.transmute_ref(); let mut get = session.get(Selector::new(key_expr, p)); if let Some(options) = options { - if !options.payload.is_null() { - if let Some(payload) = unsafe { options.payload.as_mut() } - .unwrap() - .transmute_mut() - .extract() - { - get = get.payload(payload); - } + if let Some(payload) = options.payload.as_mut() { + let payload = payload.transmute_mut().extract(); + get = get.payload(payload); } - if !options.encoding.is_null() { - let encoding = unsafe { options.encoding.as_mut() } - .unwrap() - .transmute_mut() - .extract(); + if let Some(encoding) = options.encoding.as_mut() { + let encoding = encoding.transmute_mut().extract(); get = get.encoding(encoding); } if !options.source_info.is_null() { diff --git a/src/lib.rs b/src/lib.rs index b7565306b..034489c2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,9 +61,11 @@ pub use publication_cache::*; mod querying_subscriber; pub use platform::*; pub use querying_subscriber::*; +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +pub mod context; pub mod platform; -// #[cfg(feature = "shared-memory")] -// mod shm; +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +pub mod shm; /// Initialises the zenoh runtime logger. /// @@ -84,7 +86,7 @@ fn test_no_default_features() { // " zenoh/auth_pubkey", // " zenoh/auth_usrpwd", // " zenoh/complete_n", - " zenoh/shared-memory", + //" zenoh/shared-memory", // " zenoh/stats", // " zenoh/transport_multilink", // " zenoh/transport_quic", diff --git a/src/payload.rs b/src/payload.rs index 43b0d9ef9..ed8029290 100644 --- a/src/payload.rs +++ b/src/payload.rs @@ -1,4 +1,4 @@ -use crate::errors::{self, z_error_t, Z_EINVAL, Z_EIO, Z_EPARSE, Z_OK}; +use crate::errors::{self, z_error_t, Z_EIO, Z_EPARSE, Z_OK}; use crate::transmute::{ unwrap_ref_unchecked, unwrap_ref_unchecked_mut, Inplace, TransmuteFromHandle, TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr, @@ -18,8 +18,13 @@ use zenoh::bytes::{ Deserialize, Serialize, ZBytes, ZBytesIterator, ZBytesReader, ZBytesWriter, ZSerde, }; +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +use crate::errors::Z_ENULL; +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +use crate::{z_loaned_shm_t, z_owned_shm_mut_t, z_owned_shm_t}; + pub use crate::opaque_types::z_owned_bytes_t; -decl_transmute_owned!(Option, z_owned_bytes_t); +decl_transmute_owned!(ZBytes, z_owned_bytes_t); /// The gravestone value for `z_owned_bytes_t`. #[no_mangle] @@ -32,7 +37,7 @@ extern "C" fn z_bytes_null(this: *mut MaybeUninit) { #[no_mangle] extern "C" fn z_bytes_empty(this: *mut MaybeUninit) { let this = this.transmute_uninit_ptr(); - Inplace::init(this, Some(ZBytes::empty())); + Inplace::init(this, ZBytes::empty()); } /// Drops `this_`, resetting it to gravestone value. If there are any shallow copies @@ -46,14 +51,13 @@ extern "C" fn z_bytes_drop(this: &mut z_owned_bytes_t) { /// Returns ``true`` if `this_` is in a valid state, ``false`` if it is in a gravestone state. #[no_mangle] extern "C" fn z_bytes_check(this: &z_owned_bytes_t) -> bool { - this.transmute_ref().is_some() + !this.transmute_ref().is_empty() } /// Borrows data. #[no_mangle] extern "C" fn z_bytes_loan(this: &z_owned_bytes_t) -> &z_loaned_bytes_t { let payload = this.transmute_ref(); - let payload = unwrap_ref_unchecked(payload); payload.transmute_handle() } @@ -61,7 +65,6 @@ extern "C" fn z_bytes_loan(this: &z_owned_bytes_t) -> &z_loaned_bytes_t { #[no_mangle] extern "C" fn z_bytes_loan_mut(this: &mut z_owned_bytes_t) -> &mut z_loaned_bytes_t { let payload = this.transmute_mut(); - let payload = unwrap_ref_unchecked_mut(payload); payload.transmute_handle_mut() } @@ -80,8 +83,7 @@ extern "C" fn z_bytes_is_empty(this: &z_loaned_bytes_t) -> bool { #[no_mangle] extern "C" fn z_bytes_clone(this: &z_loaned_bytes_t, dst: *mut MaybeUninit) { let dst = dst.transmute_uninit_ptr(); - let src = this.transmute_ref(); - let src = Some(src.clone()); + let src = this.transmute_ref().clone(); Inplace::init(dst, src); } @@ -160,6 +162,85 @@ pub unsafe extern "C" fn z_bytes_decode_into_slice( } } +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Decodes data into an owned SHM buffer by copying it's shared reference +/// +/// @param this_: Data to decode. +/// @param dst: An unitialized memory location where to construct a decoded string. +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn z_bytes_decode_into_owned_shm( + this: &z_loaned_bytes_t, + dst: *mut MaybeUninit, +) -> z_error_t { + use zenoh::shm::zshm; + + let payload = this.transmute_ref(); + match payload.deserialize::<&zshm>() { + Ok(s) => { + Inplace::init(dst.transmute_uninit_ptr(), Some(s.clone().to_owned())); + errors::Z_OK + } + Err(e) => { + log::error!("Failed to decode the payload: {}", e); + Inplace::empty(dst.transmute_uninit_ptr()); + errors::Z_EIO + } + } +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Decodes data into a loaned SHM buffer +/// +/// @param this_: Data to decode. +/// @param dst: An unitialized memory location where to construct a decoded string. +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn z_bytes_decode_into_loaned_shm( + this: &z_loaned_bytes_t, + dst: *mut MaybeUninit<&'static z_loaned_shm_t>, +) -> z_error_t { + use zenoh::shm::zshm; + + let payload = this.transmute_ref(); + match payload.deserialize::<&zshm>() { + Ok(s) => { + (*dst).write(s.transmute_handle()); + errors::Z_OK + } + Err(e) => { + log::error!("Failed to decode the payload: {}", e); + errors::Z_EIO + } + } +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Decodes data into a mutably loaned SHM buffer +/// +/// @param this_: Data to decode. +/// @param dst: An unitialized memory location where to construct a decoded string. +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn z_bytes_decode_into_mut_loaned_shm( + this: &mut z_loaned_bytes_t, + dst: *mut MaybeUninit<&'static mut z_loaned_shm_t>, +) -> z_error_t { + use zenoh::shm::zshm; + + let payload = this.transmute_mut(); + match payload.deserialize_mut::<&mut zshm>() { + Ok(s) => { + (*dst).write(s.transmute_handle_mut()); + errors::Z_OK + } + Err(e) => { + log::error!("Failed to decode the payload: {}", e); + errors::Z_EIO + } + } +} + unsafe impl Send for CSlice {} unsafe impl Sync for CSlice {} @@ -194,7 +275,7 @@ where { let this = this.transmute_uninit_ptr(); let payload = ZBytes::serialize(val); - Inplace::init(this, Some(payload)); + Inplace::init(this, payload); } fn z_bytes_decode_into_arithmetic(this: &z_loaned_bytes_t, val: &mut T) -> z_error_t @@ -354,7 +435,7 @@ pub unsafe extern "C" fn z_bytes_encode_from_slice( let s = CSlice::new_borrowed(data, len); let this = this.transmute_uninit_ptr(); let payload = ZBytes::from(ZSlice::from(s)); - Inplace::init(this, Some(payload)); + Inplace::init(this, payload); } /// Encodes a slice by copying. @@ -368,7 +449,7 @@ pub unsafe extern "C" fn z_bytes_encode_from_slice_copy( let s = CSlice::new_borrowed(data, len).clone(); let this = this.transmute_uninit_ptr(); let payload = ZBytes::from(ZSlice::from(s)); - Inplace::init(this, Some(payload)); + Inplace::init(this, payload); } /// Encodes slice map by aliasing. @@ -386,7 +467,7 @@ pub unsafe extern "C" fn z_bytes_encode_from_slice_map( CSlice::new_borrowed(v.data(), v.len()), ) })); - Inplace::init(dst, Some(payload)); + Inplace::init(dst, payload); } /// Encodes slice map by copying. @@ -404,7 +485,7 @@ pub unsafe extern "C" fn z_bytes_encode_from_slice_map_copy( CSlice::new_borrowed(v.data(), v.len()).clone(), ) })); - Inplace::init(dst, Some(payload)); + Inplace::init(dst, payload); } /// Encodes a null-terminated string by aliasing. @@ -435,16 +516,12 @@ pub extern "C" fn z_bytes_encode_from_pair( first: &mut z_owned_bytes_t, second: &mut z_owned_bytes_t, ) -> z_error_t { - let first = match first.transmute_mut().extract() { - Some(z) => z, - None => return Z_EINVAL, - }; - let second = match second.transmute_mut().extract() { - Some(z) => z, - None => return Z_EINVAL, - }; + let first = first.transmute_mut().extract(); + + let second = second.transmute_mut().extract(); + let b = ZBytes::serialize((first, second)); - Inplace::init(this.transmute_uninit_ptr(), Some(b)); + Inplace::init(this.transmute_uninit_ptr(), b); Z_OK } @@ -458,8 +535,8 @@ pub extern "C" fn z_bytes_decode_into_pair( ) -> z_error_t { match this.transmute_ref().deserialize::<(ZBytes, ZBytes)>() { Ok((a, b)) => { - Inplace::init(first.transmute_uninit_ptr(), Some(a)); - Inplace::init(second.transmute_uninit_ptr(), Some(b)); + Inplace::init(first.transmute_uninit_ptr(), a); + Inplace::init(second.transmute_uninit_ptr(), b); Z_OK } Err(e) => { @@ -470,7 +547,7 @@ pub extern "C" fn z_bytes_decode_into_pair( } struct ZBytesInIterator { - body: extern "C" fn(data: &mut MaybeUninit, context: *mut c_void), + body: extern "C" fn(data: &mut MaybeUninit, context: *mut c_void) -> bool, context: *mut c_void, } @@ -480,20 +557,28 @@ impl Iterator for ZBytesInIterator { fn next(&mut self) -> Option { let mut data = MaybeUninit::::uninit(); - (self.body)(&mut data, self.context); - unsafe { data.assume_init().transmute_mut().extract() }.map(|b| b.into()) + if !(self.body)(&mut data, self.context) { + return None; + } + + let mut data = unsafe { data.assume_init() }; + let buf = data.transmute_mut(); + Some(buf.extract().into()) } } /// Constructs payload from an iterator to `z_owned_bytes_t`. /// @param this_: An uninitialized location in memery for `z_owned_bytes_t` will be constructed. -/// @param iterator_body: Iterator body function, providing data items. Returning NULL +/// @param iterator_body: Iterator body function, providing data items. Returning false is treated as iteration end. /// @param context: Arbitrary context that will be passed to iterator_body. /// @return 0 in case of success, negative error code otherwise. #[no_mangle] pub extern "C" fn z_bytes_encode_from_iter( this: *mut MaybeUninit, - iterator_body: extern "C" fn(data: &mut MaybeUninit, context: *mut c_void), + iterator_body: extern "C" fn( + data: &mut MaybeUninit, + context: *mut c_void, + ) -> bool, context: *mut c_void, ) -> z_error_t { let it = ZBytesInIterator { @@ -502,7 +587,7 @@ pub extern "C" fn z_bytes_encode_from_iter( }; let b = ZBytes::from_iter(it); - Inplace::init(this.transmute_uninit_ptr(), Some(b)); + Inplace::init(this.transmute_uninit_ptr(), b); Z_OK } @@ -518,20 +603,22 @@ pub extern "C" fn z_bytes_get_iterator(data: &z_loaned_bytes_t) -> z_bytes_itera /// Constructs `z_owned_bytes` object corresponding to the next element of encoded data. /// -/// Will construct `z_owned_bytes` when iterator reaches the end. +/// Will construct null-state `z_owned_bytes` when iterator reaches the end. /// @return ``false`` when iterator reaches the end, ``true`` otherwise #[no_mangle] pub extern "C" fn z_bytes_iterator_next( iter: &mut z_bytes_iterator_t, out: *mut MaybeUninit, ) -> bool { - let res = iter.transmute_mut().next().map(|z| z.into()); - if res.is_none() { - Inplace::empty(out.transmute_uninit_ptr()); - false - } else { - Inplace::init(out.transmute_uninit_ptr(), res); - true + match iter.transmute_mut().next() { + Some(buf) => { + Inplace::init(out.transmute_uninit_ptr(), buf.into()); + true + } + None => { + Inplace::empty(out.transmute_uninit_ptr()); + false + } } } @@ -555,6 +642,54 @@ pub extern "C" fn z_bytes_iter( res } +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Encodes from an immutable SHM buffer consuming it +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn z_bytes_encode_from_shm( + this: *mut MaybeUninit, + shm: &mut z_owned_shm_t, +) -> z_error_t { + match shm.transmute_mut().take() { + Some(shm) => { + let this = this.transmute_uninit_ptr(); + Inplace::init(this, shm.into()); + Z_OK + } + None => Z_ENULL, + } +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Encodes from an immutable SHM buffer copying it +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn z_bytes_encode_from_shm_copy( + this: *mut MaybeUninit, + shm: &z_loaned_shm_t, +) { + let this = this.transmute_uninit_ptr(); + Inplace::init(this, shm.transmute_ref().to_owned().into()); +} + +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Encodes from a mutable SHM buffer consuming it +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn z_bytes_encode_from_shm_mut( + this: *mut MaybeUninit, + shm: &mut z_owned_shm_mut_t, +) -> z_error_t { + match shm.transmute_mut().take() { + Some(shm) => { + let this = this.transmute_uninit_ptr(); + Inplace::init(this, shm.into()); + Z_OK + } + None => Z_ENULL, + } +} + pub use crate::z_bytes_reader_t; decl_transmute_handle!(ZBytesReader<'static>, z_bytes_reader_t); /// Returns a reader for the data. diff --git a/src/publisher.rs b/src/publisher.rs index 527d261db..e2035807d 100644 --- a/src/publisher.rs +++ b/src/publisher.rs @@ -173,13 +173,7 @@ pub unsafe extern "C" fn z_publisher_put( options: Option<&mut z_publisher_put_options_t>, ) -> errors::z_error_t { let publisher = this.transmute_ref(); - let payload = match payload.transmute_mut().extract() { - Some(p) => p, - None => { - log::debug!("Attempted to put with a null payload"); - return errors::Z_EINVAL; - } - }; + let payload = payload.transmute_mut().extract(); let mut put = publisher.put(payload); if let Some(options) = options { diff --git a/src/put.rs b/src/put.rs index 46252075a..7eae86dd3 100644 --- a/src/put.rs +++ b/src/put.rs @@ -78,13 +78,7 @@ pub extern "C" fn z_put( ) -> errors::z_error_t { let session = session.transmute_ref(); let key_expr = key_expr.transmute_ref(); - let payload = match payload.transmute_mut().extract() { - Some(p) => p, - None => { - log::debug!("Attempted to put with a null payload"); - return errors::Z_EINVAL; - } - }; + let payload = payload.transmute_mut().extract(); let mut put = session.put(key_expr, payload); if let Some(options) = options { diff --git a/src/queryable.rs b/src/queryable.rs index a27ca212e..8efe0c849 100644 --- a/src/queryable.rs +++ b/src/queryable.rs @@ -240,14 +240,7 @@ pub unsafe extern "C" fn z_query_reply( ) -> errors::z_error_t { let query = this.transmute_ref(); let key_expr = key_expr.transmute_ref(); - - let payload = match payload.transmute_mut().extract() { - Some(p) => p, - None => { - log::debug!("Attempted to reply with a null payload"); - return errors::Z_EINVAL; - } - }; + let payload = payload.transmute_mut().extract(); let mut reply = query.reply(key_expr, payload); if let Some(options) = options { @@ -301,14 +294,7 @@ pub unsafe extern "C" fn z_query_reply_err( options: Option<&mut z_query_reply_err_options_t>, ) -> errors::z_error_t { let query = this.transmute_ref(); - - let payload = match payload.transmute_mut().extract() { - Some(p) => p, - None => { - log::debug!("Attempted to reply_err with a null payload"); - return errors::Z_EINVAL; - } - }; + let payload = payload.transmute_mut().extract(); let reply = query.reply_err(payload).encoding( options diff --git a/src/session.rs b/src/session.rs index dcbd49683..8a5d51dfb 100644 --- a/src/session.rs +++ b/src/session.rs @@ -22,6 +22,9 @@ use std::sync::Arc; use zenoh::core::Wait; use zenoh::session::Session; +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +use crate::z_loaned_shared_memory_client_storage_t; + use crate::opaque_types::z_owned_session_t; decl_transmute_owned!(Option>, z_owned_session_t); @@ -78,6 +81,45 @@ pub extern "C" fn z_open( } } +#[cfg(all(feature = "shared-memory", feature = "unstable"))] +/// Constructs and opens a new Zenoh session with specified client storage. +/// +/// @return 0 in case of success, negative error code otherwise (in this case the session will be in its gravestone state). +#[allow(clippy::missing_safety_doc)] +#[no_mangle] +pub extern "C" fn z_open_with_custom_shm_clients( + this: *mut MaybeUninit, + config: &mut z_owned_config_t, + shm_clients: &z_loaned_shared_memory_client_storage_t, +) -> errors::z_error_t { + let this = this.transmute_uninit_ptr(); + if cfg!(feature = "logger-autoinit") { + zc_init_logger(); + } + let config = match config.transmute_mut().extract() { + Some(c) => c, + None => { + log::error!("Config not provided"); + Inplace::empty(this); + return errors::Z_EINVAL; + } + }; + match zenoh::open(config) + .with_shm_clients(shm_clients.transmute_ref().clone()) + .wait() + { + Ok(s) => { + Inplace::init(this, Some(Arc::new(s))); + errors::Z_OK + } + Err(e) => { + log::error!("Error opening session: {}", e); + Inplace::empty(this); + errors::Z_ENETWORK + } + } +} + /// Returns ``true`` if `session` is valid, ``false`` otherwise. #[allow(clippy::missing_safety_doc)] #[no_mangle] diff --git a/src/shm.rs b/src/shm.rs deleted file mode 100644 index cb90ed65f..000000000 --- a/src/shm.rs +++ /dev/null @@ -1,226 +0,0 @@ -// -// Copyright (c) 2017, 2022 ZettaScale Technology. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh team, -// - -use std::{ - cell::UnsafeCell, - ops::{Deref, DerefMut}, -}; - -use libc::c_char; -use zenoh::{ - buffers::ZBuf, - shm::{SharedMemoryBuf, SharedMemoryManager}, -}; - -use crate::{z_loaned_session_t, z_owned_bytes_t, z_bytes_null}; - -#[repr(C)] -pub struct zc_owned_shm_manager_t(usize); -impl From>>> for zc_owned_shm_manager_t { - fn from(value: Option>>) -> Self { - unsafe { std::mem::transmute(value) } - } -} -impl Deref for zc_owned_shm_manager_t { - type Target = Option>>; - fn deref(&self) -> &Self::Target { - unsafe { std::mem::transmute(self) } - } -} -impl DerefMut for zc_owned_shm_manager_t { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { std::mem::transmute(self) } - } -} -impl zc_owned_shm_manager_t { - pub fn null() -> Self { - None::<_>.into() - } -} - -#[no_mangle] -pub extern "C" fn zc_shm_manager_new( - session: z_loaned_session_t, - id: *const c_char, - size: usize, -) -> zc_owned_shm_manager_t { - let _ = session; // This function will likely need the session in the future, so we start doing the association now - (move || { - let len = unsafe { libc::strlen(id) }; - let id = unsafe { std::str::from_utf8(std::slice::from_raw_parts(id as *const u8, len)) } - .ok()? - .to_owned(); - Some(Box::new(UnsafeCell::new( - SharedMemoryManager::make(id, size).ok()?, - ))) - })() - .into() -} - -#[no_mangle] -pub extern "C" fn zc_shm_manager_drop(manager: &mut zc_owned_shm_manager_t) { - manager.take(); -} - -#[no_mangle] -pub extern "C" fn zc_shm_manager_check(manager: &zc_owned_shm_manager_t) -> bool { - manager.is_some() -} - -#[no_mangle] -pub extern "C" fn zc_shm_manager_null() -> zc_owned_shm_manager_t { - zc_owned_shm_manager_t::null() -} - -/// Runs a garbage collection pass on the SHM manager. -/// -/// Returns the number of bytes that have been freed by the pass. -/// -/// # Safety -/// Calling this function concurrently with other shm functions on the same manager is UB. -#[no_mangle] -pub unsafe extern "C" fn zc_shm_gc(manager: &zc_owned_shm_manager_t) -> usize { - if let Some(shm) = manager.as_ref() { - unsafe { (*shm.get()).garbage_collect() } - } else { - 0 - } -} - -/// Runs a defragmentation pass on the SHM manager. -/// -/// Note that this doesn't trigger a garbage collection pass, nor does it move currently allocated data. -/// -/// # Safety -/// Calling this function concurrently with other shm functions on the same manager is UB. -#[no_mangle] -pub unsafe extern "C" fn zc_shm_defrag(manager: &zc_owned_shm_manager_t) -> usize { - if let Some(shm) = manager.as_ref() { - unsafe { (*shm.get()).defragment() } - } else { - 0 - } -} - -#[repr(C)] -#[derive(Default)] -pub struct zc_owned_shmbuf_t([usize; 9]); -impl From>> for zc_owned_shmbuf_t { - fn from(value: UnsafeCell>) -> Self { - unsafe { std::mem::transmute(value) } - } -} -impl Deref for zc_owned_shmbuf_t { - type Target = UnsafeCell>; - fn deref(&self) -> &Self::Target { - unsafe { std::mem::transmute(self) } - } -} -impl DerefMut for zc_owned_shmbuf_t { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { std::mem::transmute(self) } - } -} - -impl zc_owned_shmbuf_t { - pub fn null() -> Self { - UnsafeCell::new(None).into() - } -} - -/// Allocates a buffer of size `capacity` in the manager's memory. -/// -/// # Safety -/// Calling this function concurrently with other shm functions on the same manager is UB. -#[no_mangle] -pub unsafe extern "C" fn zc_shm_alloc( - manager: &zc_owned_shm_manager_t, - capacity: usize, -) -> zc_owned_shmbuf_t { - manager - .as_ref() - .map(|shm| unsafe { - match (*shm.get()).alloc(capacity) { - Ok(buf) => std::mem::transmute(buf), - Err(_) => Default::default(), - } - }) - .unwrap_or_default() -} - -/// Drops the SHM buffer, decrementing its backing reference counter. -#[no_mangle] -pub extern "C" fn zc_shmbuf_drop(buf: &mut zc_owned_shmbuf_t) { - buf.get_mut().take(); -} - -/// Returns `false` if `buf` is in its gravestone state. -#[no_mangle] -pub extern "C" fn zc_shmbuf_check(buf: &zc_owned_shmbuf_t) -> bool { - unsafe { (*buf.get()).is_some() } -} - -/// Constructs a null safe-to-drop value of type `zc_owned_shmbuf_t` -#[no_mangle] -pub extern "C" fn zc_shmbuf_null() -> zc_owned_shmbuf_t { - zc_owned_shmbuf_t::null() -} - -/// Constructs an owned payload from an owned SHM buffer. -#[no_mangle] -pub extern "C" fn zc_shmbuf_into_payload(buf: &mut zc_owned_shmbuf_t) -> z_owned_bytes_t { - match buf.get_mut().take() { - Some(buf) => ZBuf::from(buf).try_into().unwrap_or_default(), - None => z_bytes_null(), - } -} - -/// Returns the start of the SHM buffer. -#[no_mangle] -pub unsafe extern "C" fn zc_shmbuf_ptr(buf: &zc_owned_shmbuf_t) -> *mut u8 { - match &*buf.get() { - None => std::ptr::null_mut(), - Some(buf) => buf.as_slice().as_ptr().cast_mut(), - } -} - -/// Returns the capacity of the SHM buffer. -#[no_mangle] -pub unsafe extern "C" fn zc_shmbuf_capacity(buf: &zc_owned_shmbuf_t) -> usize { - match &*buf.get() { - None => 0, - Some(buf) => buf.info.length, - } -} - -/// Returns the length of the SHM buffer. -/// -/// Note that when constructing an SHM buffer, length is defaulted to its capacity. -#[no_mangle] -pub unsafe extern "C" fn zc_shmbuf_length(buf: &zc_owned_shmbuf_t) -> usize { - match &*buf.get() { - None => 0, - Some(buf) => buf.len, - } -} - -/// Sets the length of the SHM buffer. -/// -/// This lets Zenoh know how much of the data to write over the network when sending the value to non-SHM-compatible neighboors. -#[no_mangle] -pub unsafe extern "C" fn zc_shmbuf_set_length(buf: &zc_owned_shmbuf_t, len: usize) { - if let Some(buf) = &mut *buf.get() { - buf.len = len - } -} diff --git a/src/shm/buffer/mod.rs b/src/shm/buffer/mod.rs new file mode 100644 index 000000000..9238dcdc1 --- /dev/null +++ b/src/shm/buffer/mod.rs @@ -0,0 +1,16 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod zshm; +pub mod zshmmut; diff --git a/src/shm/buffer/zshm.rs b/src/shm/buffer/zshm.rs new file mode 100644 index 000000000..ffbc07062 --- /dev/null +++ b/src/shm/buffer/zshm.rs @@ -0,0 +1,127 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{ + borrow::{Borrow, BorrowMut}, + mem::MaybeUninit, +}; + +use zenoh::shm::{zshm, zshmmut, ZShm}; + +use crate::{ + transmute::{ + unwrap_ref_unchecked, unwrap_ref_unchecked_mut, Inplace, TransmuteFromHandle, + TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr, + }, + z_loaned_shm_mut_t, z_loaned_shm_t, z_owned_shm_mut_t, z_owned_shm_t, +}; + +decl_transmute_owned!(Option, z_owned_shm_t); + +decl_transmute_handle!(zshm, z_loaned_shm_t); + +/// Constructs ZShm slice from ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_from_mut( + this: *mut MaybeUninit, + that: &mut z_owned_shm_mut_t, +) { + let shm: Option = that.transmute_mut().extract().map(|val| val.into()); + Inplace::init(this.transmute_uninit_ptr(), shm); +} + +/// Constructs ZShm slice in its gravestone value. +#[no_mangle] +pub extern "C" fn z_shm_null(this: *mut MaybeUninit) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_shm_check(this: &z_owned_shm_t) -> bool { + this.transmute_ref().is_some() +} + +/// Converts borrowed ZShm slice to owned ZShm slice by performing a shallow SHM reference copy +#[no_mangle] +pub extern "C" fn z_shm_clone(this: &z_loaned_shm_t, out: *mut MaybeUninit) { + let this = this.transmute_ref(); + let copy = this.to_owned(); + Inplace::init(out.transmute_uninit_ptr(), Some(copy)); +} + +/// Borrows ZShm slice +#[no_mangle] +pub extern "C" fn z_shm_loan(this: &z_owned_shm_t) -> &z_loaned_shm_t { + let this = this.transmute_ref(); + let this: &ZShm = unwrap_ref_unchecked(this); + let shm: &zshm = this.borrow(); + shm.transmute_handle() +} + +/// Mutably borrows ZShm slice +#[no_mangle] +pub extern "C" fn z_shm_loan_mut(this: &mut z_owned_shm_t) -> &mut z_loaned_shm_t { + let this = this.transmute_mut(); + let this: &mut ZShm = unwrap_ref_unchecked_mut(this); + let shm: &mut zshm = this.borrow_mut(); + shm.transmute_handle_mut() +} + +/// Mutably borrows ZShm slice as borrowed ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_try_mut(this: &mut z_owned_shm_t) -> *mut z_loaned_shm_mut_t { + let this = this.transmute_mut(); + let this: &mut ZShm = unwrap_ref_unchecked_mut(this); + let shm: &mut zshm = this.borrow_mut(); + match shm.try_into() { + Ok(val) => { + let v: &mut zshmmut = val; + v.transmute_handle_mut() + } + Err(_) => std::ptr::null_mut(), + } +} + +/// Deletes ZShm slice +#[no_mangle] +pub extern "C" fn z_shm_drop(this: &mut z_owned_shm_t) { + let _ = this.transmute_mut().take(); +} + +/// Tries to reborrow mutably-borrowed ZShm slice as borrowed ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_try_reloan_mut(this: &mut z_loaned_shm_t) -> *mut z_loaned_shm_mut_t { + let this = this.transmute_mut(); + match this.try_into() { + Ok(val) => { + let v: &mut zshmmut = val; + v.transmute_handle_mut() + } + Err(_) => std::ptr::null_mut(), + } +} + +/// @return the length of the ZShm slice +#[no_mangle] +pub extern "C" fn z_shm_len(this: &z_loaned_shm_t) -> usize { + this.transmute_ref().len() +} + +/// @return the pointer of the ZShm slice +#[no_mangle] +pub extern "C" fn z_shm_data(this: &z_loaned_shm_t) -> *const libc::c_uchar { + let s = this.transmute_ref(); + s.as_ref().as_ptr() +} diff --git a/src/shm/buffer/zshmmut.rs b/src/shm/buffer/zshmmut.rs new file mode 100644 index 000000000..6768b0aa1 --- /dev/null +++ b/src/shm/buffer/zshmmut.rs @@ -0,0 +1,82 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{borrow::BorrowMut, mem::MaybeUninit}; + +use zenoh::shm::{zshmmut, ZShmMut}; + +use crate::{ + transmute::{ + unwrap_ref_unchecked_mut, Inplace, TransmuteFromHandle, TransmuteIntoHandle, TransmuteRef, + TransmuteUninitPtr, + }, + z_loaned_shm_mut_t, z_owned_shm_mut_t, z_owned_shm_t, +}; + +decl_transmute_owned!(Option, z_owned_shm_mut_t); + +decl_transmute_handle!(zshmmut, z_loaned_shm_mut_t); + +/// Tries to construct ZShmMut slice from ZShm slice +#[no_mangle] +pub extern "C" fn z_shm_mut_try_from_immut( + this: *mut MaybeUninit, + that: &mut z_owned_shm_t, +) { + let shm: Option = that + .transmute_mut() + .extract() + .and_then(|val| val.try_into().ok()); + Inplace::init(this.transmute_uninit_ptr(), shm); +} + +/// Constructs ZShmMut slice in its gravestone value. +#[no_mangle] +pub extern "C" fn z_shm_mut_null(this: *mut MaybeUninit) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_shm_mut_check(this: &z_owned_shm_mut_t) -> bool { + this.transmute_ref().is_some() +} + +/// Borrows ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_mut_loan_mut(this: &mut z_owned_shm_mut_t) -> &mut z_loaned_shm_mut_t { + let this = this.transmute_mut(); + let this = unwrap_ref_unchecked_mut(this); + let shmmut: &mut zshmmut = this.borrow_mut(); + shmmut.transmute_handle_mut() +} + +/// Deletes ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_mut_drop(this: &mut z_owned_shm_mut_t) { + let _ = this.transmute_mut().take(); +} + +/// @return the length of the ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_mut_len(this: &z_loaned_shm_mut_t) -> usize { + this.transmute_ref().len() +} + +/// @return the mutable pointer of the ZShmMut slice +#[no_mangle] +pub extern "C" fn z_shm_mut_data_mut(this: &mut z_loaned_shm_mut_t) -> *mut libc::c_uchar { + let s = this.transmute_mut(); + s.as_mut().as_mut_ptr() +} diff --git a/src/shm/client/mod.rs b/src/shm/client/mod.rs new file mode 100644 index 000000000..eab20733e --- /dev/null +++ b/src/shm/client/mod.rs @@ -0,0 +1,16 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod shared_memory_client; +pub mod shared_memory_segment; diff --git a/src/shm/client/shared_memory_client.rs b/src/shm/client/shared_memory_client.rs new file mode 100644 index 000000000..3f20f53b7 --- /dev/null +++ b/src/shm/client/shared_memory_client.rs @@ -0,0 +1,108 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +use std::{mem::MaybeUninit, sync::Arc}; + +use libc::c_void; +use zenoh::core::Result; +use zenoh::shm::{SegmentID, SharedMemoryClient, SharedMemorySegment}; +use zenoh_util::core::bail; + +use crate::context::DroppableContext; +use crate::transmute::TransmuteRef; +use crate::{ + context::{zc_threadsafe_context_t, ThreadsafeContext}, + errors, + shm::common::types::z_segment_id_t, + transmute::{Inplace, TransmuteUninitPtr}, +}; + +pub use crate::opaque_types::z_owned_shared_memory_client_t; + +use super::shared_memory_segment::{z_shared_memory_segment_t, DynamicSharedMemorySegment}; + +/// A callbacks for SharedMemoryClient +#[derive(Debug)] +#[repr(C)] +pub struct zc_shared_memory_client_callbacks_t { + attach_fn: unsafe extern "C" fn( + out_segment: &mut MaybeUninit, + segment_id: z_segment_id_t, + context: *mut c_void, + ) -> bool, +} + +decl_transmute_owned!( + Option>, + z_owned_shared_memory_client_t +); + +#[derive(Debug)] +pub struct DynamicSharedMemoryClient { + context: ThreadsafeContext, + callbacks: zc_shared_memory_client_callbacks_t, +} + +impl DynamicSharedMemoryClient { + pub fn new(context: ThreadsafeContext, callbacks: zc_shared_memory_client_callbacks_t) -> Self { + Self { context, callbacks } + } +} + +impl SharedMemoryClient for DynamicSharedMemoryClient { + fn attach(&self, segment: SegmentID) -> Result> { + let mut segment_data = MaybeUninit::uninit(); + unsafe { + match (self.callbacks.attach_fn)(&mut segment_data, segment, self.context.get()) { + true => Ok(Arc::new(DynamicSharedMemorySegment::new( + segment_data.assume_init(), + ))), + false => bail!("C Callback returned error"), + } + } + } +} + +/// Creates a new SHM Client +#[no_mangle] +pub extern "C" fn z_shared_memory_client_new( + this: *mut MaybeUninit, + context: zc_threadsafe_context_t, + callbacks: zc_shared_memory_client_callbacks_t, +) -> errors::z_error_t { + let client = Arc::new(DynamicSharedMemoryClient::new(context.into(), callbacks)) + as Arc; + + Inplace::init(this.transmute_uninit_ptr(), Some(client)); + errors::Z_OK +} + +/// Constructs SHM client in its gravestone value. +#[no_mangle] +pub extern "C" fn z_shared_memory_client_null( + this: *mut MaybeUninit, +) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_shared_memory_client_check(this: &z_owned_shared_memory_client_t) -> bool { + this.transmute_ref().is_some() +} + +/// Deletes SHM Client +#[no_mangle] +pub extern "C" fn z_shared_memory_client_drop(this: &mut z_owned_shared_memory_client_t) { + let _ = this.transmute_mut().take(); +} diff --git a/src/shm/client/shared_memory_segment.rs b/src/shm/client/shared_memory_segment.rs new file mode 100644 index 000000000..6d9904911 --- /dev/null +++ b/src/shm/client/shared_memory_segment.rs @@ -0,0 +1,68 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::sync::atomic::AtomicPtr; + +use libc::c_void; +use zenoh::core::Result; +use zenoh::shm::{ChunkID, SharedMemorySegment}; +use zenoh_util::core::zerror; + +use crate::context::DroppableContext; +use crate::{ + context::{zc_threadsafe_context_t, ThreadsafeContext}, + shm::common::types::z_chunk_id_t, +}; + +/// A callbacks for SharedMemorySegment +#[derive(Debug)] +#[repr(C)] +pub struct zc_shared_memory_segment_callbacks_t { + map_fn: unsafe extern "C" fn(chunk_id: z_chunk_id_t, context: *mut c_void) -> *mut u8, +} + +/// A SharedMemorySegment +#[derive(Debug)] +#[repr(C)] +pub struct z_shared_memory_segment_t { + context: zc_threadsafe_context_t, + callbacks: zc_shared_memory_segment_callbacks_t, +} + +#[derive(Debug)] +pub struct DynamicSharedMemorySegment { + context: ThreadsafeContext, + callbacks: zc_shared_memory_segment_callbacks_t, +} + +impl DynamicSharedMemorySegment { + pub fn new(data: z_shared_memory_segment_t) -> Self { + Self { + context: data.context.into(), + callbacks: data.callbacks, + } + } +} + +impl SharedMemorySegment for DynamicSharedMemorySegment { + fn map(&self, chunk: ChunkID) -> Result> { + unsafe { + let cb_result = (self.callbacks.map_fn)(chunk, self.context.get()); + cb_result + .as_mut() + .map(|p| AtomicPtr::new(p)) + .ok_or_else(|| zerror!("C callback returned null pointer!").into()) + } + } +} diff --git a/src/shm/client_storage/mod.rs b/src/shm/client_storage/mod.rs new file mode 100644 index 000000000..2f8be8399 --- /dev/null +++ b/src/shm/client_storage/mod.rs @@ -0,0 +1,202 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{mem::MaybeUninit, sync::Arc}; + +use zenoh::shm::{ + ProtocolID, SharedMemoryClient, SharedMemoryClientStorage, GLOBAL_CLIENT_STORAGE, +}; + +use crate::{ + errors::{z_error_t, Z_EINVAL, Z_OK}, + transmute::{ + unwrap_ref_unchecked, unwrap_ref_unchecked_mut, Inplace, TransmuteFromHandle, + TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr, + }, + z_loaned_shared_memory_client_storage_t, z_owned_shared_memory_client_storage_t, + z_owned_shared_memory_client_t, zc_loaned_shared_memory_client_list_t, + zc_owned_shared_memory_client_list_t, +}; + +use super::common::types::z_protocol_id_t; + +decl_transmute_owned!( + Option)>>, + zc_owned_shared_memory_client_list_t +); + +decl_transmute_handle!( + Vec<(ProtocolID, Arc)>, + zc_loaned_shared_memory_client_list_t +); + +/// Creates a new empty list of SHM Clients +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_new( + this: *mut MaybeUninit, +) -> z_error_t { + let client_list: Vec<(ProtocolID, Arc)> = Vec::default(); + Inplace::init(this.transmute_uninit_ptr(), Some(client_list)); + Z_OK +} + +/// Constructs SHM client list in its gravestone value. +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_null( + this: *mut MaybeUninit, +) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_check( + this: &zc_owned_shared_memory_client_list_t, +) -> bool { + this.transmute_ref().is_some() +} + +/// Deletes list of SHM Clients +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_drop( + this: &mut zc_owned_shared_memory_client_list_t, +) { + let _ = this.transmute_mut().take(); +} + +/// Borrows list of SHM Clients +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_loan( + this: &zc_owned_shared_memory_client_list_t, +) -> &zc_loaned_shared_memory_client_list_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} + +/// Mutably borrows list of SHM Clients +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_loan_mut( + this: &mut zc_owned_shared_memory_client_list_t, +) -> &mut zc_loaned_shared_memory_client_list_t { + let this = this.transmute_mut(); + let this = unwrap_ref_unchecked_mut(this); + this.transmute_handle_mut() +} + +#[no_mangle] +pub extern "C" fn zc_shared_memory_client_list_add_client( + id: z_protocol_id_t, + client: &mut z_owned_shared_memory_client_t, + list: &mut zc_loaned_shared_memory_client_list_t, +) -> z_error_t { + match client.transmute_mut().extract() { + Some(client) => { + list.transmute_mut().push((id, client)); + Z_OK + } + None => Z_EINVAL, + } +} + +decl_transmute_owned!( + Option>, + z_owned_shared_memory_client_storage_t +); + +decl_transmute_handle!( + Arc, + z_loaned_shared_memory_client_storage_t +); + +#[no_mangle] +pub extern "C" fn z_ref_shared_memory_client_storage_global( + this: *mut MaybeUninit, +) -> z_error_t { + Inplace::init( + this.transmute_uninit_ptr(), + Some(GLOBAL_CLIENT_STORAGE.clone()), + ); + Z_OK +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_client_storage_new_default( + this: *mut MaybeUninit, +) -> z_error_t { + Inplace::init( + this.transmute_uninit_ptr(), + Some(Arc::new( + SharedMemoryClientStorage::builder() + .with_default_client_set() + .build(), + )), + ); + Z_OK +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_client_storage_new( + this: *mut MaybeUninit, + clients: &zc_loaned_shared_memory_client_list_t, + add_default_client_set: bool, +) -> z_error_t { + let clients = clients.transmute_ref(); + if clients.is_empty() { + return Z_EINVAL; + } + + let builder = match add_default_client_set { + true => SharedMemoryClientStorage::builder() + .with_default_client_set() + .with_clients(clients), + false => SharedMemoryClientStorage::builder().with_clients(clients), + }; + Inplace::init(this.transmute_uninit_ptr(), Some(Arc::new(builder.build()))); + Z_OK +} + +/// Constructs SHM Client Storage in its gravestone value. +#[no_mangle] +pub extern "C" fn z_shared_memory_client_storage_null( + this: *mut MaybeUninit, +) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_shared_memory_client_storage_check( + this: &z_owned_shared_memory_client_storage_t, +) -> bool { + this.transmute_ref().is_some() +} + +/// Derefs SHM Client Storage +#[no_mangle] +pub extern "C" fn z_shared_memory_client_storage_drop( + this: &mut z_owned_shared_memory_client_storage_t, +) { + let _ = this.transmute_mut().take(); +} + +/// Borrows SHM Client Storage +#[no_mangle] +pub extern "C" fn z_shared_memory_client_storage_loan( + this: &z_owned_shared_memory_client_storage_t, +) -> &z_loaned_shared_memory_client_storage_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} diff --git a/src/shm/common/mod.rs b/src/shm/common/mod.rs new file mode 100644 index 000000000..222c7286b --- /dev/null +++ b/src/shm/common/mod.rs @@ -0,0 +1,15 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod types; diff --git a/src/shm/common/types.rs b/src/shm/common/types.rs new file mode 100644 index 000000000..4b4d7518f --- /dev/null +++ b/src/shm/common/types.rs @@ -0,0 +1,27 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +/// Unique protocol identifier. +/// Here is a contract: it is up to user to make sure that incompatible SharedMemoryClient +/// and SharedMemoryProviderBackend implementations will never use the same ProtocolID +#[allow(non_camel_case_types)] +pub type z_protocol_id_t = u32; + +/// Unique segment identifier +#[allow(non_camel_case_types)] +pub type z_segment_id_t = u32; + +/// Chunk id within it's segment +#[allow(non_camel_case_types)] +pub type z_chunk_id_t = u32; diff --git a/src/shm/mod.rs b/src/shm/mod.rs new file mode 100644 index 000000000..a87188da2 --- /dev/null +++ b/src/shm/mod.rs @@ -0,0 +1,20 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod buffer; +pub mod client; +pub mod client_storage; +pub mod common; +pub mod protocol_implementations; +pub mod provider; diff --git a/src/shm/protocol_implementations/mod.rs b/src/shm/protocol_implementations/mod.rs new file mode 100644 index 000000000..df92f6353 --- /dev/null +++ b/src/shm/protocol_implementations/mod.rs @@ -0,0 +1,15 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod posix; diff --git a/src/shm/protocol_implementations/posix/mod.rs b/src/shm/protocol_implementations/posix/mod.rs new file mode 100644 index 000000000..9f984d20b --- /dev/null +++ b/src/shm/protocol_implementations/posix/mod.rs @@ -0,0 +1,17 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod posix_shared_memory_client; +pub mod posix_shared_memory_provider; +pub mod protocol_id; diff --git a/src/shm/protocol_implementations/posix/posix_shared_memory_client.rs b/src/shm/protocol_implementations/posix/posix_shared_memory_client.rs new file mode 100644 index 000000000..bbe619a16 --- /dev/null +++ b/src/shm/protocol_implementations/posix/posix_shared_memory_client.rs @@ -0,0 +1,33 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{mem::MaybeUninit, sync::Arc}; + +use zenoh::shm::{PosixSharedMemoryClient, SharedMemoryClient}; + +use crate::{ + errors::{z_error_t, Z_OK}, + transmute::{Inplace, TransmuteUninitPtr}, + z_owned_shared_memory_client_t, +}; + +/// Creates a new POSIX SHM Client +#[no_mangle] +pub extern "C" fn z_posix_shared_memory_client_new( + this: *mut MaybeUninit, +) -> z_error_t { + let client = Arc::new(PosixSharedMemoryClient) as Arc; + Inplace::init(this.transmute_uninit_ptr(), Some(client)); + Z_OK +} diff --git a/src/shm/protocol_implementations/posix/posix_shared_memory_provider.rs b/src/shm/protocol_implementations/posix/posix_shared_memory_provider.rs new file mode 100644 index 000000000..ef2836d3d --- /dev/null +++ b/src/shm/protocol_implementations/posix/posix_shared_memory_provider.rs @@ -0,0 +1,61 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::mem::MaybeUninit; + +use zenoh::shm::{ + AllocLayout, PosixSharedMemoryProviderBackend, SharedMemoryProvider, + SharedMemoryProviderBuilder, StaticProtocolID, POSIX_PROTOCOL_ID, +}; + +use crate::{ + errors::{z_error_t, Z_EINVAL, Z_OK}, + shm::provider::shared_memory_provider::CSHMProvider, + transmute::{Inplace, TransmuteFromHandle, TransmuteUninitPtr}, + z_loaned_memory_layout_t, z_owned_shared_memory_provider_t, +}; + +pub type PosixSharedMemoryProvider = + SharedMemoryProvider, PosixSharedMemoryProviderBackend>; + +pub type PosixAllocLayout = + AllocLayout<'static, StaticProtocolID, PosixSharedMemoryProviderBackend>; + +/// Creates a new threadsafe SHM Provider +#[no_mangle] +pub extern "C" fn z_posix_shared_memory_provider_new( + this: *mut MaybeUninit, + layout: &z_loaned_memory_layout_t, +) -> z_error_t { + match PosixSharedMemoryProviderBackend::builder() + .with_layout(layout.transmute_ref()) + .res() + { + Ok(backend) => { + let provider = SharedMemoryProviderBuilder::builder() + .protocol_id::() + .backend(backend) + .res(); + Inplace::init( + this.transmute_uninit_ptr(), + Some(CSHMProvider::Posix(provider)), + ); + Z_OK + } + Err(e) => { + log::error!("{}", e); + Z_EINVAL + } + } +} diff --git a/src/shm/protocol_implementations/posix/protocol_id.rs b/src/shm/protocol_implementations/posix/protocol_id.rs new file mode 100644 index 000000000..2d6b4bca8 --- /dev/null +++ b/src/shm/protocol_implementations/posix/protocol_id.rs @@ -0,0 +1,20 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use libc::c_uint; +use zenoh::shm::POSIX_PROTOCOL_ID; + +// Protocol identifier for POSIX SHM Protocol +#[no_mangle] +pub static Z_SHM_POSIX_PROTOCOL_ID: c_uint = POSIX_PROTOCOL_ID as c_uint; diff --git a/src/shm/provider/alloc_layout.rs b/src/shm/provider/alloc_layout.rs new file mode 100644 index 000000000..44c1d1b75 --- /dev/null +++ b/src/shm/provider/alloc_layout.rs @@ -0,0 +1,148 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::mem::MaybeUninit; + +use crate::{ + context::{zc_threadsafe_context_t, ThreadsafeContext}, + errors::z_error_t, + shm::protocol_implementations::posix::posix_shared_memory_provider::PosixAllocLayout, + transmute::{ + unwrap_ref_unchecked, Inplace, TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr, + }, + z_loaned_alloc_layout_t, z_loaned_shared_memory_provider_t, z_owned_alloc_layout_t, + z_owned_buf_alloc_result_t, +}; +use libc::c_void; +use zenoh::shm::{ + AllocLayout, BlockOn, Deallocate, Defragment, DynamicProtocolID, GarbageCollect, JustAlloc, +}; + +use crate::context::Context; + +use super::{ + alloc_layout_impl::{alloc, alloc_async, alloc_layout_new}, + shared_memory_provider_backend::DynamicSharedMemoryProviderBackend, + types::z_alloc_alignment_t, +}; + +pub type DynamicAllocLayout = + AllocLayout<'static, DynamicProtocolID, DynamicSharedMemoryProviderBackend>; + +pub type DynamicAllocLayoutThreadsafe = + AllocLayout<'static, DynamicProtocolID, DynamicSharedMemoryProviderBackend>; + +pub enum CSHMLayout { + Posix(PosixAllocLayout), + Dynamic(DynamicAllocLayout), + DynamicThreadsafe(DynamicAllocLayoutThreadsafe), +} + +decl_transmute_owned!(Option, z_owned_alloc_layout_t); +decl_transmute_handle!(CSHMLayout, z_loaned_alloc_layout_t); + +/// Creates a new Alloc Layout for SHM Provider +#[no_mangle] +pub extern "C" fn z_alloc_layout_new( + this: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + alloc_layout_new(this, provider, size, alignment) +} + +/// Constructs Alloc Layout in its gravestone value. +#[no_mangle] +pub extern "C" fn z_alloc_layout_null(this: *mut MaybeUninit) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_alloc_layout_check(this: &z_owned_alloc_layout_t) -> bool { + this.transmute_ref().is_some() +} + +/// Borrows Alloc Layout +#[no_mangle] +pub extern "C" fn z_alloc_layout_loan(this: &z_owned_alloc_layout_t) -> &z_loaned_alloc_layout_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} + +/// Deletes Alloc Layout +#[no_mangle] +pub extern "C" fn z_alloc_layout_drop(this: &mut z_owned_alloc_layout_t) { + let _ = this.transmute_mut().take(); +} + +#[no_mangle] +pub extern "C" fn z_alloc_layout_alloc( + out_result: *mut MaybeUninit, + layout: &z_loaned_alloc_layout_t, +) { + alloc::(out_result, layout); +} + +#[no_mangle] +pub extern "C" fn z_alloc_layout_alloc_gc( + out_result: *mut MaybeUninit, + layout: &z_loaned_alloc_layout_t, +) { + alloc::(out_result, layout); +} + +#[no_mangle] +pub extern "C" fn z_alloc_layout_alloc_gc_defrag( + out_result: *mut MaybeUninit, + layout: &z_loaned_alloc_layout_t, +) { + alloc::>(out_result, layout); +} + +#[no_mangle] +pub extern "C" fn z_alloc_layout_alloc_gc_defrag_dealloc( + out_result: *mut MaybeUninit, + layout: &z_loaned_alloc_layout_t, +) { + alloc::>>(out_result, layout); +} + +#[no_mangle] +pub extern "C" fn z_alloc_layout_alloc_gc_defrag_blocking( + out_result: *mut MaybeUninit, + layout: &z_loaned_alloc_layout_t, +) { + alloc::>>(out_result, layout); +} + +#[no_mangle] +pub extern "C" fn z_alloc_layout_threadsafe_alloc_gc_defrag_async( + out_result: &'static mut MaybeUninit, + layout: &'static z_loaned_alloc_layout_t, + result_context: zc_threadsafe_context_t, + result_callback: unsafe extern "C" fn( + *mut c_void, + &mut MaybeUninit, + ), +) -> z_error_t { + alloc_async::>>( + out_result, + layout, + result_context, + result_callback, + ) +} diff --git a/src/shm/provider/alloc_layout_impl.rs b/src/shm/provider/alloc_layout_impl.rs new file mode 100644 index 000000000..0613225af --- /dev/null +++ b/src/shm/provider/alloc_layout_impl.rs @@ -0,0 +1,160 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::mem::MaybeUninit; + +use libc::c_void; +use zenoh::shm::{ + AllocLayout, AllocPolicy, DynamicProtocolID, PosixSharedMemoryProviderBackend, + ProtocolIDSource, SharedMemoryProviderBackend, StaticProtocolID, POSIX_PROTOCOL_ID, +}; +use zenoh::{prelude::*, shm::AsyncAllocPolicy}; + +use crate::{ + context::{zc_threadsafe_context_t, DroppableContext, ThreadsafeContext}, + errors::{z_error_t, Z_EINVAL, Z_OK}, + transmute::{Inplace, TransmuteCopy, TransmuteFromHandle, TransmuteUninitPtr}, + z_owned_buf_alloc_result_t, +}; +use crate::{z_loaned_alloc_layout_t, z_loaned_shared_memory_provider_t, z_owned_alloc_layout_t}; + +use super::{ + alloc_layout::CSHMLayout, shared_memory_provider_backend::DynamicSharedMemoryProviderBackend, + types::z_alloc_alignment_t, +}; + +pub(crate) fn alloc_layout_new( + this: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + let layout = match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + match provider + .alloc(size) + .with_alignment(alignment.transmute_copy()) + .into_layout() + { + Ok(layout) => CSHMLayout::Posix(layout), + Err(e) => { + log::error!("{:?}", e); + return Z_EINVAL; + } + } + } + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { + match provider + .alloc(size) + .with_alignment(alignment.transmute_copy()) + .into_layout() + { + Ok(layout) => CSHMLayout::Dynamic(layout), + Err(e) => { + log::error!("{:?}", e); + return Z_EINVAL; + } + } + } + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + match provider + .alloc(size) + .with_alignment(alignment.transmute_copy()) + .into_layout() + { + Ok(layout) => CSHMLayout::DynamicThreadsafe(layout), + Err(e) => { + log::error!("{:?}", e); + return Z_EINVAL; + } + } + } + }; + + Inplace::init(this.transmute_uninit_ptr(), Some(layout)); + Z_OK +} + +pub(crate) fn alloc( + out_result: *mut MaybeUninit, + layout: &z_loaned_alloc_layout_t, +) { + let result = match layout.transmute_ref() { + super::alloc_layout::CSHMLayout::Posix(layout) => { + layout.alloc().with_policy::().wait() + } + super::alloc_layout::CSHMLayout::Dynamic(layout) => { + layout.alloc().with_policy::().wait() + } + super::alloc_layout::CSHMLayout::DynamicThreadsafe(layout) => { + layout.alloc().with_policy::().wait() + } + }; + Inplace::init(out_result.transmute_uninit_ptr(), Some(result)); +} + +pub(crate) fn alloc_async( + out_result: &'static mut MaybeUninit, + layout: &'static z_loaned_alloc_layout_t, + result_context: zc_threadsafe_context_t, + result_callback: unsafe extern "C" fn( + *mut c_void, + &mut MaybeUninit, + ), +) -> z_error_t { + match layout.transmute_ref() { + super::alloc_layout::CSHMLayout::Posix(layout) => { + alloc_async_impl::< + Policy, + StaticProtocolID, + PosixSharedMemoryProviderBackend, + >(out_result, layout, result_context, result_callback); + Z_OK + } + super::alloc_layout::CSHMLayout::Dynamic(_) => Z_EINVAL, + super::alloc_layout::CSHMLayout::DynamicThreadsafe(layout) => { + alloc_async_impl::< + Policy, + DynamicProtocolID, + DynamicSharedMemoryProviderBackend, + >(out_result, layout, result_context, result_callback); + Z_OK + } + } +} + +pub fn alloc_async_impl< + Policy: AsyncAllocPolicy, + IDSource: ProtocolIDSource, + Backend: SharedMemoryProviderBackend + Send + Sync, +>( + out_result: &'static mut MaybeUninit, + layout: &'static AllocLayout<'static, IDSource, Backend>, + result_context: zc_threadsafe_context_t, + result_callback: unsafe extern "C" fn( + *mut c_void, + &mut MaybeUninit, + ), +) { + let result_context: ThreadsafeContext = result_context.into(); + //todo: this should be ported to tokio with executor argument support + async_std::task::spawn(async move { + let result = layout.alloc().with_policy::().await; + Inplace::init( + (out_result as *mut MaybeUninit).transmute_uninit_ptr(), + Some(result), + ); + unsafe { (result_callback)(result_context.get(), out_result) }; + }); +} diff --git a/src/shm/provider/chunk.rs b/src/shm/provider/chunk.rs new file mode 100644 index 000000000..604404cdb --- /dev/null +++ b/src/shm/provider/chunk.rs @@ -0,0 +1,59 @@ +use std::sync::atomic::AtomicPtr; + +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +use libc::c_void; +use zenoh::shm::{AllocatedChunk, ChunkDescriptor}; + +use crate::shm::common::types::{z_chunk_id_t, z_segment_id_t}; + +/// A ChunkDescriptor +#[repr(C)] +pub struct z_chunk_descriptor_t { + segment: z_segment_id_t, + chunk: z_chunk_id_t, + len: usize, +} + +impl From for ChunkDescriptor { + fn from(value: z_chunk_descriptor_t) -> Self { + Self::new(value.segment, value.chunk, value.len) + } +} + +impl From<&ChunkDescriptor> for z_chunk_descriptor_t { + fn from(value: &ChunkDescriptor) -> Self { + Self { + segment: value.segment, + chunk: value.chunk, + len: value.len, + } + } +} + +/// An AllocatedChunk +#[repr(C)] +pub struct z_allocated_chunk_t { + descriptpr: z_chunk_descriptor_t, + data: *mut c_void, +} + +impl From for AllocatedChunk { + fn from(value: z_allocated_chunk_t) -> Self { + Self::new( + value.descriptpr.into(), + AtomicPtr::from(value.data as *mut u8), + ) + } +} diff --git a/src/shm/provider/mod.rs b/src/shm/provider/mod.rs new file mode 100644 index 000000000..af20df623 --- /dev/null +++ b/src/shm/provider/mod.rs @@ -0,0 +1,21 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +pub mod alloc_layout; +pub(crate) mod alloc_layout_impl; +pub mod chunk; +pub mod shared_memory_provider; +pub mod shared_memory_provider_backend; +pub(crate) mod shared_memory_provider_impl; +pub mod types; diff --git a/src/shm/provider/shared_memory_provider.rs b/src/shm/provider/shared_memory_provider.rs new file mode 100644 index 000000000..b65663258 --- /dev/null +++ b/src/shm/provider/shared_memory_provider.rs @@ -0,0 +1,235 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::mem::MaybeUninit; + +use libc::c_void; +use zenoh::shm::{ + BlockOn, Deallocate, Defragment, DynamicProtocolID, GarbageCollect, JustAlloc, + SharedMemoryProvider, SharedMemoryProviderBuilder, +}; + +use crate::{ + context::{zc_context_t, zc_threadsafe_context_t, Context, ThreadsafeContext}, + errors::z_error_t, + shm::{ + common::types::z_protocol_id_t, + protocol_implementations::posix::posix_shared_memory_provider::PosixSharedMemoryProvider, + }, + transmute::{ + unwrap_ref_unchecked, Inplace, TransmuteIntoHandle, TransmuteRef, TransmuteUninitPtr, + }, + z_loaned_shared_memory_provider_t, z_owned_buf_alloc_result_t, + z_owned_shared_memory_provider_t, z_owned_shm_mut_t, +}; + +use super::{ + chunk::z_allocated_chunk_t, + shared_memory_provider_backend::{ + zc_shared_memory_provider_backend_callbacks_t, DynamicSharedMemoryProviderBackend, + }, + shared_memory_provider_impl::{ + alloc, alloc_async, available, defragment, garbage_collect, map, + }, + types::z_alloc_alignment_t, +}; + +pub type DynamicSharedMemoryProvider = + SharedMemoryProvider>; + +pub type DynamicSharedMemoryProviderThreadsafe = + SharedMemoryProvider>; + +pub enum CSHMProvider { + Posix(PosixSharedMemoryProvider), + Dynamic(DynamicSharedMemoryProvider), + DynamicThreadsafe(DynamicSharedMemoryProviderThreadsafe), +} + +decl_transmute_owned!(Option, z_owned_shared_memory_provider_t); +decl_transmute_handle!(CSHMProvider, z_loaned_shared_memory_provider_t); + +/// Creates a new SHM Provider +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_new( + this: *mut MaybeUninit, + id: z_protocol_id_t, + context: zc_context_t, + callbacks: zc_shared_memory_provider_backend_callbacks_t, +) { + let backend = DynamicSharedMemoryProviderBackend::new(context.into(), callbacks); + let provider = SharedMemoryProviderBuilder::builder() + .dynamic_protocol_id(id) + .backend(backend) + .res(); + + Inplace::init( + this.transmute_uninit_ptr(), + Some(CSHMProvider::Dynamic(provider)), + ); +} + +/// Creates a new threadsafe SHM Provider +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_threadsafe_new( + this: *mut MaybeUninit, + id: z_protocol_id_t, + context: zc_threadsafe_context_t, + callbacks: zc_shared_memory_provider_backend_callbacks_t, +) { + let backend = DynamicSharedMemoryProviderBackend::new(context.into(), callbacks); + let provider = SharedMemoryProviderBuilder::builder() + .dynamic_protocol_id(id) + .backend(backend) + .res(); + + Inplace::init( + this.transmute_uninit_ptr(), + Some(CSHMProvider::DynamicThreadsafe(provider)), + ); +} + +/// Constructs SHM Provider in its gravestone value. +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_null( + this: *mut MaybeUninit, +) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_check(this: &z_owned_shared_memory_provider_t) -> bool { + this.transmute_ref().is_some() +} + +/// Borrows SHM Provider +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_loan( + this: &z_owned_shared_memory_provider_t, +) -> &z_loaned_shared_memory_provider_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} + +/// Deletes SHM Provider +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_drop(this: &mut z_owned_shared_memory_provider_t) { + let _ = this.transmute_mut().take(); +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_alloc( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + alloc::(out_result, provider, size, alignment) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_alloc_gc( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + alloc::(out_result, provider, size, alignment) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_alloc_gc_defrag( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + alloc::>(out_result, provider, size, alignment) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_alloc_gc_defrag_dealloc( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + alloc::>>(out_result, provider, size, alignment) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_alloc_gc_defrag_blocking( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + alloc::>>(out_result, provider, size, alignment) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_alloc_gc_defrag_async( + out_result: &'static mut MaybeUninit, + provider: &'static z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, + result_context: zc_threadsafe_context_t, + result_callback: unsafe extern "C" fn( + *mut c_void, + z_error_t, + *mut MaybeUninit, + ), +) -> z_error_t { + alloc_async::>>( + out_result, + provider, + size, + alignment, + result_context.into(), + result_callback, + ) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_defragment( + provider: &z_loaned_shared_memory_provider_t, +) { + defragment(provider); +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_garbage_collect( + provider: &z_loaned_shared_memory_provider_t, +) { + garbage_collect(provider); +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_available( + provider: &z_loaned_shared_memory_provider_t, +) -> usize { + available(provider) +} + +#[no_mangle] +pub extern "C" fn z_shared_memory_provider_map( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + allocated_chunk: z_allocated_chunk_t, + len: usize, +) { + map(out_result, provider, allocated_chunk, len); +} diff --git a/src/shm/provider/shared_memory_provider_backend.rs b/src/shm/provider/shared_memory_provider_backend.rs new file mode 100644 index 000000000..f8040f0dd --- /dev/null +++ b/src/shm/provider/shared_memory_provider_backend.rs @@ -0,0 +1,104 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::fmt::Debug; + +use libc::c_void; +use zenoh::core::Result; +use zenoh::shm::{ChunkAllocResult, ChunkDescriptor, MemoryLayout, SharedMemoryProviderBackend}; +use zenoh_util::core::zerror; + +use crate::context::DroppableContext; +use crate::transmute::{TransmuteIntoHandle, TransmuteRef}; +use crate::{z_loaned_memory_layout_t, z_owned_chunk_alloc_result_t, z_owned_memory_layout_t}; + +use super::chunk::z_chunk_descriptor_t; + +/// A callbacks for SharedMemoryProviderBackend +#[derive(Debug)] +#[repr(C)] +pub struct zc_shared_memory_provider_backend_callbacks_t { + alloc_fn: unsafe extern "C" fn( + out_result: *mut z_owned_chunk_alloc_result_t, + layout: &z_loaned_memory_layout_t, + context: *mut c_void, + ), + free_fn: unsafe extern "C" fn(chunk: *const z_chunk_descriptor_t, context: *mut c_void), + defragment_fn: unsafe extern "C" fn(context: *mut c_void) -> usize, + available_fn: unsafe extern "C" fn(context: *mut c_void) -> usize, + layout_for_fn: unsafe extern "C" fn(layout: *mut z_owned_memory_layout_t, context: *mut c_void), +} + +#[derive(Debug)] +pub struct DynamicSharedMemoryProviderBackend +where + TContext: DroppableContext, +{ + context: TContext, + callbacks: zc_shared_memory_provider_backend_callbacks_t, +} + +impl DynamicSharedMemoryProviderBackend +where + TContext: DroppableContext, +{ + pub fn new( + context: TContext, + callbacks: zc_shared_memory_provider_backend_callbacks_t, + ) -> Self { + Self { context, callbacks } + } +} + +impl SharedMemoryProviderBackend for DynamicSharedMemoryProviderBackend +where + TContext: DroppableContext, +{ + fn alloc(&self, layout: &MemoryLayout) -> ChunkAllocResult { + let mut result = std::mem::MaybeUninit::uninit(); + unsafe { + (self.callbacks.alloc_fn)( + result.as_mut_ptr(), + layout.transmute_handle(), + self.context.get(), + ); + match result.assume_init().transmute_mut().take() { + Some(val) => val, + None => Err(zenoh::shm::ZAllocError::Other( + "Callback returned empty result".into(), + )), + } + } + } + + fn free(&self, chunk: &ChunkDescriptor) { + unsafe { (self.callbacks.free_fn)(&chunk.into(), self.context.get()) }; + } + + fn defragment(&self) -> usize { + unsafe { (self.callbacks.defragment_fn)(self.context.get()) } + } + + fn available(&self) -> usize { + unsafe { (self.callbacks.available_fn)(self.context.get()) } + } + + fn layout_for(&self, layout: MemoryLayout) -> Result { + let mut layout = Some(layout); + unsafe { + (self.callbacks.layout_for_fn)(layout.transmute_mut(), self.context.get()); + } + layout.ok_or_else(|| zerror!("{:?}: unsupported layout", self).into()) + } +} diff --git a/src/shm/provider/shared_memory_provider_impl.rs b/src/shm/provider/shared_memory_provider_impl.rs new file mode 100644 index 000000000..ffdeddcc1 --- /dev/null +++ b/src/shm/provider/shared_memory_provider_impl.rs @@ -0,0 +1,239 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use libc::c_void; +use std::mem::MaybeUninit; +use zenoh::prelude::*; +use zenoh::shm::{ + AllocPolicy, AsyncAllocPolicy, BufLayoutAllocResult, DynamicProtocolID, + PosixSharedMemoryProviderBackend, ProtocolIDSource, SharedMemoryProvider, + SharedMemoryProviderBackend, StaticProtocolID, ZLayoutAllocError, POSIX_PROTOCOL_ID, +}; + +use crate::context::{Context, DroppableContext, ThreadsafeContext}; +use crate::errors::{z_error_t, Z_EINVAL, Z_OK}; +use crate::transmute::{Inplace, TransmuteCopy, TransmuteFromHandle, TransmuteUninitPtr}; +use crate::{z_loaned_shared_memory_provider_t, z_owned_buf_alloc_result_t, z_owned_shm_mut_t}; + +use super::chunk::z_allocated_chunk_t; +use super::shared_memory_provider_backend::DynamicSharedMemoryProviderBackend; +use super::types::z_alloc_alignment_t; + +pub(crate) fn alloc( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + alloc_impl::< + Policy, + StaticProtocolID, + PosixSharedMemoryProviderBackend, + >(out_result, provider, size, alignment) + } + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { + alloc_impl::>( + out_result, provider, size, alignment, + ) + } + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + alloc_impl::< + Policy, + DynamicProtocolID, + DynamicSharedMemoryProviderBackend, + >(out_result, provider, size, alignment) + } + } +} + +pub(crate) fn alloc_async( + out_result: &'static mut MaybeUninit, + provider: &'static z_loaned_shared_memory_provider_t, + size: usize, + alignment: z_alloc_alignment_t, + result_context: ThreadsafeContext, + result_callback: unsafe extern "C" fn( + *mut c_void, + z_error_t, + *mut MaybeUninit, + ), +) -> z_error_t { + match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + alloc_async_impl::< + Policy, + StaticProtocolID, + PosixSharedMemoryProviderBackend, + >( + out_result, + provider, + size, + alignment, + result_context, + result_callback, + ); + Z_OK + } + super::shared_memory_provider::CSHMProvider::Dynamic(_) => Z_EINVAL, + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + alloc_async_impl::< + Policy, + DynamicProtocolID, + DynamicSharedMemoryProviderBackend, + >( + out_result, + provider, + size, + alignment, + result_context, + result_callback, + ); + Z_OK + } + } +} + +pub(crate) fn defragment(provider: &z_loaned_shared_memory_provider_t) { + match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + provider.defragment(); + } + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { + provider.defragment(); + } + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + provider.defragment(); + } + } +} + +pub(crate) fn garbage_collect(provider: &z_loaned_shared_memory_provider_t) { + match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + provider.garbage_collect(); + } + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { + provider.garbage_collect(); + } + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + provider.garbage_collect(); + } + } +} + +pub(crate) fn available(provider: &z_loaned_shared_memory_provider_t) -> usize { + match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => provider.available(), + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => provider.available(), + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + provider.available() + } + } +} + +#[no_mangle] +pub(crate) fn map( + out_result: *mut MaybeUninit, + provider: &z_loaned_shared_memory_provider_t, + allocated_chunk: z_allocated_chunk_t, + len: usize, +) { + let mapping = match provider.transmute_ref() { + super::shared_memory_provider::CSHMProvider::Posix(provider) => { + provider.map(allocated_chunk.into(), len) + } + super::shared_memory_provider::CSHMProvider::Dynamic(provider) => { + provider.map(allocated_chunk.into(), len) + } + super::shared_memory_provider::CSHMProvider::DynamicThreadsafe(provider) => { + provider.map(allocated_chunk.into(), len) + } + }; + + match mapping { + Ok(buffer) => Inplace::init(out_result.transmute_uninit_ptr(), Some(buffer)), + Err(e) => { + log::error!("{e}"); + Inplace::init(out_result.transmute_uninit_ptr(), None) + } + } +} + +fn alloc_impl< + Policy: AllocPolicy, + TProtocolID: ProtocolIDSource, + TBackend: SharedMemoryProviderBackend, +>( + out_result: *mut MaybeUninit, + provider: &SharedMemoryProvider, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + let result = provider + .alloc(size) + .with_alignment(alignment.transmute_copy()) + .with_policy::() + .wait(); + + parse_result(out_result, result) +} + +pub(crate) fn alloc_async_impl< + Policy: AsyncAllocPolicy, + TProtocolID: ProtocolIDSource, + TBackend: SharedMemoryProviderBackend + Send + Sync, +>( + out_result: &'static mut MaybeUninit, + provider: &'static SharedMemoryProvider, + size: usize, + alignment: z_alloc_alignment_t, + result_context: ThreadsafeContext, + result_callback: unsafe extern "C" fn( + *mut c_void, + z_error_t, + *mut MaybeUninit, + ), +) { + //todo: this should be ported to tokio with executor argument support + async_std::task::spawn(async move { + let result = provider + .alloc(size) + .with_alignment(alignment.transmute_copy()) + .with_policy::() + .await; + let error = parse_result(out_result, result); + unsafe { + (result_callback)(result_context.get(), error, out_result); + } + }); +} + +fn parse_result( + out_result: *mut MaybeUninit, + result: BufLayoutAllocResult, +) -> z_error_t { + match result { + Ok(buf) => { + Inplace::init(out_result.transmute_uninit_ptr(), Some(Ok(buf))); + Z_OK + } + Err(ZLayoutAllocError::Alloc(e)) => { + Inplace::init(out_result.transmute_uninit_ptr(), Some(Err(e))); + Z_OK + } + Err(ZLayoutAllocError::Layout(_)) => Z_EINVAL, + } +} diff --git a/src/shm/provider/types.rs b/src/shm/provider/types.rs new file mode 100644 index 000000000..78bbfeaec --- /dev/null +++ b/src/shm/provider/types.rs @@ -0,0 +1,242 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::mem::MaybeUninit; + +use zenoh::shm::{AllocAlignment, BufAllocResult, ChunkAllocResult, MemoryLayout, ZAllocError}; +use zenoh_util::core::zerror; + +use crate::{ + errors::{z_error_t, Z_EINVAL, Z_OK}, + transmute::{ + unwrap_ref_unchecked, Inplace, TransmuteCopy, TransmuteFromHandle, TransmuteIntoHandle, + TransmuteRef, TransmuteUninitPtr, + }, + z_loaned_buf_alloc_result_t, z_loaned_chunk_alloc_result_t, z_loaned_memory_layout_t, + z_owned_buf_alloc_result_t, z_owned_chunk_alloc_result_t, z_owned_memory_layout_t, + z_owned_shm_mut_t, +}; + +use super::chunk::z_allocated_chunk_t; + +/// Allocation errors +/// +/// - **NEED_DEFRAGMENT**: defragmentation needed +/// - **OUT_OF_MEMORY**: the provider is out of memory +/// - **OTHER**: other error +#[repr(C)] +#[derive(Clone, Copy)] +pub enum z_alloc_error_t { + NEED_DEFRAGMENT, + OUT_OF_MEMORY, + OTHER, +} + +impl From for z_alloc_error_t { + #[inline] + fn from(value: ZAllocError) -> Self { + match value { + ZAllocError::NeedDefragment => z_alloc_error_t::NEED_DEFRAGMENT, + ZAllocError::OutOfMemory => z_alloc_error_t::OUT_OF_MEMORY, + ZAllocError::Other(_) => z_alloc_error_t::OTHER, + } + } +} + +impl From for ZAllocError { + #[inline] + fn from(value: z_alloc_error_t) -> Self { + match value { + z_alloc_error_t::NEED_DEFRAGMENT => ZAllocError::NeedDefragment, + z_alloc_error_t::OUT_OF_MEMORY => ZAllocError::OutOfMemory, + z_alloc_error_t::OTHER => ZAllocError::Other(zerror!("other error").into()), + } + } +} + +// An AllocAlignment. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct z_alloc_alignment_t { + pow: u8, +} + +decl_transmute_copy!(AllocAlignment, z_alloc_alignment_t); + +decl_transmute_owned!(Option, z_owned_memory_layout_t); +decl_transmute_handle!(MemoryLayout, z_loaned_memory_layout_t); + +/// Creates a new Memory Layout +#[no_mangle] +pub extern "C" fn z_memory_layout_new( + this: *mut MaybeUninit, + size: usize, + alignment: z_alloc_alignment_t, +) -> z_error_t { + match MemoryLayout::new(size, AllocAlignment::new(alignment.pow)) { + Ok(layout) => { + Inplace::init(this.transmute_uninit_ptr(), Some(layout)); + Z_OK + } + Err(e) => { + log::error!("{e}"); + Z_EINVAL + } + } +} + +/// Constructs Memory Layout in its gravestone value. +#[no_mangle] +pub extern "C" fn z_memory_layout_null(this: *mut MaybeUninit) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_memory_layout_check(this: &z_owned_memory_layout_t) -> bool { + this.transmute_ref().is_some() +} + +/// Borrows Memory Layout +#[no_mangle] +pub extern "C" fn z_memory_layout_loan( + this: &z_owned_memory_layout_t, +) -> &z_loaned_memory_layout_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} + +/// Deletes Memory Layout +#[no_mangle] +pub extern "C" fn z_memory_layout_drop(this: &mut z_owned_memory_layout_t) { + let _ = this.transmute_mut().take(); +} + +/// Deletes Memory Layout +#[no_mangle] +pub extern "C" fn z_memory_layout_get_data( + out_size: &mut MaybeUninit, + out_alignment: &mut MaybeUninit, + this: &z_loaned_memory_layout_t, +) { + let layout = this.transmute_ref(); + out_size.write(layout.size()); + out_alignment.write(layout.alignment().transmute_copy()); +} + +decl_transmute_owned!(Option, z_owned_chunk_alloc_result_t); + +decl_transmute_handle!(ChunkAllocResult, z_loaned_chunk_alloc_result_t); + +/// Creates a new Chunk Alloc Result with Ok value +#[no_mangle] +pub extern "C" fn z_chunk_alloc_result_new_ok( + this: *mut MaybeUninit, + allocated_chunk: z_allocated_chunk_t, +) { + Inplace::init( + this.transmute_uninit_ptr(), + Some(Ok(allocated_chunk.into())), + ); +} + +/// Creates a new Chunk Alloc Result with Error value +#[no_mangle] +pub extern "C" fn z_chunk_alloc_result_new_error( + this: *mut MaybeUninit, + alloc_error: z_alloc_error_t, +) { + Inplace::init(this.transmute_uninit_ptr(), Some(Err(alloc_error.into()))); +} + +/// Constructs Chunk Alloc Result in its gravestone value. +#[no_mangle] +pub extern "C" fn z_chunk_alloc_result_null(this: *mut MaybeUninit) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_chunk_alloc_result_check(this: &z_owned_chunk_alloc_result_t) -> bool { + this.transmute_ref().is_some() +} + +/// Borrows Chunk Alloc Result +#[no_mangle] +pub extern "C" fn z_chunk_alloc_result_loan( + this: &z_owned_chunk_alloc_result_t, +) -> &z_loaned_chunk_alloc_result_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} + +/// Deletes Chunk Alloc Result +#[no_mangle] +pub extern "C" fn z_chunk_alloc_result_drop(this: &mut z_owned_chunk_alloc_result_t) { + let _ = this.transmute_mut().take(); +} + +decl_transmute_owned!(Option, z_owned_buf_alloc_result_t); + +decl_transmute_handle!(BufAllocResult, z_loaned_buf_alloc_result_t); + +#[no_mangle] +pub extern "C" fn z_buf_alloc_result_unwrap( + alloc_result: &mut z_owned_buf_alloc_result_t, + out_buf: *mut MaybeUninit, + out_error: &mut MaybeUninit, +) -> z_error_t { + match alloc_result.transmute_mut().extract() { + Some(Ok(val)) => { + Inplace::init(out_buf.transmute_uninit_ptr(), Some(val)); + Z_OK + } + Some(Err(err)) => { + Inplace::init(out_buf.transmute_uninit_ptr(), None); + out_error.write(err.into()); + Z_OK + } + None => Z_EINVAL, + } +} + +/// Constructs Buf Alloc Result in its gravestone value. +#[no_mangle] +pub extern "C" fn z_buf_alloc_result_null(this: *mut MaybeUninit) { + Inplace::empty(this.transmute_uninit_ptr()); +} + +/// Returns ``true`` if `this` is valid. +#[no_mangle] +pub extern "C" fn z_buf_alloc_result_check(this: &z_owned_buf_alloc_result_t) -> bool { + this.transmute_ref().is_some() +} + +/// Borrows Buf Alloc Result +#[no_mangle] +pub extern "C" fn z_buf_alloc_result_loan( + this: &z_owned_buf_alloc_result_t, +) -> &z_loaned_buf_alloc_result_t { + let this = this.transmute_ref(); + let this = unwrap_ref_unchecked(this); + this.transmute_handle() +} + +/// Deletes Buf Alloc Result +#[no_mangle] +pub extern "C" fn z_buf_alloc_result_drop(this: &mut z_owned_buf_alloc_result_t) { + let _ = this.transmute_mut().take(); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 21695a439..c4541d054 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,13 @@ file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c") foreach(file ${files}) get_filename_component(target ${file} NAME_WE) + # Exclude SHM tests if SHM feature is disabled + if(NOT(ZENOHC_BUILD_WITH_SHARED_MEMORY)) + if(${target} MATCHES "^.*_shm.*$") + continue() + endif() + endif() + # Check the filename prefix to determine the test type if (${file} MATCHES "^.*z_api_.*$") set(test_type "unit") diff --git a/tests/z_api_payload_test.c b/tests/z_api_payload_test.c index 193a5eeff..da795d403 100644 --- a/tests/z_api_payload_test.c +++ b/tests/z_api_payload_test.c @@ -153,14 +153,15 @@ void test_arithmetic() { TEST_ARITHMETIC(double, double, -105.001); } -void iter_body(z_owned_bytes_t* b, void* context) { +bool iter_body(z_owned_bytes_t* b, void* context) { uint8_t* val = (uint8_t*)context; if (*val >= 10) { - z_null(b); + return false; } else { z_bytes_encode_from_uint8(b, *val); } *val = *val + 1; + return true; } diff --git a/tests/z_api_shm_test.c b/tests/z_api_shm_test.c new file mode 100644 index 000000000..8583f796a --- /dev/null +++ b/tests/z_api_shm_test.c @@ -0,0 +1,448 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// +#include + +#include "zenoh.h" + +#define ASSERT_OK(result) \ + if (result != Z_OK) { \ + assert(false); \ + return result; \ + } + +#define ASSERT_TRUE(expr) \ + if (!(expr)) { \ + assert(false); \ + return -300; \ + } + +#define ASSERT_CHECK(var) \ + if (!z_check(var)) { \ + assert(false); \ + return -100; \ + } + +#define ASSERT_CHECK_ERR(var) \ + if (z_check(var)) { \ + assert(false); \ + return -200; \ + } + +int test_shm_buffer(z_owned_shm_mut_t* buf) { + ASSERT_CHECK(*buf); + + { z_loaned_shm_mut_t* loaned = z_loan_mut(*buf); } + + z_owned_shm_t immut; + z_shm_from_mut(&immut, z_move(*buf)); + ASSERT_CHECK(immut); + ASSERT_CHECK_ERR(*buf); + + { const z_loaned_shm_t* loaned = z_loan(immut); } + + { + z_loaned_shm_t* loaned_immut = z_loan_mut(immut); + z_loaned_shm_mut_t* loaned_mut = z_shm_try_reloan_mut(loaned_immut); + ASSERT_TRUE(loaned_mut != NULL); + } + + { + z_loaned_shm_mut_t* loaned_mut = z_shm_try_mut(&immut); + ASSERT_TRUE(loaned_mut != NULL); + } + + z_owned_shm_t immut2; + z_shm_clone(z_loan(immut), &immut2); + ASSERT_CHECK(immut2); + + z_owned_shm_mut_t mut; + z_shm_mut_try_from_immut(&mut, z_move(immut2)); + ASSERT_CHECK_ERR(immut2); + ASSERT_CHECK_ERR(mut); + + z_shm_mut_try_from_immut(&mut, z_move(immut)); + ASSERT_CHECK(mut); + + z_drop(z_move(mut)); + ASSERT_CHECK_ERR(mut); +} + +bool test_layouted_allocation(const z_loaned_alloc_layout_t* alloc_layout) { + z_owned_buf_alloc_result_t alloc; + + z_alloc_layout_alloc_gc(&alloc, alloc_layout); + ASSERT_CHECK(alloc); + + z_owned_shm_mut_t shm_buf; + z_alloc_error_t shm_error; + + ASSERT_OK(z_buf_alloc_result_unwrap(z_move(alloc), &shm_buf, &shm_error)); + if (z_check(shm_buf)) { + ASSERT_OK(test_shm_buffer(z_move(shm_buf))); + ASSERT_CHECK_ERR(shm_buf); + return true; + } else + return false; +} + +bool test_allocation(const z_loaned_shared_memory_provider_t* provider, size_t size, z_alloc_alignment_t alignment) { + z_owned_buf_alloc_result_t alloc; + + ASSERT_OK(z_shared_memory_provider_alloc_gc(&alloc, provider, size, alignment)); + ASSERT_CHECK(alloc); + + z_owned_shm_mut_t shm_buf; + z_alloc_error_t shm_error; + + ASSERT_OK(z_buf_alloc_result_unwrap(z_move(alloc), &shm_buf, &shm_error)); + if (z_check(shm_buf)) { + ASSERT_OK(test_shm_buffer(z_move(shm_buf))); + ASSERT_CHECK_ERR(shm_buf); + return true; + } else + return false; +} + +int test_provider(z_owned_shared_memory_provider_t* provider, z_alloc_alignment_t alignment, size_t buf_ok_size, + size_t buf_err_size) { + // test allocation OK + for (int i = 0; i < 100; ++i) { + ASSERT_TRUE(test_allocation(z_loan(*provider), buf_ok_size, alignment)); + } + + // test allocation ERROR + if (buf_err_size) { + ASSERT_TRUE(!test_allocation(z_loan(*provider), buf_err_size, alignment)); + } + + // OK layouted allocations + { + // make OK allocation layout + z_owned_alloc_layout_t alloc_layout; + ASSERT_OK(z_alloc_layout_new(&alloc_layout, z_loan(*provider), buf_ok_size, alignment)); + ASSERT_CHECK(alloc_layout); + // test layouted allocation OK + for (int i = 0; i < 100; ++i) { + ASSERT_TRUE(test_layouted_allocation(z_loan(alloc_layout))); + } + z_drop(z_move(alloc_layout)); + ASSERT_CHECK_ERR(alloc_layout); + } + + // ERR layouted allocation + if (buf_err_size) { + // make ERR allocation layout + z_owned_alloc_layout_t alloc_layout; + ASSERT_OK(z_alloc_layout_new(&alloc_layout, z_loan(*provider), buf_err_size, alignment)); + ASSERT_CHECK(alloc_layout); + // test layouted allocation ERROR + ASSERT_TRUE(!test_layouted_allocation(z_loan(alloc_layout))); + z_drop(z_move(alloc_layout)); + ASSERT_CHECK_ERR(alloc_layout); + } + + // additional functions + z_shared_memory_provider_defragment(z_loan(*provider)); + z_shared_memory_provider_garbage_collect(z_loan(*provider)); + + return Z_OK; +} + +typedef struct { + uint8_t* bytes; + bool* busy_flags; + size_t count; + size_t available; +} test_provider_context; + +void delete_fn(void* context) { + test_provider_context* c = (test_provider_context*)context; + free(c->bytes); + free(c->busy_flags); + c->bytes = NULL; + c->busy_flags = NULL; +} +void alloc_fn(struct z_owned_chunk_alloc_result_t* result, const struct z_loaned_memory_layout_t* layout, + void* context) { + assert(context); + assert(layout); + assert(result); + + // check size and alignment + size_t size = 0; + z_alloc_alignment_t alignment; + z_memory_layout_get_data(&size, &alignment, layout); + assert(size == 1); + assert(alignment.pow == 0); + + // perform allocation + test_provider_context* c = (test_provider_context*)context; + for (int i = 0; i < c->count; ++i) { + if (!c->busy_flags[i]) { + c->busy_flags[i] = true; + c->available--; + + z_allocated_chunk_t chunk; + chunk.data = &c->bytes[i]; + uint64_t ptr = (uint64_t)(chunk.data); + chunk.descriptpr.chunk = ptr & 0xFFFFFFFF; + chunk.descriptpr.len = 1; + chunk.descriptpr.segment = (ptr >> 32) & 0xFFFFFFFF; + + z_chunk_alloc_result_new_ok(result, chunk); + return; + } + } + z_chunk_alloc_result_new_error(result, Z_ALLOC_ERROR_OUT_OF_MEMORY); +} +void free_fn(const struct z_chunk_descriptor_t* chunk, void* context) { + assert(context); + assert(chunk); + + assert(chunk->len == 1); + + // restore data ptr from chunk descriptor + void* data = (void*)(((uint64_t)chunk->chunk) | ((((uint64_t)chunk->segment) << 32) & 0xFFFFFFFF00000000)); + + // calc index from data ptr + test_provider_context* c = (test_provider_context*)context; + int64_t index = (int64_t)data - (int64_t)c->bytes; + assert(index >= 0); + assert(index < c->count); + + // mark this entry as free + c->busy_flags[index] = false; + c->available++; +} +size_t defragment_fn(void* context) { + assert(context); + return Z_OK; +} +size_t available_fn(void* context) { + assert(context); + + test_provider_context* c = (test_provider_context*)context; + return c->available; +} +void layout_for_fn(struct z_owned_memory_layout_t* layout, void* context) { + assert(context); + assert(layout); + + assert(z_check(*layout)); + + // check size and alignment + size_t size = 0; + z_alloc_alignment_t alignment; + z_memory_layout_get_data(&size, &alignment, z_loan(*layout)); + + if (size != 1 || alignment.pow != 0) { + z_memory_layout_drop(layout); + } +} + +int run_c_provider() { + const z_protocol_id_t id = 100500; + const size_t size = 1024; + + // init test context + test_provider_context test_context; + test_context.available = size; + test_context.count = size; + test_context.busy_flags = malloc(sizeof(bool) * size); + test_context.bytes = malloc(sizeof(uint8_t) * size); + zc_context_t context = {&test_context, &delete_fn}; + + // init callbacks + zc_shared_memory_provider_backend_callbacks_t callbacks = {&alloc_fn, &free_fn, &defragment_fn, &available_fn, + &layout_for_fn}; + // create provider + z_owned_shared_memory_provider_t provider; + z_shared_memory_provider_new(&provider, id, context, callbacks); + ASSERT_CHECK(provider) + + // test provider + z_alloc_alignment_t alignment = {0}; + ASSERT_OK(test_provider(&provider, alignment, 1, 0)); + + // drop provider + z_drop(z_move(provider)); + ASSERT_CHECK_ERR(provider); + + // check that delete_fn executed + ASSERT_TRUE(test_context.busy_flags == NULL); + ASSERT_TRUE(test_context.bytes == NULL); + + return Z_OK; +} + +int run_posix_provider() { + const size_t total_size = 4096; + const size_t buf_ok_size = total_size / 4; + const size_t buf_err_size = total_size * 2; + + z_alloc_alignment_t alignment = {4}; + + z_owned_memory_layout_t layout; + ASSERT_OK(z_memory_layout_new(&layout, total_size, alignment)); + ASSERT_CHECK(layout); + + z_owned_shared_memory_provider_t provider; + ASSERT_OK(z_posix_shared_memory_provider_new(&provider, z_loan(layout))); + ASSERT_CHECK(provider); + + ASSERT_OK(test_provider(&provider, alignment, buf_ok_size, buf_err_size)); + + z_drop(z_move(provider)); + ASSERT_CHECK_ERR(provider); + + z_drop(z_move(layout)); + ASSERT_CHECK_ERR(layout); + + return Z_OK; +} + +int test_client_storage(z_owned_shared_memory_client_storage_t* storage) { + ASSERT_CHECK(*storage); + + z_owned_config_t config; + z_config_default(&config); + ASSERT_CHECK(config); + + z_owned_session_t session; + ASSERT_OK(z_open_with_custom_shm_clients(&session, z_move(config), z_loan(*storage))); + + ASSERT_CHECK(session); + z_drop(z_move(session)); + ASSERT_CHECK_ERR(session); + + return Z_OK; +} + +int run_default_client_storage() { + z_owned_shared_memory_client_storage_t storage; + ASSERT_OK(z_shared_memory_client_storage_new_default(&storage)); + + // test client storage + ASSERT_OK(test_client_storage(&storage)); + + // deref the client storage + z_drop(z_move(storage)); + ASSERT_CHECK_ERR(storage); + + return Z_OK; +} + +int run_global_client_storage() { + // obtain defaul global client storage + z_owned_shared_memory_client_storage_t storage; + ASSERT_OK(z_ref_shared_memory_client_storage_global(&storage)); + + // test client storage + ASSERT_OK(test_client_storage(&storage)); + + // deref the client storage + z_drop(z_move(storage)); + ASSERT_CHECK_ERR(storage); + + return Z_OK; +} + +int run_client_storage() { + // create client list + zc_owned_shared_memory_client_list_t list; + ASSERT_OK(zc_shared_memory_client_list_new(&list)); + ASSERT_CHECK(list); + + // create POSIX SHM Client + z_owned_shared_memory_client_t client; + ASSERT_OK(z_posix_shared_memory_client_new(&client)); + ASSERT_CHECK(client); + + // add client to the list + ASSERT_OK(zc_shared_memory_client_list_add_client(Z_SHM_POSIX_PROTOCOL_ID, z_move(client), z_loan_mut(list))); + ASSERT_CHECK_ERR(client); + + // create client storage from the list + z_owned_shared_memory_client_storage_t storage; + ASSERT_OK(z_shared_memory_client_storage_new(&storage, z_loan(list), true)); + + // test client storage + ASSERT_OK(test_client_storage(&storage)); + + // deref the client storage + z_drop(z_move(storage)); + ASSERT_CHECK_ERR(storage); + + // drop the client list + z_drop(z_move(list)); + ASSERT_CHECK_ERR(list); + return Z_OK; +} + +void delete_client_fn(void* context) { assert(context == NULL); } +void delete_segment_fn(void* context) {} + +uint8_t* map_fn(z_chunk_id_t chunk, void* context) { + return (uint8_t*)((uint64_t)chunk | ((((uint64_t)context) << 32) & 0xFFFFFFFF00000000)); +} + +bool attach_fn(struct z_shared_memory_segment_t* out_segment, z_segment_id_t id, void* context) { + assert(context == NULL); + out_segment->context.context.ptr = (void*)(uint64_t)id; + out_segment->context.delete_fn = &delete_segment_fn; + out_segment->callbacks.map_fn = &map_fn; + return true; +} + +int run_c_client() { + // create client list + zc_owned_shared_memory_client_list_t list; + ASSERT_OK(zc_shared_memory_client_list_new(&list)); + ASSERT_CHECK(list); + + // create C SHM Client + zc_threadsafe_context_t context = {NULL, &delete_client_fn}; + zc_shared_memory_client_callbacks_t callbacks = {&attach_fn}; + z_owned_shared_memory_client_t client; + ASSERT_OK(z_shared_memory_client_new(&client, context, callbacks)); + ASSERT_CHECK(client); + + // add client to the list + ASSERT_OK(zc_shared_memory_client_list_add_client(100500, z_move(client), z_loan_mut(list))); + ASSERT_CHECK_ERR(client); + + // create client storage from the list + z_owned_shared_memory_client_storage_t storage; + ASSERT_OK(z_shared_memory_client_storage_new(&storage, z_loan(list), true)); + ASSERT_CHECK(storage); + + // drop the client storage + z_drop(z_move(storage)); + ASSERT_CHECK_ERR(storage); + + // drop the client list + z_drop(z_move(list)); + ASSERT_CHECK_ERR(list); + return Z_OK; +} + +int main() { + ASSERT_OK(run_posix_provider()); + ASSERT_OK(run_c_provider()); + ASSERT_OK(run_default_client_storage()); + ASSERT_OK(run_global_client_storage()); + ASSERT_OK(run_client_storage()); + ASSERT_OK(run_c_client()); + return Z_OK; +} diff --git a/tests/z_int_pub_sub_attachment_test.c b/tests/z_int_pub_sub_attachment_test.c index 9bc60267e..a079ed7a5 100644 --- a/tests/z_int_pub_sub_attachment_test.c +++ b/tests/z_int_pub_sub_attachment_test.c @@ -38,12 +38,11 @@ typedef struct attachement_context_t { size_t iteration_index; } attachement_context_t; -void create_attachement_it(z_owned_bytes_t* kv_pair, void* context) { +bool create_attachement_it(z_owned_bytes_t* kv_pair, void* context) { attachement_context_t *ctx = (attachement_context_t*)(context); z_owned_bytes_t k, v; if (ctx->iteration_index >= ctx->num_items) { - z_null(kv_pair); - return; + return false; } else { z_bytes_encode_from_string(&k, ctx->keys[ctx->iteration_index]); z_bytes_encode_from_string(&v, ctx->values[ctx->iteration_index]); @@ -51,6 +50,7 @@ void create_attachement_it(z_owned_bytes_t* kv_pair, void* context) { z_bytes_encode_from_pair(kv_pair, z_move(k), z_move(v)); ctx->iteration_index++; + return true; }; z_error_t check_attachement(const z_loaned_bytes_t* attachement, const attachement_context_t* ctx) { diff --git a/tests/z_int_queryable_attachment_test.c b/tests/z_int_queryable_attachment_test.c index 9b8e2a0bf..1ef3edee6 100644 --- a/tests/z_int_queryable_attachment_test.c +++ b/tests/z_int_queryable_attachment_test.c @@ -36,12 +36,11 @@ typedef struct attachement_context_t { size_t iteration_index; } attachement_context_t; -void create_attachement_it(z_owned_bytes_t* kv_pair, void* context) { +bool create_attachement_it(z_owned_bytes_t* kv_pair, void* context) { attachement_context_t *ctx = (attachement_context_t*)(context); z_owned_bytes_t k, v; if (ctx->iteration_index >= ctx->num_items) { - z_null(kv_pair); - return; + return false; } else { z_bytes_encode_from_string(&k, ctx->keys[ctx->iteration_index]); z_bytes_encode_from_string(&v, ctx->values[ctx->iteration_index]); @@ -49,6 +48,7 @@ void create_attachement_it(z_owned_bytes_t* kv_pair, void* context) { z_bytes_encode_from_pair(kv_pair, z_move(k), z_move(v)); ctx->iteration_index++; + return true; }; z_error_t check_attachement(const z_loaned_bytes_t* attachement, const attachement_context_t* ctx) {