How to free memory allocated by AddTrackable()

This forum is for general developer support questions.
Post Reply
softwarefailure
Posts: 112
Joined: Fri Feb 14, 2014 10:29 pm

How to free memory allocated by AddTrackable()

Post by softwarefailure »

I'm using AddTrackable() to track an object that should be destroyed when the task is removed. That works fine. When the task is removed, my destructor function is called and I can destroy the object.

But: Once my destructor function has been called and the task has been removed, how should I free the memory allocated by AddTrackable()?
I've seen these options:

1) DeleteTrackable(): Autodocs say that this will first call the destructor function before deleting the trackable. This is of course not what I want because the destructor function has been called already. I just want to free the memory allocated by AddTrackable().

2) RemTrackable(): This won't free any memory but will just remove the trackable from the task's resource list.

So I don't see any function that just frees the trackable. How should it be done then?
User avatar
thomasrapp
Posts: 310
Joined: Sat Jun 18, 2011 11:22 pm

Re: How to free memory allocated by AddTrackable()

Post by thomasrapp »

I'd guess you don't need to. You destructor function has been called. This most likely means that the system called DeleteTrackable. Just exit from the destructor function and your trackable node will be freed automatically.
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 207
Joined: Mon Aug 15, 2011 9:20 am
Location: Brisbane, QLD. Australia.

Re: How to free memory allocated by AddTrackable()

Post by colinw »

That is correct, Remtask() actually calls DeleteTrackable() after pulling the node of the list.
You don't have to delete the trackable memory yourself DeleteTrackable() does it as the last thing after
calling the destructor hook function.

I ran into another problem in DOS, there was no information about what to do when you want to simply
remove a trackable object from being called and dump it, such as if the object is deleted normally,
rather than always requiring exec to execute the hook code via the DeleteTrackable() function later in RemTask().

I have possibly hundreds of trackables on any given task and would not like to leave all those dead resources
on the list after the fact the object it pointed at no longer exists, there may even be address reuse for
the object pointer, so I needed a way to "UnAddTrackable()" on the fly, as the objects were freed by the caller.

I suspect it was intended that DeleteTrackable() must always be eventually called, but in my case, the object
being tracked can be (and is usually) freed long before the task ends.
(I'm using the trackable as a way to prevent locks and files being left open, and memory orphaned if a task crashes.)

I considered calling RemTrackable() just to pull it out of the lists, but as AddTrackable() specifically says that
it allocates a "Trackable struct" and "copies the hook into the trackable" that alone would orphan resources.

So, I looked into what DeleteTrackable() function is doing, (because I could), and it has two modes depending
on a flag state, but in both modes it does the following...
a) It checks (trackable->Destructor.h_Entry != 0) and calls h_Entry(),
(and may alternatively do a free(object) depending on whether the flag is unset).
b) It always frees the trackable structure.

So, what I did was the following when the object is being released normally, I made a Find_Discard_Trackable()...

Code: Select all

void Find_Discard_Trackable(struct Task *t,  APTR object)
{
    struct Trackable *trak = IExec->FindTrackable(t, object); 
    if( trak )
    {
	IExec->RemTrackable(t,trak);

       /*
       ** Stop deletetrackable() executing cleanup hook,
       ** or freeing the object, just delete the trackable struct only.
       */
	trak->Destructor.h_Entry = NULL;
	trak->Object = NULL;
	trak->Flags  = 0;
	IExec->DeleteTrackable(trak);
    }
}
softwarefailure
Posts: 112
Joined: Fri Feb 14, 2014 10:29 pm

Re: How to free memory allocated by AddTrackable()

Post by softwarefailure »

Thanks, this really helped me because from the documentation it's not entirely clear what's going on...
User avatar
TSK
Beta Tester
Beta Tester
Posts: 225
Joined: Mon Dec 20, 2010 1:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki

Re: How to free memory allocated by AddTrackable()

Post by TSK »

colinw thanks big time !

If I'm telling Grim reaper to kill a crashed program, I realized that if it was launched from Workbench I'll have to call Forbid() and reply to the WBStartup message. But if the program was launched from Shell then if I'll kill it it won't return to the Shell prompt. What do I have to do to exit clean and make Shell to return to the prompt ? Disposer/destructor taking care of cleaning up is built into a library.
Keep the party going !
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 207
Joined: Mon Aug 15, 2011 9:20 am
Location: Brisbane, QLD. Australia.

Re: How to free memory allocated by AddTrackable()

Post by colinw »

You can't use this function in application software unless you know what
you are doing, and, it must never be used for anything other than what YOU
allocate yourself, the rest is done by other system components like DOS.
Even then, you need to be carefull that your hook code segment wasn't
unloaded before the hook was even called, this function is designed for
static system components that don't get unloaded from memory.
DOS will unload normal application code way before the hook will be called
in normal situations.

As far as applications go...
When you "kill" a process / task with the Reaper, you don't have to worry
about how it was started, it's already gone, it doesn't come back.
It is also very likely to leave some resources behind, ones that I currently
don't have tracked by DOS, but it is the only way to kill an un-cooperative
process at this time.

When it's a workbench started program, each one has its own process.
When it's a shell started program, it uses the same process and re-uses
the same process over and over for each program subsequently started.
When you havn't got a program started, that shell process drives the
commandline interface to make it work and accept input keys.

Only when you "run" a program, does it create a distinct new process
just for that program instance, the shell-handler still uses the old process
to accept further keyboard input.

Since a "non-runned" (sic) shell program re-uses the same process,
and if you "killed" that process via the Reaper, then the process that
makes that shell handler process work is also gone, so you end up with
what we typically call a "dead" CLI window and no further command line
input can be performed.

I might look into adding resource tracking to the con-handler to see if the
current design would allow the window to be closed instead of orphaned
if the opening process crashed.

As far as Forbid() goes with workbench started code, it hasn't been required
for nearly 20 years, infact, there is code added to workbench to "un-Forbid()"
old software still in use, so DOS doesn't try and UnLock() workbench locks
while in a Forbid() state. So don't bother doing that anymore, it's a 68K
leftover kludge, refer to the startup example code in dos/startup.h
User avatar
TSK
Beta Tester
Beta Tester
Posts: 225
Joined: Mon Dec 20, 2010 1:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki

Re: How to free memory allocated by AddTrackable()

Post by TSK »

@colinw
there is code added to workbench to "un-Forbid()"
old software still in use
Well, without doing Forbid() call I'll have a big bunch of "permit without forbid" messages in the debug buffer. Maybe something is trying to do that "un-Forbid" when it should not. Also I had Grim reaper window hanging on a screen after one test so I thought it was symptom of not doing everything correctly but I guess it was bad luck only and not related in any way. I guess the startup code handles WBstartup message in the beginning and not when a program is exiting ? So I think I don't need to reply to WBStartup when killing a program.

I forgot almost that DOS might remove the program code before the cleaning up hook is called. I was thinking to create a resident library, a child process or something on the fly, in past. But then DOS would complain that the parent was exited before a child. But in case of oo library, if I'll kill a program it will never call CloseLibrary() so the library will hang in memory forever so the code is available.

It would be the best if OS could help to handle killed programs, of course. DOS could wait Exec to finish the clean up hook before removing the code if that's possible at all. Add object type argument to AddTrackable for BOOPSI objects so Exec could dispose BOOPSI objects as well. That would remove orphaned Window class windows from a screen so we 3rd party developers would not need to try to do that ourselves. Intuition is available always because Workbench and CLI windows need it. That would be more visible to end users than removing for example a message port from memory, and people thinks that AOS don't have resource tracking feature at all still. Dealing with the BOOPSI objects people would see such feature in action.
Keep the party going !
User avatar
colinw
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 207
Joined: Mon Aug 15, 2011 9:20 am
Location: Brisbane, QLD. Australia.

Re: How to free memory allocated by AddTrackable()

Post by colinw »

If you are getting "permit without forbid" messages, then I would
assume that you havn't updated all the components that interract
with each other in this regard.

In the path to multi-core, the kernel has changed the way it handles
peeking and poking some execbase fields, and I know the nestcount
variables are in that list. There is a new accessor function to handle
these and it only came into use for the last release.
IExec->GetSystemInfoTags()

The new kernel requires co-operation with the other components that
access these fields to call the new function, my recollection is that
workbench.library, timer.device and the shell-handler from the last
update ARE required to work without giving debug error messages.
These modules will work with older kernels, but not the other way around.

Never mix new and old components, the old ones don't know about
what changes have been made since they were created and newer
components that interract may only have limited interoperability.
User avatar
TSK
Beta Tester
Beta Tester
Posts: 225
Joined: Mon Dec 20, 2010 1:15 pm
Location: Home land of Santa C., sauna, sisu and salmiakki

Re: How to free memory allocated by AddTrackable()

Post by TSK »

you havn't updated all the components
FE Update 2.
Never mix new and old components
No, I haven't. (Except I need NGFS to access all partitions. And newer USB components works good with KVM switches.)
Keep the party going !
Post Reply