[comp.sys.ibm.pc] Dos File Access In TSR's

chris@wbcs.UUCP (Chris Rott) (06/21/89)

I want to write a TSR program that periodically wakes up and accesses a file
(using DOS services).  The purpose of accessing the file is to update the
time stamp.  I know how to set up the TSR and to set alarm interrupts and all,
but I suspect I will have problems if I just invoke dos services inside this
interrupt.  Has anyone had experience writing these kind of TSR's?  Are there
flag bytes somewhere that indicate whether or not DOS is in a 'safe' state in
terms of disk i/o.  I know that these kind of programs are possible, given that
the print queue manager provides asynchronous i/o, but I cant find any docs on
how to do it.  Any help would be greatly appreciated!  Please email responses.
Thanks in advance for your help.
-- 
Chris Rott	Boeing Computer Services
MAIL: PO Box 7730, MS K79-32 / Wichita, KS 67277-7730
UUCP: {scubed!ncr-sd,fenix!ncrlnk,hplabs!hp-sdd!ncr-sd}!ncrwic!wbcs!chris

craigb@hp-sdd.hp.com (Craig Bosworth) (06/22/89)

The only thing I know about this is that DOS functions are not
reentrant.  So, if your TSR wakes up while DOS is executing a 
function, you could kill things very easily.  If you could 
check an "in DOS" flag, you could wait until the next timer
tick, check the flag again, and make your DOS calls when that 
flag is clear...

I (obviously) don't know much about this, but I would be very
interested in finding out.  Please post! :-)

BOS

lance@helios (Lance Bresee) (06/22/89)

Isn't there a dos routine which sets the date stamp on a file?
If so, you can get this vector, and have your tsr execute a far jump..
and the end of the routine, there will be an iret instruction, so
dos will jump back to the application rather than back to your
tsr.....
Also, I believe that the interrupt hierarchy makes it impossible to
interrupt a disk read...you may want to check on this though.....
lance..

gharring@enprt.Wichita.NCR.COM (Gary Harrington) (06/23/89)

In article <157@wbcs.UUCP> chris@wbcs.UUCP (Chris Rott) writes:
>I want to write a TSR program that periodically wakes up and accesses a file
>(using DOS Services).

To allow a TSR program to operate safely (and even do file I/O) without 
having to worry about DOS re-entrancy problems, several undocumented 
features of DOS can be used.  These undocumented DOS features are:

        1.  The COMMAND.COM Background Task:  INT 28h is called by
            COMMAND.COM while it is waiting for input from the keyboard.
            During this time, the "In-DOS" flag (explained below)
            will be non-zero, but you can make DOS calls safely.

        2.  The "In-DOS" flag:  A far pointer to this byte is returned
            in ES:BX by function 34h of INT 21h.  The byte is non-zero
            whenever the processor is executing code within DOS, and 
            implies that you should not try to invoke DOS (re-entrantly) 
            at the moment (except via INT 28h).

        3.  Get Current PSP: The paragraph address of the current PSP 
            is returned in BX by function 51h of INT 21h.

        4.  Set Current PSP:  You can switch to another PSP by loading 
            BX with the paragraph address of the new PSP and executing 
            function 50h of INT 21h.

Note that (3) and (4) above are required for DOS to maintain certain 
information in the PSP of the running program that relates to files - 
more specifically file handles.

Some of the Essential Elements of a TSR that wants to do file I/O are:

----------
Before Terminating and Staying Resident, it should intercept three system
interrupts by installing its own interrupt vectors and code for these
interrupts:

        INT 13h - the BIOS disk I/O interrupt

        INT 1Ch - the system timer tick interrupt

        INT 28h - the Background Task interrupt

----------
Some of the TSR's program code might go something like this:

====================
|       TSR Wake-Up routine
+-------------------
|       save current stack
|       switch to your own stack
|       save all registers
|       save current PSP  (use INT 21h func 51h to get current PSP)
|       establish (set) your own PSP  (use INT 21h func 50h)
|       [do whatever processing you have to do]
|       if you need to do file I/O, then:
|          set an I/O_REQUEST flag
|          continue processing until you require the I/O to be done
|          wait until the I/O_REQUEST flag has been reset
|       restore the old PSP  (INT 21h func 50h)
|       restore the old registers
|       restore the old stack
|       IRET
|
+===================
|       New INT 13h Interrupt (disk I/O)
+-------------------
|       set DISK_BUSY flag to BUSY
|       call the original INT 13
|       set DISK_BUSY flag to NOT_BUSY
|
+===================
|       New INT 1Ch Interrupt (timer tick)
+-------------------
|       IF the I/O_REQUEST flag is set, and
|          IF the DISK_BUSY flag indicates disk is NOT_BUSY, and
|             IF DOS is not in a critical handling section,
|                THEN do the file I/O (and reset the I/O REQUEST flag)
|       call the original INT 1C
|
+===================
|       New INT 28h Interrupt (Background Task)
+-------------------
|       IF the I/O_REQUEST flag is set
|          THEN do the file I/O (and reset the I/O REQUEST flag)
|       call the original INT 28
|
====================

And, of course, before doing the file I/O within INTs 1Ch and 28h, you
would need to switch stacks, save registers, and set your own PSP.

Not included here are the Critical Error (INT 24h), Ctrl-Break (INT 23h),
and Terminate Address (stored in interrupt vector 22h) handlers which
you may want to add for a more complete TSR implementation.

Would any of you TSR experts care to change or fix any of the above?

Gary.Harrington@ncrwic.UUCP
(Wichita, Kansas)

news@crdgw1.crd.ge.com (USENET News System) (06/23/89)

up articles mentioned checking the INDOS flag.  It is true that this
flag and the Critical Error flag both must be zero before one can
safely do I/O in an asychronous fashion.  Be aware that the INDOS flag
only protects int 21.  Other parts of DOS are not reentrant as well.
In particular you don't want to mess with int 25 and int 26 (stack switching)
and hard disk access (controller set up).  IBMDOS executes int 28h
when it is in a keyboard polling loop (caused by int 21h ah <0ch).  It
is safe to issue another dos request (ah>0ch) from an int 28h isr.  The
critical section flag will be SET at this time,  but it is ok to make
the request.
From: dixon@sagittarius.crd.ge.com (walt dixon)
Path: sagittarius!dixon

Before doing any i/o from a TSR you should set up your on critical error/
break handlers,  and you must change the PSP (int 21h ah=50h -- undocumented).
If you want further info look at Chapter 4 of "The MSDOS Developers Guide,
2nd Ed.", (Sams, 1988).  BTW I am the author of that chapter.  I get no
royalties from sales, etc.  I'm just citing a good reference.

Walt Dixon		{arpa:		dixon@crd.ge.com	}
			{us mail:	ge crd			}
			{		po box 8		}
			{		schenectady,  ny 12345	}
			{phone:		518-387-5798		}


-- 
--
Bruce G. Barnett  <barnett@ge-crd.ARPA> <barnett@steinmetz.ge.com>
		uunet!steinmetz!barnett

Ralf.Brown@B.GP.CS.CMU.EDU (06/23/89)

In article <8064@saturn.ucsc.edu>, lance@helios (Lance Bresee) writes:
}Isn't there a dos routine which sets the date stamp on a file?

Yes.

}If so, you can get this vector, and have your tsr execute a far jump..
}and the end of the routine, there will be an iret instruction, so
}dos will jump back to the application rather than back to your
}tsr.....

Doesn't work that way.  The DOS function call INT 21h does the following:
        setup
        indirect call to actual function handler
           function executes
           RET
        cleanup
        IRET
Besides, DOS is not reentrant, so you couldn't just call or jump to the
appropriate routine without first making sure that it is safe to call DOS.  If
you do that, you might as well just call DOS normally once you are sure it is
safe.

}Also, I believe that the interrupt hierarchy makes it impossible to
}interrupt a disk read...you may want to check on this though.....

Nope, disk reads/writes can be interrupted.  For a floppy disk or XT hard
drive, the basic sequence of events is
        seek to proper track, if necessary
        set up floppy controller
        set up DMA controller
        clear completion flag
        start DMA transfer
        loop until completion flag set
        loop until completion flag set
        loop until completion flag set
             DISK INTERRUPT: handler sets completion flag
        loop until completion flag set: loop terminates
        IRET
During this entire time, interrupts are enabled (have to be to allow the disk
interrupt).  The disk interrupt is not even at a very high priority.  The
floppy interrupt is IRQ6, and the XT hard drive is IRQ5.  The only thing with
a lower priority is the printer interrupt on IRQ7.

For an AT hard drive, the basic sequence of events is
        seek to proper track, if necessary
        set up HD controller
        REP INSW  or REP OUTSW     <- transfer data using the CPU
        IRET
Again, interrupts are enabled during the process.

DESQview 2.2 has no problems task-switching during heavy floppy access, such
as a large file copy or format.  Previous versions did not task switch during
floppy access, but that appears to have been a design decision (there is a
poorly-documented flag for DV 2.2 to disable task-switching during disk
accesses).

--
UUCP: {ucbvax,harvard}!cs.cmu.edu!ralf -=-=-=- Voice: (412) 268-3053 (school)
ARPA: ralf@cs.cmu.edu  BIT: ralf%cs.cmu.edu@CMUCCVMA  FIDO: Ralf Brown 1:129/46
			Disclaimer? I claimed something?
"When things start going your way, it's usually because you stopped going the
 wrong way down a one-way street."

Ralf.Brown@B.GP.CS.CMU.EDU (06/23/89)

In article <491@enprt.Wichita.NCR.COM>, gharring@enprt.Wichita.NCR.COM (Gary Harrington) writes:
}To allow a TSR program to operate safely (and even do file I/O) without 
}having to worry about DOS re-entrancy problems, several undocumented 
}features of DOS can be used.  These undocumented DOS features are:
}
}        1.  The COMMAND.COM Background Task:  INT 28h is called by
}            COMMAND.COM while it is waiting for input from the keyboard.

Minor nit: this is internal to IBMDOS.COM.  Any program that calls the
buffered input (INT 21/AH=0Ah), such as DEBUG or EDLIN, will cause INT 28h to
be called repeatedly while the INT 21h call is waiting for keystrokes.

--
UUCP: {ucbvax,harvard}!cs.cmu.edu!ralf -=-=-=- Voice: (412) 268-3053 (school)
ARPA: ralf@cs.cmu.edu  BIT: ralf%cs.cmu.edu@CMUCCVMA  FIDO: Ralf Brown 1:129/46
			Disclaimer? I claimed something?
"When things start going your way, it's usually because you stopped going the
 wrong way down a one-way street."

everett@hpcvlx.HP.COM (Everett Kaser) (06/24/89)

Besides checking the INDOS flag to see if DOS is busy, you also need to check
the IN_CRITICAL_ERROR flag, which (in DOS 3.x anyway) is usually the byte
immediately preceding the INDOS flag.  If the "foreground" program does a DOS
call to open a file, for example, and a critical error occurs, DOS clears the
INDOS flag and sets the IN_CRITICAL_ERROR flag.  If, at that point, the INT 1C
vector get's called (because the 18.2 Hz timer interrupt occurred), the INDOS
flag will indicate that DOS is not busy, when in reality it is.  Granted, this
is a border case, but it CAN occur and will crash your system at very random
times, and is almost impossible to track down if you don't know about it.

Additionally, if you come into your "background" TSR routine (through INT 28 or
INT 1C or however) and everything is in the proper state to allow you to call
DOS, you DO need to save and take the CRITICAL ERROR and CTRL-C interrupt
vectors, execute your code, then restore those two vectors (along with 
everything else) before exiting your "background" service routine.  The reason
for this is that if you do a DOS call that causes a critical error (such as a
disk not being in drive A, etc.) and you HAVEN'T taken the criterr vector, the
user will get an ABORT, RETRY, FAIL message, and if he FAILs it, DOS will 
terminate your TSR program, leaving all the interrupt vectors pointing into
space, and your system will crash.  Similarly, if the user hits CTRL-C (think-
ing that he is CTRL-C'ing the "foreground" program, but actually nailing your
"background" program), again, DOS will terminate your TSR and your system will
crash.

Everett Kaser
!hplabs!hp-pcd!everett
everett%hpcvlx@hplabs.hp.com

ralerche@lindy.Stanford.EDU (Robert A. Lerche) (06/24/89)

There is extensive documentation of the techniques for writing TSR's that
can access the DOS file system from interrupts in

	The MS-DOS Encyclopedia
	Microsoft Press, 1988

(Yes, they _did_ finally document it... thank you, Microsoft!)

rdas@hatter.Tops.Sun.COM (Robin Das) (06/24/89)

In article <157@wbcs.UUCP> chris@wbcs.UUCP (Chris Rott) writes:
>I want to write a TSR program that periodically wakes up and accesses a file
>(using DOS services).  The purpose of accessing the file is to update the
>time stamp.  I know how to set up the TSR and to set alarm interrupts and all,
>but I suspect I will have problems if I just invoke dos services inside this
>interrupt.  Has anyone had experience writing these kind of TSR's?  Are there
>flag bytes somewhere that indicate whether or not DOS is in a 'safe' state in
>terms of disk i/o.  I know that these kind of programs are possible, given that
>the print queue manager provides asynchronous i/o, but I cant find any docs on
>how to do it.  Any help would be greatly appreciated!  Please email responses.
>Thanks in advance for your help.

Before your TSR calls DOS (and don't use the standard library calls -- call the
interrupt directly), check the DOS BUSY flag.  If it is set, return control to the
program running before your TSR got control.  If it is not set, you will be all set to
make DOS calls.

Here is how you get the address of the DOS BUSY flag:

mov		ah, 34h
int		21h

es:bx contains the address of the DOS BUSY flag.  If it is '0', DOS can be called.