home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 8
/
CDASC08.ISO
/
NEWS
/
677
/
ISC
/
SERIAL
/
ISC.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-07
|
11KB
|
401 lines
///////////////////////////////////////////////////////////////////////////
// //
// File: Isc.cpp //
// started on: 5/2/92 //
// //
///////////////////////////////////////////////////////////////////////////
// //
// V3.66 //
// --------- //
// //
///////////////////////////////////////////////////////////////////////////
// //
// by Ofer Laor (AKA LeucroTTA) //
// //
///////////////////////////////////////////////////////////////////////////
#include "isc.h"; // ISC.
#include <dos.h> // MK_FP, keep, setvect, getvect.
#ifndef __NOT_TSR__
#include <alloc.h> // heapwalk.
#endif
// static variables...
char *ISC::StackFrame;
unsigned long ISC::StackFrameLen= 3000; //default stack len.
int ISC::ISCcount= 0;
// overload this function to handle software interrupts...
//
void ISC::isr (IREGS& /* regs */)
{
// by default this function will make a stack frame of 3000 bytes
// for the hardware isr's to use.
static unsigned char recursive= 0;
static unsigned old_ss, old_sp;
static ISC* me;
if (recursive) {
isr();
return;
}
// put up a new stack frame...
recursive++;
disable();
me= this; // remember this...
//This code moves the stack to another plane, please do not single
// step through this code (Turbo Debugger might not survive having lost
// some of it's variables)!
old_ss= _SS;
old_sp= _SP;
_SS= FP_SEG(&StackFrame[StackFrameLen-1]);
_SP= FP_OFF(&StackFrame[StackFrameLen-1]);
//On this new Stack Frame You may not use local functions except in this
// context:- me->local_function(); - this is because this function's
// "this" is in the old stack frame!!! Also use static variables only
// (the automatic ones are in the old stack frame context). These points
// are only relevant IN THIS ONE FUNCTION:- you can easily call another
// local function to do all the stuff for you (me->do_it() may use
// automatic variables!!!).
// call my isr routine...
me->isr();
disable();
_SS= old_ss;
_SP= old_sp;
recursive--;
}
// overload this function to handle hardware interrupts...
//
void ISC::isr (void)
{
old_vect(); // default will not work on software interrupts!!!
}
// ISCThunk.ASM routines.
//
extern "C" {
void far * far ThunkSet(void far *);
unsigned far ThunkSize(void);
void far * far ThunkGetID(void);
}
// this is the dispatcher called by asm code to call the correct object's
// isr functions.
void interrupt ISCDispatch(unsigned bp, unsigned di, unsigned si,
unsigned ds, unsigned es, unsigned dx,
unsigned cx, unsigned bx, unsigned ax,
unsigned ip, unsigned cs, unsigned flags)
{
ISC* isc= (ISC *)ThunkGetID();
IREGS regs;
regs.x.bp= bp;
regs.x.di= di;
regs.x.si= si;
regs.x.ds= ds;
regs.x.es= es;
regs.x.dx= dx;
regs.x.cx= cx;
regs.x.bx= bx;
regs.x.ax= ax;
regs.x.ip= ip;
regs.x.cs= cs;
regs.x.flags= flags;
// software dispatch();
isc->isr(regs); // software later...
bp= regs.x.bp;
di= regs.x.di;
si= regs.x.si;
ds= regs.x.ds;
es= regs.x.es;
dx= regs.x.dx;
cx= regs.x.cx;
bx= regs.x.bx;
ax= regs.x.ax;
ip= regs.x.ip;
cs= regs.x.cs;
flags= regs.x.flags;
}
// ■ returns a pointer to a new thunk.
void far * ISC::GetLocalRoutine(void)
{
if (InitFlag)
return NULL;
void far *newThunk;
void far *oldThunk= ThunkSet((void far *)this);
newThunk= new char[ThunkSize()];
if (newThunk== NULL)
return NULL;
InitFlag++; // initiated. (to prevent a class to hook more
for (int i= 0; i< ThunkSize(); i++)
((char far *)newThunk)[i]= ((char far *)oldThunk)[i];
NewServerPtr= (char *) newThunk;
return newThunk;
}
// this routine hooks isr onto the interrupt passed as an argument to it.
//
void ISC::activate(const int int_num)
{
if (int_num==NULL)
return;
interrupt_num= int_num;
old_vect= getvect(interrupt_num); // remember old vector.
setvect(interrupt_num, (void interrupt (*)(...))GetLocalRoutine()); // set up the asm. server
}
// this function deactivates the interrupt.
//
void ISC::deactivate(void)
{
if ((interrupt_num== NULL) || !InitFlag) // activate did not work.
return;
if (!this) // illegal this!!!
return;
InitFlag= 0; // allow activation.
setvect(interrupt_num, old_vect);
if (NewServerPtr)
delete NewServerPtr;
NewServerPtr= NULL;
}
#ifndef __NOT_TSR__
// this routine Terminates but keeps the program resident.
// note:- this method of staying resident dissallows new
// allocation from the heap (past heaplen)- during interrupt processing,
// that is because the end of the heap (during the call to
// this function) is DISCARDED!!!
//
// ■ does not return anything if successful.
// ■ returns 1 if HEAP problem occured.
// ■ returns 2 if KEEP was not successful.
int ISC::TSR(const int exit_code, const unsigned long heaplen)
{
struct heapinfo hi;
void *hp;
unsigned hlen;
hp= new char[hlen= 5]; // dummy heap value;
if (heapcheck()== _HEAPCORRUPT)
return 1;
hi.ptr= NULL;
while (heapwalk(&hi)== _HEAPOK) {
if (hi.in_use) {
if ((void huge *)hi.ptr> (void huge *)hp)
hp= hi.ptr;
hlen= (unsigned)hi.size;
}
}
if (heapwalk(&hi)!= _HEAPEND)
return 1;
keep (exit_code, (FP_OFF((void far *)hp)>> 4) + FP_SEG((void far *)hp) -
_psp+ 1+ (((unsigned)heaplen)>> 4)+ (hlen>> 4));
return 2;
}
// this function determines if this Tsr is already resident.
// it returns 0 if not, 1 is already resident.
// note- is_TSR utilizes the name space of the MCB,
// Dos 4.0 and up use that area to store the application name,
// so you can put a diffrent app_name than yourself resident) and you
// can check if other apps you need are currently running (put their
// exe's name - whithout extention).
//
// ■ returns 0 if not resident.
// ■ returns 1 if already resident.
int ISC::is_TSR(const char* app_name)
{
static unsigned far *segmptr; // far ptr to seg. address of MCB.
struct MCB {
char chain; // 'Z' for last 'M' for others.
unsigned pid; // pid of owner.
unsigned psize; // size of MCB data area.
char reserved[3]; // unknown.
char name[8]; // name of task.
};
static MCB huge *mcbPtr;
static unsigned my_pid, seg, off;
static int i;
// insert my id into my code mcb.
seg= _psp- 1;
mcbPtr= (MCB huge *)MK_FP(seg, 0);
for (i= 0; i< 8; i++)
mcbPtr->name[i]= app_name[i];
my_pid= mcbPtr->pid;
// could not get int86x to work properly - so I did this...
asm {
push es
push bx
mov ah, 52h
int 21h
mov dx, es
mov ax, bx
pop bx
pop es
}
seg= _DX;
off= _AX- 2;
segmptr= (unsigned far *) MK_FP(seg, off); // now I have the address where
// segmptr is supposed to be!
seg= *segmptr; // keep seg.
unsigned out_flag= 0;
do {
// set mcbPtr to point to segmptr.
//
segmptr= (unsigned far *) MK_FP(seg, 0);
mcbPtr= (MCB huge *)segmptr;
// check see what pid it is.
//
switch (mcbPtr->pid) {
case 0:
// empty MCB.
case 8:
// command com.
break;
default:
// check for a code MCB block.
//
if (mcbPtr->pid!= seg+ 1)
break;
// if it isn't my own pid.
//
if (mcbPtr->pid!= my_pid) {
// now match application names.
//
for (i= 0; i< 8 && (app_name[i]); i++)
if (mcbPtr->name[i]!= app_name[i])
break;
// if names matched, exit!!!
if (i== 8 || (mcbPtr->name[i]== app_name[i]))
out_flag++;
break;
}
break;
}
// check for end of chain.
//
if (mcbPtr->chain=='Z')
return 0; // if here, not resident.
// next mcb
seg+= mcbPtr->psize+ 1;
} while (!out_flag);
return 1; // if here-> resident.
}
#endif
// new from V3.6- will reallocate the hardware interrupt stack...
// default stackLen will be 3000 bytes...
// ■ returns 1 on success.
// ■ returns 0 on failure.
int ISC::reallocStack(unsigned StackLen)
{
StackFrameLen= StackLen;
delete[] StackFrame;
StackFrame= new char[StackLen];
return (StackFrame)?1:0;
}
ISC::ISC (void)
{
NewServerPtr= NULL;
InitFlag= 0; // not initiated yet.
ISCcount++;
// put up a stack frame if not already up.
if ((!StackFrame) && (StackFrameLen)) {
StackFrame= new char[(unsigned)StackFrameLen];
}
};
ISC::~ISC (void)
{
deactivate();
// kill stack if no more ISCs are present.
if (--ISCcount<= 0) {
delete[] StackFrame;
StackFrame= NULL;
}
};