pozar@hoptoad.uucp (Tim Pozar) (04/25/87)
I was wondering how one finds the address of a function and would apply it to setting a vector interupt with it. This is the code that I came up with. It compiles with one error (see below). If anyone has any insite on how this could be better done, I would like to hear it. Tim Pozar --- /* * CTLC.C * * A control-break or ^C handler demo. * * This programme will push the "DOS CONTROL-C Exit Address" vector * and set it to the "bye()" function. bye() should pop the old * address and then executes the users code. The old vector should * be restored if the programme ends through the remaped vector or before * a standard exit(). bye() should also come before the retrival of the * function's address with the way MSC is set up. * * This is a way to make graceful exits from complex programmes that * may have several files open or be communication programmes that need * to handle the comm paths a paticular way to exit properly. (Well, *I* * thought it was an interesting hack in "C" !) * * CTLC will count 20 seconds and exit, or if the user types a ^C or * a CONTROL-BREAK the programme will exit with our routine. If a char * is typed before the ^C is entered, the programme will exit normally * because the keyboard buffer is not polled. To correct this, keep * checking on the kbhit() function supplied with MSC 4.0 and call on * the console input, or keep watching the int 9 (KB_INT) for a keyboard * hit while you're in your routine. * * I would guess you could make this function return back into the * programme by having it call a assembly function that would pop an * appropiate number off the stack and then execute an "iret". (messy) * * BUGS: * Because we don't disable the interupts, if an interupt occurs while * the programme is in the middle of stuffing the new or old address, your * up the creek. * Also do not change the vector to the BIOS ^C vector (1Ah). It seems * that DOS has a go at the keyboard break first and so it exits leaving * the modified vector unrestored. * * This source is complier dependent. It was written for the Microsoft * C Compiler 4.0. And it goes without saying, it is VERY DOS dependent. * * At this point there is a complie waring at "funcp = bye;" in the * main function. But everything works perfectly. Has anyone any ideas * on how to make this compile cleanly? * * Tim Pozar -- 24.April.1987 * pozar@hoptoad.UUCP or Tim Pozar at Fido 125/406 * KLOK-FM * 77 Maiden Lane * San Francisco CA 94108 * (415) 788-2022 * * Copyright 1987 Timothy M. Pozar -- All rights reserved. * */ #include <stdio.h> #include <dos.h> #define CNTLBK 0x23 #define SET_VECTOR 0x25 #define GET_TIME 0x2c #define GET_VECTOR 0x35 typedef struct timetype { unsigned hour; unsigned minute; unsigned sec; unsigned hsec; } TIME, *TIME_PTR; unsigned int pvoff; unsigned int pvseg; /* * bye() * * If a keyboard break occurs, this routine is executed. * This routine needs to be stuck into the vector table and taken out * properly when the programme exits. * */ bye() { set_int(CNTLBK,pvseg,pvoff); /* reset old vector */ /* * Put code here. */ printf("Restoreing old keyboard vector and exiting. \n"); exit(0); } main() { char far *funcp; unsigned int off; unsigned int seg; funcp = bye; off = FP_OFF(funcp); seg = FP_SEG(funcp); set_int(CNTLBK,seg,off); printf("bye() is located at %04X:%04X.\n",seg,off); printf("The breakint was located at %04X:%04X.\n",pvseg,pvoff); sleep(20); printf("No keyboard break. Exiting normally.\n"); bye(); } /* * set_int(n,segm,offs) * * Set the interupt speced with the segment and offset passed to it, * and push its old address vector. * */ set_int(n,segm,offs) int n; /* interupt number */ unsigned int segm, offs; /* segment and offset to point to */ { union REGS inregs; union REGS outregs; struct SREGS segregs; inregs.h.ah = GET_VECTOR; /* get orginal vector */ inregs.h.al = n; intdosx(&inregs, &outregs, &segregs); pvoff = outregs.x.bx; /* push it old vector offset */ pvseg = segregs.es; /* and segment */ inregs.h.ah = SET_VECTOR; /* set new vector */ inregs.h.al = n; inregs.x.dx = offs; segregs.ds = segm; intdosx(&inregs, &outregs, &segregs); return(0); } /* * * get_time(n) * TIME_PTR n; * * Fills timetype structure n with current time. This function could * be replace by calles to time() and then gmtime() to get a structor, * but since were fooling with vectors anyway... * */ get_time(n) TIME_PTR n; { union REGS inregs; union REGS outregs; inregs.h.ah = GET_TIME; intdos(&inregs, &outregs); n->hour = outregs.h.ch; n->minute = outregs.h.cl; n->sec = outregs.h.dh; n->hsec = outregs.h.dl; return(0); } sleep(x) int x; { int i; unsigned s; TIME n; /* current time record */ i = 0; get_time(&n); s = n.sec; while (i < x){ printf("secs = %d \r",i); /* for debug only */ while (s == n.sec) /* while Mickey's hand hasn't moved... */ get_time(&n); s = n.sec; /* if Mickey's hand moved... */ ++i; /* increment the counter */ } } -- Tim Pozar UUCP pozar@hoptoad.UUCP Fido 125/406 USNail KLOK-FM 77 Maiden Lane San Francisco CA 94108
cim2@pyuxv.UUCP (04/30/87)
[Long example of setting interrupts via set/getting interrupts using
MSC]
Several things come to mind:
1. There is no need to do this at all in MSC since they provide the
signal() handler function - to call bye() when the user types CTRL-C
just do:
#include <signal.h>
main()
{
int bye();
signal(SIGINT,bye);
}
2. If you need to set interrupt vectors for some other reason (e.g. an
RTL) the FP_SEG and FP_OFF macros give weird results when fed a
function pointer - ( I was working on MSC 4.0 in Large memory model)
It seems these only really work with variables (Is this a bug?)
For my application, I coerced the function pointer to a long,
and then split the segment/offset off:
unsigned long lvar;
int bye();
int seg,off;
lvar=(unsigned long)bye;
off= lvar&0xFF;
seg= lvar>>16;
I know this looks kludgy - but it works :)
Rob Fair
Bellcore/CHC
rosen@mtgzz.UUCP (04/30/87)
In article <2042@hoptoad.uucp>, pozar@hoptoad.uucp (Tim Pozar) writes: > > I was wondering how one finds the address of a function and would > apply it to setting a vector interupt with it. This is the code that > I came up with. It compiles with one error (see below). If anyone > has any insite on how this could be better done, I would like to > hear it. > Tim Pozar > [. . .] I didn't have a chance to look at your program in detail, but here are a few pointers. First of all instead of playing with interrupt vectors you should be using the C library call signal(). I don't remember the exeact parameters but it is in your manual and does axactly what you want--traps on ^C. But assuming you want to do it your way... You didn't say what your compiler error was, but it could be a pointer size mismach. Are you using the large modal? You probably sould be if you want to stuff a long function address into an interrup vector. It also might help to put an '&' infront of 'bye', as in: funcp = &bye; I once wrote a similar routine in MSC to cahnge interrupt vectors and restore on exit. If you need more info contact me and I'll look it up. -- Thomas Rosenfeld @ AT&T Information Systems Labs, Middletown, NJ (201) 957-5867 UUCP: {harpo,ihnp4,burl,akgua}!mtgzz!rosen Disclaimer: I don't claim anything.
backman@interlan.UUCP (Larry Backman) (05/01/87)
In article <2042@hoptoad.uucp> pozar@hoptoad.UUCP (Tim Pozar) writes: > > I was wondering how one finds the address of a function and would >apply it to setting a vector interupt with it. This is the code that >I came up with. It compiles with one error (see below). If anyone >has any insite on how this could be better done, I would like to >hear it. > Tim Pozar > > * > * This programme will push the "DOS CONTROL-C Exit Address" vector > * and set it to the "bye()" function. bye() should pop the old > * address and then executes the users code. The old vector should > * be restored if the programme ends through the remaped vector or before > * a standard exit(). bye() should also come before the retrival of the > * function's address with the way MSC is set up. > *... > ... > * I would guess you could make this function return back into the > * programme by having it call a assembly function that would pop an > * appropiate number off the stack and then execute an "iret". (messy) > * > * BUGS: > * Because we don't disable the interupts, if an interupt occurs while > * the programme is in the middle of stuffing the new or old address, your > * up the creek. > * Also do not change the vector to the BIOS ^C vector (1Ah). It seems > * that DOS has a go at the keyboard break first and so it exits leaving > * the modified vector unrestored. > * > * This source is complier dependent. It was written for the Microsoft > * C Compiler 4.0. And it goes without saying, it is VERY DOS dependent. > * > * At this point there is a complie waring at "funcp = bye;" in the > * main function. But everything works perfectly. Has anyone any ideas > * on how to make this compile cleanly? > * > >main() >{ >char far *funcp; >unsigned int off; >unsigned int seg; > > funcp = bye; > off = FP_OFF(funcp); > seg = FP_SEG(funcp); > > set_int(CNTLBK,seg,off); > > printf("bye() is located at %04X:%04X.\n",seg,off); > printf("The breakint was located at %04X:%04X.\n",pvseg,pvoff); > > sleep(20); > printf("No keyboard break. Exiting normally.\n"); > bye(); >} First off, I suspect that our program would compile correctl if you declare your function as: char far *funcp(); Secondly, while you really shouldn't have to disable interrupts while swapping interrupt vectors, I'm the nervous type that believes that its safer. Typically, you sway vectors at program initialization or termination, at this time who cares if interrupts are off for a few hundred instructions. Third, if you are doing communications, NETBIOS as an example, ou may get a CTL-C or CTL-Break while in the middle of issueing a request. NETBIOS commands that wait do not return control to you until the have completed, this may be a 1 second delay on a LAN. In my situations, using NETBIOS over a WAN TCP network, a NETBIOS command can block for up to one minute in some circumstances. This is a long time to wait for Control C/Break. In this situation, or other lie it, you absolutely have to intercept INT 9 (KBD), test for various nasty keystrokes, (CTL-C/BREAK, or CTL-ALT-DEL), and if one of those keystrokes is seen, do some immediate housecleaning, BUT GET YOURSELF BACK TO YOUR CODE THAT WAS EXECUTING BEFORE THE INTERRUPT OCCURRED!!!!! The UNIX setjmp/longjmp game does not work properly in DOS communications programs. My code looks something like this: main() { open a NETBIOS connection; while (1) { if (break_flag) break; send_data(); receive_data(); if (done) break; } close NETBIOS connection(); } and my keyboard interrupt handler. (Written in assembly in reality) int_9_handler() { test_for_ctl_c() test_for_ctl_alt_del() if (ctl_c || ctl_break) { send_netbios_cancel(); break_flag = TRUE; } else if( ctl_alt_del) { send_netbios_cnacel(); } push flags call far old_int_9_handler(); iret; } The important thing in these lousy little fragments is the concept of cleaning up after yourself, not just in your machine, but in your LAN or WAN environment. If you don't do your communications cleanup correctly, you leave hung sockets, ports, sessions, or whatever on the other end of your communication line. Larry Backman Micom - Interlan, Inc.