eclipse-iceoryx / iceoryx2 Goto Github PK
View Code? Open in Web Editor NEWEclipse iceoryx2™ - true zero-copy inter-process-communication in pure Rust
Home Page: https://iceoryx.io
License: Apache License 2.0
Eclipse iceoryx2™ - true zero-copy inter-process-communication in pure Rust
Home Page: https://iceoryx.io
License: Apache License 2.0
To increase the code quality, fix potential undefined behavior and unravel race conditions and memory synchronization issues in lock-free code we need to integrate miri in our development workflow.
Currently, it can happen that due to some API adjustments code examples in the markdown files are no longer running. The Geoffrey solves this problem.
Only provide code examples in combination with geoffrey in markdown files.
Currently, the default config file for windows is named config_win.toml
to handle the windows path style. The unix variant is named config.toml
.
Both should be named config.toml
but the problem is, how to deliver two different default config files one for windows and one for the rest of the systems.
The ability to quickly communicate with the maintainers of iceoryx2 or to promote new features requires some kind of social media accounts. Explore what kind of mechanisms can be used and create an account.
When an application crashes, it can happen that a service is only partially removed and becomes unusable.
An internal service and/or a command line application shall cleanup the remainders of such services.
The following use cases shall be considered:
The unit tests of iceoryx2_bb_container
require the iceoryx2_bb_memory
crate as dev-dependency for relocatable container tests. This dependency must be removed.
/code/rust-trail/iceoryx2$ cargo build
Compiling iceoryx2-pal-posix v0.1.1 (~/code/rust-trail/iceoryx2/iceoryx2-pal/posix)
error: failed to run custom build command for iceoryx2-pal-posix v0.1.1 (~/code/rust-trail/iceoryx2/iceoryx2-pal/posix)
Caused by:
process didn't exit successfully: ~/code/rust-trail/iceoryx2/target/debug/build/iceoryx2-pal-posix-187ccb108511064a/build-script-build
(exit status: 101)
--- stdout
cargo:rustc-link-lib=pthread
cargo:rerun-if-changed=src/c/posix.h
cargo:rerun-if-env-changed=TARGET
cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_arm-unknown-linux-gnueabi
cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS_arm_unknown_linux_gnueabi
cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS
--- stderr
/usr/include/bits/socket.h:390:10: fatal error: 'asm/socket.h' file not found
thread 'main' panicked at iceoryx2-pal/posix/build.rs:45:18:
Unable to generate bindings: ClangDiagnostic("/usr/include/bits/socket.h:390:10: fatal error: 'asm/socket.h' file not found\n")
stack backtrace:
0: rust_begin_unwind
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/panicking.rs:72:14
2: core::result::unwrap_failed
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/result.rs:1652:5
3: core::result::Result<T,E>::expect
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/result.rs:1034:23
4: build_script_build::main
at ./build.rs:41:13
5: core::ops::function::FnOnce::call_once
at /rustc/a28077b28a02b92985b3a3faecf92813155f1ea1/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with RUST_BACKTRACE=full
for a verbose backtrace.
The RelocatableContainer
trait comes also with a conformity test suite that is used by other traits which induces a circular dependency on dev
level.
The iceoryx2_bb_container
crate is affected as well.
This may be solved by adding another crate with the test suite which than can be used by the dev
dependency of the elementary crate.
iceoryx2_bb_container
& iceoryx2_bb_container_tests
iceoryx2_bb_elementary
& iceoryx2_bb_elementary_tests
Another solution could be to combine the following crates into one.
iceoryx2_bb_container
iceoryx2_bb_elementary
iceoryx2_bb_memory
iceoryx2_bb_lock_free
iceoryx2_bb_system_types
When a fixed size byte string shall be created from a String
it would be handy if a truncated version can be stored if the whole string does not fit - otherwise one has to write the complex code all over the place in positions where it does not belong.
Add from_bytes_truncated
This issue shall be used for generic pre-release work.
When a publisher sends a sample and goes out of scope right after sending, the subscriber will update its 1-to-1 connection due to the change in the dynamic service information and will never receive the last delivered sample.
Operating system:
Rust version:
Output of: rustc 1.73
Cargo version:
Output of: cargo 1.73
elkodon version:
main
branch
Observed result or behaviour:
The test publisher_block_when_unable_to_deliver_blocks
in crate iceoryx2
deadlocks sometimes in windows
Operating system:
Rust version:
Output of: rustc 1.73
Cargo version:
Output of: cargo 1.73
elkodon version:
main
branch
Observed result or behaviour:
In iceoryx2_pal/posix/src/windows/mman.rs
the shm_unlink
call uses DeleteFileA
. When a file is opened and deleted with this call it successfully returns. If DeleteFileA
is again called while the file is opened it will set the GetLastError
to ERROR_ACCESS_DENIED
instead of ERROR_FILE_NOT_FOUND
, see: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilea
This causes all iceoryx2_cal
tests to fail that are using shared memory. Whenever std::mem::forget
is called in such a concept, the file descriptor is leaked and a subsequent second remove
call will return permission denied instead of false.
The quick-fix Errno::set(Errno::ENOENT);
in iceoryx2_pal/posix/src/windows/mman.rs
(shm_unlink
) shall be removed and the concept tests must be adjusted.
A pub-sub service has the ability to define a max buffer size for a subscriber but the subscriber is unable to reduce its buffer size - every subscriber has the same buffer size.
So we need to introduce a setting in the subscriber port factory to set a custom buffer size.
The code from the iceoryx2 discovery example will fail when the service directory does not exist, this is unexpected.
It should be interpreted as no active services.
Currently, rust 1.72.1 is required, but a first check has shown that rust 1.70.0 should suffice.
Use only the absolute minimum rust version as requirement and add cargo msrv
to verify in the CI that this minimum is correct.
Github links to iceoryx2 are wrong - correct them
If the example code is also run, we can ensure that the example is also functional working. Therefore, we should remove the no_run
tag from as many documentation code examples as possible.
Comment from @elBoberido :
@elfenpiff there is also the option for ignore. Those could then be run on a single platform, just in case the reason for no_run is platform dependent code in the lower layers
When the log output of the console logger is redirected to a file all new lines are removed.
Explore if the bot from the article: https://www.cncf.io/blog/2023/06/06/a-chatgpt-powered-code-reviewer-bot-for-open-source-projects/ can be applied to iceoryx2
There is also a github action: https://github.com/coderabbitai/ai-pr-reviewer
Finalize the implementation for mac os support
Currently, when creating/opening a service with an existing name but a different messaging pattern one receives the failure that it either exists or that the messaging pattern does not match.
It would be better if this would be allowed and that a service is uniquely identified by the messaging pattern and the name.
Should be easily implementable, just hash the messaging pattern as well to acquire the services uuid.
bindgen-0.69.2
is unable to handle macro redefines, see: rust-lang/rust-bindgen#2722
The signal SIGSTOP
and SIGCONT
are redefined under ubuntu 20.04 in the included file bits/signum.h
of signal.h
. The redefinition turns SIGCONT
into the unfetchable signal SIGSTOP
which leads to a failure in the sigaction
call.
The quick fix is to comment out the Continue
signal in the abstraction, since it is also nowhere used. When the bindgen bug report is closed, we can revert the change and close the issue.
Continue
signal in signal.rs
Continue
signal after bindgen bugfixThis should never happen! Unable to register raw sional since sigaction was called with invalid parameters.
thread "
iceorvx2-bb/posix/src/signal.rs:516:13:
panicked at
rom: SignalHandler ( registered signals: 11 ) :.: This should never happen! Unable to register raw signal since sigaction was called with inve
lid parameters
note: run with RUST BACKTRACE=1' environment variable to display a backtrace
12 [F] SianalHandler f registered sianals: [7
This should never happen! nable to register raw sional since sigaction was called with invalid parameters
thread ' ' panicked at iceoryx2-bb/posix/src/sianal,rs:516:13:
rom: SianalHandler ! registered sianals: : This should never happen: Unable
to register raw signal since sigaction was called with inva
lid parameters .
stack backtrace:
The type alias char
in iceoryx2_pal/posix/src/$PLATFORM$/types.rs
is mapped to core::ffi::c_char
and not u8
, this may lead to mixing it up with the rust primitive type char
.
To have a clear distinction, the type alias in types.rs
shall be renamed to c_char
Currently, the publish-subscribe benchmark is working in one process between two threads. The benchmark shall be extended so that it can also run between two distinct processes.
Listed on the road map is the desire to create a web app GUI that spins up basic webserver and allows the user to introspect an iceoryx2
system.
Introspection information expected to be displayed would be:
iceoryx2
participants
A good place to start would be to look at what exists for iceoryx and re-implement it here.
Looking at egui
as the basic lib, using eframe
as a starting point.
The features of the introspection GUI will be dependent on availability of introspection API's to list required info. We should link other related issues here that relate to creating / enabling introspection APIs so that once they are available the features can be added to the GUI.
If one would like to print a state overview of a service it would be nice if the port_factory::{event|publish_subscribe|...}
would have implemented Display
to show the overview from the example.
@elfenpiff I'm waiting for the code :)
When trying to build iceoryx2 with cargo, bindgen requires the libacl.h
headers in linux. So we should introduce a feature flag that enable acl
explicitly and describe in the readme how to install the library.
Operating system:
Rust version:
rustc 1.75.0 (82e1608df 2023-12-21)
Cargo version:
cargo 1.75.0 (1d8b05cdd 2023-11-20)
iceoryx2 version:
main
(9e5113f)Observed result or behaviour:
Run cargo run --release --example publish_subscribe_subscriber
in the root project directory, and I receive a panic:
brian iceoryx2 $ cargo run --release --example publish_subscribe_subscriber
Finished release [optimized] target(s) in 0.11s
Running `target/release/examples/publish_subscribe_subscriber`
0 [T] FileBuilder { file_path: FilePath { value: FixedSizeByteString<4096> { len: 20,
data: "config/iceoryx2.toml" } }, access_mode: Read, permission: OWNER_READ |
OWNER_WRITE | OWNER_EXEC | OWNER_ALL, owner: None, group: None, truncate_size:
None, creation_mode: None }
| opened
1 [T] Config { global: Global { root_path: "/tmp/iceoryx2/", prefix: "iox2_", service
: Service { directory: "services", publisher_data_segment_suffix: ".publisher_d
ata", static_config_storage_suffix: ".service", dynamic_config_storage_suffix:
".dynamic", creation_timeout: 500ms, connection_suffix: ".connection" } }, defa
ults: Defaults { publish_subscribe: PublishSubscribe { max_subscribers: 8, max_
publishers: 2, subscriber_max_buffer_size: 2, subscriber_max_borrowed_samples:
2, publisher_max_loaned_samples: 2, publisher_history_size: 1, enable_safe_over
flow: true, unable_to_deliver_strategy: Block }, event: Event { max_listeners:
2, max_notifiers: 16 } } }
| Loaded.
2 [T] Config { global: Global { root_path: "/tmp/iceoryx2/", prefix: "iox2_", service
: Service { directory: "services", publisher_data_segment_suffix: ".publisher_d
ata", static_config_storage_suffix: ".service", dynamic_config_storage_suffix:
".dynamic", creation_timeout: 500ms, connection_suffix: ".connection" } }, defa
ults: Defaults { publish_subscribe: PublishSubscribe { max_subscribers: 8, max_
publishers: 2, subscriber_max_buffer_size: 2, subscriber_max_borrowed_samples:
2, publisher_max_loaned_samples: 2, publisher_history_size: 1, enable_safe_over
flow: true, unable_to_deliver_strategy: Block }, event: Event { max_listeners:
2, max_notifiers: 16 } } }
| Set as global config.
3 [T] FileBuilder { file_path: FilePath { value: FixedSizeByteString<4096> { len: 76,
data: "/tmp/iceoryx2/services/iox2_b61bd15e8c3ea16146985e960906a8e125156a73.se
rvice" } }, access_mode: Read, permission: OWNER_READ | OWNER_WRITE | OWNER_EXE
C | OWNER_ALL, owner: None, group: None, truncate_size: None, creation_mode: No
ne }
| opened
4 [T] FileBuilder { file_path: FilePath { value: FixedSizeByteString<4096> { len: 76,
data: "/tmp/iceoryx2/services/iox2_b61bd15e8c3ea16146985e960906a8e125156a73.se
rvice" } }, access_mode: Read, permission: OWNER_READ | OWNER_WRITE | OWNER_EXE
C | OWNER_ALL, owner: None, group: None, truncate_size: None, creation_mode: No
ne }
| opened
5 [T] FileBuilder { file_path: FilePath { value: FixedSizeByteString<4096> { len: 76,
data: "/tmp/iceoryx2/services/iox2_b61bd15e8c3ea16146985e960906a8e125156a73.se
rvice" } }, access_mode: Read, permission: OWNER_READ | OWNER_WRITE | OWNER_EXE
C | OWNER_ALL, owner: None, group: None, truncate_size: None, creation_mode: No
ne }
| opened
6 [T] FileBuilder { file_path: FilePath { value: FixedSizeByteString<4096> { len: 76,
data: "/tmp/iceoryx2/services/iox2_b61bd15e8c3ea16146985e960906a8e125156a73.se
rvice" } }, access_mode: Read, permission: OWNER_READ | OWNER_WRITE | OWNER_EXE
C | OWNER_ALL, owner: None, group: None, truncate_size: None, creation_mode: No
ne }
| opened
7 [T] SharedMemory { name: FileName { value: FixedSizeByteString<255> { len: 53, data
: "iox2_b61bd15e8c3ea16146985e960906a8e125156a73.dynamic" } }, size: 16384, bas
e_address: 0x100cdc000, has_ownership: false, file_descriptor: FileDescriptor {
value: 5, is_owned: true }, memory_lock: None }
| open
8 [T] ServiceState { static_config: StaticConfig { uuid: "b61bd15e8c3ea16146985e96090
6a8e125156a73", service_name: ServiceName { value: FixedSizeByteString<255> { l
en: 19, data: "My/Funk/ServiceName" } }, messaging_pattern: PublishSubscribe(St
aticConfig { max_subscribers: 8, max_publishers: 2, history_size: 1, subscriber
_max_buffer_size: 2, subscriber_max_borrowed_samples: 2, enable_safe_overflow:
true, type_name: "transmission_data::TransmissionData" }) }, global_config: Con
fig { global: Global { root_path: "/tmp/iceoryx2/", prefix: "iox2_", service: S
ervice { directory: "services", publisher_data_segment_suffix: ".publisher_data
", static_config_storage_suffix: ".service", dynamic_config_storage_suffix: ".d
ynamic", creation_timeout: 500ms, connection_suffix: ".connection" } }, default
s: Defaults { publish_subscribe: PublishSubscribe { max_subscribers: 8, max_pub
lishers: 2, subscriber_max_buffer_size: 2, subscriber_max_borrowed_samples: 2,
publisher_max_loaned_samples: 2, publisher_history_size: 1, enable_safe_overflo
w: true, unable_to_deliver_strategy: Block }, event: Event { max_listeners: 2,
max_notifiers: 16 } } }, dynamic_storage: Storage { shm: SharedMemory { name: F
ileName { value: FixedSizeByteString<255> { len: 53, data: "iox2_b61bd15e8c3ea1
6146985e960906a8e125156a73.dynamic" } }, size: 16384, base_address: 0x100cdc000
, has_ownership: false, file_descriptor: FileDescriptor { value: 5, is_owned: t
rue }, memory_lock: None }, name: FileName { value: FixedSizeByteString<255> {
len: 40, data: "b61bd15e8c3ea16146985e960906a8e125156a73" } }, _phantom_data: P
hantomData<iceoryx2::service::dynamic_config::DynamicConfig> }, static_storage:
Storage { name: FileName { value: FixedSizeByteString<255> { len: 40, data: "b
61bd15e8c3ea16146985e960906a8e125156a73" } }, config: Configuration { path: Pat
h { value: FixedSizeByteString<4096> { len: 22, data: "/tmp/iceoryx2/services"
} }, suffix: FileName { value: FixedSizeByteString<255> { len: 8, data: ".servi
ce" } }, prefix: FileName { value: FixedSizeByteString<255> { len: 5, data: "io
x2_" } } }, has_ownership: false, file: File { path: Some(FilePath { value: Fix
edSizeByteString<4096> { len: 76, data: "/tmp/iceoryx2/services/iox2_b61bd15e8c
3ea16146985e960906a8e125156a73.service" } }), file_descriptor: FileDescriptor {
value: 4, is_owned: true } }, len: 348 } }
| open service
9 [D] SharedMemoryBuilder { name: FileName { value: FixedSizeByteString<255> { len: 8
1, data: "iox2_20123953278630464882616037414168_3866334330696831988048375888828
0.connection" } }, size: 190, is_memory_locked: false, has_ownership: true, per
mission: OWNER_READ | OWNER_WRITE | OWNER_EXEC | OWNER_ALL, creation_mode: Some
(OpenOrCreate), zero_memory: true, access_mode: ReadWrite, enforce_base_address
: None }
| Unable to open shared memory since the shared memory does not exist.
10 [T] SharedMemory { name: FileName { value: FixedSizeByteString<255> { len: 81, data
: "iox2_20123953278630464882616037414168_38663343306968319880483758888280.conne
ction" } }, size: 16384, base_address: 0x100ce0000, has_ownership: true, file_d
escriptor: FileDescriptor { value: 3, is_owned: true }, memory_lock: None }
| create
11 [T] SharedMemory { name: FileName { value: FixedSizeByteString<255> { len: 56, data
: "iox2_254_20123953278630464882616037414168.publisher_data" } }, size: 16384,
base_address: 0x100ce4000, has_ownership: false, file_descriptor: FileDescripto
r { value: 6, is_owned: true }, memory_lock: None }
| open
12 [D] "nanosleep_with_clock"
| Invalid argument in "nanosleep". Either the duration: 1s is out of range or t
| he clock type Realtime is invalid.
13 [F] Iox2
| Failed to wait with cycle time 1s in main event look, caused by (DurationOutO
| fRange).
thread 'main' panicked at iceoryx2/src/iox2.rs:96:17:
From: Iox2 ::: Failed to wait with cycle time 1s in main event look, caused by (DurationOutOfRange).
stack backtrace:
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
zsh: abort cargo run --release --example publish_subscribe_subscriber
Expected result or behaviour:
Expected to see the subscriber start and receive a message (assuming I run the publisher example as well)
Conditions where it occurred / Performed steps:
Happens on every run of the publish_subscribe example.
Currently, the enable_safe_overflow
behavior is part of the service but it should be actually a subscriber property for its buffer behavior.
Comment from @elBoberido :
I think it is not only a property of the subscriber but also the publisher. If it is only the subscriber one could easily create a denial of service. The publisher also has to opt in for the blocking.
The error handling strategy must be documented.
enum
s as error codesenum
error codes of an higher architectural levelstd::error::Error
and later (when it is in stable) core::error::Error
is implemented for all error enums.The issue shall be concluded with a markdown file explaining the above points and showing some code snippets to illustrate them.
From @elBoberido
I found another solution in the zstd crate. They use derive_more
with a feature flag to derive Error
only on std. This makes would allow no_std
on stable but without the Error
trait. Something to think of.
They basically did this
[dependencies]
derive_more = { version = "0.99", default-features = false, features = ["display", "from"] }
[features]
default = ["std"]
std = ["derive_more/error"]
#[derive(Debug, derive_more::Display, derive_more::From)]
#[cfg_attr(feature = "std", derive(derive_more::Error))]
#[non_exhaustive]
pub enum Foo {
#[display(fmt = "Bar occurred. Is: {baz}, must be either 1 or 2")]
Bar { baz: u8 },
//...
}
The attributes on the enum tags are quite similar to thiserror
so it wouldn't be too hard to switch between the two crates.
I think a first step in this direction would be to add an automatic audit using https://crates.io/crates/cargo-audit
Extending the CI file wouldn't be that hard either:
iox2_cargo_fmt_and_clippy_template: &IOX2_CARGO_FMT_AND_CLIPPY
cargo_fmt_and_clippy_script:
- cargo fmt --all -- --check
- cargo clippy -- -D warnings
- cargo audit
Originally posted by @hydroid7 in #6 (comment)
In iceoryx1 the loffli (template for the unique index set) has an ?issue? with the memory ordering of the atomic thread fences at the end of the push and pop method.
Check if the unique index set has the same issue and ensure that the memory order really fits.
iceoryx2 already runs between different docker instances and the host but we do not yet have an example. Create an example and document it.
Operating system:
Rust version:
Output of: rustc 1.73.0
Cargo version:
Output of: cargo 1.73.0
elkodon version:
main
branch
Observed result or behaviour:
The test access_control_list_string_conversion_works
fails.
Expected result or behaviour:
The test access_control_list_string_conversion_works
passes.
src/bin/*
and old rust_experiments
/tmp/elkodon
iceoryx´ strings with
elkodon`pal/settings
&[u8]
can be replaced with &str
elkodon_bb_posix::SignalHandler
from public API and examples, introduce eventloop::wait()
instead (maybe with better name)get_
prefix for getter but a set_
prefix for setter[workspace.package]
version = ""
repository = ""
homepage = ""
authors = []
edition = "2021"
license = ""
categories = ["ipx"]
description = "elkodon: zero copy ipc"
Write contribution md with the content:
elkodon
vs Elkodon
elk-##ISSUE_NUMBER##-##BRANCH_NAME##
Cargo.toml
and the subcrates inherit from itcargo-multivers
states that it can pack multiple versions of the same binary, each with a different CPU feature set, merged into a single portable optimized binary.
Maybe we can use it to provide with every release an optimized binary for each platform.
When two iceoryx2_cal
constructs interact with each other, we need to add some initial versioning information to ensure that not to incompatible versions of the same constructs are interacting. This could lead to undefined behavior and hard to unravel bugs.
They could be, for instance incompatible since the member order of shared management constructs has changed or members have been added/removed. Or the internal communication protocol was updated.
Introduce a const SHM_API_VERSION: u64
constant inside iceoryx2_cal
, that must be checked before any of these constructs start to interact on an ipc level.
Constructs that use shared memory could add this constant to the beginning, as the first value, to their shared memory. If the construct does not use shared memory, one could create a file and store the number value is binary, or human-readable value, in there.
Currently, it is not possible to store any port type easily in a container like a Vec
. This is due to the fact that the ports, even when they share the same data type, may have different lifetime requirements since they are originating from distinct services or from distinct service variations, like a zero_copy
and a process_local
publisher.
All ports shall be renamed to $NAME$Port
and we introduce traits with the common interface of the port called $NAME
. An example shall demonstrate how this can be used by the end user.
This issue takes care of setting up the CI and maintaining it
If the user wants to print out the messaging pattern of the current service only the long debug output is available.
This shall work:
println!("my service type {}", service.messaging_pattern());
The iceoryx2_bb_container::FixedSizeVec
does not implement Copy
& Clone
. Also, other traits the std version offers are missing. Add these features to be able to use these shm comp versions in most of the use cases one can use the std::Vec
.
See build log: https://docs.rs/crate/iceoryx2/0.0.4/builds/1061128
In the default environment in docs.rs the libacl.h
is not available and therefore the build fails. Either we need to install it, provide a stub implementation of the interface just for docs.rs or we deactivate all acl abstractions in docs.rs.
I would favor a solution where we make libacl.h
somehow available, even when it is just a stub.
The first affected crate is iceoryx2_bb_posix
and then every crate that depends on it.
When listing the static service config files in /tmp/iceoryx2/services/
one sees that all service files have the file suffix .dynamic
from the dynamic service config but it should be .service
.
No more typing and guessing the order of how the packages need to be published - yeah.
A user may want to receive a sample from a subscriber packed into a future, so that they can consume the sample whenever it is ready. The usage could look like:
let future_sample = subscriber.async_receive();
// do stuff here
println!("received {:?}", sample.await);
Other constructs that are maybe interesting are:
From larry-robotics/elkodon#25 (comment)
========
@elfenpiff I found this https://stackoverflow.com/questions/35988775/how-can-i-cause-a-panic-on-a-thread-to-immediately-end-the-main-thread/36031130#36031130
The following code would terminate the whole test when an assert in a thread fails. It can also be placed in a function which could be called at the start of a test
let orig_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
// invoke the default handler and exit the process
orig_hook(panic_info);
process::exit(1);
}));
========
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.