dhesi@bsu-cs.UUCP (Rahul Dhesi) (08/20/87)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # signal.c # signal.man # This will give you the C source and the manual for an implementation # of signal() for Turbo C. Only SIGINT is currently recognized. # # This archive created: Thu Aug 20 00:29:27 1987 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'signal.c'" '(2380 characters)' if test -f 'signal.c' then echo shar: "will not over-write existing file 'signal.c'" else sed 's/^X//' << \SHAR_EOF > 'signal.c' X/* Xsignal.c - a signal package for Turbo C 1.0. X XThis program and accompanying documentation, henceforth collectively known as X"this software", are copyrighted thus: (C) Copyright 1987 Rahul Dhesi, all Xrights reserved. This software may be used and distributed in any way Xwhatsoever, whether commercial or noncommercial, with the following Xexceptions: (a) this paragraph and this copyright notice must be included Xunchanged; (b) it is forbidden to copy this software for distribution as Xpart of any collection over which a compilation copyright is claimed. XNotwithstanding the above, there are no restrictions of any kind on the Xmachine-readable object code produced by compiling this program with a C Xcompiler. X X -- Rahul Dhesi 1987/08/08 X*/ X X/* XNote: When assigning an address to the variable `handler', a race Xcondition can theoretically occur if a user interrupt occurs during Xthe assignment. However, current versions of MS-DOS cause a user Xinterrupt to take effect only during system calls, so in practice it Xwon't happen. X*/ X X/* The following include files are already supplied with Turbo C */ X#include <signal.h> X#include <errno.h> X X/* XNOTE: For best results, edit your <signal.h> file, provided with XTurbo C, to include the following declaration at the end: X int (*_Cdecl signal (int sig, int (*action)())) (); X*/ X Xvoid ctrlbrk (int (*fptr)(void)); X Xstatic int (*handler)() = SIG_DFL; Xint main_handler(); X Xint (*_Cdecl signal (int sig, int (*action) ())) () X{ X int (*retval) (); X static int installed = 0; X if (sig != SIGINT) { X errno = EINVAL; X return SIG_ERR; /* error return */ X } X if (!installed) { X ctrlbrk (main_handler); /* ctrlbrk() is in Turbo C library */ X installed = 1; X } X X retval = handler; X handler = action; X return (retval); X} X X#define ABORT_PGM 0 X#define RESUME_PGM 1 X X/* Every keyboard interrupt is handled here first */ Xint main_handler() X{ X int (*old_handler)(void); X X if (handler == SIG_IGN) X return (RESUME_PGM); X if (handler == SIG_DFL) X return (ABORT_PGM); X old_handler = handler; /* Save user's handler address */ X handler = SIG_DFL; /* Reset handler, like System V does */ X (*old_handler)(); /* call the user's handler */ X return (RESUME_PGM); X} SHAR_EOF fi echo shar: "extracting 'signal.man'" '(2962 characters)' if test -f 'signal.man' then echo shar: "will not over-write existing file 'signal.man'" else sed 's/^X//' << \SHAR_EOF > 'signal.man' X-------------------------------------------------------------------- Xsignal X-------------------------------------------------------------------- X XNAME X X signal -- implements trapping of user interrupts X XUSAGE X X int (*signal (int sig, int (*action))) () X XPROTOTYPE IN X X signal.h /* but you must add it yourself */ X XDESCRIPTION X XThe function `signal' is used to establish an action routine for servicing a Xuser interrupt. Under MS-DOS, typing Ctrl-C causes a user interrupt. (On XIBM-compatible systems the Ctrl-Break key will cause the same user Xinterrupt, and may work when a Ctrl-C fails.) X XThe first argument to `signal', sig, is a number identifying the signal for Xwhich an action is established. The value for sig must be SIGINT. X XThe second parameter, `action', specifies the action to be taken when SIGINT Xoccurs. It is either the name of a user-defined function or one of the Xconstants SIG_DFL (default, which aborts the process) or SIG_IGN (ignore, Xwhich causes SIGINT to be ignored; however, in the case of MS-DOS, a '^C' Xis always echoed to the controlling device). X XThere are no special restrictions on what the action function may do, Xincluding continuing execution, returning normally or with a longjmp Xstatement, or terminating executing with exit(). If the function returns Xnormally, execution continues where it was interrupted by the occurrence of Xthe SIGINT signal, except that any MS-DOS system call that was in progress Xmay need to be restarted. X XBefore the user-defined function is called, the action on the event is Xrestored to be SIG_DFL. Thus a second SIGINT event will cause termination Xof the process unless the signal handler takes care to restore its action Xwith a call to `signal'. Even if it does so, however, a race condition Xstill exists and two SIGINTs occurring rapidly will terminate the process. X(But nobody types that fast.) X XRETURN VALUE X XIf the specified signal is not SIGINT, the return value is SIG_ERR, which is Xdefined in `signal.h', and errno is set to EINVAL. Otherwise the return Xvalue is the value of `action' that was supplied to `signal' in the most Xrecent legal call, or SIG_DFL if `signal' has never been called. X XNOTE X XA header file `signal.h' is already provided with Turbo C. Revise it by Xadding the following line at the end: X X int (*_Cdecl signal (int sig, int (*action)())) (); /* R.D */ X XAUTHOR X X Rahul Dhesi X XEXAMPLE X X#include <stdio.h> X#include <signal.h> X Xint my_handler() X{ X signal (SIGINT, SIG_IGN); /* ignore signals for now */ X fflush (stdout); X printf ("\n<Break>\n"); X fflush (stdout); X signal (SIGINT, my_handler); /* reinstall signal handler */ X} X Xunsigned _stklen = 4000; /* reserve stack */ X Xmain() X{ X int c; X signal (SIGINT, my_handler); X printf ("Control C is being trapped\n"); X printf ("Type Q then <return> to exit\n"); X for (;;) { X c = getchar(); X if (c == 'q' || c == 'Q' || c == EOF) X break; X } X} SHAR_EOF fi exit 0 # End of shell archive -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
darrylo@hpsrla.HP.COM (Darryl Okahata) (08/24/87)
In comp.sys.ibm.pc, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: > #! /bin/sh > # This is a shell archive, meaning: > # 1. Remove everything above the #! /bin/sh line. > # 2. Save the resulting text in a file. > # 3. Execute the file with /bin/sh (not csh) to create: > # signal.c > # signal.man > # This will give you the C source and the manual for an implementation > # of signal() for Turbo C. Only SIGINT is currently recognized. > # [ ... ] Thanks to Rahul Dhesi for writing this! However, there are little "gotchas" that one has to be careful of: 1. Any routine called through the handler set up by the ctrlbreak() call uses the stack given to it by DOS. The handler does not set up a stack before calling the specified routine. It *appears* that the stack used is the one that was being used when the DOS function that was called was interrupted. Because of this, there may or may not be enough room on the stack for the ctrl-break handler to properly run (there may not be enough room for local variables, recursive calls, etc.). 2. As the stack that is being used may not be the one that Turbo C uses, the Turbo C program may terminate if stack overflow checking is turned on. In my case, a TSR (Chris Dunford's PCED) was doing some processing when I hit CTRL-C. Because PCED sets up a local stack and because I had turned on stack overflow checking in my Turbo C program, the Turbo C program was aborting with a "stack overflow" error upon entry to main_handler(). -- Darryl Okahata UUCP: { hplabs!hpcea, hpfcla }!hpsrla!darrylo CompuServe: 75206,3074 Disclaimer: the above is the author's personal opinion and is not the opinion or policy of his employer or of the little green men that have been following him all day.
dhesi@bsu-cs.UUCP (Rahul Dhesi) (08/26/87)
In article <2670002@hpsrla.HP.COM> darrylo@hpsrla.HP.COM (Darryl Okahata) writes about my signal() for Turbo C: > Thanks to Rahul Dhesi for writing this! However, there are little >"gotchas" that one has to be careful of: > > 1. Any routine called through the handler set up by the ctrlbreak() > call uses the stack given to it by DOS. The handler does not set > up a stack before calling the specified routine. It *appears* that > the stack used is the one that was being used when the DOS function > that was called was interrupted. When I tested the signal() handler code, I did run out of stack space. Then I initialized _stklen to a bigger value and the program ran correctly. So any shortage of stack space is occurring simply because the Turbo C stack is not big enough. The default stack, if you don't create _stklen, is only 128 bytes, which is peanuts. To set up the stack (this is not given in the Turbo C manual but was on a readme file on the disk) just declare a global variable thus: unsigned _stklen = 3000; /* set up 3000 byte stack */ Also note that I believe that the small model start-up code for Turbo C does not properly handle _stklen to set a bigger stack. I changed and recompiled the startup module for the small memory model to fix this apparent bug. I made the following changes in C0.ASM: 1. Search for the line _stklenOK label near and after it insert the statement: mov bx,di 2. The following statements occur in two places in C0.ASM: cmp bp,di ja ExcessOfMemory Comment these out the FIRST time they occur. For the small model startup code at least, the above changes seemed to solve two problems: (a) It seemed to me that _stklen wasn't working; (b) Even when I thought I had _stklen working, the startup code was allocating as much stack space as was available, even if you specified less. The above is only for the small model code, and only for version 1.0 of Turbo C (but note that all versions of Turbo C are called version 1.0, so the startup code for your version 1.0 could be different from mine). I have a lot of weasel words here because I didn't exhaustively test to see if what I thought happened really did happen. But I'm happy with the results of the changes I made, and signal() works perfectly now. -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
ralf@b.gp.cs.cmu.edu (Ralf Brown) (08/28/87)
In article <1059@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: >In article <2670002@hpsrla.HP.COM> darrylo@hpsrla.HP.COM (Darryl Okahata) >writes about my signal() for Turbo C: >> [...] > >When I tested the signal() handler code, I did run out of stack space. >Then I initialized _stklen to a bigger value and the program ran >correctly. So any shortage of stack space is occurring simply because >the Turbo C stack is not big enough. The default stack, if you don't >create _stklen, is only 128 bytes, which is peanuts. NO! The default stack length is 4096 bytes (there is a module in the library whose sole purpose is to define _stklen). The 128 bytes is the initial startup stack, which gets moved as soon as C0.ASM figures out where to place it. No matter what value you give _stklen, the startup stack stays 128 bytes. >Also note that I believe that the small model start-up code for Turbo C >does not properly handle _stklen to set a bigger stack. I changed and >recompiled the startup module for the small memory model to fix this >apparent bug. I made the following changes in C0.ASM: Actually, the bug is in determining how much memory to allocate to the program. The problem is that when less than 64K is available in tiny model, the code does not use all available memory, but only CODE+DATA+minSTACK, where minSTACK is 256 bytes. My fix for this (posted some time ago) is to change the two lines in C0.ASM between the two "ja ExcessOfMemory" statements to mov di,bp cmp bp,bx DI contains the amount to allocate, BP contains the amount available, and BX contains the minimum amount needed. (Which is too little, because it only allocates 256 bytes for the stack). Note that this patch can also be applied to the .COM file, as the instructions are the same size as those they replace. >-- >Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi -- -=-=-=-=-=-=-=-= {harvard,seismo,ucbvax}!b.gp.cs.cmu.edu!ralf =-=-=-=-=-=-=-=- ARPAnet: RALF@B.GP.CS.CMU.EDU BITnet: RALF%B.GP.CS.CMU.EDU@CMUCCVMA AT&Tnet: (412) 268-3053 (school) FIDOnet: Ralf Brown at 129/31 DISCLAIMER? Who ever said I claimed anything? "I do not fear computers. I fear the lack of them..." -- Isaac Asimov
darrylo@hpsrlc.HP.COM (Darryl Okahata) (08/31/87)
In comp.sys.ibm.pc, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: > In article <2670002@hpsrla.HP.COM> darrylo@hpsrla.HP.COM (Darryl Okahata) > writes about my signal() for Turbo C: > > Thanks to Rahul Dhesi for writing this! However, there are little > >"gotchas" that one has to be careful of: > > > > 1. Any routine called through the handler set up by the ctrlbreak() > > call uses the stack given to it by DOS. The handler does not set > > up a stack before calling the specified routine. It *appears* that > > the stack used is the one that was being used when the DOS function > > that was called was interrupted. > > When I tested the signal() handler code, I did run out of stack space. > Then I initialized _stklen to a bigger value and the program ran > correctly. So any shortage of stack space is occurring simply because > the Turbo C stack is not big enough. The default stack, if you don't > create _stklen, is only 128 bytes, which is peanuts. [ ... ] > To set up the stack (this is not given in the Turbo C manual but was on > Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi > ---------- When main_handler() is entered, the stack that the routine uses MAY NOT be that of the Turbo C program. With Chris Dunford's PCED (a TSR) loaded, I'm using a Turbo C routine to read a line from the console via DOS function 0x09 or 0x0a (I can't remember which -- it is the function to read a complete line from the console). If I hit ^C while performing the DOS call (which is intercepted by PCED), main_handler() gets the stack used by PCED; not only is the offset different, but the stack SEGMENT is totally different. main_handler() may or may not have enough stack room in which to work. Everything may work fine, or your system may crash. I think the bug here is in Turbo C -- the library routines should handle messy details like making sure that the stack is correct. I don't know any easy way around this. In fact, the only way that I can think of to get around this is to write a short assembly routine to set up a local playground (stack) before calling main_handler(). Of course, the problem with this is that main_handler() will have to eventually return. -- Darryl Okahata {hplabs!hpcea!, hpfcla!} hpsrla!darrylo CompuServe: 75206,3074 Disclaimer: the above is the author's personal opinion and is not the opinion or policy of his employer or of the little green men that have been following him all day.
dhesi@bsu-cs.UUCP (09/02/87)
In article <3320049@hpsrlc.HP.COM> darrylo@hpsrlc.HP.COM (Darryl Okahata) writes: [about problems caused by Turbo C ctrlbrk() apparently not switching to Turbo C's own stack]: >If I hit ^C while performing the DOS >call (which is intercepted by PCED), main_handler() gets the stack used by >PCED; not only is the offset different, but the stack SEGMENT is totally >different. main_handler() may or may not have enough stack room in which >to work. Everything may work fine, or your system may crash. > > I think the bug here is in Turbo C -- the library routines should >handle messy details like making sure that the stack is correct. I looked at Microsoft's official guide to MS-DOS, written by Ray Duncan. The description for the control-C trapping system call, which Turbo C's ctrlbrk() function must be using, says nothing about which stack is used. Can anybody check any other documentation about this? But the description given by Duncan does say that the control-C handler can do anything that the rest of the program does. This does seem to imply that the control-C handler is not executing on an interrupt stack, but is using the original application program's stack. This would be consistent with Microsoft attempting (albeit rather weakly) to provide facilities similar to those provided by UNIX. I wonder if the bug is in MS-DOS? I heard somebody say somewhere that the signal() function provided by one of the C compilers (Lattice's or Microsoft's) uses some undocumented features of MS-DOS. Why would it do so, unless it were necessary? Why would it be necessary, if MS-DOS sets up the stack correctly before passing control to the handler? On the other hand, could it be that PCED is doing something funny with the stack? It does bypass MS-DOS, so it's hard to guarantee that it will coexist with all generic MS-DOS software. -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
darrylo@hpsrlc.HP.COM (Darryl Okahata) (09/03/87)
In comp.sys.ibm.pc, dhesi@bsu-cs.UUCP (Rahul Dhesi) writes: > In article <3320049@hpsrlc.HP.COM> darrylo@hpsrlc.HP.COM (Darryl Okahata) > writes: > [about problems caused by Turbo C ctrlbrk() apparently not switching to > Turbo C's own stack]: > >If I hit ^C while performing the DOS > >call (which is intercepted by PCED), main_handler() gets the stack used by > >PCED; not only is the offset different, but the stack SEGMENT is totally > >different. main_handler() may or may not have enough stack room in which > >to work. Everything may work fine, or your system may crash. > > > > I think the bug here is in Turbo C -- the library routines should > >handle messy details like making sure that the stack is correct. > [ ... ] > > But the description given by Duncan does say that the control-C handler > can do anything that the rest of the program does. This does seem to [ ... ] > > I wonder if the bug is in MS-DOS? I heard somebody say somewhere that [ ... ] > > On the other hand, could it be that PCED is doing something funny with > the stack? It does bypass MS-DOS, so it's hard to guarantee that it > will coexist with all generic MS-DOS software. > -- > Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi > ---------- Hmmm. Come to think of it, the bug could be in PCED. Originally, I had set a breakpoint at the entry to main_handler(), and noticed that the stack given to main_handler() was that of PCED. I'll look into it more this weekend. -- Darryl Okahata {hplabs!hpcea!, hpfcla!} hpsrla!darrylo CompuServe: 75206,3074 Disclaimer: the above is the author's personal opinion and is not the opinion or policy of his employer or of the little green men that have been following him all day.