I am newbie of C++/CLI.
I already know that the pin_ptr's functionality is making GC not to learn to specified object.
now let me show you msdn's example.
https://msdn.microsoft.com/en-us//library/1dz8byfh.aspx
// pin_ptr_1.cpp
// compile with: /clr
using namespace System;
#define SIZE 10
#pragma unmanaged
// native function that initializes an array
void native_function(int* p) {
for(int i = 0 ; i < 10 ; i++)
p[i] = i;
}
#pragma managed
public ref class A {
private:
array<int>^ arr; // CLR integer array
public:
A() {
arr = gcnew array<int>(SIZE);
}
void load() {
pin_ptr<int> p = &arr[0]; // pin pointer to first element in arr
int* np = p; // pointer to the first element in arr
native_function(np); // pass pointer to native function
}
int sum() {
int total = 0;
for (int i = 0 ; i < SIZE ; i++)
total += arr[i];
return total;
}
};
int main() {
A^ a = gcnew A;
a->load(); // initialize managed array using the native function
Console::WriteLine(a->sum());
}
hear is the question.
Isn't it okay, the passed object(arr) not pinned ?
because the unmanaged code(native_function) is sync operation and finished before the C++/CLI code (load)
is there any chance the gc destory arr, even though the main logic is running?
(I think A is main's stack variable and arr is A's member variable, so while running main, it should visible)
if so, how can we guarantee that the A is there before invoking load?
(only while not running in native-code?)
int main() {
A^ a = gcnew A;
// I Think A or arr can be destroyed in here, if it is able to be destroyed in native_function.
a->load();
...
}
Thanks, in advance.
The problem that is solved by pinning a pointer is not a normal concurrency issue. It might be true that no other thread will preempt the execution of your native function. However, you have to count in the garbage collector, which might kick in whenever the .NET runtime sees fit. For instance, the system might run low on memory, so the runtime decides to collect disposed objects. This might happen while your native function executes, and the garbage collector might relocate the array it is using, so the pointer you passed in isn't valid anymore.
The golden rule of thumb is to pin ALL array pointers and ALL string pointers before passing them to a native function. ALWAYS. Don't think about it, just do it as a rule. Your code might work fine for a long time without pinning, but one day bad luck will strike you just when it's most annoying.
Related
I have array of objects holding primitive types and enums; how do I marshal a pointer to this data to a native function with the signature native_func(void* ptr[]).
array<System::Object^>^ values = gcnew array<System::Object>(64);
// ... populate the managed array with primitives ...
// data is pinned and won't be moved by the GC
pin_ptr<object> pinned = &values[0];
// not sure what do here... data is corrupted in the native code
native_func((void**)pinned);
Thanks!
EDIT. My second attempt was to do the following:
pin_ptr<object> pinned = &values[0];
void* testArray[64];
for (auto i = 0; i < values->Length; i++)
{
testArray[i] = (void*)Marshal::UnsafeAddrOfPinnedArrayElement(values, i);
}
native_func(testArray);
Now, the addresses stored in testArray are getting passed correctly to the native side but the contents of the memory is not what I am expecting. What am I doing wrong now?
Enums are not blittable so marshaling an array of objects require special consideration (i.e. you can't just pin_ptr the array and pass it over the native/managed boundary). I decided to use a VARIANT to hold the primitive & enum values and did so with the following code:
// allocate a managed array of size 64 (it's enough for my application)
array<System::Object^>^ values = gcnew array<System::Object>(64);
// stack allocate a native array of size 64
VARIANT nativeValueArray[64] = {};
// ... populate the managed array ...
for (auto i = 0; i < values->Length; i++)
{
Marshal::GetNativeVariantForObject(values[i], (IntPtr)(void*)&nativeValueArray[i]);
}
// pass the array of native VARIANTS to the native function "native_function"
native_function(nativeValueArray);
The native function's signature became
void native_function(VARIANT values[]);
There might be a more efficient way to do this but this is what I was able to come up with. Please let me know if you have a more efficient way to accomplish what am I doing.
RANT-BEGIN
Before jumping right into already answered band wagon, please read this paper about SE outdated answers https://ieeexplore.ieee.org/document/8669958
Things changes after a time, and I am afraid Computer science is one of the most if not the most field out there where APIs and Interfaces change radically very very fast. Needless to say that a solution that might worked last month might not after latest feature added to a platform/framework. I humbly request you to not mark this question as answered with decade old post when many mainstream things did not even existed. If you dont know latest solution dont bother about it and leave question for someone else who might.
For a community representative of Computer Science where innovations is everyday thing, it is very toxic, new comer unfriendly and conservative.
END-RANT
This question has already been answered by me and will be accepted tomorrow (SE policy). Thank you for your interest.
Many times you have function pointers in unmanaged context which are called by some kind of events, We will see how it can be achieved with Top-Level Functions and also with member functions of a managed class.
Again, Please dont mark it as answered by linking to a decade old posts.
PS:
So many edits due to unstable internet in third world country, yeah bite me!
unmanaged.cpp
#pragma unmanaged
// Declare an unmanaged function type that takes one int arguments and callbacks
// our function after incrementing it by 1
// Note the use of __stdcall for compatibility with managed code
// if your unmanaged callback uses any other calling convention you can
// UnmanagedFunctionPointerAttribute (check msdn for more info) on your delegate
typedef int(__stdcall* ANSWERCB)(int);//Signature of native callback
int TakesCallback(ANSWERCB fp, int a) {
if (fp) {
return fp(a+1);//Native Callback
}
// This code will be executed when passed without fp
return 0;
}
#pragma managed
managed.cpp
using namespace System;
using namespace System::Runtime::InteropServices;
namespace Callbacks {
// Following delegate is for unmanaged code and must match its signature
public delegate void MyNativeDelegate(int i);
// This delegate is for managed/derived code and ideally should have only managed parameters
public delegate void MyManagedDelegate(int i);
public ref class TestCallback {// Our demo Managed class
private:
GCHandle gch;// kept reference so that it can be freed once we are done with it
void NativeCallbackListener(int i);//unmanaged code will call this function
public:
void TriggerCallback(int i); // Its here for demo purposes, usually unmanaged code will call automatically
event MyManagedDelegate^ SomethingHappened;//plain old event
~TestCallback();//free gch in destructor as its managed.
};
};
void Callbacks::TestCallback::NativeCallbackListener(int i) {
// Callback from Native code,
// If you need to transform your arguments do it here, like transforming void* to somekind of native structure.
// and then pass SomethingHappened::raise with Managed Class/Struct
return SomethingHappened::raise(i); // similar to SomethingHappened.Invoke() in c#
}
void Callbacks::TestCallback::TriggerCallback(int i)
{
MyNativeDelegate^ fp = gcnew MyNativeDelegate(this, &TestCallback::NativeCallbackListener);
// use this if your nativecallback function is not a member function MyNativeDelegate^ fp = gcnew MyNativeDelegate(&NativeCallbackListener);
gch = GCHandle::Alloc(fp);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer());// (ANSWERCB)ip.ToPointer(); works aswell
// Simulating native call, it should callback to our function ptr NativeCallbackListener with 2+1;
// Ideally Native code keeps function pointer and calls back without pointer being provided every time.
// Most likely with a dedicated function for that.
TakesCallback(cb, i);
}
void Callbacks::TestCallback::~TestCallBack() {
gch.Free();//Free GCHandle so GC can collect
}
implementation.cpp
using namespace System;
void OnSomethingHappened(int i);
int main(array<System::String^>^ args)
{
auto cb = gcnew Callbacks::TestCallback();
cb->SomethingHappened += gcnew Callbacks::MyManagedDelegate(&OnSomethingHappened);
cb->TriggerCallback(1);
return 0;
}
void OnSomethingHappened(int i)
{
Console::WriteLine("Got call back with " + i);
}
Dear,
Recently I run into a general issue, I am writing a DLL, which will be used/invoked by another program. It has structure like this :
DLLEXT long AMI_Init(void **AMI_dll_memory)
{
mem = (struct model_memory*)malloc(sizeof(struct model_memory));
mem->submem = (struct submem*)malloc(sizeof(struct submem));
......
*AMI_dll_memory = (void*)mem;
}
DLLEXT long AMI_Get(void *AMI_dll_memory)
{
....
mem = (struct model_memory*)AMI_dll_memory;
mem->submem->init();
}
// Defined in submem module
struct {
int data;
struct list* next;
}list;
void init()
{
struct list* n;
n = (struct list*)malloc(sizeof(struct list));
// access n->data caused memory access violation.
}
Another software will invoke the AMI_Init() first, then call AMI_Get() with passing the AMI_dll_memory in between, but I got access violation once I tried to access the data "n->data" of "mem->submem->init()". Why it is ? I confirmed I can apply memory since the malloc funtion returned successfully, but just can't access n->data, anyone know why it is ? n->data didn't belong to current process after memory passing in funtions ? Thanks so much.
Guys,
I figure out what is going on here, it is related to implicit declaration of malloc() function, when I malloc memory in second places, I didn't include stdlib.h in that file, which caused the issue.
It is possible to cast a managed array<Byte>^ to some non-managed struct only using pin_ptr, AFAIK, like:
void Example(array<Byte>^ bfr) {
pin_ptr<Byte> ptr = &bfr[0];
auto data = reinterpret_cast<NonManagedStruct*>(ptr);
data->Header = 7;
data->Length = sizeof(data);
data->CRC = CalculateCRC(data);
}
However, is with interior_ptr in any way?
I'd rather work on managed data the low-level-way (using unions, struct-bit-fields, and so on), without pinning data - I could be holding this data for quite a long time and don't want to harass the GC.
Clarification:
I do not want to copy managed-data to native and back (so the Marshaling way is not an option here...)
You likely won't harass the GC with pin_ptr - it's pretty lightweight unlike GCHandle.
GCHandle::Alloc(someObject, GCHandleType::Pinned) will actually register the object as being pinned in the GC. This lets you pin an object for extended periods of time and across function calls, but the GC has to track that object.
On the other hand, pin_ptr gets translated to a pinned local in IL code. The GC isn't notified about it, but it will get to see that the object is pinned only during a collection. That is, it will notice it's pinned status when looking for object references on the stack.
If you really want to, you can access stack memory in the following way:
[StructLayout(LayoutKind::Explicit, Size = 256)]
public value struct ManagedStruct
{
};
struct NativeStruct
{
char data[256];
};
static void DoSomething()
{
ManagedStruct managed;
auto nativePtr = reinterpret_cast<NativeStruct*>(&managed);
nativePtr->data[42] = 42;
}
There's no pinning at all here, but this is only due to the fact that the managed struct is stored on the stack, and therefore is not relocatable in the first place.
It's a convoluted example, because you could just write:
static void DoSomething()
{
NativeStruct native;
native.data[42] = 42;
}
...and the compiler would perform a similar trick under the covers for you.
When I return a direct ByteBuffer to JNI, how long until it can get reclaimed by the JVM/GC?
Suppose I have a function like this:
void* func()
{
[ ... ]
jobject result = env->CallStaticObjectMethod(testClass, doSomethingMethod);
void* pointerToMemory = env->GetDirectBufferAddress(result);
return pointerToMemory;
}
The JVM can't possibly know how long I'm going to use that pointerToMemory, right? What if I want to hold on to that address and the corresponding memory for a while?
Suppose I want to circumvent this issue and return a byte[] from Java to JNI like this:
ByteBuffer buf;
byte[] b = new byte[1000];
buf = ByteBuffer.wrap(b);
buf.order(ByteOrder.BIG_ENDIAN);
return buf.array();
AND THEN do the same as above, I store a pointer to that byte[] and want to hold on to it for a while. How / when / why is the JVM going to come after that backing byte[] from Java?
void* function()
{
jbyteArray byteArr = (jbytearray)env->CallStaticObjectMethod(testClass, doSomethingMethod);
jbyte *b= env->GetByteArrayElements(byteArr, 0);
return b;
}
The short answer is: If the function implements a native method, the pointer will be invalid as soon as you return.
To avoid this, you should get a global reference for all objects that you intend to keep valid after returning. See the documentation on local and global references for more information.
To understand better how JNI manages references from native code, see the documentation on PushLocalFrame/PopLocalFrame.