[comp.sys.amiga] Sample Exception Handler

iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) (07/24/88)

Well, I guess I answered my own question out of necessity.  Here is
my attempt at writing an Exception Handler.  The program will loop
indefinitely, and catch the signals that result from typing either
^C, ^D, ^E, or ^F.  In addition, ^C will abort the program.
If people out there with experience in these matters see any mistakes
I've made, please let me know..


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: ...psuvax1!mtsunix1.bitnet!iphwk
"He learned to communicate with birds and discovered that their conversation
was fantastically boring.  It was all to do with wind speed, wingspan,
power-to-weight ratios and a fair bit about berries."

----------------

/* An illustration of how to write an Exception Handler */
/* Bill Kinnersley - IPHWK@MTSUNIX1.BITNET - 7/23/88    */
/* Compiled using Aztec 3.4a, 16-bit integers.          */
/* ^D, ^E, ^F will print a message, ^C will abort.      */

#include <stdio.h>
#include <exec/types.h>
#include <exec/tasks.h>
#include <libraries/dos.h>
#include <functions.h>

extern short Enable_Abort;
long aborted, cursigs, mysigs, oldsigs;

struct Task *mytask;

main() {
/* Install my handler */

        install();

/* Make sure that Aztec does not catch any ^C's */

        Enable_Abort = 0;

/* Busy loop simulating something useful...             */
/* Note that each Exception DOES break into this loop.  */
/* The aborted flag is polled only because              */
/* I want to generate a clean exit from main(),         */
/* not try to call cleanup from inside the handler.     */

        while (!aborted) {}

/* It's essential to put things back the way they were  */
/* Exceptions are task-specific, but all programs run   */
/* from the same CLI will reuse the same Task structure */

        cleanup();
}

APTR oldcode;

install() {
        int face();

        mysigs = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
                SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F;
        mytask = FindTask(0L);

/* Don't anyone else bother me while I'm changing my Task structure */

        Forbid();

/* Save the old Exception Handler and install my own */

        oldcode = mytask->tc_ExceptCode;
        mytask->tc_ExceptCode = (APTR)face;

/* I won't use the tc_ExceptData field...leave it unchanged */

        Permit();

/* Save the old Exception signals so we can put them back later */

        oldsigs = SetExcept(mysigs, mysigs);
}

cleanup() {
/* Restore the previous Exception Handler (ROM-wack?) */
        Forbid();
        mytask->tc_ExceptCode = oldcode;
        Permit();
        SetExcept(0L,mysigs);
}

#asm
_face:
;the signals will be passed to me in d0
        move.l  d0,-(a7)
;restore a4, which points to Aztec's small data segment */
        public  _geta4
        jsr     _geta4
        move.l  (a7)+,_cursigs

        jsr     _hdlr

;return signals to the system so they can be reset
        move.l  _cursigs,d0
        rts
#endasm

hdlr() {
/* Note that even AmigaDOS stuff can be done from here */
        printf("Exception %lx   Control-",cursigs);
        if (cursigs & SIGBREAKF_CTRL_C) {printf("C\n"); aborted=1;}
        if (cursigs & SIGBREAKF_CTRL_D) printf("D\n");
        if (cursigs & SIGBREAKF_CTRL_E) printf("E\n");
        if (cursigs & SIGBREAKF_CTRL_F) printf("F\n");
}

ewhac@well.UUCP (Leo L. Schwab) (07/27/88)

In article <3447@louie.udel.EDU> iphwk%MTSUNIX1.BITNET@cunyvm.cuny.edu (Bill Kinnersley) writes:
>Well, I guess I answered my own question out of necessity.  Here is
>my attempt at writing an Exception Handler.  [ ... ]
> [ code deleted ]

	Congratulations, you got it.  I would recommend that you also
restore the tc_ExceptCode pointer when done as well; it may be important to
someone.

	There are some caveats that you should be aware of.  Kickstart does
not internally interlock asynchronous operations.  When you enter a
Kickstart routine, the routine assumes that it will run to completion before
returning to you.  Thus, certain Kickstart routines may procure some
resources upon entry, and free them upon exit.  If you interrupt them and
don't return, Bad Things will happen.

	As an example, suppose you call Draw().  Draw() calls OwnBlitter(),
then performs weird sex on the blitter to draw the lines.  If, during this
time, your exception routine gets called, and your exception routines calls
exit() or longjmp(), or in any way fails to return back to where it came
from, you will have left the blitter allocated (since Draw() never got a
chance to call DisownBlitter()).  If you exit(), the system will appear to
stop, since no one can get control of the blitter again.  Similar situations
exist in DOS.

	As long as your exception routine returns without trying to re-route
the execution thread, you can use exceptions safely.  However, be very
careful of interrupting Kickstart routines; weird things may happen.

	You may wish to look at Matt Dillon's Qint routines which help
alleviate this problem.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	INET: well!ewhac@ucbvax.Berkeley.EDU
 \_ -_		Recumbent Bikes:	UUCP: pacbell > !{well,unicom}!ewhac
O----^o	      The Only Way To Fly.	      hplabs / (pronounced "AE-wack")
"Hmm, you're right.  Air is made up of suspended meat loaf."  -- Josh Siegel