[comp.sys.amiga] Use of Resident

john13@garfield.UUCP (John Russell) (10/24/87)

--
I recently read that non-reentrant programs can still be made resident as
long as you only attempt to run one copy at a time.

The fellow who mentioned it talked about doing this with his Modula-II
compiler, and it does indeed sound like a useful setup if you DO have enough
ram to keep a semi-large executable in memory but DON'T have enough to run
Sculpt 3D, Videoscape 3D and a compile/edit session all at the same time.

I know this isn't the favourite topic for the CBM people on the net, but is
this fact at least accurate? It would seem to be handy for advanced users
who would take adequate care. (On the wish list, if not a resident that
works well for everything, how about a DOS loader that looks at a resident
program's reference count and refuses to let you run it if it's non-zero
and the program is non-reentrant?).

John

PS: Killer .sig line, Bryce :-).
-- 
To preserve deniability, I have not informed the University of this posting.
But if I had, they would have been 100% behind it, yessirree bob.
This posting has statements that are evasive, misleading, and just plain wrong.
But that is only because I love the UseNet with all my heart!

page@ulowell.cs.ulowell.edu (Bob Page) (10/24/87)

john13@garfield.UUCP (John Russell) wrote:
>I recently read that non-reentrant programs can still be made resident as
>long as you only attempt to run one copy at a time.

Absolutely untrue.

Suppose you have global variables in your program.  On startup they're
zero.  Your program mucks around with them, then exits.  The data
stays resident too, not just the text.  You start up your program
again, your program uses the data from the last run.  That includes
things like loop counters, File Handles, Window Pointers, devices,
etc, which might not be there any more.  Guess what happens...

Sure, you could program around this by always freeing and zeroing
everything you use on exit, and zeroing everything on startup, but you
can't depend on other programmers to do that, and even so, there are
other dangers of RESIDENT lurking, which I have more than once
discussed here.

Don't use RESIDENT.  The concept is great; the implementation flawed.
Wait until there's one that works.

..Bob
-- 
Bob Page, U of Lowell CS Dept.   page@ulowell.{uucp,edu,csnet} 

bryce@hoser.berkeley.edu (Bryce Nesbitt) (10/25/87)

In article <4086@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>--
>I recently read that non-reentrant programs can still be made resident as
>long as you only attempt to run one copy at a time....

This is nice if you have enough memory to keep ONE copy of the program
(say, a compiler) in RAM, but not enough to keep the program in RAM *and*
in the RAM disk.


>I know this isn't the favourite topic for the CBM people on the net, but is
>this fact at least accurate?

Not a CBM person, but... yes it is... read on.
 
 
>It would seem to be handy for advanced users
>who would take adequate care. (On the wish list, if not a resident that
>works well for everything, how about a DOS loader that looks at a resident
>program's reference count and refuses to let you run it if it's non-zero
>and the program is non-reentrant?).

There are two clases of resident compatibility:

REUSABLE  This means you can run a program, exit, then run the same memory
image again.  The only restriction is no self modifying code that does
not unmodify itself, and don't destroy any static initialized data that
is need next run.  Most C programs qualify.
For the purposes of this resident, RESUABLE also implied CLEAN.  This means
that at any time a copy of the program could be made... no self modifying
of any initized code or data permitted.  This was expected to change to
accomodate static initilization better... probably by keeping a separate
copy of any volitile hunks.

REENTRANT  This means you can run the same program twice in the same memory
image.  We'll assume a single progcessor environment :-).  MMU's can be
convinced this type of thing is proper, so no troubles here.
With this more stringent requirement you can't do *any* self modifying code,
you must specifically AllocMem *ANY* memory that you write to.  THIS MEANS
NO GLOBALS FROM C!  Worse yet, the standard startup modules violate this
rule for stdin, stdout, sysbase etc.
Since local varriables are allocated on the stack at run time, that is ok.
Few Amiga programs qualify as of yet.  All the BCPL programs in the c:
directory do.
For comparison, all of the Amiga ROM routines must be reentrant, since
any task can call them.  Under V1.1 DisplayBeep() was not reentrant,
causing problems (source: V1.2 change notes).

REENTRANT implies RESUSABLE and CLEAN.


A while back I wrote most of a Resident that used a great deal of heuristics 
to determine what class an executable was in.  For example it could detect
BCPL and notice BSS hunks.  It could also notice a special HUNK that had
a format something like this:

	hunk_startupinfo
	LONG numlongs		;how long is this hunk?
	LONG minstacksize	;absolute minimum stack needed
	LONG flags

This project lost steam when I got enough memory not to care.  Now everything
lives in VD0: and will come back "from the dead".  A recoverable resident
is a hot idea...

The flags are I_AM_REENTRANT I_AM_REUSABLE I_AM_CLEAN and SEPARATE_INVOCATION.
(more flags could be added)

The first three are obvious, the third can be set to force separete invocation
even if the program is reentrant and/or reusable.


If the program is NOT reusable the new resident was to treat itself as
a RAM disk, it would "reload" the program for each invocation.

If the program was clean and reusable, but NOT reentrant, the new resident was
to look at the use count.  If it was in use, it would "reload" another copy.
Else it would simply start it running in place.

Not clean, but not resuable was only at the planning stage. It would either
require another entire copy of the program, or a way to flag the dirty hunks.

If the program WAS reentrant, the new resident would increment the use
counter and start the program in place.


None of this was very complex.  As a long term solution it is probably better
to have a "real" DOS. (or some real CAOS :-)

|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce
 (")
  U	"Here. This'll shoot the lips off a cockroch" -Freedom Fighter	

dillon@CORY.BERKELEY.EDU (Matt Dillon) (10/25/87)

>I recently read that non-reentrant programs can still be made resident as
>long as you only attempt to run one copy at a time.

	I am pretty sure the 'resident' programs are stored as segment
lists (via LoadSeg).  In this case, you cannot make a program resident 
unless it was written to be resident, EVEN IF YOU ONLY RUN ONE COPY AT A 
TIME!.

	The reason is simply... global variables.  If the program modifies
any of it's global variables, they will stay modified when the program is
rerun at some later time.  When one makes a declaration like:

int GlobalVariable = 4;

	One assumes that the variable will hold 4 when the program is first 
run.  Not so if the program modifies it and you then attempt to run the 
program again (if it is resident).  The value will not initially be 4 on
the second running.

					-Matt

shs@ji.Berkeley.EDU (Steve Schoettler) (10/27/87)

In article <21428@ucbvax.BERKELEY.EDU> bryce@hoser.berkeley.edu.UUCP (Bryce Nesbitt) writes:
>
>REENTRANT  This means you can run the same program twice in the same memory
>image.  We'll assume a single progcessor environment :-).

  You don't have to.

  The requirements for multiple processors running the same code image
are the same as those for multiple tasks running the same code (in terms of
code and data spaces).
  Now, if you have to synchronize them, that's another story.

>
> A recoverable resident is a hot idea...
>
>If the program is NOT reusable the new resident was to treat itself as
>a RAM disk, it would "reload" the program for each invocation.
>

  I had an idea about a year ago but forgot about it until now.

  What about sorting an exacutable file's hunks on the disk so that the data
hunks come first?  Then rewrite LoadSeg() to first look and see if the
program is "resident" and if so, only load in the new data hunks.
  This could result in much faster loading for programs already running, and
more efficient memory usage.
  Programs could modify variables (including globals) however they wanted
because they would all have their own data space.
  You also have to rewrite UnloadSeg to know about this.

  Since each task has a segment list, it would have to be organized as follows,
with the data segments at the head of the list and the code segments at the
tail:

task1->seglist-> first   second           last
                 data -> data   -> ... -> data   -
                 block   block            block   \
                                                   \
                                                    \   first           last
                                                    /-> code  -> ... -> code
                                                   /    block           block
task2->seglist-> first   second           last    /
                 data -> data   -> ... -> data   -
                 block   block            block  


  Reorganization like this would make a fork() routine trivial: :-}
      copy all data blocks,
      create a task and build a its segment list as shown above,
      copy the stack and registers,
      do a get_aX() (whatever it takes to point to the base of data space)
      and return from fork() appropriately.

  Now that I remember, I started to write something to do this, but when you
start getting into the internals of LoadSeg and the DOS loaders, it gets ugly.

  Is this plausible?  Anyone else want to pick up the ball?

  Steve Schoettler
  ...ucbvax!ji!shs

bryce@hoser.berkeley.edu (Bryce Nesbitt) (10/27/87)

In article <21466@> shs@ji.Berkeley.EDU.UUCP (Steve Schoettler) writes:
>In article <21428@> bryce@hoser.berkeley.edu.UUCP (Bryce Nesbitt) writes:
>>
>>If the program is NOT reusable the new resident was to treat itself as
>>a RAM disk, it would "reload" the program for each invocation.
>
>  I had an idea about a year ago but forgot about it until now.
>
>  What about sorting an exacutable file's hunks on the disk so that the data
>hunks come first?  Then rewrite LoadSeg() to first look and see if the
>program is "resident" and if so, only load in the new data hunks.
>....
>  Programs could modify variables (including globals) however they wanted
>because they would all have their own data space.

You forget that code segments have absolute references into the data
segements.  For this reason it is not possible to have multiple data
segments for multitple tasks.

(Unless the programs knew about it in advance... which is not what we
are talking about)

>  Steve Schoettler
>  ...ucbvax!ji!shs

|\ /|  . Ack! (NAK, SOH, EOT)
{o O} . bryce@hoser.berkeley.EDU -or- ucbvax!hoser!bryce
 (")
  U	"Fanitic: One who can't change his mind, and won't change the
	 subject."

keith@tic.UUCP (Keith Clifford) (11/01/87)

In article <21466@ucbvax.BERKELEY.EDU>, shs@ji.Berkeley.EDU (Steve Schoettler) writes:
>   What about sorting an exacutable file's hunks on the disk so that the data
> hunks come first?  Then rewrite LoadSeg() to first look and see if the
> program is "resident" and if so, only load in the new data hunks.
>   Programs could modify variables (including globals) however they wanted
> because they would all have their own data space.

It's always disappointing to find out a great idea which you had, someone else
had first (multiple processes running the same code, the rest of the stuff is
new to me).

Some distinctive way of telling that the code is reentrant would have to be
determined (one that some other non-reentrant code would not mimmick by
accident). So I would prefer adding new routines like LoadRentrant and
CreateRentrant and leave the house keeping up to the programmer as is consistant
with exec programming philosophy. Processes are entered at the first location
of the first segment by the caller, possibly a CreateProc, but this would
require putting code in a data segment (ICH). All of this is of course
surmountable but the monster grows.

When the idea first came to me, I approached it with the intent of replacing
C: for useful routines like copy, cd, dir, and newcli. Rewriting all of these
routines in assembly creating a device driver/handler that could load a copy of
data into memory from the device and would pass control to it. I have a hack
set of routines that sets up and runs multiple tasks using the same code. If
anyone is interested I could ship you source and executables.

But thank you. You've given me some ideas which could prove fruitful (if I
ever get motivatuffic