digitalmars.D.learn - Delegates and C function pointers
- Nicolas Sicard (8/8) Nov 08 2014 I would like to register a D delegate to a C API that takes a
- Gary Willoughby (15/23) Nov 08 2014 It looks very similar to what i'm doing here:
- Nicolas Sicard (4/30) Nov 08 2014 Yes that's simpler! Thanks.
- anonymous (39/47) Nov 08 2014 I think it's a little more complicated than it needs to be.
- Nicolas Sicard (4/56) Nov 08 2014 Thanks for the advice about the GC managed references! I'll have
I would like to register a D delegate to a C API that takes a function pointer as a callback and a void* pointer to pass data to this callback. My solution is in http://dpaste.dzfl.pl/7d9b504b4b965. Is this code correct? Is there something simpler or already in Phobos that I have overlooked? Thanks -- Nicolas
Nov 08 2014
On Saturday, 8 November 2014 at 12:23:45 UTC, Nicolas Sicard wrote:I would like to register a D delegate to a C API that takes a function pointer as a callback and a void* pointer to pass data to this callback. My solution is in http://dpaste.dzfl.pl/7d9b504b4b965. Is this code correct? Is there something simpler or already in Phobos that I have overlooked? Thanks -- NicolasIt looks very similar to what i'm doing here: https://github.com/nomad-software/tkd/blob/master/source/tkd/element/element.d#L174 I think you can simplify it though by just using a delegate member in the data struct. Like this (untested): static struct Data { void delegate() callback; } static extern(C) void adapter(void* ptr) { auto d = *(cast(Data*) ptr); d.callback() }
Nov 08 2014
On Saturday, 8 November 2014 at 15:29:01 UTC, Gary Willoughby wrote:On Saturday, 8 November 2014 at 12:23:45 UTC, Nicolas Sicard wrote:Yes that's simpler! Thanks. -- NicolasI would like to register a D delegate to a C API that takes a function pointer as a callback and a void* pointer to pass data to this callback. My solution is in http://dpaste.dzfl.pl/7d9b504b4b965. Is this code correct? Is there something simpler or already in Phobos that I have overlooked? Thanks -- NicolasIt looks very similar to what i'm doing here: https://github.com/nomad-software/tkd/blob/master/source/tkd/element/element.d#L174 I think you can simplify it though by just using a delegate member in the data struct. Like this (untested): static struct Data { void delegate() callback; } static extern(C) void adapter(void* ptr) { auto d = *(cast(Data*) ptr); d.callback() }
Nov 08 2014
On Saturday, 8 November 2014 at 12:23:45 UTC, Nicolas Sicard wrote:I would like to register a D delegate to a C API that takes a function pointer as a callback and a void* pointer to pass data to this callback. My solution is in http://dpaste.dzfl.pl/7d9b504b4b965. Is this code correct? Is there something simpler or already in Phobos that I have overlooked? Thanks -- NicolasI think it's a little more complicated than it needs to be. Instead of going delegate->DelegateData*->delegate you can pass a pointer to the delegate: void doSomethingFromD(void delegate() dg) { static extern(C) void adapter(void* ptr) { auto dg = *cast(void delegate()*)ptr; dg(); } dosomething(&adapter, &dg); } &dg is fine if dosomething calls the callback before doSomethingFromD returns. If the callback is stored and called later on, you have to put the delegate somewhere more lasting. And you have to make sure that the GC doesn't collect it in the meantime. In your code you're new-ing, but you don't keep the reference around in D-land. The GC would happily collect the delegate then, because it doesn't look in C-land for references. For example, you could add all callbacks to a module level array: void delegate()[] activeCallbacks; void doSomethingFromD(void delegate() dg) { static extern(C) void adapter(void* ptr) { auto dg = *cast(void delegate()*)ptr; dg(); } activeCallbacks ~= dg; dosomething(&adapter, &activeCallbacks[$ - 1]); } Then when everything's done and you know that the callbacks are not needed anymore, empty activeCallbacks so that the GC can collect them. Essentially, you're back to manual management, and have to think about the life times of the callbacks.
Nov 08 2014
On Saturday, 8 November 2014 at 16:01:09 UTC, anonymous wrote:On Saturday, 8 November 2014 at 12:23:45 UTC, Nicolas Sicard wrote:Thanks for the advice about the GC managed references! I'll have a look at it. -- NicolasI would like to register a D delegate to a C API that takes a function pointer as a callback and a void* pointer to pass data to this callback. My solution is in http://dpaste.dzfl.pl/7d9b504b4b965. Is this code correct? Is there something simpler or already in Phobos that I have overlooked? Thanks -- NicolasI think it's a little more complicated than it needs to be. Instead of going delegate->DelegateData*->delegate you can pass a pointer to the delegate: void doSomethingFromD(void delegate() dg) { static extern(C) void adapter(void* ptr) { auto dg = *cast(void delegate()*)ptr; dg(); } dosomething(&adapter, &dg); } &dg is fine if dosomething calls the callback before doSomethingFromD returns. If the callback is stored and called later on, you have to put the delegate somewhere more lasting. And you have to make sure that the GC doesn't collect it in the meantime. In your code you're new-ing, but you don't keep the reference around in D-land. The GC would happily collect the delegate then, because it doesn't look in C-land for references. For example, you could add all callbacks to a module level array: void delegate()[] activeCallbacks; void doSomethingFromD(void delegate() dg) { static extern(C) void adapter(void* ptr) { auto dg = *cast(void delegate()*)ptr; dg(); } activeCallbacks ~= dg; dosomething(&adapter, &activeCallbacks[$ - 1]); } Then when everything's done and you know that the callbacks are not needed anymore, empty activeCallbacks so that the GC can collect them. Essentially, you're back to manual management, and have to think about the life times of the callbacks.
Nov 08 2014