Storing local struct instance in a dynamic library

Hi all.

I'm trying to solve one problem is more than two weeks, but no results :frowning: I have a microkernel system, which is extended by dynamic libraries (dll files under windows). Every time, new library is loaded, core code calls special init function from it. One of plugins creates a GUI (I use piston library for drawing) for this system. During init() call, core code passes configuration parameters, like user window width, height and so on... So, the window may be created within init() function only. Later, core code calls another function of plugin, which is called idle(). idle() uses created window for drawing, so it should use some internal window handler, canvas object , etc.

As a starting point I used this example: piston-examples/paint.rs at master ยท PistonDevelopers/piston-examples ยท GitHub
The difference here is that, this code stores all objects in local variables and not in a struct, which I need to use between different functions calls.

So, my question is how to create and store all drawing related stuff like piston window, canvas, texture and so on in a struct between different functions calls? Is it possible to use some kind of reference to singleton struct instance within a dll?

I tried:

// gui.dll file
// globally
static mut gui: Option<Gui> = None;
// in init() function
gui = unsafe { Some(Gui{ ... }) }
// in idle() function
gui.unwrap()... // produces an error, because some properties of Gui dont implement Copy trait

And this is logical, because Window should be only one, as well as a canvas.

If you want to avoid static mut a common solution is to pass some sort of opaque "user data" pointer to each event handler that is created by init().


struct State { ... }

#[no_mangle]
pub extern "C" fn init() -> *mut c_void {
  let state = Box::new(State { ... });
  Box::into_raw(state).cast()
}

#[no_mangle]
pub extern "C" fn idle(user_data: *mut c_void) {
  let state = &mut *(user_data as *mut State);
  ...
}

Otherwise if the function signatures don't allow passing around extra state like this, your only option will be static variables. That's one of the reasons you see so many static variables in embedded code - hardware interrupts just switch execution to some arbitrary function so there is nowhere to put extra state apart from static variables.

Thanks! It looks great. But what about destroying of this struct?

You can use drop(Box::from_raw(ptr)) to destroy it. This will both run the destructor and deallocate the memory.

1 Like

Your kernel should expect plugins to have some sort of unload() function which does cleanup when unloading the plugin (i.e. by calling drop(Box::from_raw(ptr))).

FWIW, the method using static variables also has the same issue where we never clean up things created during init(). It's just that we've been trained to see a pointer and ask who is responsible for freeing it while you don't really think about cleaning up your statics with dynamically loaded modules.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.