Re: alpha: down_interruptible() won't wake up

Richard Henderson (rth@twiddle.net)
Thu, 18 Mar 1999 23:58:23 -0800


On Thu, Mar 18, 1999 at 06:46:43PM +0300, Ivan N. Kokshaysky wrote:
> > I'm having a problem with semaphores on a LX164 Alpha with 2.2.3.
> >
> > I'm trying use semaphores to wake up a kernel thread. When the thread
> > first starts, it does a down_interruptible() on a semaphore. The thread
> > sleeps until another part of my kernel code does an up() on that semaphore.
> > The thread then does some work and then sleeps on the semaphore again.
> >
> > At least that's how it's supposed to work. My problem is that on the Alpha,
> > the thread never wakes up. If I run the code on an i686 (again with 2.2.3)
> > the thread wakes up. If I change the down_interruptible() to a down()
> > (on the alpha), the thread wakes up. This leads me to believe that
> > something's wrong with down_interruptible().
> >
> > Test case (module):
>
> [skipped]
>
> Thanks for figuring out the problem. I hope the following patch
> should fix it.

[patch deleted]

I don't think such a large change is necessary. Moving to
IA-32 biases doesn't make the logic any more or less clear,
it only means that you can't rely on nice sign bits being set.

But you do point out the essential problem -- incrementing the
32-bit `count' in the 64-bit register when there are waiters
(count < 0) produces overflow into `waking'.

A tad more care in waking_non_zero_interruptible cures this.

r~

--- 2.2.3/include/asm-alpha/semaphore-helper.h Sat Mar 13 10:43:40 1999
+++ 2.2.3-axp/include/asm-alpha/semaphore-helper.h Thu Mar 18 23:42:33 1999
@@ -73,7 +73,10 @@ waking_non_zero_interruptible(struct sem
ret = 1;
}
else if (pending) {
- tmp += 1;
+ // Since -1 + 1 carries into the high word, we have
+ // to be more careful adding 1 here.
+ tmp = (tmp & 0xffffffff00000000)
+ | ((tmp + 1) & 0x00000000ffffffff;
ret = -EINTR;
}
else {
@@ -89,11 +92,13 @@ waking_non_zero_interruptible(struct sem
__asm__ __volatile__(
"1: ldq_l %1,%4\n"
" lda %0,0\n"
- " addq %1,1,%2\n"
- " ldah %3,0x8000(%1)\n"
" cmovne %5,%6,%0\n"
- " ldah %3,0x8000(%3)\n"
+ " addq %1,1,%2\n"
+ " and %1,%7,%3\n"
+ " andnot %2,%7,%2\n"
" cmovge %1,1,%0\n"
+ " or %3,%2,%2\n"
+ " addq %1,%7,%3\n"
" cmovne %5,%2,%1\n"
" cmovge %2,%3,%1\n"
" stq_c %1,%4\n"
@@ -103,7 +108,8 @@ waking_non_zero_interruptible(struct sem
"3: br 1b\n"
".previous"
: "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(tmp3), "=m"(*sem)
- : "r"(signal_pending(tsk)), "r"(-EINTR));
+ : "r"(signal_pending(tsk)), "r"(-EINTR),
+ "r"(0xffffffff00000000));

return ret;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/