ng@pur-phy (Nicholas J. Giordano) (09/03/88)
About a month ago there was a discussion of how to catch signals like ^C, etc. An example program was posted to the net (see below), and people seemed to agree that it was the right way to go about things, although one must be careful not too take control away from certain system routines, without letting them finish their work. Well, I was playing with this last night, and I ran into a problem which I don't understand. The program below catches ^C, ^D, ^F, and ^E, prints a little message, and then returns. If a ^C was typed, a global variable is set, and the program finishes. There is a busy loop in which nothing is done [while {}] for illustrative purposes, and the program works fine when this loop is empty. However, when I added some code inside this loop, the program crashes (gurus). The code I added was a simple printf, and is indicated below. Can somebody tell me why there is a guru, and what I need to do to get rid of it?? Thanks. Nick NOTE: I have removed some of the comments from the original program. Also, this is compiled with Manx 3.6a with 16 bit ints. /* 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() { int i = 0; install(); 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) { printf("%d\n",++i); <----------- Adding this brings the guru } cleanup(); } APTR oldcode; install() { int face(); mysigs = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F; mytask = FindTask(0L); Forbid(); oldcode = mytask->tc_ExceptCode; mytask->tc_ExceptCode = (APTR)face; Permit(); 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"); }
dillon@CORY.BERKELEY.EDU (Matt Dillon) (09/04/88)
This is an easy one! The problem is that C.LIB is NOT REENTRANT. While the Amiga may be a multitasking machine, this does not mean that linked-in libraries for a given task are reentrant... the run-time libraries certainly are (in most cases), but most of the routines in the link libraries are not. Specifically, STDIO is not reentrant. Of the run-time libraries, the DOS.LIBRARY is not reentrant for a SPECIFIC PROCESS... i.e. many different processes can call it simultaniously, but a given process cannot be in the middle of a DOS command, interrupt itself, and send another DOS command in the interrupt handler. So, your problem is two fold: (1) STDIO is not reentrant and you are interrupting a printf() with the printf() in the exception handler, and (2) DOS is not reentrant on a per-process basis and STDIO calls DOS. -Matt : while (!aborted) { : printf("%d\n",++i); <----------- Adding this brings the guru : } :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"); :}
vkr@osupyr.mast.ohio-state.edu (Vidhyanath K. Rao) (09/05/88)
I am taking a wild guess here. So bear with me if I am wrong. Manx 'Chk_Abort()' routine munges the task signals before looking at the Enable_Abort variable. Now Printf calls Chk_Abort(). This must be causing the interaction. The solution would be to change the Chk_Abort routine. I was going to ask Manx about this but left on my summer travels. Now I have got finish some other work and may not do this for a while. If any of you get some info on this, I will appreciate E-mail. -Nath vkr@osupyr.mast.ohio-state.edu