[comp.sys.amiga.tech] Memory swapping necessary for a true fork

deven@rpi.edu (Deven T. Corzine) (02/26/90)

On 24 Feb 90 03:35:28 GMT, peter@sugar.hackercorp.com (Peter da Silva) said:

Peter> (I said, re: fork()): Not under AmigaOS you can't.

In article <DEVEN.90Feb22134329@netserv2.rpi.edu> deven@rpi.edu (I) write:
Deven> Don't count on that, Peter, m'boy...

Peter> That's the best news I've heard in a long time! Where have you been?

Oh, you know...  Life has this silly tendency to get in the way of
ambitious projects.  People wanting you to "work", pay bills, rent,
whatnot.  Not to mention that I can't even afford an Amiga myself, so
I have to develop on a friend's.  Not conducive to speedy development,
particularly considering that his Amiga is an A500 w/1Meg ram.  At
least he finally got a second disk drive, which makes a big
difference.  And I managed to create a _usable_ development
environment, considering available resources.

I worked some more towards writing fork(), and was somewhat dismayed
to note that the dates in the comments of the source files indicated
that I hadn't touched it in 8 months (!!!) for one piece and 2 more
months for another.  *sigh*  Anyway, the file I hadn't touched in that
8 months was the one I had half-written to deal with swapping memory.

A little background -- to write a true fork() for the Amiga, a rather
nasty kludge is utterly necessary.  Specifically, I need to swap
memory on task context switches.  Ugly, but necessary.  I was long
aware of this necessity, but never _quite_ sure how I was going to
handle the actual implementation.  (I had done enough research to
convince myself that the approach is plausible and will work, albeit
slowly.)

On the other hand, I DID know what _goals_ I had in mind for memory
swapping.  I wanted a mechanism general enough that I might be able to
reuse it for some other purpose.  I wanted a model consistent with
that of the Exec system itself.  I wanted memory to be swapped ONLY on
demand.  I wanted full flexibility in the design so as not to be
forced to allow memory allocation from a statically allocated data
segment.  And so on.  (there were/are other considerations.)

When I looked at the code I had started to write, I found myself
wondering why the hell I did it like that.  :-)  That I had such a
reaction was no great surprise, as I had put it aside for so long that
I had forgotten my original approach, and was working out a new one
already.  Also, (as a general rule) you usually think of a better way
the second time around.  Because of that, I would like to do a full
rewrite of everything I do, at some point.  (everything important,
that is.)

So, I simply scrapped the code I had and started over.  This time, I
had an arrangement that made more sense to me than my original code,
and it makes more sense that my original code did when I _wrote_ it
also.  (as I was writing that old code, that pleasant little mantra
kept wandering through my head...  "There MUST be a better way...
There MUST be a better way...  There MUST...")  Well, I found a better
way.

As for the method I used, I shan't describe it in great detail (it may
yet change) but it is modelled after the AllocEntry structures and
calls.  I haven't actually written the tc_Launch hook code yet to
handle the actual swap, but I know exactly how I intend to do it, and
I'm sure I can do it pretty efficiently, considering.  As for
performance, I have yet to discover the impact involved.

For a process which does a fork() but no exec() or exit(), the
overhead is guaranteed to be nearly unbearable, but it WILL run.  For
a program which does a fork() and then quickly an exec() [by far the
most common case] or exit(), I hope to keep the overhead as minimal as
I can and to minimize the performance hit.  I also intend to implement
vfork(), which should be FAST.

So, in summary, I have done most of the coding and (I think) all of
the design work necessary for the memory swapping mechanism necessary
to be able to write a true fork() function.  This is a major piece of
the work necessary for writing fork(), but there is more left.  First
approximation, I have maybe 20% of the code and 80% of the design work
done for fork().  But, for fork(), I also need exec(), exit(), wait()
and other related functions and underlying support structure to be of
any use.  But I AM working on it...

If there is anyone out there unconvinced of the need for memory
swapping, consider the consequences of moving a program's stack or
data out from under it.  There may be pointers to the data anywhere,
and you can't simply relocate them.  So, whenever the process
executes, it's stack and data (and program code) must be in their
original locations.  System structures will require special care.
Don't bother saying all you need is a 68020 w/MMU.  I don't have
either available for development, and regardless, I want the system to
work on a 68000 w/no MMU and 512K of memory.  Supporting an MMU might
be nice, but it won't happen yet.

Deven
-- 
Deven T. Corzine        Internet:  deven@rpi.edu, shadow@pawl.rpi.edu
Snail:  2151 12th St. Apt. 4, Troy, NY 12180   Phone:  (518) 274-0327
Bitnet:  deven@rpitsmts, userfxb6@rpitsmts     UUCP:  uunet!rpi!deven
Simple things should be simple and complex things should be possible.