per@philabs.Philips.Com (Paul Rutter) (06/24/87)
When playing with "multi-tasking", it is useful to be able to move the stack pointer to one of several stack areas. The "stack sniffer" routine checks whether the stack overlaps the heap during every tick, and bombs if it does. How do I disable the stack sniffer? As far as I can tell "IM" Vols 1-4 only tell what the stack sniffer does, not how to control it. Someone mentioned that there is a global flag that enables/disables; if so, what is it's address (I can't find it in my compiler's include files). thanx, paul
james@cantuar.UUCP (J. Collier) (07/02/87)
Paul Rutter (per@philabs.Philips.Com) writes: >When playing with "multi-tasking", it is useful to be able to move the stack >pointer to one of several stack areas. The "stack sniffer" routine checks >whether the stack overlaps the heap during every tick, and bombs if it does. > >How do I disable the stack sniffer? Steve Munson (sbm@purdue.edu) suggested an alternative solution to this problem some weeks ago. I used a similar method in an experiment earlier this year - and found it effective to the extent that I tested it (not much). Hope I'm not deluding myself in thinking other people might be interested... NB - the suggestions which follow are most unlikely to work on anything newer than a 128k ROM, if at all. APPLE THOUGHT POLICE PLEASE HIT 'j' NOW...:-) Unfortunately, the 60Hz stack sniffer is not the only ROM routine which checks the stack. Disabling the stack sniffer (by setting StkLowPt to 0, if I remember correctly) also has some messy side-effects. Besides which, it's quite nice to have the sniffer look after the behaviour of ones own heap-resident stacks. The sniffing routines work by comparing the value of the stack pointer to the global HeapEnd. Somewhat surprisingly, changing the value of this global to the new stack limit at each context switch appears to achieve the desired effect. Of course, various other ROM routines will be using HeapEnd. However, after several cross-eyed hours searching a 128k ROM, I found only the following references to HeapEnd: 4008fc : Stack Sniffer (read) 409172 : GetFInfo - stack check (read) 40c218 : MapRgn - stack check (read) 40fed6 : SetApplBase (set) 4100b4 : SetApplLimit (set) 4108xx : MoreMasters (read & set) 4135a6 : InitResources (can't remember, but who cares?) So it seems that HeapEnd is normally used only to mark the limit of the stack area. SetApplBase, SetApplLimit and InitResources shouldn't be called after the application is under way. MoreMasters is trickier; I just allocated a large block of masters during initialisation and hoped for the best, but you will probably want to patch the trap. BTW, how are you initiating context switches? Doing it on the 60Hz interrupt I came across several problems: 1. I found I had to patch the interrupt vector and do the switch *after* the normal VBL tasks. 2. I had to disable switching during ROM routines (non-reentrant code :-(). This involved (don't barf) hooking the trap dispatcher. Tricky. Scott Knaster mentions (in "How to Write Macintosh Software") a particularly revolting system patch which relies on the value of the return address being from a certain ROM routine. The dispatcher therefore has to replace the stack frame if the routine was called from user code, but not if called from another ROM routine. Oh, what the ***, the bored will have stopped reading by now, so here goes.. It breaks every rule in the book: self modification, RTE, etc. etc. Do you want to run this on a 68020? %-Q ----------------------------------------------------------------------- /* set A-trap vector to "mytrdsp" */ #define CANTXFER APPLSCRATCH /* inhibit context switch if set */ #define XFERPEND APPLSCRATCH+1 /* c-s blocked during ROM call? */ /* (refer VBLtrap.c) */ #define SAVERA APPLSCRATCH+2 /* save return address here */ /* <oldTOS> <4EA> <2SR> <-SP */ mytrdsp: tst.b CANTXFER /* set if called from ROM */ bne.s jtdisp /* if set, we can't mess with the stack */ addq.b #1, CANTXFER /* disable hook in ROM-ROM calls */ movem.l A0/A1, -(A7) /* <oldTOS> <4EA> <2SR> <8SV>*/ movea.l 10(A7), A0 /* EA -> A0 */ lea trpcpy, A1 /* &(word after jmp) -> A1 */ move.w (A0), (A1) /* Axxx -> (word after jmp) */ addq.l #2, A0 /* skip trap word on rte */ move.l A0, SAVERA /* RA -> global */ move.l A1, 10(A7) /* <oldTOS><4MYEA><2SR><8SV> */ movem.l (A7)+, A0/A1 /* <oldTOS><4MYEA><2SR> */ jtdisp: jmp <trap dispatch> /* initialise on load */ trpcpy: dc.w 0xA000 /* dummy trap copied from code */ move.l SAVERA, -(A7) /* restore saved return address */ move.l SR, -(A7) /* push SR - cc's not needed */ /* assert : CANTXFER == 1 */ clr.b CANTXFER /* returning to user code - clear flag */ tst.b XFERPEND /* set if process xfer was blocked */ beq.s immrtn /* if not, return now */ jsr <cont switcher> /* context switching routine */ immrtn: rte /* return & restore saved SR */ ------------------------------------------------------------------------------ Grubbiness rules, OK? Have fun. ------------------------- James Collier (james@cantuar.uucp / {watmath,munnari,mcvax}!cantuar!james Computer Science Dept., University of Canterbury, Christchurch, New Zealand. My supervisor doesn't know that I'm doing this.
jwhitnel@csib.UUCP (Jerry Whitnell) (07/07/87)
In article <135@cantuar.UUCP> james@cantuar.UUCP (J. Collier) writes: >Paul Rutter (per@philabs.Philips.Com) writes: >>When playing with "multi-tasking", it is useful to be able to move the stack >>pointer to one of several stack areas. The "stack sniffer" routine checks >>whether the stack overlaps the heap during every tick, and bombs if it does. >> >>How do I disable the stack sniffer? I've not tried this but I've heard that if you store a 0 in StackLowPt (sp? my Inside Mac is at home), it disables the stack sniffer. I think Scott Knaster's book mentions it in his discription of launching a program Jerry Whitnell Communication Solutions, Inc.
olson@mmm.UUCP (Al Olson) (07/07/87)
I have also been playing around with "multi-tasking" on the Mac and ran into the some of the same problems. I discovered that placing a process stack in a heap block causes major-league problems. (The MoreMasters trap also looks for heap zones on the stack in its search. Blammo!) This approach gave me so much grief that I did the only logical thing -- I gave up. Well, not completely. The Mac firmly believes that the stack is the stack and the heap is the heap, so why fool it? I tried another approach which works faily well - link the process stack on to the scheduler stack a context switch. Where does it come from? When a process is prempted (either synchronously or asynchronously), copy the process portion of the stack (including registers, etc) into a newly allocated heap block. Then save the handle in the process descriptor. Now deallocate the process stack and restore the scheduler. This is nice because when a process is not executing its saved stack relocates in memory. When resumeing a process, do the reverse: create space on the scheduler stack, copy the proc stack in and throw the block away. (of course you have to lock the handle during transfer). This method has the advantage of keeping the stack and the heap seperate and allowing the stack sniffer to work *for* you. The disadvantage is the increased time to perform a context switch. (the BlockMove trap is pretty damn fast though). Process premption and toolbox reentrancy is another issue, however. I approached this in a slightly different, but equally illegal way. After a few sessions with Tmon, I discovered the format of the stack during the execution of a VBL task. Way down deep, but in a fixed location, lie the SR and PC value pushed during the exception by the 68000. Now what? Prior to entering the scheduler, I located and locked the resource map for the application (scheduler + processes) ank kept a pointer to the CODE resource list. During my VBL task I compare the interrupt PC value with all loaded code segments. If the PC lies in a loaded CODE segment (not the scheduler's, however) then I *replace* the interrupt PC and SR with my own premption routine. (after saving them, of course). The result: asynchronous premption. The only real advantage of this method is that I have not patched *any* trap routine. (although blasting the stack is certainly more severe) I guess there is no easy way to initiate asynchronous premption without resorting to subterfuge... Any way, these are just some thoughts I had on the subject. Maybe I should wait for a Mac II and Unix... -- Alan Olson ihnp4!mmm!olson