Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Dec 1999 11:10:39 -0800 (PST)
From:      jburkhol@home.com
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/15440: support atomic locks in the UP kernel
Message-ID:  <19991212191039.F2AB01FCD@io.yi.org>

next in thread | raw e-mail | index | archive | help

>Number:         15440
>Category:       kern
>Synopsis:       support atomic locks in the UP kernel
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Sun Dec 12 11:20:01 PST 1999
>Closed-Date:
>Last-Modified:
>Originator:     Jake Burkholder
>Release:        FreeBSD 4.0-CURRENT i386
>Organization:
none
>Environment:

4.0-CURRENT

>Description:

This patch brings in alpha inline asm versions of s_lock_init, s_lock,
s_lock_try and s_unlock from netbsd, and converts the existing i386
routines to inline asm as well.  This way the locks are useable from
userland, simply by including <machine/lock.h>.  It is hoped that 
these routines will aid in making the linuxthreads port pltaform
independent, and serve as a basis for more advanvced synchronization
primitives when native threads are developed.

I've tested this on a UP i386 machine, but do not have access to
SMP or alpha hardware.  An SMP kernel compiles, and there should
be no functional changes in that case, since the debug versions
in simplelock.s are used rather than these inline ones.  The alpha
versions are taken directly from netbsd, so I assume they work fine.

>How-To-Repeat:

n/a

>Fix:

The patch is included below, and is also available at
http://io.yi.org/lock.diff.

Index: alpha/include/lock.h
===================================================================
RCS file: /home/ncvs/src/sys/alpha/include/lock.h,v
retrieving revision 1.5
diff -c -r1.5 lock.h
*** lock.h	1999/08/28 00:38:47	1.5
--- lock.h	1999/12/12 10:24:43
***************
*** 29,34 ****
--- 29,38 ----
  #ifndef _MACHINE_LOCK_H_
  #define _MACHINE_LOCK_H_
  
+ #define COM_LOCK()
+ #define COM_UNLOCK()
+ 
+ #define	SIMPLELOCK_LOCKED	1
  
  /*
   * Simple spin lock.
***************
*** 38,44 ****
  	volatile int	lock_data;
  };
  
! #define COM_LOCK()
! #define COM_UNLOCK()
  
  #endif /* !_MACHINE_LOCK_H_ */
--- 42,165 ----
  	volatile int	lock_data;
  };
  
! /* inline simplelock functions */
! static __inline void s_lock_init __P((struct simplelock *));
! static __inline void s_lock	__P((struct simplelock *));
! static __inline void s_lock_try	__P((struct simplelock *));
! static __inline void s_unlock	__P((struct simplelock *));
! 
! /*
!  * void
!  * s_lock_init(struct simplelock *lkp)
!  * {
!  *	lkp->lock_data = 0;
!  * }
!  */
! static __inline void
! s_lock_init(lkp)
! 	struct simplelock *lkp;
! {
! 
! 	__asm __volatile(
! 		"# BEGIN cpu_simple_lock_init\n"
! 		"	stl	$31, %0		\n"
! 		"	mb			\n"
! 		"	# END cpu_simple_lock_init"
! 		: "=m" (lkp->lock_data));
! }
! 
! /*
!  * void
!  * s_lock(struct simplelock *lkp)
!  * {
!  *	while (test_and_set(&lkp->lock_data))
!  *		continue;
!  * }
!  */
! static __inline void
! s_lock(lkp)
! 	struct simplelock *lkp;
! {
! 	unsigned long t0;
! 
! 	/*
! 	 * Note, if we detect that the lock is held when
! 	 * we do the initial load-locked, we spin using
! 	 * a non-locked load to save the coherency logic
! 	 * some work.
! 	 */
! 
! 	__asm __volatile(
! 		"# BEGIN cpu_simple_lock\n"
! 		"1:	ldl_l	%0, %3		\n"
! 		"	bne	%0, 2f		\n"
! 		"	bis	$31, %2, %0	\n"
! 		"	stl_c	%0, %1		\n"
! 		"	beq	%0, 3f		\n"
! 		"	mb			\n"
! 		"	br	4f		\n"
! 		"2:	ldl	%0, %3		\n"
! 		"	beq	%0, 1b		\n"
! 		"	br	2b		\n"
! 		"3:	br	1b		\n"
! 		"4:				\n"
! 		"	# END cpu_simple_lock\n"
! 		: "=r" (t0), "=m" (lkp->lock_data)
! 		: "i" (SIMPLELOCK_LOCKED), "1" (lkp->lock_data));
! }
! 
! /*
!  * int
!  * s_lock_try(struct simplelock *lkp)
!  * {
!  *	return (!test_and_set(&lkp->lock_data));
!  * }
!  */
! static __inline int
! s_lock_try(lkp)
! 	struct simplelock *lkp;
! {
! 	unsigned long t0, v0;
! 
! 	__asm __volatile(
! 		"# BEGIN cpu_simple_lock_try\n"
! 		"1:	ldl_l	%0, %4		\n"
! 		"	bne	%0, 2f		\n"
! 		"	bis	$31, %3, %0	\n"
! 		"	stl_c	%0, %2		\n"
! 		"	beq	%0, 3f		\n"
! 		"	mb			\n"
! 		"	bis	$31, 1, %1	\n"
! 		"	br	4f		\n"
! 		"2:	bis	$31, $31, %1	\n"
! 		"	br	4f		\n"
! 		"3:	br	1b		\n"
! 		"4:				\n"
! 		"	# END cpu_simple_lock_try"
! 		: "=r" (t0), "=r" (v0), "=m" (lkp->lock_data)
! 		: "i" (SIMPLELOCK_LOCKED), "2" (lkp->lock_data));
! 
! 	return (v0);
! }
! 
! /*
!  * void
!  * s_unlock(struct simplelock *lkp)
!  * {
!  *	lkp->lock_data = 0;
!  * }
!  */
! static __inline void
! s_unlock(lkp)
! 	struct simplelock *lkp;
! {
! 
! 	__asm __volatile(
! 		"# BEGIN cpu_simple_unlock\n"
! 		"	stl	$31, %0		\n"
! 		"	mb			\n"
! 		"	# END cpu_simple_unlock"
! 		: "=m" (lkp->lock_data));
! }
  
  #endif /* !_MACHINE_LOCK_H_ */
Index: i386/i386/simplelock.s
===================================================================
RCS file: /home/ncvs/src/sys/i386/i386/simplelock.s,v
retrieving revision 1.11
diff -c -r1.11 simplelock.s
*** simplelock.s	1999/08/28 00:43:50	1.11
--- simplelock.s	1999/12/12 10:28:58
***************
*** 57,75 ****
  
  /*
   * void
-  * s_lock_init(struct simplelock *lkp)
-  * {
-  * 	lkp->lock_data = 0;
-  * }
-  */
- ENTRY(s_lock_init)
- 	movl	4(%esp), %eax		/* get the address of the lock */
- 	movl	$0, (%eax)
- 	ret
- 
- 
- /*
-  * void
   * s_lock(struct simplelock *lkp)
   * {
   * 	while (test_and_set(&lkp->lock_data))
--- 57,62 ----
***************
*** 84,106 ****
   *	the local cache (and thus causing external bus writes) with repeated
   *	writes to the lock.
   */
! #ifndef SL_DEBUG
! 
! ENTRY(s_lock)
! 	movl	4(%esp), %eax		/* get the address of the lock */
! 	movl	$1, %ecx
! setlock:
! 	xchgl	%ecx, (%eax)
! 	testl	%ecx, %ecx
! 	jz	gotit			/* it was clear, return */
! wait:
! 	cmpl	$0, (%eax)		/* wait to empty */
! 	jne	wait			/* still set... */
! 	jmp	setlock			/* empty again, try once more */
! gotit:
! 	ret
! 
! #else /* SL_DEBUG */
  
  ENTRY(s_lock)
  	movl	4(%esp), %edx		/* get the address of the lock */
--- 71,77 ----
   *	the local cache (and thus causing external bus writes) with repeated
   *	writes to the lock.
   */
! #ifdef SL_DEBUG
  
  ENTRY(s_lock)
  	movl	4(%esp), %edx		/* get the address of the lock */
***************
*** 143,164 ****
   * 	return (!test_and_set(&lkp->lock_data));
   * }
   */
! #ifndef SL_DEBUG
  
  ENTRY(s_lock_try)
- 	movl	4(%esp), %eax		/* get the address of the lock */
- 	movl	$1, %ecx
- 
- 	xchgl	%ecx, (%eax)
- 	testl	%ecx, %ecx
- 	setz	%al			/* 1 if previous value was 0 */
- 	movzbl	%al, %eax		/* convert to an int */
- 
- 	ret
- 
- #else /* SL_DEBUG */
- 
- ENTRY(s_lock_try)
  	movl	4(%esp), %edx		/* get the address of the lock */
  	movl	_cpu_lockid, %ecx	/* add cpu id portion */
  	incl	%ecx			/* add lock portion */
--- 114,122 ----
   * 	return (!test_and_set(&lkp->lock_data));
   * }
   */
! #ifdef SL_DEBUG
  
  ENTRY(s_lock_try)
  	movl	4(%esp), %edx		/* get the address of the lock */
  	movl	_cpu_lockid, %ecx	/* add cpu id portion */
  	incl	%ecx			/* add lock portion */
***************
*** 172,191 ****
  	ret
  
  #endif /* SL_DEBUG */
- 
- 
- /*
-  * void
-  * s_unlock(struct simplelock *lkp)
-  * {
-  * 	lkp->lock_data = 0;
-  * }
-  */
- ENTRY(s_unlock)
- 	movl	4(%esp), %eax		/* get the address of the lock */
- 	movl	$0, (%eax)
- 	ret
- 
  
  /*
   * These versions of simple_lock block interrupts,
--- 130,135 ----
Index: i386/include/lock.h
===================================================================
RCS file: /home/ncvs/src/sys/i386/include/lock.h,v
retrieving revision 1.11
diff -c -r1.11 lock.h
*** lock.h	1999/11/19 22:47:19	1.11
--- lock.h	1999/12/12 10:34:22
***************
*** 211,220 ****
  	volatile int	lock_data;
  };
  
! /* functions in simplelock.s */
! void	s_lock_init		__P((struct simplelock *));
  void	s_lock			__P((struct simplelock *));
  int	s_lock_try		__P((struct simplelock *));
  void	ss_lock			__P((struct simplelock *));
  void	ss_unlock		__P((struct simplelock *));
  void	s_lock_np		__P((struct simplelock *));
--- 211,229 ----
  	volatile int	lock_data;
  };
  
! /* functions used by both UP and SMP */
! static __inline void s_lock_init __P((struct simplelock *));
! static __inline void s_unlock	__P((struct simplelock *));
! 
! #ifndef SL_DEBUG
! static __inline void s_lock	__P((struct simplelock *));
! static __inline int s_lock_try	__P((struct simplelock *));
! #else
  void	s_lock			__P((struct simplelock *));
  int	s_lock_try		__P((struct simplelock *));
+ #endif /* SL_DEBUG */
+ 
+ /* functions in simplelock.s */
  void	ss_lock			__P((struct simplelock *));
  void	ss_unlock		__P((struct simplelock *));
  void	s_lock_np		__P((struct simplelock *));
***************
*** 222,232 ****
--- 231,305 ----
  
  /* inline simplelock functions */
  static __inline void
+ s_lock_init(struct simplelock *lkp)
+ {
+ 	lkp->lock_data = 0;
+ }
+ 
+ static __inline void
  s_unlock(struct simplelock *lkp)
  {
  	lkp->lock_data = 0;
  }
  
+ #ifndef SL_DEBUG
+ 
+ /*
+  * void
+  * s_lock(struct simplelock *lkp)
+  * {
+  *	while (test_and_set(&lkp->lock_data))
+  *		continue;
+  * }
+  */
+ static __inline void
+ s_lock(struct simplelock *lkp)
+ {
+ 
+ 	__asm __volatile(
+ 		"	movl	$1, %%eax	\n"
+ 		"1:				\n"
+ 		"	xchgl	%%eax, %0	\n"
+ 		"	testl	%%eax, %%eax	\n"
+ 		"	jz	3f		\n"
+ 		"2:				\n"
+ 		"	cmpl	$0, %0		\n"
+ 		"	jne	2b		\n"
+ 		"	jmp	1b		\n"
+ 		"3:				\n"
+ 		: "=m" (lkp->lock_data)
+ 		: "0" (lkp->lock_data)
+ 		: "eax");
+ }
+ 
+ /*
+  * int
+  * s_lock_try(struct simplelock *lkp)
+  * {
+  *	return (!test_and_set(&lkp->lock_data));
+  * }
+  */
+ static __inline int
+ s_lock_try(struct simplelock *lkp)
+ {
+ 	int r;
+ 
+ 	__asm __volatile(
+ 		"	movl	$1, %1		\n"
+ 		"	xorl	%%ecx, %%ecx	\n"
+ 		"	xchgl	%1, %0		\n"
+ 		"	testl	%1, %1		\n"
+ 		"	setz	%%cl		\n"
+ 		"	movzbl	%%cl, %1	\n"
+ 		: "=m" (lkp->lock_data), "=r" (r)
+ 		: "0" (lkp->lock_data)
+ 		: "ecx");
+ 
+ 	return (r);
+ }
+ 
+ #endif /* SL_DEBUG */
+ 
  /* global data in mp_machdep.c */
  extern struct simplelock	imen_lock;
  extern struct simplelock	cpl_lock;
***************
*** 239,245 ****
  
  #if !defined(SIMPLELOCK_DEBUG) && NCPUS > 1
  /*
!  * This set of defines turns on the real functions in i386/isa/apic_ipl.s.
   */
  #define	simple_lock_init(alp)	s_lock_init(alp)
  #define	simple_lock(alp)	s_lock(alp)
--- 312,318 ----
  
  #if !defined(SIMPLELOCK_DEBUG) && NCPUS > 1
  /*
!  * This set of defines turns on the real functions in i386/i386/simplelock.s.
   */
  #define	simple_lock_init(alp)	s_lock_init(alp)
  #define	simple_lock(alp)	s_lock(alp)

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19991212191039.F2AB01FCD>