1. Wrapping Callback Functions

Hello all,

I need a little help. I'm wondering if this is how you wrap callback functions.

//C Code 
	typedef void* (*NewtonAllocMemory) (int sizeInBytes); 
	typedef void (*NewtonFreeMemory) (void* const ptr, int sizeInBytes); 

--Is this correct? 
constant xNewtonAllocMemory = define_c_func(dll,"NewtonAllocMemry",{C_INT},C_POINTER) 
 
public function NewtonAllocMemory(integer size) 
 
 return c_func(xNewtonAllocMemory,{size}) 
 
end function 
 
constant xNewtonFreeMemory = define_c_proc(dll,"NewtomFreeMemory",{C_POINTER,C_INT}) 
 
public procedure NewtonFreeMemory(atom ptr,integer size) 
 
 c_proc(xNewtonFreeMemory,{ptr,size}) 
 
end procedure 
new topic     » topic index » view message » categorize

2. Re: Wrapping Callback Functions

Icy_Viking said...
--Is this correct? 
constant xNewtonAllocMemory = define_c_func(dll,"NewtonAllocMemry",{C_INT},C_POINTER)  
--                 It looks ok,                                ^ apart from that 
constant xNewtonFreeMemory = define_c_proc(dll,"NewtomFreeMemory",{C_POINTER,C_INT}) 
--                                                   ^ and that 
new topic     » goto parent     » topic index » view message » categorize

3. Re: Wrapping Callback Functions

petelomax said...
Icy_Viking said...
--Is this correct? 
constant xNewtonAllocMemory = define_c_func(dll,"NewtonAllocMemry",{C_INT},C_POINTER)  
--                 It looks ok,                                ^ apart from that 
constant xNewtonFreeMemory = define_c_proc(dll,"NewtomFreeMemory",{C_POINTER,C_INT}) 
--                                                   ^ and that 

Is the name in quotes not supposed to be there? Or do I need to add a + in front of the name?

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

4. Re: Wrapping Callback Functions

Spelling counts, but beside that -

As far as I know, putting a + in front of the name is a good idea, at least on Windows.

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

5. Re: Wrapping Callback Functions

Icy_Viking said...

Is the name in quotes not supposed to be there?

YOU CANNOT BE SERIOUS!!! The names in quotes are supposed to be spelt correctly....

(And yes/as irv said, a + may well help)

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

6. Re: Wrapping Callback Functions

petelomax said...
Icy_Viking said...

Is the name in quotes not supposed to be there?

YOU CANNOT BE SERIOUS!!! The names in quotes are supposed to be spelt correctly....

(And yes/as irv said, a + may well help)

Oops, just noticed the typo. My eyesight isn't what it used to be. I thought something was wrong with the entire quotes.

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

7. Re: Wrapping Callback Functions

You can save some grief if you assign a type for the callbacks, so that you get notified when you try to look up an invalid c routine, otherwise, you have to check each one to see if it succeeds. Something like this, off the top of my head:

type handle(integer x) 
return x > -1 
end type 
 
handle xNewtonAllocMemory = define_c_func(dll,"+NewtonAllocMemory",{C_INT},C_POINTER) 
 
handle xNewtonFreeMemory = define_c_proc(dll,"+NewtonFreeMemory",{C_POINTER,C_INT})  
 
new topic     » goto parent     » topic index » view message » categorize

8. Re: Wrapping Callback Functions

Icy_Viking said...

Hello all,

I need a little help. I'm wondering if this is how you wrap callback functions.

//C Code 
typedef void* (*NewtonAllocMemory) (int sizeInBytes); 
typedef void (*NewtonFreeMemory) (void* const ptr, int sizeInBytes); 

No, that is not at all correct. These are typedefs which name a new type. In this case, that type is the signature of each call back function. They're call backs which means they're addresses of functions where the library calls you. (Insert Yakov Smirnoff joke here.)

Call back functions by their nature should not exist in the library you're calling. The docs for NewtonAlocMemory even state: This is not a library function, but a callback event. So you need to define your call back functions to match the signatures as provided. In Euphoria, that means each parameter must be an atom.

Then the library should have a way to set those call back addresses so it can call your function when the time comes. In this case it looks like that's NewtonSetMemorySystem. Which, by the way, states it is not neccesary to call this function at all in the documentation, so in this particular case all of this work may be moot (unless you want to set up custom memory allocation).

Edit: since we've determined this uses cdecl on 32-bit Windows, we also need to preface our call backs with '+' to force cdecl inside Euphoria.

-- 
-- This is the library function to set the call backs. 
-- 
 
constant xNewtonSetMemorySystem = define_c_proc( newton "NewtonSetMemorySystem", {C_POINTER,C_POINTER} ) 
 
-- void NewtonSetMemorySystem (NewtonAllocMemory malloc, NewtonFreeMemory free) 
public procedure NewtonSetMemorySystem( atom malloc_func, atom free_func ) 
    c_proc( xNewtonSetMemorySystem, {malloc_func,free_func} ) 
end procedure 
 
-- 
-- This is our implementation of the alloc function. 
-- 
 
-- typedef void* (*NewtonAllocMemory) (int sizeInBytes); 
function NewtonAllocMemory( atom sizeInBytes ) 
    return allocate( sizeInBytes ) 
end function 
 
constant NewtonAllocMemory_id = routine_id( "NewtonAllocMemory" ) 
constant NewtonAllocMemory_cb = call_back({ '+', NewtonAllocMemory_id }) 
 
-- 
-- This is our implementation of the free function. 
-- 
 
-- typedef void (*NewtonFreeMemory) (void* const ptr, int sizeInBytes) 
function NewtonFreeMemory( atom ptr, atom sizeInBytes ) 
    free( ptr ) 
    return NULL 
end function 
 
constant NewtonFreeMemory_id = routine_id( "NewtonFreeMemory" ) 
constant NewtonFreeMemory_cb = call_back({ '+', NewtonFreeMemory_id }) 
 
-- 
-- Call the library function to set the call back addresses. 
-- 
 
NewtonSetMemorySystem( NewtonAllocMemory_cb, NewtonFreeMemory_cb  ) 

-Greg

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

9. Re: Wrapping Callback Functions

One neat feature that was implemented in Euphoria 4.0 (or maybe 4.1? can't remember) but not really advertised is the "stacking" of default parameters that are evaluated at runtime at the callee's location.

What I mean by "stacking" is that parameters are evaluated from left to right, so you can use a previous parameter's value later down the line. So you can "clean up" code above by adding a few default parameters:

Edit: since we've determined this uses cdecl on 32-bit Windows, we also need to preface our call backs with '+' to force cdecl inside Euphoria.

public procedure NewtonSetMemorySystem( sequence malloc_name, sequence free_name, integer malloc_id=routine_id(malloc_name), integer free_id=routine_id(free_name) ) 
 
    atom malloc_cb = call_back({ '+', malloc_id }) 
    atom free_cb = call_back({ '+', free_id }) 
 
    c_proc( xNewtonSetMemorySystem, {malloc_cb,free_cb} ) 
end procedure 

And now you can eliminate all the separate calls to routine_id and call_back and just call NewtonSetMemorySystem like this:

function NewtonAllocMemory( atom sizeInBytes ) 
    return allocate( sizeInBytes ) 
end function 
 
function NewtonFreeMemory( atom ptr, atom sizeInBytes ) 
    free( ptr ) 
    return NULL 
end function 
 
NewtonSetMemorySystem( "NewtonAllocMemory", "NewtonFreeMemory" ) 

-Greg

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

10. Re: Wrapping Callback Functions

Icy_Viking said...
petelomax said...
Icy_Viking said...

Is the name in quotes not supposed to be there?

YOU CANNOT BE SERIOUS!!! The names in quotes are supposed to be spelt correctly....

(And yes/as irv said, a + may well help)

Oops, just noticed the typo. My eyesight isn't what it used to be. I thought something was wrong with the entire quotes.

So this raises the following questions:

What is the '+' for?

The '+' character is used to force the cdecl calling convention on 32-bit Windows, where the default is stdcall (which is strictly an x86 convention). On any other system, and all 64-bit systems, the default is already cdecl, so the '+' has no effect.

Therefore, if you're using a library that requires cdecl on 32-bit Windows, you can wrap it with '+' in the function names without having to maintain two separate versions with and without '+' everywhere.

How do we know when to use '+'?

This can be a little tricky. You need to dig into the code a little. If you walk through the header you should see if it defines any particular calling convention.

If we start at the definition for a function, like NewtonSetMemorySystem we see it's defined as:

NEWTON_API void NewtonSetMemorySystem (NewtonAllocMemory malloc, NewtonFreeMemory free); 

That NEWTON_API macro is likely going to contain our calling convention, if the authors of the library have intended to change it.

Sure enough, if we scroll up to the top of Newton.h we find several ifdef's that control the content of the NEWTON_API macro.

#if defined(_MSC_VER) 
    #define DG_LIBRARY_EXPORT __declspec(dllexport) 
    #define DG_LIBRARY_IMPORT __declspec(dllimport) 
    #define DG_LIBRARY_STATIC 
#else 
    #define DG_LIBRARY_EXPORT __attribute__((visibility("default"))) 
    #define DG_LIBRARY_IMPORT __attribute__((visibility("default"))) 
    #define DG_LIBRARY_STATIC 
#endif 
 
#ifdef _NEWTON_STATIC_LIB 
    #define NEWTON_API DG_LIBRARY_STATIC 
#elif defined(_NEWTON_BUILD_DLL) 
    #define NEWTON_API DG_LIBRARY_EXPORT 
#else 
    #define NEWTON_API DG_LIBRARY_IMPORT 
#endif 

Which means if the library is built as shared library (dll/so) and on Visual Studio (where _MSC_VER is defined) then the value of NEWTON_API will become __declspec(dllexport), which is the cdecl calling convention.

-Greg

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

11. Re: Wrapping Callback Functions

Thanks for all your help Greg. The new function routines and helpers in 4.1 really help with wrapping libraries. We really are just missing a struct function in Euphoria. Which would also greatly help with wrapping certain libraries.

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

12. Re: Wrapping Callback Functions

Icy_Viking said...

Thanks for all your help Greg. The new function routines and helpers in 4.1 really help with wrapping libraries.

You're welcome, glad to be of help.

Icy_Viking said...

We really are just missing a struct function in Euphoria. Which would also greatly help with wrapping certain libraries.

I've been digging into the Euphoria source to better understand how to finish Matt's work on memstruct as described here: https://openeuphoria.org/forum/134782.wc

So far it's been slow-going but it's coming together. Just takes a while to understand how all the little parts and pieces work with each other to do what they do.

-Greg

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

13. Re: Wrapping Callback Functions

ghaberek said...
Icy_Viking said...

Thanks for all your help Greg. The new function routines and helpers in 4.1 really help with wrapping libraries.

You're welcome, glad to be of help.

Icy_Viking said...

We really are just missing a struct function in Euphoria. Which would also greatly help with wrapping certain libraries.

I've been digging into the Euphoria source to better understand how to finish Matt's work on memstruct as described here: https://openeuphoria.org/forum/134782.wc

So far it's been slow-going but it's coming together. Just takes a while to understand how all the little parts and pieces work with each other to do what they do.

-Greg

That's good to hear Greg.

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

Search



Quick Links

User menu

Not signed in.

Misc Menu