On Saturday, February 13, 2021 at 4:21:34 PM UTC+1 Ian Lance Taylor wrote:

>
>
> > I was naively assuming that the unloading issue is easy to tackle when 
> the runtime is not shared between .so. Is it true ? 
>
> No. The current Go runtime has no ability to shut down all 
> goroutines. If any goroutines are left running, and the plugin is 
> unloaded, the program will crash. 
>
>
I was not assuming a synchronous uncooperative way for the runtime to kill 
a running goroutine.  I was more thinking about some cooperative strategy. 
Like a running go routine could check sometimes (maybe in the function 
prologue, or when doing an allocation) that it is time to die.  
Anycase, that could be also a constraint of the business code in the 
plugin.  Like in C, they are not supposed to be actively running when the 
.so is *dlclosed*.
In fact, what happens in practice today if we *dlclose* a plugin that has 
no running goroutine (and also no cgo invocations).  Does it "*work*" 
somehow ?  Are we leaking threads, waiting on some dead semaphore or 
something ?


> > A last technical question, do you link the shared object with the ld 
> flag `- z nodelete` (which turn dlclose into no op). 
>
> As far as I know we do not. 
>
>
This `ld` flag makes me think of another approach.  Maybe it is  ok to just 
turn off the effective unloading of the .so (with that ld flag).  So 
*dlclose* is no-op.  But if the business code takes care of cleaning most 
of its global state, maybe the gc has the opportunity to return some memory 
back to the OS (well, since the gc is not moving stuff, maybe the hope is 
slim, I don't know).
That approach does not solve the problem of the developer iteratively 
working on a plugin.  Apart from that, this looks like an acceptable 
compromise for someone who wants to ship an loadable plugin that can be "
*unloaded*".  At least it *works* somehow, leaking a bit of memory.  But it 
does not crash.
Of course, it is expected that if I load *libfoo.so* unload it, and load it 
again, everything works.  I don't see why it would not.  The second *dlopen* 
is presumably no-op.

Now about the unique  runtime constraint.  In the previous message, you 
said that we might be able to run several runtimes in the same process 
(private runtime symbols, ...)
If that works, it would mean that if the runtime symbols are public, but 
*versioned*, then maybe the runtime constraint is gone, isn't it?  
If two lib *libfoo.so* and *libbar.so* are built with different runtimes, 
we get two instantiated runtime in the binary that loads them 
simultaneously.  Well, too bad, we lose a bit of memory, but at least it 
works.  It looks acceptable to me.
In the favorable case, they share the same runtime and every one is happy.

I am curious about what happens on MacOS today.  Because my understanding 
of their *two level namespace  
*(https://developer.apple.com/library/archive/documentation/Porting/Conceptual/PortingUnix/compiling/compiling.html#//apple_ref/doc/uid/TP40002850-BCIHJBBF)
 
implies that you instantiate a new runtime whenever you load a c-shared 
.dylib.  I'm not sure at all.  It seems there is a way to force a flat 
namespace (it does not seem to be the default, thought).  I haven't 
verified that yet.  By the way, what the most efficient way to detect if 
two runtime are being instantiated ?  Something like a debug log that is 
supposed to happen once, or a similar trick.

Thanks
Fred


-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/edc90dd0-9f6d-4fbb-8629-db52b11ede42n%40googlegroups.com.

Reply via email to