Re: [Mono-list] Re: Calling back from unmanaged code to managed code.
Would be good to note, on Windows, that your C code expecting a __cdecl or __stdcall function pointer can make all the difference. Gave me a nice 2 day long headache with debugging :) On Thu, 16 Dec 2004 21:04:15 -0500, Jonathan Pryor [EMAIL PROTECTED] wrote: Just for fun, I'll write the equivalent C# declarations inline with the C code. Note that I haven't tried to compile this, but the basic idea should be seen... On Thu, 2004-12-16 at 13:32 -0500, Nigel Benns wrote: Here is a C example to do a DeleteEvent: void delete_cb(Ewl_Widget *w, void *event, void *data) { ewl_widget_destroy(w); ewl_main_quit(); } delegate void EwlDeleteCallback (IntPtr w, IntPtr event, IntPtr data); class MyTest { private const string LIB = ewl; [DllImport (LIB)] private static extern void ewl_widget_destroy (IntPtr w); [DllImport (LIB)] private static extern void ewl_main_quit (); private void delete_cb (IntPtr w, IntPtr event, IintPtr data) { ewl_widget_destroy (w); ewl_main_quit (); } int main(int argc, char **argv) { ewl_init(); [DllImport (LIB)] private static extern void ewl_init (); ... win = ewl_window_new(); [DllImport (LIB)] private static extern IntPtr ewl_window_new(); ... /*Where this function appends the callback to a calback list read by ewl_main(). */ ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL); // Here's what you're interested in: [DllImport(LIB)] private static extern void ewl_callback_append (IntPtr win, int callback_type, EwlDeleteCallback cb, IntPtr data); // I'd assume that ewl_callback_append can take a variety of // function pointer types (the callback is probably void*), // so you could overload this function for each function // pointer type that ewl_callback_append accepts. // obviously, this needs to be set to the correct value. private const int EWL_CALLBACK_DELETE_WINDOW = 0xdeadbeef; /*The NULL is for the Data to pass */ ... ewl_main(); [DllImport(LIB)] private static extern void ewl_main (); } Ok, so what I'm trying figure out is how to add the ewl_callback_append as a delegate in C#. public static void Main () { ewl_init (); IntPtr win = ewl_window_new (); EwlDeleteCallback cb = new EwlDeleteCallback (delete_cb); ewl_callback_append (win, EWL_CALLBACK_DELETE_WINDOW, cb, IntPtr.Zero); ewl_main (); System.GC.KeepAlive (cb); } } Note that the System.GC.KeepAlive is necessary so that the GC doesn't collect your delegate before EWL is finished using the function pointer it has (the delegate is marshaled as a function pointer). It would be bad to have the GC collect the delegate early. It doesn't seem write to me that I could pass a C# function to C, even if I could figure out how to do that? You can pass a delegate referring to a C# method to C. I would suggest reading my guide, Everything you (n)ever wanted to know about marshaling (and were afraid to ask!): http://www.jprl.com/~jon/interop.html It's also available through monodoc (though the above is more recent -- I've been lazy about committing): http://www.go-mono.com/docs/[EMAIL PROTECTED] You may also want to look into Gtk#, just to see how the wrapper code can be used. - Jon ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list -- Cory Nelson http://www.int64.org ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list
[Mono-list] Re: Calling back from unmanaged code to managed code.
Ok, this is a little different, I think anyway, mabey I just don't have it in my head right, so I'll give the example I'm working on. I'm trying to bind EWL (Enlightenment Widget Library) to C#. I've got the windows working, but no events. I've read your email... seems easy enough, but I think it does it a little different. Here is a C example to do a DeleteEvent: void delete_cb(Ewl_Widget *w, void *event, void *data) { ewl_widget_destroy(w); ewl_main_quit(); } int main(int argc, char **argv) { ewl_init(); ... win = ewl_window_new(); ... /*Where this function appends the callback to a calback list read by ewl_main(). */ ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL); /*The NULL is for the Data to pass */ ... ewl_main(); } Ok, so what I'm trying figure out is how to add the ewl_callback_append as a delegate in C#. It doesn't seem write to me that I could pass a C# function to C, even if I could figure out how to do that? Is that where I need to add the glue, or is this different. my C# Lib looks kinda like this: namespace Ewl { public class Window : Embed { IntPtr Handle; public override IntPtr Raw { get { return Handle; } } //I'm guessing I can't do this [DllImport(libewl)] static extern int ewl_callback_append(IntPtr wid, CallType CallType.DeleteEvent, //however you would give a function?) } Any one with a suggestion on this would be GREATLY appreciated. Thanks I REALLY HATE C, it makes my head hurt, and managed code to C is even worse :). But the challenge is half the reason I'm doing this. ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list
Re: [Mono-list] Re: Calling back from unmanaged code to managed code.
Just for fun, I'll write the equivalent C# declarations inline with the C code. Note that I haven't tried to compile this, but the basic idea should be seen... On Thu, 2004-12-16 at 13:32 -0500, Nigel Benns wrote: Here is a C example to do a DeleteEvent: void delete_cb(Ewl_Widget *w, void *event, void *data) { ewl_widget_destroy(w); ewl_main_quit(); } delegate void EwlDeleteCallback (IntPtr w, IntPtr event, IntPtr data); class MyTest { private const string LIB = ewl; [DllImport (LIB)] private static extern void ewl_widget_destroy (IntPtr w); [DllImport (LIB)] private static extern void ewl_main_quit (); private void delete_cb (IntPtr w, IntPtr event, IintPtr data) { ewl_widget_destroy (w); ewl_main_quit (); } int main(int argc, char **argv) { ewl_init(); [DllImport (LIB)] private static extern void ewl_init (); ... win = ewl_window_new(); [DllImport (LIB)] private static extern IntPtr ewl_window_new(); ... /*Where this function appends the callback to a calback list read by ewl_main(). */ ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL); // Here's what you're interested in: [DllImport(LIB)] private static extern void ewl_callback_append (IntPtr win, int callback_type, EwlDeleteCallback cb, IntPtr data); // I'd assume that ewl_callback_append can take a variety of // function pointer types (the callback is probably void*), // so you could overload this function for each function // pointer type that ewl_callback_append accepts. // obviously, this needs to be set to the correct value. private const int EWL_CALLBACK_DELETE_WINDOW = 0xdeadbeef; /*The NULL is for the Data to pass */ ... ewl_main(); [DllImport(LIB)] private static extern void ewl_main (); } Ok, so what I'm trying figure out is how to add the ewl_callback_append as a delegate in C#. public static void Main () { ewl_init (); IntPtr win = ewl_window_new (); EwlDeleteCallback cb = new EwlDeleteCallback (delete_cb); ewl_callback_append (win, EWL_CALLBACK_DELETE_WINDOW, cb, IntPtr.Zero); ewl_main (); System.GC.KeepAlive (cb); } } Note that the System.GC.KeepAlive is necessary so that the GC doesn't collect your delegate before EWL is finished using the function pointer it has (the delegate is marshaled as a function pointer). It would be bad to have the GC collect the delegate early. It doesn't seem write to me that I could pass a C# function to C, even if I could figure out how to do that? You can pass a delegate referring to a C# method to C. I would suggest reading my guide, Everything you (n)ever wanted to know about marshaling (and were afraid to ask!): http://www.jprl.com/~jon/interop.html It's also available through monodoc (though the above is more recent -- I've been lazy about committing): http://www.go-mono.com/docs/[EMAIL PROTECTED] You may also want to look into Gtk#, just to see how the wrapper code can be used. - Jon ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list
Re: [Mono-list] Re: Calling back from unmanaged code to managed code.
On 12/12/04 Jonathan Pryor wrote: If so is it that difficult to add this feature to mono (say once the work on code security is finished) It's not so much difficult, as questionable. Questionable as in, should we do this?. The answer is: yes, we need to implement the support for it. There are two requirements/changes lupus mentioned: 1. The native delegate should marshal the thread into the correct AppDomain. This probably wouldn't be too difficult (says the guy who hasn't done *any* runtime hacking). It's not so much the issue of marshaling the thread object: this belongs to point 2, IMHO. The issue is to decide what application domain should be used when entering the new thread. This also means that the wrapper method (the method that makes the transition from unmanaged to managed code) needs to be much more complex: it needs to do a domain transition when entering and a domain restore when exiting (if the domain was changed). 2. Setup/initialize non-mono threads so that mono can use them. This includes determining the stack information so that the GC can properly trace the entire GC heap. (2) is the problematic requirement. Should mono take over all threads that enter mono? *Can* mono do that? (I don't know if it's possible to get the stack size from the pthreads API.) Taking over any thread that It's not possible to get the stack info for a thread portably, unless we started the thread. This is part of the problem. A better approach is what mono already requires -- all threads that used by mono should call mono_thread_attach before entering or being used by mono. Unfortunately this requires partitioning your application so that non-mono threads don't call into mono, directly or indirectly, but this is probably the only usable solution. We can make the wrapper automatically call mono_thread_attach(), but that's just part of the issue. lupus -- - [EMAIL PROTECTED] debian/rules [EMAIL PROTECTED] Monkeys do it better ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list
Re: [Mono-list] Re: Calling back from unmanaged code to managed code.
On Fri, 2004-12-10 at 19:02 +, Gregory Bowyer wrote: Paolo Molaro wrote: We could easily remove this assert and instead add the code to setup the thread to execute managed code. This won't solve the whole issue, though: the GC needs to know about the thread and its stack limits or it won't work correctly. There is also the issue of deciding which application domain should be set for the new thread. We should probably add a call to a function that does all this setup to the wrapper methods used to go from unmanaged to managed code. lupus If i am reading this correctly, is the lack of support for unmanaged code in mono a case of three incomplete features namely: 1) Lack of Code access security stuff 2) Bits of monos internal setup 3) GC pinning and stack issues To simplify greatly on Francis Brosnan Blzquez's response: 1) No, Code Access Security has nothing to do with it 2) Yes, it has to do with Mono's internal requirements, mostly from... 3) The GC has it's own requirements. If so is it that difficult to add this feature to mono (say once the work on code security is finished) It's not so much difficult, as questionable. Questionable as in, should we do this?. There are two requirements/changes lupus mentioned: 1. The native delegate should marshal the thread into the correct AppDomain. This probably wouldn't be too difficult (says the guy who hasn't done *any* runtime hacking). 2. Setup/initialize non-mono threads so that mono can use them. This includes determining the stack information so that the GC can properly trace the entire GC heap. (2) is the problematic requirement. Should mono take over all threads that enter mono? *Can* mono do that? (I don't know if it's possible to get the stack size from the pthreads API.) Taking over any thread that enters mono's runtime is questionable, at best -- these may be threads created by Wine, or Xine, or Evolution, or... Altering them to make them suitable for use by mono may be a questionable tactic, at best. A better approach is what mono already requires -- all threads that used by mono should call mono_thread_attach before entering or being used by mono. Unfortunately this requires partitioning your application so that non-mono threads don't call into mono, directly or indirectly, but this is probably the only usable solution. - Jon ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list
Re: [Mono-list] Re: Calling back from unmanaged code to managed code.
About this issue: Finally I've found a solution. I think it's a litle complex, but really integrated not only with mono but also with other .NET runtime and you get lot of powerful features doing like I'm going to say. Maybe mono still lacks support for this case, I mean, integrate unmanaged threads with managed ones. But this exposes, not only a not-easy-to-solve mono problem, but also a problem on how to bind this type of libraries in a proper way which allows you to get better results. The whole problem comes from trying to bind a C API which callbacks asynchronously to the caller as it is. Reading about what support should give .NET runtime and how native .NET code can be translated into asynchronous code I've realized that the best way to bind asynchronous libraries is to keep unmanaged and managed code separated. Try to think about every thread model we can find in every platform and you'll realize that you should not really on mono to support this. Microsoft .NET binding says that the runtime must detect newly unmanaged created threads and support them [1], but, they talks from its points of view: Microsoft Windows platforms. In short, if you have a library with a C API to bind like the follows: // signature for the response callback typedef void (*Callback) (SomeCStruct * response, gpointer data); // request api void my_async_func_to_bind (gint value, Callback cb, gpointer data); In which your callback cb will be executed at the end of the my_async_func_to_bind execution. The response, with the user data provided, will be passed to cb, in a newly unmanaged created thread appart from the main thread which have call my_async_func_to_bind. In this context, it won't be a good idea (and you should NOT) to bind this C API directly because you are relaying on the runtime to get it working as I say. Instead of that you need to create an litle c-glue to transfor your asynchronous C API into a new synchronous C API. To do this, you can use GAsyncQueues from glib in this way: // support function which only catch the response void return_my_value_on_my_queue (SomeCStruct * response, gpointer data) { GAsyncQueue * queue = (GAsyncQueue *) data; g_async_queue_ref (queue); g_async_queue_push (queue, response); g_async_queue_unref (queue); return; } // synchronous version of my_async_func_to_bind SomeCStruct * my_sync_func_to_bind (gint value) { GAsyncQueue * queue= g_async_queue_new (); SomeCStruct * response = NULL; my_async_func_to_bind (value, return_my_value_on_my_queue, queue); response = g_async_queue_pop (queue); return response; } With the code above, the caller thread (in this context, a managed thread with have entered into the unmanaged code) will be blocked on g_async_queue_pop until reponse arrives and a g_async_queue_push occur. Now, you have a really simple signature to bind. To bind this you only need to declare all needed DllImport stuff as follows: [StructLayout(LayoutKind.Sequential)] public class SomeCStruct { // members declarations as they are ordered in the C API } public class YourLib { [DllImport(yourlib)] extern static SomeCStruct my_sync_func_to_bind (int value); public static SomeCStruct Get (int value) { return my_sync_func_to_bind (value); } } You need to import SomeCStruct as a class and set that StructLayout. Read the Jonathan Pryor document to get more information [3]. Okay, I know what your thinking at this moment: But, we are not talking about asynchronous API? I need the same asynchronous functionality. With this approach, we have only synchronous API. Keep on reading. .NET have a really powerful support to create Asynchronous version from synchronous method [2]. If you want to have an asynchronous version from a synchronous method do as follows: 1) Add a delegate into your class implementation file (not into the class itself) with the same signature as your wanted to make asynchronous class Method: public delegate SomeCStruct AsyncGet (int value); 2) Now, the consumer class code must do something like this to invoke asynchronously your Get method: int value = // some value AsyncGet dlgt = new AsyncGet (YourLib.Get); dlgt.BeginInvoke (value, new AsyncCallback (ProcessGet),dlgt); // your code have invoke the Get method and it doesn't get // blocked. The response will be recieved at ProcessGet 3) Your ProcessGet method needs to implement the AsyncCallback interface and the IAsyncResult interface as follows: public void ProcessGet (IAsyncResult ar) { AsyncGet dlgt= ar.AsyncState as AsyncGet; SomeCStruct response = dlgt.EndInvoke (ar); // do all the stuff need with response }
[Mono-list] Re: Calling back from unmanaged code to managed code.
Paolo Molaro wrote: On 11/29/04 Francis Brosnan Blázquez wrote: I'm trying to make the c# binding for some set of libraries which, in sort, makes petitions to a remote server without blocking the caller. In this context, the caller must suply a handler to manage the server response. Later, when server response arrives, these libraries initiate a thread and execute on it the Caller's handler. The binding works fine until unmanaged code invoke the caller's handler inside the newly thread create. I've made a litle test to show more presiselly what I'm trying to do. The follwing file is the unmanaged pice of code that has two ways to notify the caller throught its handler: 1) by creating a new thread, 2) by using the actual caller's thread. [...] When I execute this test I get the following: $ ./Callback.exe Test init.. Recieved call on unmanaged side.. Calling back to managed side.. Recieved callback on managed side Values: 2 and some text Calling back finished.. Recieved call on unmanaged side.. Calling back to managed side.. ** ERROR **: file mini.c: line 6558 (mono_get_lmf_addr): should not be reached We could easily remove this assert and instead add the code to setup the thread to execute managed code. This won't solve the whole issue, though: the GC needs to know about the thread and its stack limits or it won't work correctly. There is also the issue of deciding which application domain should be set for the new thread. We should probably add a call to a function that does all this setup to the wrapper methods used to go from unmanaged to managed code. lupus If i am reading this correctly, is the lack of support for unmanaged code in mono a case of three incomplete features namely: 1) Lack of Code access security stuff 2) Bits of monos internal setup 3) GC pinning and stack issues If so is it that difficult to add this feature to mono (say once the work on code security is finished) ___ Mono-list maillist - [EMAIL PROTECTED] http://lists.ximian.com/mailman/listinfo/mono-list