2005-04-16 15:20:36 -07:00
/* semaphore.c: FR-V semaphores
*
* Copyright ( C ) 2003 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
* - Derived from lib / rwsem - spinlock . c
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/sched.h>
# include <linux/module.h>
# include <asm/semaphore.h>
struct sem_waiter {
struct list_head list ;
struct task_struct * task ;
} ;
2007-05-08 00:25:02 -07:00
# ifdef CONFIG_DEBUG_SEMAPHORE
2005-04-16 15:20:36 -07:00
void semtrace ( struct semaphore * sem , const char * str )
{
if ( sem - > debug )
printk ( " [%d] %s({%d,%d}) \n " ,
current - > pid ,
str ,
sem - > counter ,
list_empty ( & sem - > wait_list ) ? 0 : 1 ) ;
}
# else
# define semtrace(SEM,STR) do { } while(0)
# endif
/*
* wait for a token to be granted from a semaphore
* - entered with lock held and interrupts disabled
*/
void __down ( struct semaphore * sem , unsigned long flags )
{
struct task_struct * tsk = current ;
struct sem_waiter waiter ;
semtrace ( sem , " Entering __down " ) ;
/* set up my own style of waitqueue */
waiter . task = tsk ;
get_task_struct ( tsk ) ;
list_add_tail ( & waiter . list , & sem - > wait_list ) ;
/* we don't need to touch the semaphore struct anymore */
spin_unlock_irqrestore ( & sem - > wait_lock , flags ) ;
/* wait to be given the semaphore */
set_task_state ( tsk , TASK_UNINTERRUPTIBLE ) ;
for ( ; ; ) {
if ( list_empty ( & waiter . list ) )
break ;
schedule ( ) ;
set_task_state ( tsk , TASK_UNINTERRUPTIBLE ) ;
}
tsk - > state = TASK_RUNNING ;
semtrace ( sem , " Leaving __down " ) ;
}
EXPORT_SYMBOL ( __down ) ;
/*
* interruptibly wait for a token to be granted from a semaphore
* - entered with lock held and interrupts disabled
*/
int __down_interruptible ( struct semaphore * sem , unsigned long flags )
{
struct task_struct * tsk = current ;
struct sem_waiter waiter ;
int ret ;
semtrace ( sem , " Entering __down_interruptible " ) ;
/* set up my own style of waitqueue */
waiter . task = tsk ;
get_task_struct ( tsk ) ;
list_add_tail ( & waiter . list , & sem - > wait_list ) ;
/* we don't need to touch the semaphore struct anymore */
set_task_state ( tsk , TASK_INTERRUPTIBLE ) ;
spin_unlock_irqrestore ( & sem - > wait_lock , flags ) ;
/* wait to be given the semaphore */
ret = 0 ;
for ( ; ; ) {
if ( list_empty ( & waiter . list ) )
break ;
if ( unlikely ( signal_pending ( current ) ) )
goto interrupted ;
schedule ( ) ;
set_task_state ( tsk , TASK_INTERRUPTIBLE ) ;
}
out :
tsk - > state = TASK_RUNNING ;
semtrace ( sem , " Leaving __down_interruptible " ) ;
return ret ;
interrupted :
spin_lock_irqsave ( & sem - > wait_lock , flags ) ;
if ( ! list_empty ( & waiter . list ) ) {
list_del ( & waiter . list ) ;
ret = - EINTR ;
}
spin_unlock_irqrestore ( & sem - > wait_lock , flags ) ;
if ( ret = = - EINTR )
put_task_struct ( current ) ;
goto out ;
}
EXPORT_SYMBOL ( __down_interruptible ) ;
/*
* release a single token back to a semaphore
* - entered with lock held and interrupts disabled
*/
void __up ( struct semaphore * sem )
{
struct task_struct * tsk ;
struct sem_waiter * waiter ;
semtrace ( sem , " Entering __up " ) ;
/* grant the token to the process at the front of the queue */
waiter = list_entry ( sem - > wait_list . next , struct sem_waiter , list ) ;
/* We must be careful not to touch 'waiter' after we set ->task = NULL.
2007-10-20 01:09:42 +02:00
* It is allocated on the waiter ' s stack and may become invalid at
2005-04-16 15:20:36 -07:00
* any time after that point ( due to a wakeup from another source ) .
*/
list_del_init ( & waiter - > list ) ;
tsk = waiter - > task ;
mb ( ) ;
waiter - > task = NULL ;
wake_up_process ( tsk ) ;
put_task_struct ( tsk ) ;
semtrace ( sem , " Leaving __up " ) ;
}
EXPORT_SYMBOL ( __up ) ;