[comp.os.minix] critical sections

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!leisner

ast@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)