2 * $Id: locks.c,v 1.25 1999/09/10 10:40:13 davem Exp $
6 * Written by Cort Dougan (cort@cs.nmt.edu)
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/delay.h>
13 #include <linux/spinlock.h>
14 #include <asm/processor.h>
15 #include <asm/system.h>
21 #define INIT_STUCK 200000000 /*0xffffffff*/
23 void _spin_lock(spinlock_t
*lock
)
25 int cpu
= smp_processor_id();
27 unsigned int stuck
= INIT_STUCK
;
28 #endif /* DEBUG_LOCKS */
29 while (__spin_trylock(&lock
->lock
)) {
32 printk("_spin_lock(%p) CPU#%d NIP %p"
33 " holder: cpu %ld pc %08lX\n",
34 lock
, cpu
, __builtin_return_address(0),
35 lock
->owner_cpu
,lock
->owner_pc
);
38 /*xchg_u32((void *)&lock->lock,0);*/
40 #endif /* DEBUG_LOCKS */
42 lock
->owner_pc
= (unsigned long)__builtin_return_address(0);
43 lock
->owner_cpu
= cpu
;
46 int spin_trylock(spinlock_t
*lock
)
48 if (__spin_trylock(&lock
->lock
))
50 lock
->owner_cpu
= smp_processor_id();
51 lock
->owner_pc
= (unsigned long)__builtin_return_address(0);
57 void _spin_unlock(spinlock_t
*lp
)
61 printk("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp
,
62 smp_processor_id(),current
->comm
,current
->pid
);
63 if ( lp
->owner_cpu
!= smp_processor_id() )
64 printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
65 lp
, smp_processor_id(), (int)lp
->owner_cpu
,
66 lp
->owner_pc
,lp
->lock
);
67 #endif /* DEBUG_LOCKS */
68 lp
->owner_pc
= lp
->owner_cpu
= 0;
75 * Just like x86, implement read-write locks as a 32-bit counter
76 * with the high bit (sign) being the "write" bit.
79 void _read_lock(rwlock_t
*rw
)
82 unsigned long stuck
= INIT_STUCK
;
83 int cpu
= smp_processor_id();
84 #endif /* DEBUG_LOCKS */
87 /* get our read lock in there */
89 atomic_inc((atomic_t
*) &(rw
)->lock
);
90 if ( (signed long)((rw
)->lock
) < 0) /* someone has a write lock */
92 /* turn off our read lock */
93 atomic_dec((atomic_t
*) &(rw
)->lock
);
94 /* wait for the write lock to go away */
95 while ((signed long)((rw
)->lock
) < 0)
100 printk("_read_lock(%p) CPU#%d\n", rw
, cpu
);
103 #endif /* DEBUG_LOCKS */
105 /* try to get the read lock again */
111 void _read_unlock(rwlock_t
*rw
)
115 printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n",
116 current
->comm
,current
->pid
,current
->thread
.regs
->nip
,
118 #endif /* DEBUG_LOCKS */
120 atomic_dec((atomic_t
*) &(rw
)->lock
);
124 void _write_lock(rwlock_t
*rw
)
127 unsigned long stuck
= INIT_STUCK
;
128 int cpu
= smp_processor_id();
129 #endif /* DEBUG_LOCKS */
133 if ( test_and_set_bit(31,&(rw
)->lock
) ) /* someone has a write lock */
135 while ( (rw
)->lock
& (1<<31) ) /* wait for write lock */
140 printk("write_lock(%p) CPU#%d lock %lx)\n",
144 #endif /* DEBUG_LOCKS */
150 if ( (rw
)->lock
& ~(1<<31)) /* someone has a read lock */
152 /* clear our write lock and wait for reads to go away */
153 clear_bit(31,&(rw
)->lock
);
154 while ( (rw
)->lock
& ~(1<<31) )
159 printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
163 #endif /* DEBUG_LOCKS */
171 void _write_unlock(rwlock_t
*rw
)
174 if ( !(rw
->lock
& (1<<31)) )
175 printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n",
176 current
->comm
,current
->pid
,current
->thread
.regs
->nip
,
178 #endif /* DEBUG_LOCKS */
180 clear_bit(31,&(rw
)->lock
);
184 void __lock_kernel(struct task_struct
*task
)
187 unsigned long stuck
= INIT_STUCK
;
189 if ( (signed long)(task
->lock_depth
) < 0 )
191 printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
192 task
->comm
,task
->pid
,task
->thread
.regs
->nip
,
195 #endif /* DEBUG_LOCKS */
197 if (atomic_inc_return((atomic_t
*) &task
->lock_depth
) != 1)
200 while (__spin_trylock(&klock_info
.kernel_flag
)) {
203 printk("_lock_kernel() CPU#%d NIP %p\n",
205 __builtin_return_address(0));
208 #endif /* DEBUG_LOCKS */
211 klock_info
.akp
= smp_processor_id();
212 /* my kernel mode! mine!!! */
215 void __unlock_kernel(struct task_struct
*task
)
218 if ((task
->lock_depth
== 0) || (klock_info
.kernel_flag
!= KLOCK_HELD
))
220 printk("__unlock_kernel(): %s/%d (nip %08lX) "
221 "lock depth %x flags %lx\n",
222 task
->comm
,task
->pid
,task
->thread
.regs
->nip
,
223 task
->lock_depth
, klock_info
.kernel_flag
);
224 klock_info
.akp
= NO_PROC_ID
;
225 klock_info
.kernel_flag
= 0;
228 #endif /* DEBUG_LOCKS */
229 if (atomic_dec_and_test((atomic_t
*) &task
->lock_depth
))
232 klock_info
.akp
= NO_PROC_ID
;
234 klock_info
.kernel_flag
= KLOCK_CLEAR
;
239 void reacquire_kernel_lock(struct task_struct
*task
, int cpu
,int depth
)
245 task
->lock_depth
= depth
;