[PATCH] m32r: Fix sys_tas() syscall
This patch fixes a deadlock problem of the m32r SMP kernel. In the m32r kernel, sys_tas() system call is provided as a test-and-set function for userspace, for backward compatibility. In some multi-threading application program, deadlocks were rarely caused at sys_tas() funcion. Such a deadlock was caused due to a collision of __pthread_lock() and __pthread_unlock() operations. The "tas" syscall is repeatedly called by pthread_mutex_lock() to get a lock, while a lock variable's value is not 0. On the other hand, pthead_mutex_unlock() sets the lock variable to 0 for unlocking. In the previous implementation of sys_tas() routine, there was a possibility that a unlock operation was ignored in the following case: - Assume a lock variable (*addr) was equal to 1 before sys_tas() execution. - __pthread_unlock() operation is executed by the other processor and the lock variable (*addr) is set to 0, between a read operation ("oldval = *addr;") and the following write operation ("*addr = 1;") during a execution of sys_tas(). In this case, the following write operation ("*addr = 1;") overwrites the __pthread_unlock() result, and sys_tas() fails to get a lock in the next turn and after that. According to the attatched patch, sys_tas() returns 0 value in the next turn and deadlocks never happen. Signed-off-by: Hitoshi Yamamoto <Yamamoto.Hitoshi@ap.MitsubishiElectric.co.jp> Signed-off-by: Hirokazu Takata <takata@linux-m32r.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
bce61dd49d
commit
91f4ab056d
1 changed files with 4 additions and 2 deletions
|
@ -41,7 +41,8 @@ asmlinkage int sys_tas(int *addr)
|
|||
return -EFAULT;
|
||||
local_irq_save(flags);
|
||||
oldval = *addr;
|
||||
*addr = 1;
|
||||
if (!oldval)
|
||||
*addr = 1;
|
||||
local_irq_restore(flags);
|
||||
return oldval;
|
||||
}
|
||||
|
@ -59,7 +60,8 @@ asmlinkage int sys_tas(int *addr)
|
|||
|
||||
_raw_spin_lock(&tas_lock);
|
||||
oldval = *addr;
|
||||
*addr = 1;
|
||||
if (!oldval)
|
||||
*addr = 1;
|
||||
_raw_spin_unlock(&tas_lock);
|
||||
|
||||
return oldval;
|
||||
|
|
Loading…
Reference in a new issue