1. pass map to shared library

Euphoria Interpreter v4.1.0 development
32-bit Windows, Using System Memory
Revision Date: unknown, Id: 0:unknown

is it possible to pass a euphoria map to a shared library .so/.dll?
if so, it would be a great bonus when developing eui shared libraries

i have the following code compiled as a dll

--// maplib.e 
--// euc -dll maplib.e 
 
include std/map.e 
 
export function mapfunc(map params) 
   if map(params)      then printf(1, "map\n")      end if 
   if object(params)   then printf(1, "object\n")   end if 
   if sequence(params) then printf(1, "sequence\n") end if 
   if integer(params)  then printf(1, "integer\n")  end if 
   if atom(params)     then printf(1, "atom\n")     end if 
   ? map:get(params, "integer") 
   ? map:get(params, "atom") 
   puts(1, map:get(params, "sequence") & "\n") 
   map:put(params,"retval", "return value") 
   return params 
end function 


and the following code to load and test the library

--// testmap.e 
--// eui testmap.e 
 
include std/dll.e 
include std/map.e 
include lib/maplib.e 
 
   map testmap = map:new() 
   map:put(testmap, "integer", 1) 
   map:put(testmap, "atom", 2.0) 
   map:put(testmap, "sequence", "string") 
 
   --// call directly 
   mapfunc(testmap) 
 
   --// call via dll 
   constant libhandle = open_dll("maplib.dll") 
   constant __mapfunc = define_c_proc(libhandle, "mapfunc", { E_OBJECT }) 
 
   if (libhandle > 0) then 
      ? { libhandle, __mapfunc } 
      c_proc(__mapfunc, { testmap }) 
   end if 

provides the following output

map
object
integer
atom
1
2
string
{50921472,39}
object
integer
atom

the program fails when attempting to read from the map
via the dll function call

any help appreciated

ras

new topic     » topic index » view message » categorize

2. Re: pass map to shared library

raseu said...

Euphoria Interpreter v4.1.0 development
32-bit Windows, Using System Memory
Revision Date: unknown, Id: 0:unknown

is it possible to pass a euphoria map to a shared library .so/.dll?
if so, it would be a great bonus when developing eui shared libraries

The problem is that the map data isn't easily accessible to the shared library. I think the simplest is to use a fairly low level hack, plus some editing of your translated shared library C code. In 4.1, you can write your own debuggers, which requires some low level access to euphoria data. We can use this to communicate between the main program and the library.

The following code will find the location in memory where a particular symbol is stored:

include euphoria/symstruct.e 
include euphoria/debug/debug.e 
debug:initialize_debugger( machine_func( M_INIT_DEBUGGER, {} ) ) 
 
public function find_sym( sequence name ) 
	atom symtab = debug:get_symbol_table() 
	integer size = peek_pointer( symtab ) 
	for i = 1 to size - 1 do 
		atom sym = symtab + ST_ENTRY_SIZE * i 
		atom name_ptr = peek_pointer( sym + ST_NAME ) 
		if name_ptr then 
			if equal( name, peek_string( name_ptr ) ) then 
				return sym 
			end if 
		end if 
	end for 
	return 0 
end function 

FYI...I just noticed that euphoria/debug/debug.e gets installed to euphoria/debug.e, which is incorrect. You'll need to either move the file manually or modify the include statement.

The rest of my main program:

include std/console.e 
include std/dll.e 
include std/eumem.e 
include std/map.e 
 
 
constant 
	RAS         = open_dll( "./ras.so" ), 
	SET_RAM     = define_c_proc( RAS, "set_ram", {E_ATOM} ), 
	DISPLAY_MAP = define_c_proc( RAS, "display_map", {E_ATOM}), 
	MAP_PUT     = define_c_proc( RAS, "put", { E_ATOM, E_OBJECT, E_OBJECT } ) 
 
map foo = map:new() 
 
map:put( foo, 1, "one" ) 
c_proc( SET_RAM, { find_sym( "ram_space" ) } ) 
c_proc( DISPLAY_MAP, { foo } ) 
 
 
c_proc( MAP_PUT, { foo, 2, "two" } ) 
c_proc( DISPLAY_MAP, { foo } ) 
 
display( map:pairs( foo ) ) 

That's all pretty straightforward, even though we haven't looked at the library code:

include std/eumem.e 
include std/map.e 
include std/console.e 
 
sequence local_ram = {} 
sequence remote_ram = {} 
 
public procedure display_map( map foo ) 
	use_remote() 
	display( map:pairs( foo ) ) 
	use_local() 
end procedure 
 
public procedure put( map the_map, object key, object value ) 
	use_remote() 
	map:put( the_map, key, value ) 
	use_local() 
end procedure 
 
public procedure set_ram( sequence ram ) 
	remote_ram = ram 
	local_ram = eumem:ram_space 
end procedure 
 
without inline 
procedure use_remote() 
	eumem:ram_space = remote_ram 
end procedure 
 
procedure use_local() 
	eumem:ram_space = local_ram 
end procedure 

If you look at display_map() and put(), you'll notice that we have to swap out eumem:ram_space in order to operate on the map passed from the main program. If you just wanted to read the map, this might work. In order to be able to read and write, however, we need to modify the C code for set_ram(), use_remote() and use_local().

In particular, we have to comment out some reference counting code, and change some of the assignments. Here's what my locally modified version looks like:

void _1set_ram(object _ram_14280) 
{ 
    object _0, _1, _2; 
 
 
    /** ras.e:21		remote_ram = ram*/ 
//     RefDS(_ram_14280); 
//     DeRef(_1remote_ram_14261); 
 
    _1remote_ram_14261 = get_pos_int( "get sym pointer", _ram_14280 ); 
 
    /** ras.e:22		local_ram = eumem:ram_space*/ 
//     RefDS(_2ram_space_171); 
//     DeRef(_1local_ram_14260); 
    _1local_ram_14260 = _2ram_space_171; 
 
    /** ras.e:23	end procedure*/ 
    DeRef(_ram_14280); 
    return; 
    ; 
} 
void set_ram() __attribute__ ((alias ("_1set_ram"))); 
 
 
void _1use_remote() 
{ 
    object _0, _1, _2; 
 
 
    /** ras.e:27		eumem:ram_space = remote_ram*/ 
//     RefDS(_1remote_ram_14261); 
//     DeRef(_2ram_space_171); 
    _2ram_space_171 = *(intptr_t*)_1remote_ram_14261; 
 
    /** ras.e:28	end procedure*/ 
    return; 
    ; 
} 
 
 
void _1use_local() 
{ 
    object _0, _1, _2; 
 
 
    /** ras.e:31		eumem:ram_space = local_ram*/ 
//     RefDS(_1local_ram_14260); 
//     DeRef(_2ram_space_171); 
	*(intptr_t*)_1remote_ram_14261 = _2ram_space_171; 
    _2ram_space_171 = _1local_ram_14260; 
 
 
    /** ras.e:32	end procedure*/ 
    return; 
    ; 
} 

The actual variable names will probably be different for your library, of course.

Matt

new topic     » goto parent     » topic index » view message » categorize

3. Re: pass map to shared library

thanks for the informative reply.

i resolved the issue by converting and returning
the map as a sequence via map:pairs and map:new_from_kvpairs

ras

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu