Skip to content

Comments

Dynamic Loader (dyld)#137

Open
georgemorgan wants to merge 176 commits intomasterfrom
dyld
Open

Dynamic Loader (dyld)#137
georgemorgan wants to merge 176 commits intomasterfrom
dyld

Conversation

@georgemorgan
Copy link
Collaborator

@georgemorgan georgemorgan commented Feb 18, 2018

Not ready to merge.

Implement a dynamic loader across libflipper and the device. Goal: Resolve symbols from higher level languages to make it easier to write bindings.

Changes

This PR basically removes the need to worry about a struct _lf_module * in user-land. Although this data type still exists, it is internal to libflipper and shouldn't be touched from the outside.

The signatures of lf_invoke, lf_push, lf_pull are now as follows:

int lf_invoke(struct _lf_device *device, char *module, lf_function function, lf_type ret, lf_return_t *retval, struct _lf_ll *args);
int lf_push(struct _lf_device *device, void *dst, void *src, size_t len);
int lf_pull(struct _lf_device *device, void *dst, void *src, size_t len);
  1. All of these functions accept a struct _lf_device * as the first parameter.
  2. Instead of accepting a struct _lf_module *, they now accept a char * for the module parameter. This is the name of the module that is to be invoked, pushed, or pulled on.

lf_bind has gone bye-bye

There is no need for lf_bind anymore! When an invoke is performed, libflipper will automatically do what lf_bind did behind the scenes. The user doesn't have to worry about it anymore.

So to change the language bindings:

  1. Remove all concept of struct _lf_module *.
    • The bindings should no longer have a concept of a user module or a standard module. To them a module is now just a string literal.
  2. Remove lf_bind.
    • There is no need to bind to modules anymore.

let flipper = flipper::Flipper::attach();
let led = flipper::fsm::led::Led::new(&flipper);
led.rgb(red, green, blue);
let flipper = flipper::Flipper::attach_hostname("localhost");
Copy link
Member

Choose a reason for hiding this comment

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

Please make sure you change this back to regular attach, and let's both try to be more mindful of this, it's a mistake I find myself making a lot too :)

}
let ret = libflipper::lf_invoke(flipper.device, module.as_ptr(), index, T::lf_type(), arglist);
args.map(|args|
for arg in args.iter() {
Copy link
Member

Choose a reason for hiding this comment

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

"Map" functions are generally not intended to have side effects, you can get rid of that outer loop and just use:

for arg in args.iter() {
    // ...
}

/// let output: u8 = invoke(&flipper, &module, 0, args);
/// ```
pub fn lf_invoke<T: LfReturnable>(flipper: &Flipper, module: &ModuleFFI, index: u8, args: Args) -> T {
pub fn invoke<T: LfReturnable>(module: &str, index: u8, args: Option<Args>) -> T {
Copy link
Member

Choose a reason for hiding this comment

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

With this API, the rust bindings have no means of specifying which Flipper device they would like to use, only the "default" one specified by libflipper will ever be used. Before we wrap this up I would like to add in the capability of creating module instances which are paired to a specific Flipper device.

}
let ret = libflipper::lf_push(flipper.device, module.as_ptr(), index, data.as_ptr() as *const c_void, data.len() as u32, arglist);
args.map(|args|
for arg in args.iter() {
Copy link
Member

Choose a reason for hiding this comment

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

Same comment as above, should remove the outer "args.map" block and just use

for args in args.iter() {
    // ...
}

}
let ret = libflipper::lf_pull(flipper.device, module.as_ptr(), index, buffer.as_mut_ptr() as *mut c_void, buffer.len() as u32, arglist);
args.map(|args|
for arg in args.iter() {
Copy link
Member

Choose a reason for hiding this comment

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

Same comment as above, should remove the outer "args.map" block and just use

for args in args.iter() {
    // ...
}

#![deny(unused_import_braces)]
#![deny(unused_qualifications)]
#![deny(warnings)]
//#![deny(warnings)]
Copy link
Member

Choose a reason for hiding this comment

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

Please make sure you put this back when you're done :)

/// is used when communicating with libflipper to specify which
/// device functions should be executed on.
device: _lf_device,
device: _lf_device
Copy link
Member

Choose a reason for hiding this comment

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

I tend to like keeping the trailing commas on multi line lists like structs. If you remember to set this back that'd be cool.

ModuleFFI,
_lf_module,
};
pub struct Led;
Copy link
Member

Choose a reason for hiding this comment

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

I think we need to find some way to provide both an instance-level API and a module-level (similar to Java static) API such that the module level Led::rgb uses the default device and the instance-level led.rgb will use a specific device.

use ::{ModuleFFI, _lf_module};
use std::ffi::CString;

pub type _lf_device = *const c_void;
Copy link
Member

Choose a reason for hiding this comment

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

I'm wondering whether the _lf_device type should just be c_void so that in the lf_invoke signature it's clearer that it's a pointer by having lf_invoke(device: *const _lf_device, ...)

Copy link
Collaborator Author

@georgemorgan georgemorgan Mar 14, 2018

Choose a reason for hiding this comment

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

That is a good point. Should I change that?

fn from(ret: LfReturn) -> Self { ret.0 as u64 }
}

pub fn current_device() -> _lf_device {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should have a public function which returns a raw pointer. This should either be pub(crate) or we should find a way to do without this entirely.


impl Flipper {
pub fn attach() -> Self {
pub fn attach() -> _lf_device {
Copy link
Member

Choose a reason for hiding this comment

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

The _lf_device type shouldn't appear in the public API at all. If it needs to exist, it should be stored as a private field in a struct.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

👍

@nicholastmosher nicholastmosher changed the title Dyld Dynamic Loader (dyld) Apr 20, 2018
#define LF_WEAK __attribute__((weak))

#ifdef __clang__
#define LF_FUNC(MODULE) __attribute__((section("__TEXT,.lm."MODULE), used))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you add a space between "__TEXT,.lm." and MODULE? When this header is imported in C++, this breaks, because MODULE is interpreted as a literal suffix

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 9757f9b

@georgemorgan
Copy link
Collaborator Author

ASF time! Soon!

wasv and others added 2 commits November 10, 2018 15:07
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