 6ab3d5624e
			
		
	
	
	6ab3d5624e
	
	
	
		
			
			Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de> Signed-off-by: Adrian Bunk <bunk@stusta.de>
		
			
				
	
	
		
			132 lines
		
	
	
	
		
			3.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
	
		
			3.7 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  Generic semaphore code. Buyer beware. Do your own
 | |
|  * specific changes in <asm/semaphore-helper.h>
 | |
|  */
 | |
| 
 | |
| #include <linux/sched.h>
 | |
| #include <linux/init.h>
 | |
| #include <asm/semaphore-helper.h>
 | |
| 
 | |
| #ifndef CONFIG_RMW_INSNS
 | |
| spinlock_t semaphore_wake_lock;
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * Semaphores are implemented using a two-way counter:
 | |
|  * The "count" variable is decremented for each process
 | |
|  * that tries to sleep, while the "waking" variable is
 | |
|  * incremented when the "up()" code goes to wake up waiting
 | |
|  * processes.
 | |
|  *
 | |
|  * Notably, the inline "up()" and "down()" functions can
 | |
|  * efficiently test if they need to do any extra work (up
 | |
|  * needs to do something only if count was negative before
 | |
|  * the increment operation.
 | |
|  *
 | |
|  * waking_non_zero() (from asm/semaphore.h) must execute
 | |
|  * atomically.
 | |
|  *
 | |
|  * When __up() is called, the count was negative before
 | |
|  * incrementing it, and we need to wake up somebody.
 | |
|  *
 | |
|  * This routine adds one to the count of processes that need to
 | |
|  * wake up and exit.  ALL waiting processes actually wake up but
 | |
|  * only the one that gets to the "waking" field first will gate
 | |
|  * through and acquire the semaphore.  The others will go back
 | |
|  * to sleep.
 | |
|  *
 | |
|  * Note that these functions are only called when there is
 | |
|  * contention on the lock, and as such all this is the
 | |
|  * "non-critical" part of the whole semaphore business. The
 | |
|  * critical part is the inline stuff in <asm/semaphore.h>
 | |
|  * where we want to avoid any extra jumps and calls.
 | |
|  */
 | |
| void __up(struct semaphore *sem)
 | |
| {
 | |
| 	wake_one_more(sem);
 | |
| 	wake_up(&sem->wait);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Perform the "down" function.  Return zero for semaphore acquired,
 | |
|  * return negative for signalled out of the function.
 | |
|  *
 | |
|  * If called from __down, the return is ignored and the wait loop is
 | |
|  * not interruptible.  This means that a task waiting on a semaphore
 | |
|  * using "down()" cannot be killed until someone does an "up()" on
 | |
|  * the semaphore.
 | |
|  *
 | |
|  * If called from __down_interruptible, the return value gets checked
 | |
|  * upon return.  If the return value is negative then the task continues
 | |
|  * with the negative value in the return register (it can be tested by
 | |
|  * the caller).
 | |
|  *
 | |
|  * Either form may be used in conjunction with "up()".
 | |
|  *
 | |
|  */
 | |
| 
 | |
| 
 | |
| #define DOWN_HEAD(task_state)						\
 | |
| 									\
 | |
| 									\
 | |
| 	current->state = (task_state);					\
 | |
| 	add_wait_queue(&sem->wait, &wait);				\
 | |
| 									\
 | |
| 	/*								\
 | |
| 	 * Ok, we're set up.  sem->count is known to be less than zero	\
 | |
| 	 * so we must wait.						\
 | |
| 	 *								\
 | |
| 	 * We can let go the lock for purposes of waiting.		\
 | |
| 	 * We re-acquire it after awaking so as to protect		\
 | |
| 	 * all semaphore operations.					\
 | |
| 	 *								\
 | |
| 	 * If "up()" is called before we call waking_non_zero() then	\
 | |
| 	 * we will catch it right away.  If it is called later then	\
 | |
| 	 * we will have to go through a wakeup cycle to catch it.	\
 | |
| 	 *								\
 | |
| 	 * Multiple waiters contend for the semaphore lock to see	\
 | |
| 	 * who gets to gate through and who has to wait some more.	\
 | |
| 	 */								\
 | |
| 	for (;;) {
 | |
| 
 | |
| #define DOWN_TAIL(task_state)			\
 | |
| 		current->state = (task_state);	\
 | |
| 	}					\
 | |
| 	current->state = TASK_RUNNING;		\
 | |
| 	remove_wait_queue(&sem->wait, &wait);
 | |
| 
 | |
| void __sched __down(struct semaphore * sem)
 | |
| {
 | |
| 	DECLARE_WAITQUEUE(wait, current);
 | |
| 
 | |
| 	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
 | |
| 	if (waking_non_zero(sem))
 | |
| 		break;
 | |
| 	schedule();
 | |
| 	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
 | |
| }
 | |
| 
 | |
| int __sched __down_interruptible(struct semaphore * sem)
 | |
| {
 | |
| 	DECLARE_WAITQUEUE(wait, current);
 | |
| 	int ret = 0;
 | |
| 
 | |
| 	DOWN_HEAD(TASK_INTERRUPTIBLE)
 | |
| 
 | |
| 	ret = waking_non_zero_interruptible(sem, current);
 | |
| 	if (ret)
 | |
| 	{
 | |
| 		if (ret == 1)
 | |
| 			/* ret != 0 only if we get interrupted -arca */
 | |
| 			ret = 0;
 | |
| 		break;
 | |
| 	}
 | |
| 	schedule();
 | |
| 	DOWN_TAIL(TASK_INTERRUPTIBLE)
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| int __down_trylock(struct semaphore * sem)
 | |
| {
 | |
| 	return waking_non_zero_trylock(sem);
 | |
| }
 |