Re: pass map to shared library

new topic     » goto parent     » topic index » view thread      » older message » newer message
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 thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu