johnc@rtmvax.UUCP (John Connin) (07/19/88)
I thought the following "critial section" code from Thomas Wagner's
excellent public domain "Ctask" package, might be of interest. In
addition to the clean notation, note that the 'lock' and 'restore'
routines only operate on the psw interrupt bit -- leaving all other
flags unaltered. Though restoring the whole psw as done currently
in Minix and Xinu seems to work, only changing the interrupt flag
seems to me like a better way of doing business.
#define CRITICAL int crit_save
#define C_ENTER crit_save = lock()
#define C_LEAVE restore(crit_save)
foo()
{
CRTIICAL;
C_ENTER;
while( .... ) {
....
if ( .... ) {
C_LEAVE:
return;
....
}
C_LEAVE;
}
;--------------------------------------------------------------------
;
; int lock(void)
;
; Returns current state of the interrupt flag (1 if ints were
; enabled), then disables interrupts.
;
_lock proc
;
pushf ;
cli ;
pop ax ; extract and return the flag
mov cl,9 ; interrupt bit.
shr ax,cl ;
and ax,1 ;
ret ;
; ;
_lock endp
;
;--------------------------------------------------------------------
;
; void restore(int state)
;
; Enables interrupts if 'state' is nonzero.
;
_restore proc
;
push bp ;
mov bp,sp ;
mov ax,4[bp] ; ax - state
pop bp ;
or ax,ax ; if (state) sti
jz _rstend ;
sti ;
_rstend: ;
ret ;
;
_restore endp
;
BTW: Ctask is a public domain software package which enables multi-tasking
within MSDOS programs. Ctask is available on BIX and is authored by
Thomas Wagner, Patschkauer Weg 31, D-1000 Berlin 33, West Germany.Leisner.Henr@xerox.com (marty) (07/23/88)
John,
I've been using the following similar functions and their equivalents on a
number of processor architectures (including National 32xxx, TI34010, 8085/Z80,
80[12]86.
Lock() returns the old PSW (processor status word) and disables interrupts.
Restore(psw) sets the psw. Restore can also be used from C to do other things
to the PSW. If anything I think the CTASK implementation is less advantageous.
The following is easier and faster to implement since no bit
shifting/twiddling is involved.
Generally programs don't care about the PSW. But simple disable/enable doesn't
work because you don't know what the interrupts were doing on the way in.
It fits into the CTASK structure, since the data returned is not used by the
program.
I do like the syntax.
The following is the Aztec assembler code for 80286 (procdef just provides
convenient ways to pass arguments):
; File: int80286.asm - created by Marty Leisner
; leisner.Henr 20-Jul-88 14:53:05
; Copyright (C) 1987, 1988 by Martin Leisner. All rights reserved.
include lmacros.h
; C callable routines to handle critical sections similar to the Xinu
; approach.
;
; C program would execute
; ps = disable();
; ....
; restore(ps)
; to alter disable interrupts without changing them at the outcome.
procdef disable
pushf
cli
pop ax
pret
pend disable
procdef restore, <<proc_status, word>>
push proc_status
popf ; flags are according to proc_status
pret
pend restore
finish
end
For a TI34010 (to see another example), it looks like this:
unsigned disable()
{
asm(" getst a8"); /* save status to a8, TI GSP C compiler returns
answers
* in a8
*/
asm(" dint");
}
void restore(ps)
register unsigned ps; /* force C compiler to shove ps into A9 (!?! check) */
{
asm(" putst a9");
}
marty
ARPA: leisner.henr@xerox.com
GV: leisner.henr
NS: martin leisner:wbst139:xerox
UUCP: nsc!nscimg!amps!marty, hplabs!parcvax!leisnerast@cs.vu.nl (Andy Tanenbaum) (07/23/88)
I changed the locking in V1.3. The two calls are now: old_value = lock(); . . . restore(old_value) These nest properly and you can build critical sections more easily. I am leaving for a month today. I may get a chance to see news around the beginning of August, but I won't be reading my mail until Aug 24. I hope no other postings have been garbled. Maybe I will mail Vincent Broman all the postings so he can verify them against the archive. Andy Tanenbaum (ast@cs.vu.nl)