[comp.sys.mac] Tasking on the Mac

conybear@moncsbruce.oz (Roland Conybeare) (02/11/88)

	I have received several responses to my posting about stack
sniffer problems when multitasking on the Macintosh.  This posting
summarises the information I have learnt.  Thank you to all the people
who wrote to me, particularly Paul Mercer and Bryan Stearns from Apple,
who entertained several exchanges of E-mail.

	Quick summary: there's more to getting tasking to work on the Mac
than just disabling the stack sniffer.

	Normal operation of the Macintosh depends on the following model of
the Mac's memory being correct:

		+----+
		|    |
		|    |
		+----+ <-- SP
		|    |
		+----+ <-- StkLowPt ($00000110)
		|    |
		+----+ <-- HeapEnd
		|    |
		|    |
		+----+

	The sniffer invokes a system error if SP < StkLowPt.  Normally,
StkLowPt will be moved by the Memory Manager when the heap expands.  However,
I understand that *if* StkLowPt is 0, the sniffer is *disabled* and
the Memory Manager will no longer alter StkLowPt when the heap changes size.
The sniffer can be re-enabled by putting -1 in StkLowPt.

	However, we are not out of the woods yet!  QuickDraw expects
HeapEnd to be less than SP.  Some QuickDraw operations (I don't know 
the complete subset, but certainly CopyBits and region operations) divvy
up memory between HeapEnd and SP into buffers.  Note that this is not the
same as just using lots of stack space.  To call QD without error, *all*
memory from HeapEnd to SP must be unused.

	A consequence of QD's behaviour is that we cannot blithely move
SP around, even if we promise to keep it out of the heap, if we also want
to call QD.

	Now for some implementations.  There are a number of approaches
I know of for making tasking work, as follows:

Avoiding the Stack Sniffer:

(1) we allocate space for each task's stack on the heap (this is known
    as a 'cactus' stack).  Tasks may release stack space, leaving
    'holes'.  The memory in these 'holes' becomes available again when
    the lower limit of the stack moves up to expose the hole again.

    This approach avoids the sniffer entirely, but we can't call QD from
    such a stack organisation.

(2) allocate each task's stack on the heap.  Now the community of
    tasks can be dynamic, although the heap may well become fragmented,
    since it is difficult to make stacks relocatable.

    This scheme can be made to work by storing zero in StkLowPt,
    disabling the stack sniffer.  We still need to call QD from the
    'system' stack.

Calling QD correctly:

(3) we could have one process permanently residing in the system stack,
    said process taking responsibility for all QD calls.  The trouble
    with this is it will also have to handle any other toolbox call which
    uses QD.  We will pay a high price for this service, that is, two
    context switches of 20-30 instructions each, per toolbox call.

(4) Even better, we reserve stack some stack space above HeapEnd for
    calling QD.  To make a toolbox call, we just move the stack pointer to
    this reserved area, call the appropriate trap, and return the stack
    pointer to its original value.  This approach works because every
    68000 compiler I have seen uses A6 to refer to local variables,
    and thus doesn't even notice that we have moved the stack.  
    We have to be careful to keep enough 'normal' stack space available
    in this way, or we can't call QD anymore.  I recall around 3K being
    sufficient for CopyBits...

    The price of (4) is simply that our code gets bigger: several
    instructions per toolbox call of overhead, if we do the above stack
    finessing inline.

BTW, while the disabling of the sniffer is not documented as far as I can
tell,  I would not expect it to break, since Apple is reportedly rewriting
the toolbox with several goals including 'better support for multitasking'.
I hope this means that traps will make fewer assumptions about the Mac's
memory organisation.

I hope this posting helps someone else avoid the stackfalls :-) of 
taking the Mac to task.

Roland Conybeare
(conybear@moncsbruce.oz)