gUSA: Simple User space atomicity emulation

NIIBE Yutaka (gniibe@m17n.org)
Wed, 22 May 2002 11:55:08 +0900 (JST)


While I considered the implementation of atomicity.h of GNU C library
(for SuperH processor), I got an idea. I named it "gUSA", where g
stands for generic (it can be applied to other processors) and general
(other OS).

gUSA is user space atomicity emulation for uniprocessor system which
doesn't have support of memory lock operation such as ll/sc.

The idea is quite simple. When kernel preempts the critical region
(or sends a signal when it's in critical region), we let the control
go back to reentrance point. To do that, we need to define ABI of
critical region, and modify kernel slightly (in case of Linux,
handle_signal and reschedule).

SuperH ABI is:
Stack pointer (r15) < 0 means control is in the critical region.
r0: end point
r1: saved stack pointer
r0 + r15 - 2 = re-enterance point #1 (signal)
r0 + r15 = re-entrance point #2 (preemption)

Here is an implementation of exchange_and_add:
----------------------------
static inline int
__attribute__ ((unused))
exchange_and_add (volatile uint32_t *mem, int val)
{
register unsigned long end_r0 __asm__ ("r0");
register unsigned long ssp_r1 __asm__ ("r1");
unsigned long dummy;
int result;

__asm__ (".align 2\n\t"
"mova 1f,%0\n\t"
"mov r15,%1\n\t"
"mov #-6,r15 ! critical region start: reentrance point #1\n"
"0: mov.l @%4,%2 ! reentrance point #2\n\t"
"add %2,%3\n\t"
"mov.l %3,@%5\n"
"1: mov %1,r15 ! critical region end"
: "=&r" (end_r0), "=&r" (ssp_r1), "=&r" (result), "=r" (dummy)
: "r" (mem), "3" (val)
: "memory");

return result;
}
----------------------------

On rescheduling, if kernel finds it's in the critical region and
regs->pc < r0, it sets regs->pc = r0+r15 (re-entrance point #2).
On signaling, if kernel finds it's in the critical region, and
regs->pc < r0, it sets regs->r15 = r1 (saved stack pointer)
and regs->pc = r0 + r15 -2 (re-entrance point #1) before the
setting of signal frame (so that it goes re-entrance point #1
after signal handler).

Here's a patch for kernel enhancement for SuperH (against our 2.4.18-sh).

I think that this scheme is useful for other processors.

Comments are welcome.

Please see for full patch of GNU C library:
http://sources.redhat.com/ml/libc-hacker/2002-05/msg00029.html

2002-05-22 NIIBE Yutaka <gniibe@m17n.org>

gUSA ("g" User Space Atomicity) support.
* arch/sh/kernel/signal.c (handle_signal): Added gUSA handling.
* arch/sh/kernel/entry.S (reschedule): Added gUSA handling.

Index: arch/sh/kernel/entry.S
===================================================================
RCS file: /cvsroot/linuxsh/linux/arch/sh/kernel/entry.S,v
retrieving revision 1.1.1.1.2.4
diff -u -3 -p -r1.1.1.1.2.4 entry.S
--- arch/sh/kernel/entry.S 10 May 2002 17:58:54 -0000 1.1.1.1.2.4
+++ arch/sh/kernel/entry.S 22 May 2002 02:15:26 -0000
@@ -94,6 +94,7 @@ OFF_R5 = 20 /* New ABI: ar
OFF_R6 = 24 /* New ABI: arg2 */
OFF_R7 = 28 /* New ABI: arg3 */
OFF_SP = (15*4)
+OFF_PC = (16*4)
OFF_SR = (16*4+8)
OFF_TRA = (16*4+6*4)

@@ -455,12 +456,24 @@ __INV_IMASK:

.align 2
reschedule:
- mova SYMBOL_NAME(ret_from_syscall), r0
- mov.l 1f, r1
- jmp @r1
+ ! gUSA handling
+ mov.l @(OFF_SP,r15), r1 ! get user space stack pointer
+ cmp/pz r1
+ bt/s 1f
+ mov.l 2f, r4
+ mov #OFF_PC, r0
+ mov.l @(r0,r15), r2 ! get user space PC (program counter)
+ mov.l @(OFF_R0,r15), r3 ! end point
+ cmp/hs r3, r2 ! r2 >= r3?
+ bt 1f
+ add r2, r1 ! reentrance point #2
+ mov.l r1, @(r0,r15) ! reset PC to reentrance point #2
+ !
+1: mova SYMBOL_NAME(ret_from_syscall), r0
+ jmp @r4
lds r0, pr
.align 2
-1: .long SYMBOL_NAME(schedule)
+2: .long SYMBOL_NAME(schedule)

ret_from_irq:
ret_from_exception:
Index: arch/sh/kernel/signal.c
===================================================================
RCS file: /cvsroot/linuxsh/linux/arch/sh/kernel/signal.c,v
retrieving revision 1.1.1.1.2.1
diff -u -3 -p -r1.1.1.1.2.1 signal.c
--- arch/sh/kernel/signal.c 29 Mar 2002 00:01:07 -0000 1.1.1.1.2.1
+++ arch/sh/kernel/signal.c 22 May 2002 02:15:26 -0000
@@ -533,6 +533,17 @@ handle_signal(unsigned long sig, struct
case -ERESTARTNOINTR:
regs->pc -= 2;
}
+ } else {
+ /* gUSA handling */
+ if (regs->regs[15] >= 0x80000000) {
+ int offset = (int)regs->regs[15];
+
+ /* Reset stack pointer: clear critical region mark */
+ regs->regs[15] = regs->regs[1];
+ if (regs->pc < regs->regs[0])
+ /* Go to reentrance point #1 */
+ regs->pc = regs->regs[0] + offset - 2;
+ }
}

/* Set up the stack frame */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/