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

Ivan N. Kokshaysky (ink@jurassic.park.msu.ru)
Thu, 18 Mar 1999 18:46:43 +0300


Kenneth Preslan (kpreslan@zarniwoop.com) 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.

Ivan

--- linux/include/asm-alpha/semaphore-helper.h.orig Thu Feb 25 21:02:11 1999
+++ linux/include/asm-alpha/semaphore-helper.h Thu Mar 18 16:16:55 1999
@@ -9,6 +9,10 @@
*/

/*
+ * Modified 1999-03-17 by Ivan Kokshaysky
+ */
+
+/*
* These two _must_ execute atomically wrt each other.
*
* This is trivially done with load_locked/store_cond,
@@ -17,10 +21,28 @@

static inline void
wake_one_more(struct semaphore * sem)
+/* if (count <= 0) waking++ */
{
- atomic_inc(&sem->waking);
+ long tmp,tmp1;
+
+ __asm__ __volatile__(
+ "1: ldq_l %0,%2\n"
+ " lda %1,1\n"
+ " sll %1,32,%1\n"
+ " addq %1,%0,%1\n"
+ " subl %0,1,%0\n"
+ " bge %0,2f\n"
+ " stq_c %1,%2\n"
+ " beq %1,3f\n"
+ "2:\n"
+ ".section .text2,\"ax\"\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=r"(tmp), "=r"(tmp1), "=m"(*sem)
+ : "0"(0));
}

+
static inline int
waking_non_zero(struct semaphore *sem)
{
@@ -73,7 +95,9 @@
ret = 1;
}
else if (pending) {
- tmp += 1;
+ tmp += 1; // if (int)tmp=-1, we have an overflow
+ // to the high longword, so
+ if ((int)tmp = 0) tmp += 0xffffffff00000000;
ret = -EINTR;
}
else {
@@ -88,11 +112,14 @@

__asm__ __volatile__(
"1: ldq_l %1,%4\n"
+ " ldah %3,-32768(%1)\n"
+ " addl %1,1,%0\n"
+ " mov %1,%2\n"
+ " ldah %3,-32768(%3)\n"
+ " cmoveq %0,%3,%2\n"
" lda %0,0\n"
- " addq %1,1,%2\n"
- " ldah %3,0x8000(%1)\n"
+ " addq %2,1,%2\n"
" cmovne %5,%6,%0\n"
- " ldah %3,0x8000(%3)\n"
" cmovge %1,1,%0\n"
" cmovne %5,%2,%1\n"
" cmovge %2,%3,%1\n"
--- linux/include/asm-alpha/semaphore.h.orig Tue Mar 9 12:04:12 1999
+++ linux/include/asm-alpha/semaphore.h Thu Mar 18 16:11:51 1999
@@ -112,45 +112,52 @@
* We must manipulate count and waking simultaneously and atomically.
* Do this by using ll/sc on the pair of 32-bit words.
*/
-
+ /* 1999-03-17 Modified by Ivan Kokshaysky accordingly to i386 behavior:
+ * if (count > 0) { count--; return 0 };
+ * if (waking >= 0) { count--; waking--; return 0 };
+ * return 1;
+ */
extern inline int down_trylock(struct semaphore * sem)
{
- long ret, tmp, tmp2;
+ long ret, tmp, tmp2, sub;

/* "Equivalent" C. Note that we have to do this all without
(taken) branches in order to be a valid ll/sc sequence.

do {
tmp = ldq_l;
- ret = 0;
- tmp -= 1;
- if ((int)tmp < 0) // count
- break;
- if ((long)tmp < 0) // waking
- break;
- tmp += 0xffffffff00000000;
- ret = 1;
+ tmp2 = (int)tmp;
+ sub = 0x0000000100000000;
+ ret = (tmp2 <= 0); // count =< 0 ?
+ if (tmp2 >= 0) sub = 0; // note that if count=0
+ // subq overflows to the high
+ // longword (i.e waking)
+ tmp2 = (tmp < 0); // waking < 0 ?
+ sub += 1;
+ ret &= tmp2;
+ if (ret) sub = 0;
+ tmp -= sub;
tmp = stq_c = tmp;
} while (tmp == 0);
*/

__asm__ __volatile__(
- "1: ldq_l %1,%3\n"
- " lda %0,0\n"
- " subl %1,1,%2\n"
- " subq %1,1,%1\n"
- " blt %2,2f\n"
- " blt %1,2f\n"
- " ldah %1,0x8000(%1)\n"
- " ldah %1,0x8000(%1)\n"
- " lda %0,1\n"
- " stq_c %1,%3\n"
- " beq %1,3f\n"
- "2: mb\n"
+ "1: ldq_l %1,%4\n"
+ " addl %1,0,%2\n"
+ " sll %0,32,%3\n"
+ " cmple %2,0,%0\n"
+ " cmovge %2,0,%3\n"
+ " cmplt %1,0,%2\n"
+ " addq %3,1,%3\n"
+ " and %0,%2,%0\n"
+ " cmovne %0,0,%3\n"
+ " subq %1,%3,%1\n"
+ " stq_c %1,%4\n"
+ " beq %1,2f\n"
".section .text2,\"ax\"\n"
- "3: br 1b\n"
+ "2: br 1b\n"
".previous"
- : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2)
+ : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
: "m"(*sem)
: "memory");

-
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/