⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsr.cpp

📁 多任务操作系统控制的DOS环境下的实现的C语言源程序。 利用时间片的方式
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//--------------------------------------------------------------------------
//
//      TSR.CPP: body of DOS TSR class.
//      Copyright (c) J.English 1993.
//      Author's address: je@unix.brighton.ac.uk
//
//      Permission is granted to use copy and distribute the
//      information contained in this file provided that this
//      copyright notice is retained intact and that any software
//      or other document incorporating this file or parts thereof
//      makes the source code for the TSR class of which this file
//      is a part freely available.
//
//--------------------------------------------------------------------------
//
//      Note: this class is highly DOS specific and hence non-portable.
//      It also involves the use of assembly language and interrupt
//      functions, so it is also very compiler-specific.  Will require
//      modifications for use with compilers other than Borland C++ 3.0
//      or later.  If Borland compilers prior to version to version 3.0
//      are used, note that they do not support nesting of types within
//      classes (so TSR::F1 etc. will need changing to a global name F1)
//      and that the "_chain_intr" function used here was introduced with
//      version 3.0.
//
//      Revision history:
//      1.0     March 1993      Initial coding
//
//--------------------------------------------------------------------------

#include "tsr.h"
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <bios.h>

//--------------------------------------------------------------------------
//
//      Constants.
//
const int  MIN_STACK  = 512;            // minimum stack size in bytes
const int  ALT_FKEY   = 0x68 - TSR::F1; // hotkey change for Alt-Fn
const int  CTRL_FKEY  = 0x5E - TSR::F1; // hotkey change for Ctrl-Fn
const int  SHIFT_FKEY = 0x54 - TSR::F1; // hotkey change for Shift-Fn
const long DAY_LENGTH = 1573040L;       // length of day in timer ticks

const char far* COPYRIGHT = "C++ TSR class, Copyright (c) J.English 1993";
                                        // copyright notice for self-identify

//--------------------------------------------------------------------------
//
//      Global (static) variables.
//
static TSR* instance = 0;               // pointer to the TSR instance
static char TSRname [32];               // TSR identifying string
static unsigned char hotshift;          // shift state for hotkey
static unsigned char hotscan;           // scancode for hotkey
static int interval;                    // length of timeslice in timer ticks
static int TSRfunction;                 // Int 2F function used to find TSR

static char far* stack;                 // stack for TSR execution
static unsigned stacklen;               // size of TSR stack in bytes
static unsigned pspseg;                 // saved PSP segment
static unsigned dtaseg;                 // saved DTA segment
static unsigned dtaoff;                 // saved DTA offset
static volatile char far* indos;        // saved INDOS flag address
static volatile char far* critical;     // saved critical error flag address

static volatile int diskflag   = 0;     // set if disk interrupt in progress
static volatile int breakflag  = 0;     // set if ctrl-break has been pressed
static volatile int hotkeyflag = 0;     // set if hotkey pressed
static volatile int TSRrequest = 0;     // set if TSR should wake up
static volatile int TSRactive  = 0;     // set if TSR already active
static volatile long nexttick  = 0;     // next timer tick to wake up at

static volatile long far* timer    = (volatile long far*) MK_FP(0x40,0x6C);
static volatile char far* midnight = (volatile char far*) MK_FP(0x40,0x70);
                                        // timer values in BIOS data area

//--------------------------------------------------------------------------
//
//      Functions and function pointers.
//
typedef void interrupt (*Handler)(...); // interrupt handler address type

static Handler oldint8;                 // old int 8 vector  (timer)
static Handler oldint9;                 // old int 9 vector  (keyboard)
static Handler oldint13;                // old int 13 vector (disk)
static Handler oldint21;                // old int 21 vector (DOS services)
static Handler oldint23;                // old int 23 vector (control-break)
static Handler oldint24;                // old int 24 vector (critical error)
static Handler oldint28;                // old int 28 vector (DOS scheduler)
static Handler oldint2F;                // old int 2F vector (multiplex)

static int unhook ();                   // unload function used by int 2F

//--------------------------------------------------------------------------
//
//      Compare two far strings.
//
//      This is the same as "strcmp" except that we need a function to
//      compare far pointers in all memory models, and "strcmp" only
//      handles near pointers in the small and medium models.
//
int compare (const char far* a, const char far* b)
{
    while (*a == *b)
    {   if (*a == '\0')
            return 0;
        a++, b++;
    }
    return *a - *b;
}



//--------------------------------------------------------------------------
//
//      Check if a key has been pressed.
//
//      This nasty little routine is necessary because bioskey(1) does
//      not recognise extended keyboards and will swallow keystrokes
//      such as "ctrl-del" not supported on 84-key keyboards.  This
//      makes it necessary to use bioskey(0x11) instead, but there
//      is a problem in that this function does not leave AX clear
//      if no key has been pressed (it just sets the zero flag) so
//      some assembler is needed to deal with this.  It also means
//      this library will not work with old (pre-AT) BIOSes that
//      don't support int 16h, function 11h.
//
int check_key ()
{
    asm {
        mov ah,0x11;        // do function 11h,
        int 0x16;           // ... int 16h
        jnz key_found;      // skip if a key has been pressed
        mov ax,0;           // else set AX = 0
    };
  key_found:
    return _AX;
}

//--------------------------------------------------------------------------
//
//      Int 08 (timer) handler.
//
//      This handler first calls the original timer handler and then
//      checks if either timeslicing has been selected or the hotkey
//      has been pressed (as shown by "hotkeyflag").  If so, the TSR
//      request flag is set.  If DOS is in a safe state, the TSR is
//      then activated.
//
static void interrupt TSRint8 ()
{
    // chain to old int 8
    oldint8 ();

    // exit if TSR is already running
    if (TSRactive)
        return;

    // amend "nexttick" if midnight has passed
    if (*midnight != 0 && nexttick >= DAY_LENGTH)
        nexttick -= DAY_LENGTH;

    // check if TSR should be activated
    if (hotkeyflag == 0 && (interval == 0 || (*timer - nexttick) < 0))
        return;

    // set request flag if so
    TSRrequest = 1;

    // reset timer if past last activation period
    if (interval != 0 && (*timer - nexttick) >= 0)
        nexttick += interval;

    // activate TSR if DOS is safe
    if (*indos == 0 && *critical == 0 && diskflag == 0)
        activate ();
}

//--------------------------------------------------------------------------
//
//      Int 09 (keyboard) handler.
//
//      This handler first calls the original keyboard handler (with
//      interrupts enabled) and then looks to see if the keys pressed
//      match the hotkey.  If so, "hotkeyflag" is set.  If a keycode
//      is included in the hotkey code (i.e. it is not just a set of
//      shift keys only) the key is removed from the keyboard buffer.
//
static void interrupt TSRint9 ()
{
    // chain to old int 9
    asm { sti; }
    oldint9 ();

    // check if TSR uses hotkey
    if (hotshift == 0 && hotscan == 0)
        return;

    // check if hotkey modifier keys are pressed
    if ((bioskey(2) & 0x0F) != hotshift)
        return;

    // check if hotkey (if any) has been pressed
    if (hotscan == 0 || (check_key() >> 8) == hotscan)
    {   hotkeyflag = 1;
        if (hotscan != 0)
            bioskey (0x10);
    }
}

//--------------------------------------------------------------------------
//
//      Int 13 (disk) handler.
//
//      This handler sets a flag to show that a (time-critical) disk
//      transfer is in progress and then calls the original disk handler.
//      It is declared as a far non-interrupt function, although it will
//      be called as an interrupt handler; the code here does not affect
//      any registers, and we want the flag settings from the original
//      disk handler to be returned to the caller.
//
//      On entry, BP has been pushed on the stack.  DS must be set up
//      so that "diskflag" and "oldint13" can be accessed, so DS is
//      pushed on the stack and the BP is used to reset it.  On exit,
//      DS and BP are popped from the stack and we return via a RETF 2
//      which will throw away the flag register on the stack below the
//      return address.
//
//      The code here is highly dependent on the compiler-generated entry
//      sequence, so CHECK WITH CARE if any compiler other than Borland
//      is being used!
//      
static void far TSRint13 ()
{
    // set correct data segment
    asm { push ds; mov bp,seg diskflag; mov ds,bp; }

    // set flag while disk operation in progress
    diskflag = 1;

    // chain to old int 13
    oldint13 ();

    // clear disk flag
    diskflag = 0;

    // return using "retf 2" to leave flags intact
    asm { pop ds; pop bp; retf 2; }
}

//--------------------------------------------------------------------------
//
//      Int 21 (DOS service) handler.
//
//      This handler is installed immediately prior to activating the
//      TSR, and checks that the TSR does not call any unsafe services.
//      The unsafe services are 00-0C (character I/O services), 3E (close
//      file) for standard handles (0-4), 48 (allocate memory) and 4C
//      (terminate process), or functions above 0C if a critical error
//      is being handled.  If any of these are called from the TSR, the
//      virtual function "dos_error" will be called with the service
//      number as a parameter.  All other calls are passed to DOS in
//      the normal way.
//
static void interrupt TSRint21 (unsigned,    unsigned,    unsigned,
                                unsigned,    unsigned,    unsigned,
                                unsigned,    unsigned bx, unsigned ax,
                                unsigned ip, unsigned cs)
{
    // static flag keeps track of whether called from "dos_error"
    static int dosflag = 0;
    
    // ignore DOS calls from within "dos_error"
    if (dosflag != 0)
        return;

    // trap and ignore unsafe calls
    const unsigned ah = ax >> 8;
    if ((!*critical && (ah <= 0x0C || ah == 0x48 || ah == 0x4C
                        || (ah == 0x3E && bx <= 4)))
        || (*critical && ah > 0x0C))
    {   dosflag = 1;
        instance->dos_error (ah, *critical, cs, ip);
        dosflag = 0;
        return;
    }

    // chain to old handler for safe calls
    _chain_intr (oldint21);
}

//--------------------------------------------------------------------------
//
//      Int 23 (control-break) handler.
//
//      This handler is installed immediately prior to activating the
//      TSR.  It just sets a flag to record that control-break has been
//      pressed.  The main TSR function can poll this flag using the
//      member function "userbreak", which returns the flag value and
//      also resets the flag.
//
static void interrupt TSRint23 ()
{
    breakflag = 1;
}



//--------------------------------------------------------------------------
//
//      Int 24 (critical error) handler.
//
//      This handler is installed immediately prior to activating the
//      TSR.  It just calls the virtual function "critical_error" to
//      deal with the error.
//
static void interrupt TSRint24 (unsigned, unsigned di, unsigned,
                                unsigned, unsigned,    unsigned,
                                unsigned, unsigned,    unsigned ax)
{
    ax = instance->critical_error (di & 0x00FF);
    if (ax == 2 || ax > 3)
        ax = 3;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -