[comp.sys.ibm.pc] Dos Calls and Interrupts

mjbo@orstcs.UUCP (mjbo) (01/07/87)

Subject:  DOS calls from interrupts

---------------------------------------

I have read in several places, including the most recent BIX
section of Byte,  that it is not legal to call on DOS
services from an interrupt-service routine.
I would like to write a TSR program to hide in the
background and receive data from a serial port using
an interrupt routine to store the data in a buffer.
When the buffer fills, I would like to store the
data in a Hard-disk file dedicated to that purpose.
(sort of a print spooler in reverse).  Can this be done
safely?   If so, what restrictions are there on the
DOS file-handling calls?   Can a foreground program
read from the input spooler file  without messing 
it up for the interrrupt service routine>

Any hints, answers or references to books or
magazine articles would be appreciated.

Mark J. Borgerson
Dept. of Computer Science.
Oregon State University
(mjbo@orstcs.csnet)  

Just Get my name right--so you don't confuse me with my employer.
 

backman@interlan.UUCP (Larry Backman) (01/12/87)

In article <216700005@orstcs.UUCP> mjbo@orstcs.UUCP (mjbo) writes:
>
>I have read in several places, including the most recent BIX
>section of Byte,  that it is not legal to call on DOS
>services from an interrupt-service routine.
>I would like to write a TSR program to hide in the
>background and receive data from a serial port using
>an interrupt routine to store the data in a buffer.
>When the buffer fills, I would like to store the
>data in a Hard-disk file dedicated to that purpose.
>(sort of a print spooler in reverse).  Can this be done
>safely?   If so, what restrictions are there on the
>DOS file-handling calls?   Can a foreground program
>read from the input spooler file  without messing 
>it up for the interrrupt service routine>
>

	Calling DOS from an ISR can be done safely; its tricky, and there
	are a number of things to be taken into account.  However, you must
	use undocumented DOS calls to do so.

	When an interrupt service routine is kicked off, there is no guarentee
	where your CS:IP and stack pointeres were before the interrupt occurred.
	For all you know, you may have interrupted DOS itself, possibly in the
	middle of a critical section of code.  As evryone knows, DOS is not a
	re-entrant operating system, it is singled threaded, and cannot handle
	concurrent system calls.  However, the folks in Bellevue still needed
	to be able to detremine when it was safe to do something within their
	own operating system thus the following two undocumented functions.

		1).   The "dirty bit".
			INT 21 function 34 returns the status of DOS's dirty
			bit indicating whether DOS is in a critical section.
			If AL returns with a 0, its safe to access DOS, if
			it returns non-zero, DOS cannot be safely interrupted.

		2).   The scheduler	
			INT 28 is the DOS scheduler interrupt.  When DOS is
			active but idle ( the keyboard scan loop for instance)
			it periodically issues an INT 28, allowing other 				sleeping processes a chance to run.  A resident program
			(such as PRINT or MODE) can grab this vector, and do its
			thing safely when scehduled by an INT 28.

	Thes two functions provide the hooks necessary to call DOS from an ISR.
	Needless to say your ISR must be tied to some sort of non-interrupt code
	which is capable of performing actions at a later time.

	Lets say your ISR captures an interrupt, has a full buffer and wants to
	write that buffer out to file.  First the ISR saves the state of the
	machine and switches the stack.  The stack switch is necessary since
	the DOS stack is only guarenteed to be 80 bytes deep, not enough for
	any serious processing especially if you intend to re-enter DOS!

	Once you have swapped stacks you may re-enable interrupts if you so
	desire.  Now comes the fun part!  Issue an INT 21 function 34; if it
	comes back with AL set to 0 your golden; do whatever you want right
	then and there!  If however, it comes back indicating that DOS is in
	a critical section you must then use the scheduler interrupt to do 
	your DOS access.

	So, when you started this program you undoubtabl did things like
	replacing interrupt vectors, well make sure you replace INT 28 with
	a function of your own.  Your printer interrupt handler should be
	able to share a semaphore with the INT 28 handler, so that when
	your printer handler is blocked from performing a DOS access, it
	sets this semaphore saves a pointer to the buffer cleans up after
	itself and IRETS.  Now next time DOS calls INT 28 our handler is 
	activated; it checks the semaphore and if it is set performs the DOS
	access that was previously blocked.  If the semaphore is not set, as
	should be the case 99% of the time, the INT 28 handler simply IRETS. 

	I hope this provides enough information to get you started, be warned
	that its tricky and a good debugger is a must.  I also suggest disassem-
	bling PRINT.COM to see how a Microsoft approved resident DOS access 
	works.  Feel free to call me if you need more information..


					Larry Backman
					Micom - Interlan, Inc.
					155 Swanson Rd
					Boxborough, Ma. 01719
					617-263-9929 x291

					ulowell!  -\
					mit-eddie!  -->  interlan!backman
					ihnp4!    -/

jrv@siemens.UUCP (01/13/87)

backman@interlan writes:

>	<deleted discussion of DOS re-entrancy>
>
>		1).   The "dirty bit".
>			INT 21 function 34 returns the status of DOS's dirty
>			bit indicating whether DOS is in a critical section.
>			If AL returns with a 0, its safe to access DOS, if
>			it returns non-zero, DOS cannot be safely interrupted.
>

Something is a little strange here. When the resident program gets control via
an interrupt and decides it is time to do a DOS function it seems to me to be
a little touch and go to CALL DOS and execute function 34 to find out if
you can safely make a DOS CALL!

Instead Int 21 function 34 should be called before the program is made
resident. This function also returns a pointer to the location for
the DOS dirty bit in ES:BX. This address should be saved and when the
resident program needs to test if DOS calls are safe the value can be
tested directly.


Jim Vallino
Siemens Research and Technology Lab.
Princeton, NJ
{allegra,ihnp4,seismo,philabs}!princeton!siemens!jrv
CSNet: jrv@siemens.siemens-rtl.com

news@cit-vax.Caltech.Edu (Usenet netnews) (01/15/87)

Organization : California Institute of Technology
Keywords: TSR, DOS Re-entrancy
From: tim@tomcat.Caltech.Edu (Tim Kay)
Path: tomcat!tim

(1014-Larry Backman) writes:
>
>	Calling DOS from an ISR can be done safely; its tricky, and there
>	are a number of things to be taken into account.  However, you must
>	use undocumented DOS calls to do so.
>
>  [description of how to do it deleted]

I wonder if a ^C handler could be written that would kill the current
program even if the program isn't doing any dos calls.

Currently, if you hit ^Break or ^C, a bit is set.  Then when you call
dos, it checks the bit.  If set, the ^C handler is called, and your
program (by default) is terminated.  The problem is that many programs
don't make dos calls, and they can't be killed.  For example, if you
are running a Turbo Pascal program that gets into an infinite loop,
you have to reboot the machine.  (I know that there is a {$U+} switch,
but this makes the program run slower, so I would rather not use it.
My C compiler doesn't have the equivalent of {$U+}.)

Would it be possible to write a TSR program that notices when ^C is
hit and sets a bit.
The next time a clock interrupt happens (as described in the article),
both this bit and the dirty bit are checked.  If ^C has been hit, and
it is safe to call dos, then the handler should issue a dos terminate
call to terminate the interrupted program.

However, before the current program is terminated, this handler should check
the address of the ^C handler (int 23h) to see
if the current program is handling its own ^Cs.  If it is, then the
handler should let the current program take the ^C.

Does this make sense?  Has such a program been written?  Could it be done?
(Can you call terminate from inside the clock interrupt handler?)

Timothy L. Kay				tim@csvax.caltech.edu
Department of Computer Science
Caltech, 256-80
Pasadena, CA  91125

backman@interlan.UUCP (Larry Backman) (01/19/87)

>I wonder if a ^C handler could be written that would kill the current
>program even if the program isn't doing any dos calls.
>
>Currently, if you hit ^Break or ^C, a bit is set.  Then when you call
>dos, it checks the bit.  If set, the ^C handler is called, and your
>program (by default) is terminated.  The problem is that many programs
>don't make dos calls, and they can't be killed.  For example, if you
>are running a Turbo Pascal program that gets into an infinite loop,
>you have to reboot the machine. 
>Would it be possible to write a TSR program that notices when ^C is
>hit and sets a bit.
>The next time a clock interrupt happens (as described in the article),
>both this bit and the dirty bit are checked.  If ^C has been hit, and
>it is safe to call dos, then the handler should issue a dos terminate
>call to terminate the interrupted program.
>
>Does this make sense?  Has such a program been written?  Could it be done?
>(Can you call terminate from inside the clock interrupt handler?)
>

	I just spent a couple days last week playing the ^Break/^C game from
	within a NETBIOS application.  If a NETBIOS request has been issued
	and is pending on the network's response, the only keys that work are\
	Ctl-Alt-Del.  The INT 23 handler does not see the ^Break or ^C until
	after a NETBIOS request completes.  However, if the NETBIOS request is
	hung, your dead!!  The BIOS break interrupt, INT 1B, will see the ^Break
	key, but not the Control-C key.  In my situation, I fortunately have
	already captured the keyboard at INT 9, and can filter out whatever
	keystrokes I want from there, and set semaphores from within the
	 keyboard handler that will be later used by an event processor.

	I also remember going through contortions to be able to terminate from
	within the clock handler.  I don't have code in front of me but as I
	recall, the trick was to call INT 21 function 49 (FREE MEMORY) twice,
	first to free the programs allocated memory, and second to free the
	PSP of the program.  At this point we exitted using INT 21 function 4C,


					Larry Backman
					Micom - Interlan, Inc.

michaelm@3comvax.UUCP (Michael McNeil) (01/22/87)

In article <119@interlan.UUCP> backman@interlan.UUCP (1014-Larry Backman)
writes:
>	I also remember going through contortions to be able to terminate from
>	within the clock handler.  I don't have code in front of me but as I
>	recall, the trick was to call INT 21 function 49 (FREE MEMORY) twice,
>	first to free the programs allocated memory, and second to free the
>	PSP of the program.  At this point we exitted using INT 21 function 4C,
>
>					Larry Backman
>					Micom - Interlan, Inc.

The memory block of the program begins with the program's PSP,
and therefore the PSP is freed with the program.  You meant that
the second call frees the program's environment, didn't you?

Michael McNeil
3Com Corporation
Santa Clara, California
	{hplabs|fortune|idi|ihnp4|tolerant|allegra|glacier|olhqma}
	!oliveb!3comvax!michaelm

brianc@cognos.UUCP (Brian Campbell) (01/23/87)

In article <1501@cit-vax.Caltech.Edu> tim@tomcat.caltech.edu (Tim Kay) writes:
>>
>>	Calling DOS from an ISR can be done safely; its tricky, and there
>>	are a number of things to be taken into account.  However, you must
>>	use undocumented DOS calls to do so.
>>
>>  [description of how to do it deleted]
>
>I wonder if a ^C handler could be written that would kill the current
>program even if the program isn't doing any dos calls.
>
>Currently, if you hit ^Break or ^C, a bit is set.  Then when you call
>dos, it checks the bit.  If set, the ^C handler is called, and your
>program (by default) is terminated.  The problem is that many programs
>don't make dos calls, and they can't be killed.  For example, if you
>are running a Turbo Pascal program that gets into an infinite loop,
>you have to reboot the machine.  (I know that there is a {$U+} switch,
>but this makes the program run slower, so I would rather not use it.
>My C compiler doesn't have the equivalent of {$U+}.)
>
>Would it be possible to write a TSR program that notices when ^C is
>hit and sets a bit.
>The next time a clock interrupt happens (as described in the article),
>both this bit and the dirty bit are checked.  If ^C has been hit, and
>it is safe to call dos, then the handler should issue a dos terminate
>call to terminate the interrupted program.

I believe that there is such a TSR utility.  It was presented in one of
the earlier issues of PC-Magazine last year.  I think it was called UNCRASH.
The idea was that hitting Ctrl-Break once would function as always, hitting 
it twice did something further, and hitting it three times would get you out
of just about anything (including a JMP $+0) and terminate the program.  I 
think it was implemented using the keyboard interrupt, but I'm not sure on 
that.

If necessary, I can dig out the issue and either post or email the code
(assuming I'm not breaking any copyrights Ziff-Davis may have).

Brian Campbell