I'm playing around with dynamic linkage again.

The reason is: the webserver currently has various translators
hard coded into it. I want to make these translators dynamically
loaded so people can write a translator for Felix, Python, C,
Fdoc, Ocaml, etc etc without having to relink the webserver.

I noticed a nastiness:

///   xlat1.flx ///////////
println "xlat1 initialising";
var s = "init string";
fun xlat(x:string)=> "XLATED <" + x + "> XLATEDEND " + s;
export fun xlat of (string) as "xlat";


///// dlx.flx /////////////////////
println "Dynamic loader test";

var linst1 = Dynlink::init_lib("xlat1.dylib");
println$ "Library initialised";
var lib1 = Dynlink::get_library linst1;
var tf = Dynlink::get_thread_frame linst1;

var addr1 = Dynlink::dlsym$ lib1, "xlat";
println$ "Got function address " + str addr1;

var fn1 = C_hack::cast[address * string --> string] addr1;

println$ fn1 (tf, "Hello World");
///////////////////////////

~/felix>flx --test=build/release dlx
Dynamic loader test
xlat1 initialising
Library initialised
Got function address 879072
XLATED <Hello World> XLATEDEND init string
/////////////////////////////

Now, the nastiness is that you write:

export fun xlat of (string) as "xlat";

but you actually get:

var fn1 = C_hack::cast[address * string --> string] addr1;

The initial argument is the thread frame of the library.
This is present even if the function doesn't seem to need it.

This gets in the way of being able to create "pure C libraries" with
Felix. That is something we want to do. Of course such libraries
cannot use garbage collection, etc etc, at least unless the GC or
thread frame object is explicitly passed.

BTW: "export" creates extern "C" functions. There's no way to
create C++ functions at the moment. This doesn't matter if you're
making a library for "dlopen/dlsym" style usage. But it does if you're
just linking it at load time OR you're using a table lookup
(for example, this is what Python does).


By way of explanation of how dynamic linkage works in Felix:

Felix loads a library the usual way, but you technically need an instance
handle to be created. This captures the thread frame. The instances
are reference counted. When you run out of instances the library
is dlclosed. Felix does some garbage collection here, to help
release libraries.

However .. unloading libraries doesn't work very well: this is a design
bug in C and Unix which cannot be corrected. The primary killer
is static data, however it isn't just data in initialised or uninitialised
CSECT (C static data) that's the problem: TEXT (code) is a problem
too: code sections can contain read-only constants .. including 
functions of course.

In order to unload a library you have to be sure there are no
references at all into the library address space(s).

Felix is very pedantic about NEVER generating static variables
(although you can hack it in C when required for signal handling, etc).

However a lot of stuff it has no control over happens like string
literals. [Lets no even get into the impossibility of managing 
standard I/O streams properly :]

So the bottom line is: in general unless one is 100% certain there
are no residual references to a dynamically loaded object .. 
don't try to unload it :)

The gc will try to unload it at program termination IF the gc
is run then (which it isn't by default). Hopefully that won't crash anything.

--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
This SF email is sponsosred by:
Try Windows Azure free for 90 days Click Here 
http://p.sf.net/sfu/sfd2d-msazure
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to