Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust integration: Adding variables & clients. #102

Merged
merged 12 commits into from
Nov 3, 2023

Conversation

SirVer
Copy link
Contributor

@SirVer SirVer commented Oct 10, 2023

Co-authored-by: Dima Dorezyuk ddo@qwello.eu
Signed-off-by: Holger Rapp hra@qwello.eu

@SirVer
Copy link
Contributor Author

SirVer commented Oct 10, 2023

@hikinggrass Kai, could you run clang-format for me again, please? I still do not have access to a Linux dev machine.

Update: Figured it out.

@SirVer
Copy link
Contributor Author

SirVer commented Oct 10, 2023

We updated also EVerest/everest-core#344 to work with this new code.

@SirVer
Copy link
Contributor Author

SirVer commented Oct 16, 2023

@hikinggrass @a-w50 Friendly ping? This has been sitting for a week now.

@hikinggrass
Copy link
Contributor

@hikinggrass @a-w50 Friendly ping? This has been sitting for a week now.

I'm still working on the cmake integration, but I hope to have something to push sometime today

@hikinggrass
Copy link
Contributor

@hikinggrass @a-w50 Friendly ping? This has been sitting for a week now.

I'm still working on the cmake integration, but I hope to have something to push sometime today

This (in combination with the changes I just pushed on everest-core) should allow rust modules to be built with cmake without having to manually specify the location of everest-framework or to rely on heuristics. There have been some changes to the config handling in everest-framework recently which I've already rebased against.
The cmake support isn't completely ready yet and still needs some adjusting before merging.

One thing I've noticed with the rust modules in general: it looks like they do not yet publish true to everest/<module_id>/ready once their initialization code has run and triggering this manually doesn't seem to call the on_ready handler yet. That's probably something we should fix before merging this as well.

a-w50
a-w50 previously requested changes Oct 17, 2023
Comment on lines 233 to 252
pub fn set_subscriber(&self, sub_impl: Weak<dyn Subscriber>) {
*self.sub_impl.write().unwrap() = Some(sub_impl);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from an api perspective, set_subscriber can only be called once, right? If so, this should belong into the constructor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The better place would be the ctor but for our user facing api we have following dependencies

  • The publishers need a ref to the runtime
  • the subscribers need a ref to the publishers
  • The runtime needs a ref to the subscribers.

to brake this vicious cycle we pass the subscribers after the construction to the runtime

have a look at the core or for how it works together

self.cpp_module
.as_ref()
.unwrap()
.provide_command(self, implementation_id.clone(), name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: The runtime (self) is passed here via provide_command. Are rust references direct pointers, i.e. do they point to a specific memory location? If so, this makes the Runtime class non-moveable, correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. But we have to pin not the subscriber reference but the runtime. The cxx bridge and set_subscribers should probably take Pin since this is the point from which we aren’t allowed to move. By not implementing Unpin we make sure that the runtime remains pinned once the set_subscriber is called

return json::parse(blob.data.begin(), blob.data.end());
});
}

void Module::subscribe_variable(const Runtime& rt, rust::String implementation_id, rust::String name) const {
// TODO(hrapp): I am not sure how to model the multiple slots that could theoretically be here.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SirVer : what do you mean by multiple slots?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@a-w50 I mean that num_connections != 1 for this implementation_id. I did not understand the C++ code around this, hence I did not model it in Rust at all currently. My understanding is that the c++ code initially assumed that there would only be one connection, but then this was extendended to allow for more than one connection. To me this is a topic that needs addressing, but can be done at a later point. I also need a clinic where somebody explains this to me (or @dorezyuk, whoever implements this for rust).

@@ -7,6 +7,10 @@ struct Libraries {
}

fn find_everest_workspace_root() -> PathBuf {
if let Ok(everest_framework_dir) = env::var("EVEREST_RS_FRAMEWORK_SOURCE_LOCATION") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming is a bit off here, is it everest framework dir OR everestrs framework source location?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention with naming here was that this environment variable is meant for everestrs and contains the location to the source of everest-framework

Comment on lines +32 to +43
if let Ok(everest_framework_dir) = env::var("EVEREST_RS_FRAMEWORK_BINARY_LOCATION") {
let everest_framework_path = PathBuf::from(everest_framework_dir);
(
everest_framework_path.join("everestrs/libeverestrs_sys.a"),
everest_framework_path.join("lib/libframework.so"),
)
} else {
(
root.join("everest-framework/build/everestrs/libeverestrs_sys.a"),
root.join("everest-framework/build/lib/libframework.so"),
)
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about rust best practices, but for me this if let Ok(..) = ... { doesn't naturally read. Also the implicit returns are hard to spot (but could just be me ...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd prefer a match statement here too. The implicit returns are rustic - i.e. idiomatic. They are like meaningful whitespace in Python - one first finds them appalling, once used to them they become rather nice.

let everestrs_sys = root.join("everest-framework/build/everestrs/libeverestrs_sys.a");
let framework = root.join("everest-framework/build/lib/libframework.so");
let (everestrs_sys, framework) =
if let Ok(everest_framework_dir) = env::var("EVEREST_RS_FRAMEWORK_BINARY_LOCATION") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compare the naming:
if let Ok(everest_framework_dir) = env::var("EVEREST_RS_FRAMEWORK_SOURCE_LOCATION") {
and
if let Ok(everest_framework_dir) = env::var("EVEREST_RS_FRAMEWORK_BINARY_LOCATION") {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do need the binary location here, not the source location, which are usually not identical

let everestrs_sys = root.join("everest-framework/build/everestrs/libeverestrs_sys.a");
let framework = root.join("everest-framework/build/lib/libframework.so");
let (everestrs_sys, framework) =
if let Ok(everest_framework_dir) = env::var("EVEREST_RS_FRAMEWORK_BINARY_LOCATION") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you pass locations by environment variables, why don't you pass the the complete path to libeverestrs_sys.a and libframework.so directly, this would be more stable. Note that at least inside cmake you can get the full path to library-targets (using generator expressions: FRAMEWORK_LIB=$<TARGET_FILE:everest::framework>)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely, would add yet another environment variable but I guess the cost of that is quite low

src/manager.cpp Outdated
@@ -199,6 +200,26 @@ static SubprocessHandle exec_cpp_module(const ModuleStartInfo& module_info, std:
return handle;
}

static SubprocessHandle exec_rust_module(const ModuleStartInfo& module_info, std::shared_ptr<RuntimeSettings> rs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is really no point here in passing the RuntimeSettings as shared pointer, just pass it as a (ideally const) reference.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment this is just to keep it in line with the other exec_* functions, I would suggest we refactor this in a new PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a TODO then for now so we do not forget? Reference this MR for posterity.

src/manager.cpp Outdated Show resolved Hide resolved
@SirVer
Copy link
Contributor Author

SirVer commented Oct 18, 2023

I did a flyby of the code, I have little time this week, so might not be able to dive deeper - thanks for the work and review so far!

@SirVer
Copy link
Contributor Author

SirVer commented Nov 3, 2023

@hikinggrass What is this still waiting on?

SirVer and others added 12 commits November 3, 2023 17:52
Co-authored-by: Dima Dorezyuk <ddo@qwello.eu>
Signed-off-by: Holger Rapp <hra@qwello.eu>
Signed-off-by: Holger Rapp <HolgerRapp@gmx.net>
Signed-off-by: Holger Rapp <HolgerRapp@gmx.net>
Signed-off-by: Holger Rapp <HolgerRapp@gmx.net>
Signed-off-by: Kai-Uwe Hermann <kai-uwe.hermann@pionix.de>
Signed-off-by: Kai-Uwe Hermann <kai-uwe.hermann@pionix.de>
Signed-off-by: Kai-Uwe Hermann <kai-uwe.hermann@pionix.de>
Signed-off-by: Kai-Uwe Hermann <kai-uwe.hermann@pionix.de>
Signed-off-by: Kai-Uwe Hermann <kai-uwe.hermann@pionix.de>
Signed-off-by: aw <aw@pionix.de>
- clean target still needs to be fixed

Signed-off-by: aw <aw@pionix.de>
Signed-off-by: Kai-Uwe Hermann <kai-uwe.hermann@pionix.de>
@hikinggrass
Copy link
Contributor

@hikinggrass What is this still waiting on?

just a rebase, I'm squashing right now :)

@hikinggrass hikinggrass merged commit 49f5f30 into EVerest:main Nov 3, 2023
1 of 3 checks passed
@SirVer
Copy link
Contributor Author

SirVer commented Nov 6, 2023

❤️ ❤️ 🎆 H O O R A Y 🚀 ❤️ ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants