The assert was there to make a rare random crash into a reliable crash. The thing is
that symbol resolution needs to take a mutex, because in very rare cases it might be
running in parallel to someone loading an additional shared object. This taking of a mutex
may block the thread, and when in non-preemptable state, will cause a crash at that
point. So the idea of the assert is to make you aware of this problem much earlier,
before you start seeing it once a year in the field.
This was explained in the commit that added this assert, back in 2014: 930cb83d9.
The "z,now" solution will work, but there is another problem you should be aware of:
When user code is running in non-preemptable state, both the code's stack, and the code
itself, must already be in memory and cannot be swapped-in. The latter in particular means
that the executable must be entirely loaded into memory, not page by page ("demand paging")
as we normally do.
We have a trick that will do both the on-load symbol resolution and loading the entire object
and not page by page: If you add:
asm(".pushsection .note.osv-mlock, \"a\"; .long 0, 0, 0; .popsection");
To your source code, both things will auto-magically happen :-)
We have in <osv/elf.hh> a macro doing this, OSV_ELF_MLOCK_OBJECT(), but you don't really need that macro, you can just copy this line.
I suggest you use this trick, instead of the "z,now" thing.
Unless you executable is huge, I don't think you'll have problems doing this for the entire executable (you only need this "section" thing in one place in your source code), but if that bothers you, you can always put the problematic code in a separate shared object, and only that object will be marked with this special section.