Category : C++ Source Code
Archive   : ISC36.ZIP
Filename : README.TXT

 
Output of file : README.TXT contained in archive : ISC36.ZIP
----------------------------------------------------------------------------
ISC V3.6- by Ofer Laor (AKA LeucroTTA)
----------------------------------------------------------------------------


ISC- Interrupt Service Class
-----------------------------------------------
hooking interrupts into C++ objects made easy
-----------------------------------------------

----------------------------------------------------------------------------
OVERVIEW
----------------------------------------------------------------------------

This article describes a class for Turbo C++ (checked with versions 3.x),
for hooking interrupts into C++ objects. For those of us who need to write
heavy TSRs or regular programs that need interrupt handlers - hooking the
interrupt handlers into the C++ code was a bit of a fuss. Borland made it
easy enough for us to hook interrupts into C code through the "interrupt"
keyword, but objects could not use this feature. The reason for this is
that every C++ object needs an identifier to be passed to it when using
one of it's functions. This identifier (called "this") is the real name
of the object and is used by it to access data and function members. When
a member function is called - (a.foo() for example) a is the "this" and
foo() is the function to be called. When the actual call is made - a is
pushed unto the stack and foo() is called. Now, foo() uses data members
through "this" and knows it's own name through it. If you could somehow
get foo's address and called it (something that C++ prohibits and protects
it's programmers from) you would not pass on the right "this" and cause a
malfunction when foo() accesses an internal data member or calls a
virtual function. What people would usually do is to make a static interrupt
function for each of the interrupts in the system. This is a common solution
(in lack of a better one). ISC offers a different approach - and a more useful
one.

A class that uses ISC will derive from it and overload a function called
isr() - (Interrupt Service Routine). Now all that needs doing is activating
the interrupt (activate(int_num)) and the interrupt is hooked into that
OBJECT!!! What this means is that if you have a class for Serial
communications that works through interrupts - you don't have to make a
different interrupt function for each of the possible ports you'd be using-
you would write the class as you would any other. Each of the instances of
the Serial class you are writing will hook into a different interrupt (or the
same one if needs be).

ISC works in a simple way, it produces what Windows 3.x programmers call
a thunk (a small piece of code that contains your data segment and sets it
just before the real call is made- or in this case the id of your object) for
each of the objects that are currently hooked into interrupts through ISC.
ISC reproduces the thunk for each object. Each Thunk contains in it's code
- the id of the object that owns it. Then it calls a special dispatcher that
handles the call to the right ISC derived object. The dispatcher also sets
up the stack for all the ISC users (so that no stack cramming is needed in
your interrupt routines). The dispatcher also sets up a structure that
contains the registers that the interrupt entered through (so you may modify
them or use them if they are needed).

In the first two versions of this class I tried to utilize (without much
success) properties in the local C++ compilers (how the virtual function
tables work) and tried to call virtual functions directly from ASM. While
this was fairly easy to do (a bit of reverse engineering) - it was compiler
dependent (and even compiler version dependent). I have seen the light and
this version is COMPILER INDEPENDENT (although the ASM routines are written
to work specifically under tasm - and a bit of semantic changes might be
needed to make it work under different assemblers). A close look will have
taught you that porting the code to your local machine, and compiler is a
simple enough task!

Since the ISC class is mainly for use in TSRs (although it is usable in
regular programs just as well)- these are some of the pitfalls that TSR
writers in C++ will encounter:

þ I strongly advise you TSR writers to use ASSUME DS!=SS in SMALL, MEDIUM
models. Also - turn off the CHECK STACK OVERFLOW option if you turned it
on - it sometimes causes trouble in the interrupt routine.

þ ISC CANNOT be compiled under the TINY memory model (the linker will not
work correctly in the asm module). Presently I havn't found an answer
to this problem. Hope it doesn't spoil it for you.

----------------------------------------------------------------------------
ISC functions.
----------------------------------------------------------------------------
ISC provides your classes with the ability to hook into hardware and
software interrupts.

it does this by providing 2 "overloadable" functions: both named isr.


* HARDWARE INTERRUPTS: virtual void isr(void);

just overload this function and when your class is activated the isr will
be called whenever the hardware calls it.

* SOFTWARE INTERRUPTS: virtual void isr(IREGS& regs);

IREGS is NOT compatible with the regular REGS union although it is very
close to it (it has MORE registers than REGS). The 32 bit option is not
supported in the interrupt keyword - so I have not incorporated it into ISC.

* IREGS contains two structures:

struct IBYTEREGS {
unsigned char al, ah, bl, bh;
unsigned char cl, ch, dl, dh;
};

struct IWORDREGS {
unsigned int ax, bx, cx, dx;
unsigned int si, di, ds, es, cs, flags, ip, bp;
};

you may access IWORDREGS and IBYTEREGS through .x and .h :-

IREGS regs;
...
regs.x.ax= regs.h.bl+ regs.h.dl;

all of these registers are what the register situation was BEFORE the
interrupt was called.

if you change the content of the regs parameter that is passed to you in
the isr function - this will be the value of that register when the
interrupt exits.

* void activate(const int in_num) - will hook the interrupt handler to the
function isr (software). The default software isr calls the hardware isr,
so that if you hook to the hardware isr - you will be called as required.
But if you overload both - you must literally call the hardware interrupt
handler in order for it to work. This function prevents the programmer
from activating an ISC derived class twice (you must deactivate it first).

* void deactivate(void) - will unhook you from the interrupt. The destructor
of ISC also does that - so unless you'd like to unhook and rehook to another
interrupt - you shouldn't need this function. The function enables you to call
activate again (for rehooking to another interrupt, for example).

some GENERAL PURPOSE functions are also available here as part of ISC -
since I use ISC to build TSR's in C++ (for example a real time communication
program that runs in the background)- I though it useful to provide TSR
functions here as well. These STATIC functions ( is_TSR and TSR) take care
of managing your TSR needs (the most basic ones).

* static int is_TSR(const char *app_name)- will figure out if your program is
running already as a TSR. You must choose a unique application name and put
it's name as parameter. Returns (1) if you are RESIDENT already and (0) if
you're not. I used a simple method for this - (for more info. read the
source file).

* static int TSR(const int exit_code= 0, unsigned long extra_heap= 0)- will
keep you resident in memory. if you call TSR() it will attempt to stay
resident (minimal memory possible) and return 0 to DOS. You can return any
exit code by calling TSR(1) for example. If your TSR needs more room to grow
(extra interrupt-time heap for example) put the extra heap (in bytes) in the
second parameter. Remember that in the LARGER models malloc and new use the
far heap so that you may not be able to use your preallocated memory in them
(and most likely no heap at all will be available in those memory models at
all). Problem with run time heap (SMALLER MEMORY MODELS ONLY) is that when
you allocate past the max heap you declared (in parameter extra_heap) the
program will crash (in a probably very bizarre way!!!). USE THOUGHTFULLY.

þ One ISC specific static function is reallocStack(unsigned long stacklen):-

* static int reallocStack(unsigned stackLen)- will reallocate the hardware
interrupt stack frame to the specified size. If you need to call this
function you must:- either call it while no ISC derived class is active or
simply disable interrupts before you call it (don't forget to re-enable them).

The method for finding the minimum memory necessary for reallocation is
an algorithm I am quite proud of- it works in all the memory models and with
a lot less memory that the sources Borland provides in their help of KEEP.
It can be converted to C very easily (change new into malloc!). This is a
brand new method (new from V3.6) and is not prone to heap failures and
possible problems (as the previous versions were).

----------------------------------------------------------------------------
ISC data members.
----------------------------------------------------------------------------
þ* There are 2 data members of major importance - int_num and old_vect;

both must not be changed (since deactivate uses them to recover the state
of the interrupt as it was before ISC was used.

int_num - contains the number of the interrupt hook.

old_vect - is a pointer to the function that was the previous interrupt
vector. It can be called - by -> old_vect();
DO NOT CALL IT WITH PARAMETERS!!!!
To get the registers to be as they were use PSEUDO VARIABLE (_AX, _BX...)
or call the vector in some alternative way!!!

*þ There are 3 static data members that refer to the hardware stack frame:-

StackFrame- points to the actual stack frame.

StackFrameLen- contains the current stack frame length.

ISCcount- holds the number of ISC objects that currently exist in the
system.

----------------------------------------------------------------------------
EXAMPLES.
----------------------------------------------------------------------------
þ There are 4 examples:-

þþ EXAMPLE1:- is a resident that keeps a timer tick watcher on screen (by
incrementing the first char on the top left of the screen once every timer
tick). Also, it keeps a keyboard interrupt watcher right next to it. This
example shows how to make an ISC derivative- how to check if already
resident. How to use 2 ISCs together...

þþ EXAMPLE2:- is an example of a software interrupt - it is a software
interrupt that beeps with a length and pitch which are passed as register
parameters. The main routine will test it and verify that it had not
failed through return values (also through register as well as flags).

þþ EXAMPLE3:- is a more complex example of a class that has to do a lot of
processing (each one taking longer than the

EXAMPLE4:- sends a novell look alike "send" message onto the screen (which
stops the forground and waits for the user to free it).

----------------------------------------------------------------------------
MORE DIRECTORIES.
----------------------------------------------------------------------------
þ Also included are some more files and directories:-

þþ ISC :- This directory contains all that you need in order to work with
ISC. (Include ISC.cpp and ISCSERVE.asm into your project and #include
ISC.h in your source files).

þþ SERIAL :- Some more advanced ISC derivative classes that handle interrupt
driven serial and modem communications. Although ISC has changed in the
past year - no changes have been made to these sources. Previously these
sources were distributed under XSERIAL.arj and XSERIAL1.arj. Also included
is a sample of a Buffer class I used that a colleague of mine wrote...
þ there are two examples in serial- RECEIVE and TRANSMIT:- RECEIVE
will set COM1 to 9600baud, 8bytes, 1stopbit, No parity- and put on the
screen anything that comes in from the port. The program will stop if
a key is typed in, as well as if the string "hello there!!!" is entered
from the com port.
TRANSMIT will transmit the string "hello there!!!" to com1 (same port
settings as receive), wait until the string is completely sent and exit.

These classes works great in TSRs (that's what I use it for).

----------------------------------------------------------------------------
NOTE.
----------------------------------------------------------------------------
þ If you need to hook with ISC to a software interrupt like int13h or int21h
don't forget that when you call { old_vect() } you must set the correct
registers to what they were when isr was called (these register values
are in the IREGS parameter passed to isr). Usually the pseudo variables
_AX, _BX, _FLAGS, etc... will do just fine. Also remember that the values
of the registers after the software interrupts are called might be needed
by the forground too (so you can put them back into the IREGS parameter).
WARNING- if you do not do these things you will probably either crash the
forground or mash things up.

þ Use and abuse!!!
examples, bugs, and large donations only by writing to:

+++++
|_ ^| Ofer Laor (LeucroTTa)
@|* o|@ 27 KKL St., Kiriat Bialik (27000)
| ^ | Israel.
|---| telephone @ work (972) - 3 - 983608
- @ home (972) - 4 - 701845






  3 Responses to “Category : C++ Source Code
Archive   : ISC36.ZIP
Filename : README.TXT

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/