[comp.os.msdos.programmer] Aborting program with ^C

cpp@cci632.UUCP (Carl P. Petito) (09/03/90)

I have a program that I would like to be able to terminate from the
keyboard.  QC2.5 has an example using 'signal' that I used; however, it appears
that the only time ^C is effective is when the program is doing i/o to
the console.  To confirm this, I modified the example program as shown
below, and I found that if I hit ^C nothing happens until the string
starts to print; I get the first two characters followed by ^C.
What's worse, if output is redirected to a file, ^C doesn't do anything
while the program is running.  What am I doing wrong?  Any pointers would
be appreciated.  By the the way I'm using MS-DOS 3.3.

Carl Petito



#include <stdio.h>
#include <conio.h>
#include <signal.h>
#include <process.h>
#include <setjmp.h>
#include <stdlib.h>
#include <float.h>
#include <dos.h>
#include <bios.h>

void ctrlchandler( void );          /* Prototypes */
void safeout( char *str );
int safein( void );

void main()
{
    long i;

    /* Modify CTRL+C behavior. */
    if( signal( SIGINT, ctrlchandler ) == SIG_ERR )
    {
	fprintf( stderr, "Couldn't set SIGINT\n" );
	abort();
    }

    /* loop illustrates results. */

    for (i = 0; i < 999999l; i++)
	;
    printf("First loop done\n");

    for (i = 0; i < 999999l; i++)
	;
    printf("Second loop done\n");

}

/* Handles SIGINT (CTRL+C) interrupt. */
void ctrlchandler()
{
    int ch;

    /* Disallow CTRL+C during handler. */
    signal( SIGINT, SIG_IGN );

    safeout( "Abort processing? " );
    ch = safein();
    safeout( "\r\n" );
    if( (ch == 'y') || (ch == 'Y') )
	abort();
    else

	/* The CTRL+C interrupt must be reset to our handler since by
	 * default it is reset to the system handler.
	 */
	signal( SIGINT, ctrlchandler );
}

/* Outputs a string using system level calls. */
void safeout( char *str )
{
    union REGS inregs, outregs;

    inregs.h.ah = 0x0e;
    while( *str )
    {
	inregs.h.al = *str++;
	int86( 0x10, &inregs, &outregs );
    }
}

/* Inputs a character using system level calls. */
int safein()
{
    return (_bios_keybrd( _KEYBRD_READ ) & 0xff );
}

mitchell (Bill Mitchell) (09/04/90)

In article <39616@cci632.UUCP> cpp@cci632.UUCP (Carl P. Petito) writes:
>I have a program that I would like to be able to terminate from the
>keyboard.  QC2.5 has an example using 'signal' that I used; however, it appears
>that the only time ^C is effective is when the program is doing i/o to
>the console.  To confirm this, I modified the example program as shown
>below, and I found that if I hit ^C nothing happens until the string
>starts to print; I get the first two characters followed by ^C.
>What's worse, if output is redirected to a file, ^C doesn't do anything
>while the program is running.  What am I doing wrong?  Any pointers would
>be appreciated.  By the the way I'm using MS-DOS 3.3.
>

I'm replying with remembered info without checking it out.  Sorry,
but this may help.

I recall from examining the bios listings in the IBM tech ref manual
that ctrl-brk recognition is done as raw scan codes are extracted from
the typeahead buffer.  You might want to look at that for details.

Also, placing a line containing the words "break on" in your autoexec.bat
file will, I think, get this interpretation made whenever disk I/O is
in progress.  SIGINT should then work whenever the program hangs a read
for the keyboard or for a disk.  Won't help if your program is in a
compute-bound loop, but better than nothing.

Hope this helps.

browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) (09/05/90)

In article <39616@cci632.UUCP>, cpp@cci632.UUCP (Carl P. Petito) writes:
> I have a program that I would like to be able to terminate from the
> keyboard.  QC2.5 has an example using 'signal' that I used; however, it appears
> that the only time ^C is effective is when the program is doing i/o to
> the console.

[detailed description omitted]

Carl, this is probably related to a missing BREAK command.

Before running your program, at the DOS prompt type
	BREAK
You'll probably see "BREAK is off".  This means that the only time DOS is
monitoring for ^C is during console and printer I/O.  (There may be one
or two other instances.)

If you type the command
	BREAK ON
and then run your program, you should be able to interrupt it with ^C at
any time.

Note: ^C and ^Break are not quite the same.  If you have a running program
and type keystrokes into the keyboard buffer, ^C won't get processed until
after those keystrokes.  However, ^Break gets processed right away (if
BREAK is on) even if there are unused keystrokes in the input buffer.  It
seems strange that this should be so, since the manuals talk about them as
interchangeable, but the above has been my experience.  (Also, the ^Break
or Ctrl-Break combination may be obtained by pressing and holding the Ctrl
key, then pressing ScrollLock, then releasing both keys.  Depends on your
keyboard.)

Check your DOS manual for the exact format of BREAK command in CONFIG.SYS.
In AUTOEXEC.BAT, it's the same as at the command prompt.

Stan Brown, Oak Road Systems, Cleveland, Ohio, U.S.A.         (216) 371-0043
The opinions expressed are mine. Mine alone!  Nobody else is responsible for
them or even endorses them--except my cat Dexter, and he signed the power of
attorney only under my threat to cut off his Cat Chow!