www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to make sure GC allocated resources stay around when used in C

reply "Gary Willoughby" <dev nomad.so> writes:
Based on this conversation in another thread: 
http://forum.dlang.org/thread/wdddgiowaidcojbrklsg forum.dlang.org?page=5#post-yjmrqgesjtadecutvk
e:40forum.dlang.org 
I've realised i may have a nasty bug lurking in the code. Now i 
want to completely understand what is happening.

Take the following code:

struct Args
{
	Element element;
	string uniqueData;
	Callback callback;
}

class Element
{
	void foo(Callback callback, string uniqueData = null)
	{
		auto handler = function(ClientData data)
		{
			// Use data.
		};

		auto cleanup = function(ClientData data)
		{
			free(data);
		};

		Args* args = cast(Args*)malloc(Args.sizeof);

		(*args)            = Args.init;
		(*args).element    = this;
		(*args).uniqueData = uniqueData;
		(*args).callback   = callback;

		c_function(handler, args, cleanup);
	}
}

I want to make sure that `callback` and `uniqueData` are never 
cleaned up by the GC until i wish to allow them to be freed. A 
comment was made that in the above scenario `callback` and 
`uniqueData` allow the potential of being cleaned up and that a 
call to `GC.addRoot` might fix this problem.

Would it be as simple to just add:

GC.addRoot(cast(void*)args);
GC.setAttr(cast(void*)args, GC.BlkAttr.NO_MOVE);

to the above example? Would this not allow collection until a 
call to GC.removeRoot(). Or do i have to handle `callback` and 
`uniqueData` individually? If so how do you stop a delegate and 
string from being cleaned up by the GC?

Any help or explanations are very much appreciated.

This is the actual production code: 
https://github.com/nomad-software/tkd/blob/master/source/tkd/element/element.d#L172
May 12 2014
parent reply "Kagamin" <spam here.lot> writes:
AFAIK, addRoot is for memory allocated in GC heap, and addRange 
is for other types of memory, so you can't add non-gc memory as 
root (just a guess, see docs). I would allocate whole Args in GC 
heap and add is as root, yes, it would prevent collection until 
the root is removed. A better way would be to store Args in a 
linked list in the widget, this way it will be fully managed, and 
Args will live as long as the widget class instance references 
them without additional tinkering with GC.
May 12 2014
next sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
On Monday, 12 May 2014 at 19:13:28 UTC, Kagamin wrote:
 AFAIK, addRoot is for memory allocated in GC heap, and addRange 
 is for other types of memory, so you can't add non-gc memory as 
 root (just a guess, see docs). I would allocate whole Args in 
 GC heap and add is as root, yes, it would prevent collection 
 until the root is removed. A better way would be to store Args 
 in a linked list in the widget, this way it will be fully 
 managed, and Args will live as long as the widget class 
 instance references them without additional tinkering with GC.
Ah yeah, i never thought, i could allocate Args on the GC heap. I have to allocate it on the fly and not store it in the widget because there could be many. I'll have a fiddle.
May 12 2014
parent reply "Kagamin" <spam here.lot> writes:
Why many? I'd say, you typically have 0 subscriptions (label, 
textbox) per widget, seldom - 1 (button, combobox, checkbox).
May 12 2014
next sibling parent "Kagamin" <spam here.lot> writes:
combobox and checkbox usually don't require a subscription 
either. Only button requires a reaction from your code, 
everything else usually works on its own.
May 12 2014
prev sibling parent reply "Gary Willoughby" <dev nomad.so> writes:
On Monday, 12 May 2014 at 20:03:46 UTC, Kagamin wrote:
 Why many? I'd say, you typically have 0 subscriptions (label, 
 textbox) per widget, seldom - 1 (button, combobox, checkbox).
There are many events that can be bound to on any widget. https://github.com/nomad-software/tkd/blob/master/source/tkd/element/uielement.d#L328
May 12 2014
parent reply "Kagamin" <spam here.lot> writes:
Do you always bind all of them?
May 12 2014
parent reply "Gary Willoughby" <dev nomad.so> writes:
On Tuesday, 13 May 2014 at 06:27:14 UTC, Kagamin wrote:
 Do you always bind all of them?
They are not bound automatically but may be bound later. You can bind to events such as mouse-enter, mouse-click, keypresses, etc. In fact this is how keyboard shortcuts are handled. I've added a potential fix to remove the allocation from the unmanaged heap and let the GC handle it. See what you think: https://github.com/nomad-software/tkd/commit/d77ff8603e26e7645c60b2613b996f1b21e751fc
May 13 2014
next sibling parent reply "Kagamin" <spam here.lot> writes:
It must be scanned, so you shouldn't specify NO_SCAN attribute, 
it's for memory blocks, which are guaranteed to not hold pointers 
to GC memory, like ubyte[] buffers for i/o, so managed blocks can 
be safely collected without looking at content of NO_SCAN blocks.
May 14 2014
parent "Gary Willoughby" <dev nomad.so> writes:
On Wednesday, 14 May 2014 at 07:11:45 UTC, Kagamin wrote:
 It must be scanned, so you shouldn't specify NO_SCAN attribute, 
 it's for memory blocks, which are guaranteed to not hold 
 pointers to GC memory, like ubyte[] buffers for i/o, so managed 
 blocks can be safely collected without looking at content of 
 NO_SCAN blocks.
Ah yes. I've completed the changes and that has cured the problems i was experiencing and fixed a nasty bug. Thanks.
 They are not bound automatically but may be bound later.
So they will be allocated on demand - only if it's bound, Args will be allocated,
Yes.
 so widget will have only one Args allocated, or as many as were 
 actually bound. Or do you want to save on one pointer per 
 widget?
By default most widget have none bound until a command or binding is added. Only one command can be added to widgets that support it (e.g. buttons) but all can have many events bound if the developer so wishes.
 Keyboard shortcuts are probably rare too, widgets should handle 
 most common shortcuts like text editing or copying on their own 
 without special handling by the user program, right?
They do but you are free to bind actions to more events if you wish.
May 14 2014
prev sibling parent "Kagamin" <spam here.lot> writes:
On Tuesday, 13 May 2014 at 18:47:45 UTC, Gary Willoughby wrote:
 They are not bound automatically but may be bound later.
So they will be allocated on demand - only if it's bound, Args will be allocated, so widget will have only one Args allocated, or as many as were actually bound. Or do you want to save on one pointer per widget? Keyboard shortcuts are probably rare too, widgets should handle most common shortcuts like text editing or copying on their own without special handling by the user program, right?
May 14 2014
prev sibling parent "Kagamin" <spam here.lot> writes:
Another option is to allocate from pool.
May 12 2014