New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
callback from native linux library (.so) of .NET core managed function - problem #19696
Comments
It should work. Let me look into that. |
@rottor12 I have looked into it and found you have a bug there. You need to create a handle for the delegate itself, not the function pointer. So you need to do WrapperAPILib.DlgSimpleCallback d = fnSimpleCallback;
gchSimpleCallback = GCHandle.Alloc(d); // it cannot be pinned and it would also not make sense to pin the delegate object.
p_fnSimpleCallback = Marshal.GetFunctionPointerForDelegate<WrapperAPILib.DlgSimpleCallback>(d);
WrapperAPILib.SetSimpleCallback( p_fnSimpleCallback ); Then it works as expected. |
I've made the changes you described, but .. the behavior is still the same this behavior is repeatable, and the Main() function doesn't even finish, so the pointer to a function nor delegate should'n't be garbage collected just after the specific line is executed |
It doesn't matter that the main function doesn't finish. When the variable is not used in the code flow anymore and it is not stored in a global or referred to by another heap object, the GC can collect it any time. You would need to use GC.KeepAlive at the end of Main to ensure that. That is another way to solve the issue with your example, but creating GC handle works as well. I have tried to create and run your example on my local machine without my fix, but with the env var COMPlus_GCStress=3. The delegate was getting collected. When I have fixed the problem like I have said, the issue went away, the delegate was not collected anymore and the test successfully called the callback twice, waited for the key press and then exited. Let me paste here the complete testing code I was using: using System;
using System.Runtime.InteropServices;
namespace reversepinvokefromthread
{
class WrapperAPILib
{
public delegate void DlgSimpleCallback();
[DllImport("reversepinvokefromthread.so")]
static public extern void SetSimpleCallback(IntPtr cb);
[DllImport("reversepinvokefromthread.so")]
static public extern void StartTestThread();
}
class Program
{
static IntPtr p_fnSimpleCallback;
static GCHandle gchSimpleCallback;
static void fnSimpleCallback()
{
Console.WriteLine("Got here");
}
static void Main(string[] args)
{
WrapperAPILib.DlgSimpleCallback del = new WrapperAPILib.DlgSimpleCallback(fnSimpleCallback);
p_fnSimpleCallback = Marshal.GetFunctionPointerForDelegate<WrapperAPILib.DlgSimpleCallback>(del);
gchSimpleCallback = GCHandle.Alloc(del);
WrapperAPILib.SetSimpleCallback(p_fnSimpleCallback);
WrapperAPILib.StartTestThread();
Console.WriteLine("Sleeping in Main ...");
System.Threading.Thread.Sleep( 6000);
WrapperAPILib.StartTestThread();
Console.ReadKey();
}
}
} C++ code built with #include <iostream>
#include <thread>
#include <unistd.h>
void (*fnSimpleCallback)();
void call_from_thread()
{
std::cout << "sleeping for 5 sec ... " << std::flush ;
usleep(5000000);
std::cout << " ... after sleep trying to callback from new thread .. " << (void *)fnSimpleCallback << std::endl;
if (nullptr != fnSimpleCallback)
fnSimpleCallback(); // does nothing
}
extern "C" void StartTestThread()
{
std::thread thread(call_from_thread);
thread.detach();
}
extern "C" void SetSimpleCallback(void* cb)
{
fnSimpleCallback = (void (*)())cb;
}
Output:
|
I'll take a look at this once again ... the only difference is that I'm using g++: thanks for your time to help me with this |
closing the issue here but @rottor12 please feel free to reopen it if you still have issue with the proposed changes. thanks. |
I want to callback a method in C# code (.NET Core) from C++ code in my .so library on Linux
when I execute a callback from this function, all works fine:
however, when I try to execute a callback from a thread (std::thread), it either crashes or does nothing
here is the code:
======================
here is the C# code:
as you can notice, I've already tried using GCHandle to keep reference to my delegate alive
when I uncomment subsequent Sleep(6000). the first StartTestThread() correctly executes my callback, but after the Sleep(6000) passes, the second StartTestThread() does nothing
The text was updated successfully, but these errors were encountered: