Subject: README: Scheduler locking changes coming Very Very Soon
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-kern
Date: 08/17/2000 18:19:55
Hi folks...

This is a somewhat short-notice heads-up.  There are some locking
changes that I'll be committing Very Very Soon (possibly tonight)
that change the locking protocol for context switches.  This is
for multiprocessor support.

The new locking protocol is:

	- mi_switch() always called at splhigh and with the
	  sched_lock held.

	- mi_switch() returns at splhigh and with the
	  sched_lock not held.

	- cpu_switch() is always called at splhigh and with
	  the sched_lock held.

	- cpu_switch() is responsible for releasing the
	  sched_lock before returning.

	- Idle loop must release sched_lock before lowering
	  spl and reacquire it after raising spl.

It's mostly quite simple, and I've made changes for most of the ports
already (well, I still have pc532, sparc, and vax to do, but those should
be easy).  I will NOT be making the changes to arm32, powerpc ports, and
sh3 ports ports because it wasn't terribly strightforward for me to do so.
PORTMASTERS -- YOU MUST MAKE THESE CHANGES.

Note that in the LOCKDEBUG case, your locore *MUST* manipulate the
sched_lock via two convenience functions: sched_lock_idle() and
sched_unlock_idle().  You must also adjust the assumptions made
about interrupts in your locore.  Actually, it's simpler now, because
it used to be that cpu_switch() could be called with interrupts blocked
or not blocked.

Attached below is the diff needed to make this all happen on the Alpha.
It's quite simple.  Once the MI changes hit the tree, please update your
ports ASAP, as they will be broken until you do.

Index: locore.s
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/alpha/alpha/locore.s,v
retrieving revision 1.78
diff -c -r1.78 locore.s
*** locore.s	2000/07/19 14:00:24	1.78
--- locore.s	2000/08/18 01:06:14
***************
*** 68,73 ****
--- 68,74 ----
  
  #include "opt_ddb.h"
  #include "opt_multiprocessor.h"
+ #include "opt_lockdebug.h"
  #include "opt_compat_linux.h"
  
  #ifdef COMPAT_LINUX
***************
*** 781,793 ****
  	/* Note: GET_CURPROC clobbers v0, t0, t8...t11. */
  	GET_CURPROC
  	stq	zero, 0(v0)			/* curproc <- NULL for stats */
  	mov	zero, a0			/* enable all interrupts */
  	call_pal PAL_OSF1_swpipl
  2:	ldl	t0, sched_whichqs		/* look for non-empty queue */
  	beq	t0, 2b
  	ldiq	a0, ALPHA_PSL_IPL_HIGH		/* disable all interrupts */
  	call_pal PAL_OSF1_swpipl
! 	jmp	zero, cpu_switch_queuescan	/* jump back into the fray */
  	END(idle)
  
  /*
--- 782,800 ----
  	/* Note: GET_CURPROC clobbers v0, t0, t8...t11. */
  	GET_CURPROC
  	stq	zero, 0(v0)			/* curproc <- NULL for stats */
+ #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ 	CALL(sched_unlock_idle)			/* release sched_lock */
+ #endif
  	mov	zero, a0			/* enable all interrupts */
  	call_pal PAL_OSF1_swpipl
  2:	ldl	t0, sched_whichqs		/* look for non-empty queue */
  	beq	t0, 2b
  	ldiq	a0, ALPHA_PSL_IPL_HIGH		/* disable all interrupts */
  	call_pal PAL_OSF1_swpipl
! #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
! 	CALL(sched_lock_idle)			/* acquire sched_lock */
! #endif
! 	jmp	zero, cpu_switch_queuescan	/* jump back into the fire */
  	END(idle)
  
  /*
***************
*** 821,828 ****
  	ldl	t0, sched_whichqs		/* look for non-empty queue */
  	beq	t0, idle			/* and if none, go idle */
  
- 	ldiq	a0, ALPHA_PSL_IPL_HIGH		/* disable all interrupts */
- 	call_pal PAL_OSF1_swpipl
  cpu_switch_queuescan:
  	br	pv, 1f
  1:	LDGP(pv)
--- 828,833 ----
***************
*** 863,868 ****
--- 868,880 ----
  5:
  	mov	t4, s2				/* save new proc */
  	ldq	s3, P_MD_PCBPADDR(s2)		/* save new pcbpaddr */
+ #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ 	/*
+ 	 * Done mucking with the run queues, release the
+ 	 * scheduler lock, but keep interrupts out.
+ 	 */
+ 	CALL(sched_unlock_idle)
+ #endif
  
  	/*
  	 * Check to see if we're switching to ourself.  If we are,
***************
*** 874,880 ****
  	 * saved it.  Also note that switch_exit() ensures that
  	 * s0 is clear before jumping here to find a new process.
  	 */
! 	cmpeq	s0, t4, t0			/* oldproc == newproc? */
  	bne	t0, 7f				/* Yes!  Skip! */
  
  	/*
--- 886,892 ----
  	 * saved it.  Also note that switch_exit() ensures that
  	 * s0 is clear before jumping here to find a new process.
  	 */
! 	cmpeq	s0, s2, t0			/* oldproc == newproc? */
  	bne	t0, 7f				/* Yes!  Skip! */
  
  	/*
***************
*** 1038,1043 ****
--- 1050,1059 ----
  	/* Schedule the vmspace and stack to be freed. */
  	mov	s2, a0
  	CALL(exit2)
+ 
+ #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ 	CALL(sched_lock_idle)			/* acquire sched_lock */
+ #endif
  
  	/*
  	 * Now jump back into the middle of cpu_switch().  Note that

-- 
        -- Jason R. Thorpe <thorpej@zembu.com>