home *** CD-ROM | disk | FTP | other *** search
- /**
- *
- * Name ivinstal -- Install intervention function
- *
- * Synopsis ercode = ivinstal(pfunc,pident,pstack,stksize,
- * pkeytable,numkeys,ptimetable,numtimes,
- * option);
- *
- * int ercode Zero if correctly installed; other values
- * include:
- * IV_INSTALLED - Already installed.
- * void cdecl (*pfunc)(IV_EVENT *)
- * Address of intervention function to be
- * installed.
- * char *pident Pointer to array of 16 bytes of
- * identifying information
- * char *pstack Address of beginning of memory block
- * (already allocated) to be used for the
- * intervention function's stack
- * int stksize Size (in bytes) of the stack
- * (must be at least 64 bytes).
- * IV_KEY *pkeytable Address of array of IV_KEY structures
- * listing hot keys.
- * int numkeys Number of hot keys listed.
- * IV_TIME *ptimtable
- * Address of array of IV_TIME structures
- * listing timer events.
- * int numtimes Number of timer events listed.
- * int option Requirements of the intervention
- * function. Three bits are relevant
- * (all other bits should be zero):
- *
- * Symbol Meaning
- * --------------- ----------------------------
- * IV_DOS_NEED DOS functions used.
- * IV_NO_DOS_NEED No DOS functions used.
- *
- * IV_DKEY_NEED DOS functions 1-12 used.
- * IV_NO_DKEY_NEED DOS functions 1-12 not used.
- *
- * IV_FLOAT_NEED Reinstall floating point vectors
- * upon invocation.
- * IV_NO_FLOAT_NEED No need to reinstall floating
- * point vectors.
- *
- * IV_DAILY Repeat moment events daily.
- *
- *
- * Description This function installs an intervention function (*pfunc)
- * and arranges for it to be invoked when a hot key is
- * pressed or when a given time of day passes.
- *
- * The hot key(s) (if any) are specified by one or more
- * IV_KEY structures which describe the character value and
- * scan code of the key and the action to be taken if the
- * key is pressed:
- *
- * to invoke the intervention function;
- * to put the intervention function to sleep; or
- * to wake the intervention function from sleep.
- *
- * The array of IV_KEY structures can be moved or changed
- * in size by modifying the pkeytab and ktsize members in
- * the intervention control block (which is defined in
- * IVCTRL.ASM). (Turn interrupts off while doing so.)
- *
- * The timer event(s) (if any) are specified by one or more
- * IV_TIME structures which describe whether each event is
- * a specific time of day ("moment events") or whether it
- * will recur periodically ("interval events"). Each
- * IV_TIME structure specifies a number of clock ticks to
- * indicate the specific time of day or the period between
- * invocations. The array of IV_TIME structures must not
- * be moved as long as the intervention function is
- * installed.
- *
- * Timer events that are scheduled for a specific time of
- * day are repeated daily if IV_DAILY is specified.
- * Without IV_DAILY, moment events can be invoked only once
- * unless their time of day is modified.
- *
- * The IV_DAILY rescheduling takes place whenever the time
- * of day gets set back (as it normally does at midnight).
- * If a user sets the system time back manually, events
- * scheduled for earlier in the day will recur immediately.
- * To avoid an event occurring more than once in a day, you
- * may wish to check the system date in your intervention
- * function.
- *
- * The calling function must allocate space for the
- * intervention function's stack and pass its address as
- * pstack. This space must be static as long as the
- * intervention function is installed. 2048 bytes is a
- * typical stack size, but more may be needed if the
- * intervention function (or any function invoked by it)
- * has large local arrays.
- *
- * Two bits of "option" must be set to indicate how the
- * intervention function uses DOS functions (if at all).
- * If the intervention function uses DOS and these bits are
- * incorrect, serious system malfunctions will result. If
- * option indicates that DOS functions are used, then the
- * intervention function will not be invoked as frequently
- * as if option were zero.
- *
- * The IV_FLOAT_NEED option causes the floating point
- * interrupt vectors (if used by the floating point math
- * library) to be temporarily reloaded whenever the
- * intervention function is invoked. Use the IV_FLOAT_NEED
- * option if the following conditions are all met:
- *
- * 1) your intervention function (*pfunc) uses floating
- * point arithmetic;
- * 2) your program may be linked with a math library
- * that installs interrupt vectors (see the README.DOC
- * file for instructions);
- * 3) your intervention function may be invoked while
- * other programs are running.
- *
- * If condition (1) is met, it may be safest to specify
- * IV_FLOAT_NEED without regard to the other two
- * conditions.
- *
- * The sixteen bytes of identifying information are stored
- * in the intervention control block to permit other
- * applications to detect this program. (See IVSENSE.C for
- * an example of this.)
- *
- * The global variable b_ivmask lists the intervention
- * filters that will be installed.
- *
- * Warning Do not specify IV_TM_NONE for any of the timer events.
- *
- * Returns ercode The return code is 0 if the vector is
- * is successfully set; other values
- * include:
- * IV_INSTALLED - Already installed.
- *
- * Version 6.00 (C)Copyright Blaise Computing Inc. 1987-1989
- *
- **/
-
- #include <dos.h> /* For use with isgetvec(), */
- /* isputvec(), REGS, and int86()*/
-
- #include <binterv.h>
- #include <bintrupt.h>
- #include <bkeybrd.h>
-
- int b_ivusex = KB_USE_EXTEND; /* Whether to use extended */
- /* keyboard services when */
- /* testing for hot keys: */
- /* KB_USE_EXTEND or */
- /* KB_USE_NORMAL. */
-
- extern void ivtimer(void); /* Intervention code filters */
- extern void ivkeybd(void); /* (in ISCTRL.ASM) */
- extern void ivcom2(void);
- extern void ivcom1(void);
- extern void ivdisk(void);
- extern void ivdos(void);
- extern void ividle(void);
-
- extern void ivbiosky(void); /* These two filters are */
- extern void ivcbreak(void); /* installed by the scheduler */
- /* before invoking the */
- /* intervention function and */
- /* removed after it exits. */
-
- /* Local variables used by scheduler, initialized by installer. */
-
- static IV_CTRL far *pctrl = FARNIL; /* Pointer to internal values */
- /* used by filters. */
- /* */
- static IV_TIME *ptimtab; /* Address and size of user's */
- static int timtabsize; /* table of timer events. */
- static int timindex; /* Index of found timer event. */
- static int timaction; /* Type of timer action last */
- /* requested. */
- static long idleticks; /* Clock ticks since last */
- /* service. */
- static long lasttime; /* Time of last call. */
- /* */
- static int daily; /* Whether to reschedule moment */
- /* events daily. */
- /* */
- static void /* Pointer to user's */
- (*ptask)(IV_EVENT *); /* intervention function. */
- /* */
- static unsigned char /* Pointer to interrupt 0x24 */
- far *pint24h_flag; /* busy flag. */
-
- #if (IS_NUM_FLOAT_VECS > 0)
- static char float_need;
- /* Storage for floating point */
- /* vectors. */
- static void far *float_vec[IS_NUM_FLOAT_VECS];
- #endif
-
- /* Internal functions */
- static void scheduler(ALLREG *,ISRCTRL *,ISRMSG *);
- static void timer_req(void);
- static int readytask(void);
- static void unschedule(void);
- static void reschedule(void);
-
-
- int ivinstal(pfunc,pident,pstack,stksize,
- pkeytable,numkeys,ptimetable,numtimes,option)
- void (*pfunc)(IV_EVENT *);
- const char *pident;
- char *pstack;
- int stksize;
- IV_KEY *pkeytable;
- int numkeys;
- IV_TIME *ptimetable; /* This table must not move. */
- int numtimes;
- int option;
- {
- int ints_were_on,i;
- IV_VECTORS vecs;
- unsigned int i24_seg,i24_offset;
- static ISRCTRL schedblk = {0}; /* ISR control block for */
- /* scheduler. */
-
- pctrl = ivctrl(); /* Find intervention control */
- /* structure. */
-
- ints_were_on = utintflg(UT_INTOFF); /* Prevent interrupts while */
- /* checking enabled state. */
- if (pctrl->enabled) /* */
- { /* Error: this function must */
- utintflg(ints_were_on); /* not be used more than once. */
- return IV_INSTALLED; /* */
- } /* */
- pctrl->enabled = 1; /* Prevent second use. */
- utintflg(ints_were_on); /* Restore interrupt state. */
-
- /* Initialize local variables used by scheduler. */
-
- ptask = pfunc; /* Address of user's */
- /* intervention function. */
- ptimtab = ptimetable; /* Address and size of user's */
- timtabsize = numtimes; /* table of timer events. */
- timindex = -1; /* Index of found timer event. */
- timaction = IV_TM_NONE; /* Type of timer action last */
- /* requested. */
- idleticks = 0L; /* Clock ticks since last */
- /* service. */
-
- if (option & IV_DAILY)
- { /* Moment events happen once */
- /* daily. */
- utgetclk(&lasttime); /* Start time for reschedule(). */
- unschedule(); /* Cancel today's events whose */
- /* time has passed. */
- daily = 1;
- }
- else
- daily = 0;
-
- #if (IS_NUM_FLOAT_VECS > 0)
- float_need = (char)(0 != (option & IV_FLOAT_NEED));
- /* Save floating point vectors */
- for (i = 0; i < IS_NUM_FLOAT_VECS; i++)
- float_vec[i] = isgetvec(IS_1ST_FLOAT_VEC + i);
- #endif
-
- /* Set up ISR control block through which the scheduler will be */
- /* called. */
-
- isprep(scheduler,"TCT6.00 INTSCHED",&schedblk,pstack,stksize,1);
-
- /* Initialize most items in intervention control structure. */
-
- pctrl->psp = utpspseg; /* PSP of this program. */
- /* */
- ivvecs(IV_RETVEC,&pctrl->prev_vec); /* Save previous contents of */
- /* interrupt vectors. */
- /* */
- /* Set the dos_need flag if */
- /* either the IV_DOS_NEED or */
- /* IV_DKEY_NEED bit is set. */
- pctrl->dos_need = (char)
- (0 != (option & (IV_DOS_NEED | IV_DKEY_NEED)));
- pctrl->dkey_need = (char)(0 != (option & IV_DKEY_NEED));
-
- pctrl->pkeytab = pkeytable; /* Address and size of user's */
- pctrl->ktsize = numkeys; /* table of hot keys. */
-
- pctrl->key_event.ch = 0; /* No hot key found yet. */
- pctrl->key_event.keycode = 0;
- pctrl->key_event.action = IV_KY_NONE;
-
- if ( b_ivusex == KB_USE_NORMAL
- || kbequip() == KB_NOEXTENDED)
- pctrl->kb_ext = 0; /* Use normal keyboard services.*/
- else
- pctrl->kb_ext = 1; /* Extended keyboard services. */
-
- pctrl->wait = 0; /* INT 21h and INT 28h filters */
- /* don't need to be in wait */
- /* loop yet. */
- pctrl->req = 0; /* No service yet requested. */
- pctrl->awake = 1; /* Intervention code is not */
- /* asleep. */
- pctrl->timer_busy = 0; /* Clear the busy flags. */
- pctrl->kb_busy = 0;
- pctrl->com2_busy = 0;
- pctrl->com1_busy = 0;
- pctrl->disk_busy = 0;
- pctrl->idle_busy = 0;
-
- pctrl->idle_safe = 0;
-
- /* Entry point to scheduler. */
- pctrl->pschedblk = ((char far *)(&schedblk)) + ICB_ENTRY_OFFSET;
-
- utcrit(); /* Address of DOS critical */
- pctrl->pdos_crit = b_critad; /* section flag (busy flag). */
-
- /* Address of interrupt 0x24 */
- if (utdosmajor < 3) /* busy flag. */
- i24_offset = utoff(b_critad) + 1;
- else if (utdosver == 0x0300)
- i24_offset = 0x0167;
- else
- i24_offset = utoff(b_critad) - 1;
- i24_seg = utseg(b_critad);
- pint24h_flag = uttofaru(i24_seg,i24_offset);
-
- for (i = 0; i < sizeof(pctrl->_reserved); i++)
- pctrl->_reserved[i] = '\0';
-
- /* User's identifying string. */
- utmovmem(pident,pctrl->ident,sizeof(pctrl->ident));
-
- /* Identifying signature. */
- pctrl->signature = (unsigned int)IV_SIGNATURE;
- pctrl->sign2 = (unsigned int)~IV_SIGNATURE;
-
- /* Install the filters. This will activate the intervention */
- /* function. */
-
- pctrl->filter_mask = b_ivmask;
- vecs.ptimer = ivtimer;
- vecs.pkeybd = ivkeybd;
- vecs.pdisk = ivdisk;
- vecs.pdos = ivdos;
- vecs.pidle = ividle;
- vecs.pcom1 = ivcom1;
- vecs.pcom2 = ivcom2;
- ivvecs(IV_SETVEC,&vecs);
-
- return IV_NO_ERROR;
- }
-
- /**
- *
- * Name scheduler -- Invoke intervention function if appropriate
- *
- * Description This function checks whether the intervention function
- * is eligible to be invoked and invokes it if appropriate,
- * based on the time of day and whether DOS services are
- * necessary and available. It also maintains certain
- * fields in the intervention control block to control the
- * intervention filters.
- *
- * This function is built as an interrupt service routine
- * (ISR) to be called from the intervention timer filter
- * via the ISR dispatcher.
- *
- * Interrupts are enabled.
- *
- * Returns Members of intervention control block:
- *
- * wait Set to zero to release INT 21h and
- * INT 28h filters from wait loop.
- * awake Whether intervention code is asleep
- * or awake.
- * key_event The most recent detected hot key
- * is cleared.
- * req 1 to indicate that the intervention
- * function needs service but must wait
- * for DOS availability;
- * 0 to indicate that the intervention
- * function does not need service.
- *
- * Member of user's table of timer events:
- *
- * ptimetable[].ticks
- * If this event is a moment event,
- * the IV_RESCHED bit in the time of day
- * is set, effectively preventing
- * the event from occurring again.
- * At midnight, the bit is cleared.
- * (The user can reschedule the event
- * by changing the ticks member again.)
- *
- **/
-
- static void scheduler(pregs,pisrblk,pmsg)
- ALLREG *pregs;
- ISRCTRL *pisrblk;
- ISRMSG *pmsg;
- {
- IV_EVENT signal;
- void far *pint_1bh;
- unsigned oldproc;
- int dos_saved;
- char *p;
- #if (IS_NUM_FLOAT_VECS > 0)
- void far *save_float[IS_NUM_FLOAT_VECS];
- int float_switched;
- #endif
-
- p = (char *) pregs; /* Get rid of pesky compiler */
- p = (char *) pisrblk; /* warnings. */
- p = (char *) pmsg;
- p++;
-
- pctrl->wait = 0; /* Release INT 21h or INT 28h */
- /* filters if they are waiting.*/
-
- if ((!pctrl->awake) && pctrl->key_event.action != IV_KY_WAKE)
- return;
-
- if (daily) /* Reschedule yesterday's */
- reschedule(); /* moment events for today if */
- /* this is a new day. */
-
- if (timaction == IV_TM_NONE) /* If no timer action pending, */
- timer_req(); /* analyze time of day to see */
- /* whether a timer action */
- /* should be pending. */
-
- if ( pctrl->key_event.action != IV_KY_NONE
- || timaction != IV_TM_NONE)
- {
- if (readytask())
- { /* Now we know that we can */
- /* execute the task. */
- pctrl->req = 0;
- if (timaction == IV_TM_INTERVAL)
- idleticks = 0L;
- else if (timaction == IV_TM_MOMENT)
- /* Disable the event. */
- ptimtab[timindex].ticks |= IV_RESCHED;
- /* (The user can reschedule the */
- /* event by modifying the time */
- /* table.) */
-
- /* Build signal to tell user */
- /* task what event(s) */
- /* triggered the task. */
- utmovmem((char far *) &pctrl->key_event,
- (char far *) &signal.key,
- sizeof(IV_KEY));
- signal.time_action = timaction;
- signal.time_index = timindex;
- utgetclk(&signal.time);
-
- pctrl->cbreak = 0; /* No Ctrl-Break or Ctrl-C */
- /* encountered yet. */
-
- if (pctrl->dos_need) /* Take special precautions if */
- { /* DOS is used: */
-
- /* Prevent Ctrl-Break and */
- /* Ctrl-C. */
- pctrl->prev_16h_vec = isgetvec(0x16);
- pint_1bh = isgetvec(0x1b);
- isputvec(0x16,(void far *) ivbiosky);
- isputvec(0x1b,(void far *) ivcbreak);
- /* Set current process to point */
- /* to us. */
- if (utdosmajor >= 3)
- oldproc = iscurprc(IS_SETPROC,utpspseg);
- dos_saved = 1;
- }
- else
- dos_saved = 0;
-
- #if (IS_NUM_FLOAT_VECS > 0)
- if (float_need)
- {
- /* Save current floating point */
- /* vectors. */
- utintflg(UT_INTOFF);
- utpeekn(uttofar(0,4 * IS_1ST_FLOAT_VEC,char),
- save_float,
- sizeof(save_float));
- /* Reinstall our own floating */
- /* point vectors. */
- utpoken(float_vec,
- uttofar(0,4 * IS_1ST_FLOAT_VEC,char),
- sizeof(float_vec));
- utintflg(UT_INTON);
- float_switched = 1;
- }
- else
- float_switched = 0;
- #endif
-
-
- (*ptask)(&signal); /* Invoke the user task. */
-
-
- #if (IS_NUM_FLOAT_VECS > 0)
- if (float_switched)
- { /* Restore float vectors. */
- utintflg(UT_INTOFF);
- utpoken(save_float,
- uttofar(0,4 * IS_1ST_FLOAT_VEC,char),
- sizeof(save_float));
- utintflg(UT_INTON);
- }
- #endif
-
- if (dos_saved)
- {
- /* Restore current process. */
- if (utdosmajor >= 3)
- iscurprc(IS_SETPROC,oldproc);
- /* Restore former Ctrl-Break */
- /* and BIOS keyboard handling. */
- isputvec(0x1b,pint_1bh);
- isputvec(0x16,pctrl->prev_16h_vec);
- }
-
- if (pctrl->key_event.action == IV_KY_SLEEP)
- pctrl->awake = 0;
- else if (pctrl->key_event.action == IV_KY_WAKE)
- pctrl->awake = 1;
-
- pctrl->key_event.ch = 0;
- pctrl->key_event.keycode = 0;
- pctrl->key_event.action = IV_KY_NONE;
- timaction = IV_TM_NONE;
- }
- else
- pctrl->req = 1;
- }
-
- if (timaction != IV_TM_INTERVAL)
- idleticks++;
- }
-
- /**
- *
- * Name timer_req -- Scan table of timer events to find one
- * that is eligible for service.
- *
- * Synopsis timer_req();
- *
- * Returns timaction IV_TM_NONE if no timer event is
- * eligible;
- * IV_TM_MOMENT if a one-time event is
- * eligible;
- * IV_TM_INTERVAL if a periodic event is
- * eligible.
- * timindex Index of found event in user's table of
- * timer events. This is meaningless
- * if IV_TM_NONE is returned.
- *
- **/
-
- static void timer_req()
- {
- long now;
- int i;
-
- utgetclk(&now);
-
- for (i = 0;
- i < timtabsize && timaction == IV_TM_NONE;
- i++)
- {
- if ( ( ptimtab[i].action == IV_TM_MOMENT
- && ptimtab[i].ticks <= now)
- || ( ptimtab[i].action == IV_TM_INTERVAL
- && ptimtab[i].ticks <= idleticks))
- {
- timaction = ptimtab[i].action;
- timindex = i;
- }
- }
- }
-
- /**
- *
- * Name readytask -- Return nonzero if intervention function
- * is eligible for service.
- *
- * Synopsis ready = readytask();
- *
- * int ready 1 if intervention function can be
- * safely executed,
- * 0 if not.
- *
- **/
-
- static int readytask()
- {
- if (pctrl->idle_busy) /* We're inside an INT 28h call,*/
- { /* so DOS functions 1-12 aren't */
- /* available, but other DOS */
- /* functions are. */
- if (pctrl->idle_safe && !pctrl->dkey_need)
- return 1;
- else
- return 0;
- }
- /* We're not in an INT 28h call.*/
-
- else if (pctrl->dos_need) /* If intervention function */
- { /* needs any DOS or disk */
- /* functions, */
- if ( pctrl->disk_busy
- || !utdosrdy()
- || *pint24h_flag)
- return 0; /* Disk or DOS is busy so fail. */
- else
- return 1; /* Disk & DOS are available. */
- }
- else
- return 1;
- }
-
- /**
- *
- * Name unschedule -- Cancel for today all "moment" events
- * whose time has passed.
- *
- * Synopsis unschedule();
- *
- * Description This function sets the IV_RESCHED bit in all "moment"
- * events if necessary, preventing them from executing
- * today.
- *
- **/
-
- static void unschedule()
- {
- long now;
- int i;
-
- utgetclk(&now);
-
- for (i = 0; i < timtabsize; i++)
- if ( ptimtab[i].action == IV_TM_MOMENT
- && ptimtab[i].ticks < now)
- ptimtab[i].ticks |= IV_RESCHED;
- }
-
- /**
- *
- * Name reschedule -- Reschedule all "moment" events if
- * midnight has passed.
- *
- * Synopsis reschedule();
- *
- * Description This function clears the IV_RESCHED bit from all
- * "moment" events if necessary, allowing them to execute
- * again. It takes action only if the time of day is
- * observed to go backward (as it normally does at
- * midnight.)
- *
- **/
-
- static void reschedule()
- {
- long now;
- int i;
-
- utgetclk(&now);
-
- if (now < lasttime)
- { /* Time went backward, so this */
- /* must be a new day. */
- /* Reschedule all moment events.*/
- for (i = 0; i < timtabsize; i++)
- if (ptimtab[i].action == IV_TM_MOMENT)
- ptimtab[i].ticks &= ~IV_RESCHED;
- }
-
- lasttime = now; /* Save current time. */
- }