[Mono-list] Calling back from unmanaged code to managed code.

Francis Brosnan Blázquez francis@aspl.es
Mon, 29 Nov 2004 20:05:27 +0100


Hi,

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.

----
#include <stdio.h>
#include <glib.h>

typedef struct {
        gint    value;
        gchar * text_response;
}Response;

typedef void (*Callback) (Response * res);


gpointer Work (Callback cb) {

        g_print ("Recieved call on unmanaged side..\n");

        Response * res     = g_new (Response, 1);
        res->value         = 2;
        res->text_response = g_strdup ("some text");

        g_print ("Calling back to managed side..\n");
        cb (res);

        g_print ("Calling back finished..\n");
        return NULL;
}

void Function  (Callback cb)
{
        Work (cb);

        return;
}

void Function2 (Callback cb)
{

        g_thread_create ((GThreadFunc) Work, cb, FALSE, NULL);

        return;
}
----

The following file is a simple test that dll-import the previous two
functions: Function and Function2 and invoke them.

----
using System;
using System.Threading;
using System.Runtime.InteropServices;

public class Callback {

        [StructLayout(LayoutKind.Sequential)]
        public struct Response {
                public int    value;
                public string text_response;
        }

        public delegate void CallbackFunc (ref Response res);

        [DllImport("libcallback")]
        extern static void Function (CallbackFunc cb);

        [DllImport("libcallback")]
        extern static void Function2 (CallbackFunc cb);


        public static void ProcessResponse (ref Response res) {
                Console.WriteLine ("Recieved callback on managed side");
                Console.WriteLine ("  Values: {0} and {1}", res.value,
    res.text_response); 
        }


        public static void Main (string [] args) {

                Console.WriteLine ("Test init..");

                CallbackFunc cb = new CallbackFunc (ProcessResponse);

                Function (cb);
                Thread.Sleep (2000);

                Function2 (cb);
                Thread.Sleep (2000);


                Console.WriteLine ("Test finished..");
        }
}
----

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
aborting...
Abortado
----

I've been reading about .Net Threading system and it seems that there is
no problem to invoke static or instance methods from unmanaged create
threads.

What I'm missing? Is not possible to invoke a managed method from a
newly created thread on the unmanaged side? 

I've also uploaded a zip file with both files and a makefile to get the
whole compiled: http://dolphin.aspl.es/~acinom/files.zip
 
Cheers,

-- 
Francis Brosnan Blázquez <francis@aspl.es>