-
Notifications
You must be signed in to change notification settings - Fork 320
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
Dev plugins support upstream submit 01 branch #9
Dev plugins support upstream submit 01 branch #9
Conversation
This mechanism allows to register a function for creating a context, in a generic way. It is intended to be used for backend implementations. This patch only implement the factory registration / unregistration functions, which isn't useful by itself until some backend implementation actually uses it. A static array of factories, with a limited size, keeps track of all the factories registered so far. Change-Id: I0533490532e40f92ceef113314f4f4098d79aad9
This patch implements a way to actually retrieve a factory, knowing it's name and uses it for the local backend's creation. Registration for the local backend's context factory is done in it's constructor initialization function, thus saving the need of an extra function call at startup and above all, making the context factories registrations independant of the actual list of backends implemented. This opens the way for plugins implementation. The local.c file is compiled iif LOCAL_BACKEND is defined, the construction of it's context will be successful if it's factory has already been registered and will return NULL if not. Change-Id: I134a0d17da7742475587b1597c69a1085e175841
Some backends must be parametrized before their context is created. It's the case for the network backend which needs an hostname. So this patch proposes a generic yet simple way to do so with properties. They are key/value string pairs, attached to a factory, which can then retrieve their value and adapt the context creation process accordingly. The iio_property is exposed in the public API, because it will be used by the client program, for parametrizing the construction of the context it is interested in. Change-Id: I761462450e0abb4f3ccd6e880a37291b159c293d
In an analog manner as for the local backend, the network backend is now created by the factory it registers in it's module constructor. The only difference is that, as it may use an hostname, we pass it via an iio_property. Change-Id: Iaa4465855c5feb31438289693c4428f2b2c1eedd
This patch adds an API for plugins support to libiio. It simply dlopens each .so matching a certain pattern (defaulting to libiio-*.so), in a certain directory (defaulting to /usr/lib/libiio-plugins/). The plugin can then do things in it's module constructor, for example, registering support for a new backend with a context factory. Change-Id: I9e60d490f95f0d8ffbb2b9c4ec05ec2bb384cf06
Plugin implementors willing to add for example, the support for a new backend, must access some internal APIs. This patch prevents some functions from being hidden. The functions concerned are those making possible to compile the local backend as an independent plugin. Note: they are not exposed as a public API in the iio.h file because they should only be exposed to plugin implementors who will have to include the iio-private.h header and certainly also debug.h. Change-Id: Ib8d202cebe0ec8302d4fa5f7bd77ba079f2cf516
This patch adds the implementation of iio_create_context(), which allows to instanciate an arbitrary context, provided a corresponding factory has previously been registered. The context creation can be parametrized with a property set. Change-Id: I9fd5db94b1cb3e598f17b497b43d9c86ba85eb72
Hi Nicolas, Thanks for this contribution, this is really appreciated. Having support for plug-ins is definitely something that we want. However I don't think that this implementation is optimal, for the following reasons:
At some point I was toying with a USB backend (via libusb) which gave me ideas about how to handle external plugins while keeping all the complexity in the private part of the library; I will explain this different approach. Let's define this structure, in a public file struct iio_backend {
int init(...);
void exit(void);
const char * (*get_xml)(void);
struct iio_backend_ops *ops;
}; The idea behind this, is that you only need to specify the structure of the context that you want to create as a XML string. A new built-in backend named e.g. "dynamic", created with This would allow an external plug-in to create a new IIO context structure without accessing the internals of libiio, which is much more robust vs. updates. Another advantage of this method, is that you can save a pointer to the loaded plugin in the context's pdata, and free it from the destroy( ) callback. This avoids having to call any other function to load / unload the plugin, and it removes all the complexity of the "factory". It is also less intrusive, in the sense that all the complexity stays in one place (e.g. Any thoughts about this approach? |
Hello,
This is a super good news for us, we really need it too. Portability issues
It seems possible to do the same with VS. But I'm no competent to implement it. The main portability issue is IMHO the plug-in loading mechanism. Factory
These points can be summarized by : parametrize context creation with an ellipsis VS key value properties Dependency on the libiio internalsI agree that it is not a good thing to depend on the internals of libiio. I think there is a need to identify a clear part of libiio's internals which should be extracted to a libiio-plugins included (or linked by) plugin implementors. These would become part of a public API, which should be maintained, just for plugins. About the xmlI think that the xml part is orthogonal to the backend context creation. If I understand well, it's role is to create the "devices tree structure" behind the backend. Backend implementors should be free to create this structure in the way they want. XML not being the right solution for every use cases. iio_init_plugins and iio_cleanup_pluginsI made an error exposing these two and they must be removed: they are not needed. They can just be constructor/destructor functions like the plugins initialization functions. I have just tested it and it works fine. I feared an "order of execution hazard", but in fact, there is none. Plugin de-registration
Again it implies plugin == backend implementation, which is an unneeded restriction. The destructor can take care of cleanup and is called directly by the dlclose() call issued by the plugins subsystem. To sum upThe struct iio_backend is a good approach, but has the default of coupling not so related functionalities, which can be separated at a really low cost, that is :
In my humble opinion...I think we should :
I can work on items 1, 2 and 5 on my own. I am not competent for 3 and 4 I don't even have access to a windows pc... I can work on 6, but it will need some more discussion to design the API and choose which inner functions to move to it. |
Hi, Let me clear up some points: The problem with accessing the internals of libiio is not only about the visibility of the functions. If the plug-in has visibility on the internal structures, e.g. the About the XML, it is a 1:1 representation of the IIO context. It only contains public information about the context, that the application could otherwise retrieve with the public API functions when using any backend. This is a requirement for the remote feature to work. This has two implications:
Concretely, the local backend could very well generate a XML string representing the context, and have all the internal structures created via the XML backend (just like the network backend does). It would just store its private data in its A final thought (for now) about the loading of the plug-ins: I think it is a really bad idea to automatically load all the plug-ins from a given directory and allow them to call a constructor. This is a huge security hole... |
Hello,
IMHO it is just a matter of how much you expose of the libiio to the plugin implementors. It is hard to settle, as providing too little will reduce the interest of the plugin interface but providing too much will provoke the problems you lay stress on wisely.
I'd rather not have forced the use of XML, but in the end, I'm fine with it.
Here I really don't understand. I proposed loading plugins from a well controlled location, written in the library at build time. Why would this be a security hole ? If one isn't able to control what goes to this location, why would he/she be able to control the location where the libiio.so is ? Then one should be able to replace/hack it... The most important for me is to provide a plugin support which will allow us to do what we need. So even if I don't completely agree with your point of view, I am currently trying to work on an implementation based on your proposal. I will come back to you when I'll have questions. |
Hi, If you control the directory where the plug-ins are located, and don't allow a regular user to load plug-ins from a different directory then there is indeed no security problem. I will wait for your new implementation then. Thanks for your work! |
Hello, So what concretely should we expose to a plugin ? |
Hi, The struct iio_backend_ops should be visible to the plug-ins, that's certain. The callbacks, on the other hand, should resort to use the public API as much as possible. I don't think that it would be hard to do; most of the fields of the iio_* structures defined in "iio-private.h" can already be retrieved using API functions. Some fields cannot (e.g. device->ctx or channel->dev have no equivalent API function), but it would make sense to have API functions for those as well. For the iio_[context|device|channel]_pdata, we could just have public accessors à la iio_device_get_data / iio_device_set_data, not part of the public API and defined in a separate header (e.g. iio-backend.h) reserved for the backend implementations. From my experience, the network backend could very well be using the public API of libiio (with the few additions listed above); the main reason why it currently doesn't, is because it is faster to type The local backend uses the internals much more as it does all the work of creating the IIO context from what it sees in sysfs. It would be possible though to simplify it enough so that it only uses API functions and backend-specific functions, by making it generate XML from what it sees in sysfs, and use the XML backend to create all the structures. The XML backend, in that case, would be the only one built into the library and the only one with a full visibility on the internals. I can work on de-coupling the local backend from the core of the library once we have a well-defined API; for now I think we can keep it built-in. Having the network backend decoupled, on the other hand, seems a good way to test the robustness of the plug-in implementation. Paul |
Ok, |
There are no automated tests - I just use the static analyzer of clang to identify the most obvious mistakes. |
I will continue the work of Nicolas. From what I understand of the discussion, I have tried to write a patch following your implementation suggestion Paul. A small preview is available at Parrot-Developers/libiio@1a7c2a6 (the commit has been done after commits of pull request #17). Here are the main steps of my work :
I have still question about this draft :
I will continue to work on this patch (I need to check if it fits our needs, and then improve it), but I would like to have a feedback from you, as I'm not sure of the implementation to provide. |
Hi, Inside dynamic.c, you actually include "iio-private.h", so you have access to the internal structures, unlike the external plugins. This means that you don't actually need functions like "iio_context_set_ops( )", you can just do "ctx->ops = ops;". About where to store the handle: About parameters passing: I have a a preference on using a variadic function "iio_create_context(name, ...)", where the additional parameters are passed to the plugin's init() function, but I am fine with alternatives if they are simple enough. You don't have to update the network backend, it can certainly be done later. |
Ok, I should work to store the handle in this way. I will implement a variadic function, I have no specific suggestion for this point. I will work on this way. Once I manage to implement dynamic backends for our needs, I will send you an update for this pull request. Thanks ! |
Closing this, the "dev" branch has support for plugins. |
Hello,
Here is a patch set which implements plugins support for libiio.
The main goal is to allow implementing libiio backends outside of libiio, in plugin form.
The base idea is that a given directory is scanned for .so files, whose name match a given pattern.
These .so are dlopened and have access to some functions from the internal libiio API (from iio-private.h and debug.h).
For the particular case of backend implementation, two functions are provided, allowing plugins to register context factories, iio_context_factory_register() and iio_context_factory_unregister().
A factory allows the creation of an iio_context, parametrized with key/value string properties.
The local and network plugins are modified to register factories and their context creation function wrappers in context.c are modified to use these factories.
A public API function is added, to allow the access to an arbitrary backend implementation: iio_create_context().
The main drawback I see of this patch set is that it may break libiio on windows. Since I have absolutely no knowledge of this platform, I'm not competent for fixing that issue. I hope some more knowledgeable people will be able to do it. Maybe a conditional compilation approach, disabling the feature in non-dlopen capable platform would be a correct first attempt.
Having the possibility to create custom backends would allow a lot of possibilities, for example :
I am open to any suggestion or remark.