[comp.sys.amiga] resource reclamation

iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) (08/19/88)

[In "Re: resource reclamation", Chuck McManis said:]
>
> In article <YX2ERcy00Uh0IEQFxo@andrew.cmu.edu> (Miles Bader) writes:
> > How come simple resource reclamation isn't done?  It seems like it
> > would be pretty simple to hang a list of allocated resources off a
> > task...
>
> Because it isn't. The original DOS specified for the Amiga included
> resource reclamation, however when time got tight and Commodore had
> to go with MetaCompCo's modified version of TriPOS, there wasn't time
> to put it in. If you look at some of the structures you will notice
> that there entries for Tasks such as tc_MemEntry which were for this
> kind of stuff.
>

It still is.

> That is not to say that it isn't possible. The ARP project (AmigaDOS
> Replacement Project) has created a library which allows you to track
> resources and free them on exit.
>
> uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
>

Let's discuss how memory tracking is presently handled.  There are
three categories to consider: Task, Process, and CLI command.

1) Task

You create a task by calling

AddTask(task, initialPC, finalPC),

which adds a given task to the TaskReady list.  Here "task" is an existing
Task structure, "initialPC" is the entry point, and "finalPC" is an optional
cleanup routine.

The final code is pushed on the stack as if it were the outermost return
address.  If finalPC is 0, the system default cleanup is used instead,
which merely calls RemTask().  RemTask() removes the task from the Ready
list and deallocates the MemEntry list.  Deallocation of the Task structure
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
itself is left to the parent who created it.


2) Process

There are two ways of creating processes.  The external AmigaDOS function

CreateProc(*name, pri, seg, stkszb)

and the internal (undocumented) function

createproc(segarray, stkszlw, ^name, ^gv)

The internal function differs in that:
        The process name is a BSTR.
        The stack size is in long words.
        The code is passed as an entire SegArray, not just one SegList.
Both NEWCLI and RUN call this function.

The external function allocates memory for the Process structure and the
stack, and puts this as a single entry on the MemList.  It AllocMem's
space for the SegArray, but does not put this on the MemList.  The 1st
and 2nd SegLists in the SegArray are copied from the parent, the 3rd is
the one supplied by the caller.  It then calls AddTask() with special
initialPC and finalPC.  The finalPC code frees the SegArray.

3) CLI command

A CLI command is not a separate task or process.  It reuses the Task
Process and CLI structures of the CLI.  It is called from the CLI as
a subroutine but uses its own stack.  (This effectively makes it a
coroutine, but it does not use the BCPL coroutine mechanism.)
The CLI handles all the allocation and deallocation internally.
This includes:

LoadSeg'ing and UnLoadSeg'ing the code.
Allocating and deallocating the requested stack.
Locking and UnLocking the Current Directory.



Anyway, the moral is that the AmigaOS is quite diverse.  Memory resources
cannot be tracked from Exec at present because much goes on that Exec
does not know about.  The MemEntry will be deallocated automatically
whenever a Task ends, but when this will happen depends on whether you are
running from the CLI or from the Workbench.

The Workbench creates a new process each time it launches a program, but
the CLI does not.  If the CLI is used, a Task will end only when ENDCLI
is executed or when a background (RUN) CLI commits suicide.
(Unless of course the program spawns Tasks of its own.)



True resource tracking is even more complicated.  In addition to memory
you could keep track of open file handles, and close them automatically
when you terminate.  This is done in ARP.  Of course this kind of tracking
is also done for you when you use the Unix-compatible malloc() and fopen()
functions.

But on the Amiga there are many more resources to worry about.  An aborted
process may have opened MessagePorts, IORequests, Windows, Screens, etc.
Each of these requires a different specific cleanup action, not just
freeing of memory.  The actions may even have to be taken in a definite
order.

Conceivably you could keep track of all these things and write a general
cleanup routine.  Then someone will add his own library and expect the
system to cleanup those resources too.


--

Bill Kinnersley
  Physics Department            BITNET: iphwk@mtsunix1
  Montana State University      INTERNET: iphwk%mtsunix1.bitnet@cunyvm.cuny.edu
  Bozeman, MT 59717             CSNET: iphwk%mtsunix1.bitnet@relay.cs.net
  (406)994-3614                 UUCP: ...ucbvax!mtsunix1.bitnet!iphwk
"This message was packed as full as practicable by modern electronic
equipment.  Some settling of contents may have occurred during transmission."

peter@sugar.uu.net (Peter da Silva) (08/19/88)

Ooh! Info!

In article <3763@louie.udel.EDU>, iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu
	(Bill Kinnersley) writes:

> The 1st and 2nd SegLists in the SegArray are copied from the parent, the
> 3rd is the one supplied by the caller....

OK, what are the first and second SegLists? What's the purpose of this
shenanigans?

> Conceivably you could keep track of all these things and write a general
> cleanup routine.  Then someone will add his own library and expect the
> system to cleanup those resources too.

One thing you could do inside your program, then, would be to write a cleanup
routine for the Exec to call and mash it into the FinalPC slot for your kill
routine to handle...

If this became anything like standard, then we could add "kill" to C:...?
-- 
		Peter da Silva  `-_-'  peter@sugar.uu.net
		 Have you hugged  U  your wolf today?

michael@stb.UUCP (Michael) (09/01/88)

In article <3763@louie.udel.EDU> iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
> ...
>But on the Amiga there are many more resources to worry about.  An aborted
>process may have opened MessagePorts, IORequests, Windows, Screens, etc.
>Each of these requires a different specific cleanup action, not just
>freeing of memory.  The actions may even have to be taken in a definite
>order.
>
>Conceivably you could keep track of all these things and write a general
>cleanup routine.  Then someone will add his own library and expect the
>system to cleanup those resources too.

Perfect. I couldn't have put it better myself. Consider this:

O/S 1 prints a file by having a print program. It knows all about various types
of files, and can handle just about everything out there. Then someone adds
a new type of file with their handy-dandy wiz-bang program.
	REsult: Printing fails.
O/S 2 prints a file by having a default tool for each file, with a command to
print sent to it. A new handy-dandy program is added, and the print routines
are supplied with it.
	REsult: Printing works.

Now, O/S 2 is object-oriented. (It also is the Mac, but thats not important).
Replace printing with resource allocation/de-allocation. Now:

Method one: A special library is written to track all resource usage. Then
a new resource is defined. It fails.
Method two: All libraries are written to track their own resource allocations
and releases. Now things work.

Method zero (none of the above) is the Amiga. Method 1 is ARP.

This is a suggestion for 2.0:
Define a resource. All tasks/processes/whatever have a list of lists.
(Allows the CLI to have one set of resources and its "children" other sets).
Each sublist contains a list of the resources this thing owns. All things
that work with resources have the following operations defined:
RS_ALLOC: Resource being allocated
RS_FREE:  Resource is to be free'd.
RS_TRANS: Resource is being transfered from one owner to another
RS_SPLIT: Resource is being duplicated

others as needed.

Implementation of a resource would be a structure with two elements: a
function pointer, and a void * (initialized to NULL) (8 bytes, AllocMem's
favorite size). The function would take 2 args, one is the command, the
other is the resource for which this is done. ALLOC would take the
structure, malloc() some memory, and set the void * to it. FREE would
clean up, and free() that memory.  For cli task killing, just call
FREE on each resource in the sublist.  For complete process killing,
do this on every sublist in the list.

Examples:
Opening a file. User calls Open(). Open gets the current sublist for this
process, adds a resource structure, calls the filesystem-handler for
the appropriate device, (File-system handler would add a structure for the
file lock, handle an internal ALLOC), does an internal ALLOC for the
File Handle, then returns it to the user.

Hmm... brings up two points. One, the ALLOC would generally be internal
to the library and not generally available (but not always. ALLOC would
be well defined for creating I/O requests (no more hard coding for all the
different possible i/o request size and device specific initializations)),
and two, another pointer for sub-resources is needed
(consider that when a user wants to dup() that file handle, the lock
will need to be duplicated also. Ditto for tansfered. So thats 12 bytes
total, a node overhead (this is an exec list, after all) (next, prev,
etc.), about 32 bytes for the complete structure. Ok, so we don't use it
for memory allocation tracking :-)

Followups to c.s.a.tech
: --- 
: Michael Gersten			 uunet.uu.net!denwa!stb!michael
:				sdcsvax!crash!gryphon!denwa!stb!michael
: Coff Coff <=== Stop smoking.