Async Threads symbol not found when building

I’m trying to shift some code out into an async thread on the MM so loading files doesn’t block but I’ve got a problem with symbols not being found.
As per the 2.0 docs I’ve included the right header #include "CoreModules/async_thread.hh" and I’ve written my callback

    std::atomic<bool> needsLoad{false};

    // CoreModules/async_thread.hh
    MetaModule::AsyncThread asyncFileLoad{[this]()
                                          {
                                              if (this->needsLoad)
                                              {
                                                  this->sampleNames = samples::loadFolder(this->loadedFolder, &this->sampleInfo, &this->sampleBuffer, true);
                                                  this->needsLoad = false;
                                              }
                                          }};

The plugin compiles but symbols related to the Async thread are not found

Symbol in plugin not found in api: _ZN10MetaModule11AsyncThread5startEj
Symbol in plugin not found in api: _ZN10MetaModule11AsyncThreadC1EO13CallbackSizedILj8EE
Symbol in plugin not found in api: _ZN10MetaModule11AsyncThreadD1Ev

What obvious thing am I missing here?

Also is there a chance in future we could get a AsyncThread stop() too? Since something like file loads are only needed at specific times and I assume there’s some overhead to the callback always running and returning because the guard if (this->needsLoad) is false it would be great if we could only activate that thread when explicitly needed.

Hmm… Looks like in one of the merges those symbols got lost of the api_symbols file. I’ll figure it out and push a new version.

Yes, good idea. I was also thinking of run_once() or something similar for non-recurring tasks

1 Like

Thank you!

That would definitely work as well.

Ok, I have it implemented. I actually re-did AsyncThreads because the way I had it wasn’t friendly to the cpu load-balancing thing I had done a little while back. Now, the async threads are pegged to the same CPU that its parent module is running on (not that you need to know that, it just happens automatically). In case of large data sharing, this should make it more efficient with caches.

The API has changed a bit, too. I got rid of needing to pass the module id.

Instead, you do this:

MetaModule::AsyncThread asyncFileLoad{this, [](){ ... }};

Notice, the this pointer must be passed to the AsyncThread constructor.

You can also do async.stop(), which pauses the thread (it won’t halt execution if it’s in the middle of running, it will just prevent it from running again). Then async.start() will start it (unpause).

And you can have a thread run once and then stop with async.run_once(). This is equivalent to calling start() and then calling stop() after it runs once. So you can still call start() on a one-shot thread to have to loop, and you can call run_once(); on a looping thread to have it fire once more.

I’ll update the docs, too. You can go ahead and try it out, it requires the latest v2.0-dev firmware commit (I haven’t made the release yet), and the latest v2.0-dev plugin-sdk commit (tagged api-v2.0-dev-12.2)

That’s great that you implemented both stop and run_once! Thank you.

Has something else changed in the most recent firmware? because after having built and updated to it I’ve found that regardless of the async stuff I have an error now which prevents my plugins from loading

Error loading plugin: Missing symbol: _ZTIN4rack3app10PortWidgetE

I don’t see this when I build locally but when I try to load the module on the MM.

Hmm… If you get a missing symbol error when loading the plugin but not when building, then that indicates the SDK version is different between what you’re using the build and what’s being used by the firmware.

This symbol was added in the plugin SDK in api-v2.0-dev-12.0. What firmware version are you using? Or if you compiled the firmware yourself, which commit did you compile (and of course make sure submodules are updated since the SDK could be out of date).

I just posted a release v2.0.0-dev-12.2: Release Firmware Version: firmware-v2.0.0-dev-12.2 · 4ms/metamodule · GitHub

I can confirm this version will run all the v2.0-dev-12.0 plugins from the latest dev-plugins.zip file

Using your build of the latest firmware I have the same issue with the symbol not being found on the device so there’s definitely something weird going on here.
I made sure that as well as pulling the latest dev before building I had the submodules in sync and i’m using the sdk folder from the metamodule firmware repo so that everything should always be in sync. I’ll DM you the bundle so you can have a look.

omfg, I’m sorry this was totally my fault. Turns out I had some firmware on both my sd card and my usb stick, and it was preferring the older one on the sd every time I hit install. I didn’t even think about this, and because you can’t see the full version on the info page because it’s too long and goes off the edge of the screen I just had assumed it was using the right one :see_no_evil: sorry to waste your time

Oh, ha! yes I’ve been meaning to make the firmware version text wrap around for that very reason.

1 Like