1c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#ifndef _I386_SEMAPHORE_H 2c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#define _I386_SEMAPHORE_H 3c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 4c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#include <linux/linkage.h> 5c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 6c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#ifdef __KERNEL__ 7c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 8c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru/* 9c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * SMP- and interrupt-safe semaphores.. 10c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * 11c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * (C) Copyright 1996 Linus Torvalds 12c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * 13c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in 14c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * the original code and to make semaphore waits 15c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * interruptible so that processes waiting on 16c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * semaphores can be killed. 17c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper 18c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * functions in asm/sempahore-helper.h while fixing a 19c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * potential and subtle race discovered by Ulrich Schmid 20c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * in down_interruptible(). Since I started to play here I 21c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * also implemented the `trylock' semaphore operation. 22c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * 1999-07-02 Artur Skawina <skawina@geocities.com> 23c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Optimized "0(ecx)" -> "(ecx)" (the assembler does not 24c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * do this). Changed calling sequences from push/jmp to 25c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * traditional call/ret. 26c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Modified 2001-01-01 Andreas Franck <afranck@gmx.de> 27c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Some hacks to ensure compatibility with recent 28c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * GCC snapshots, to avoid stack corruption when compiling 29c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * with -fomit-frame-pointer. It's not sure if this will 30c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * be fixed in GCC, as our previous implementation was a 31c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * bit dubious. 32c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * 33c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * If you would like to see an analysis of this implementation, please 34c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * ftp to gcom.com and download the file 35c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz. 36c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * 37c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru */ 38c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 39c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#include <asm/system.h> 40c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#include <asm/atomic.h> 41c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#include <linux/wait.h> 42c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#include <linux/rwsem.h> 43c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 44c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustruct semaphore { 45c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru atomic_t count; 46c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru int sleepers; 47c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru wait_queue_head_t wait; 48c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru}; 49c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 50c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 51c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#define __SEMAPHORE_INITIALIZER(name, n) \ 52c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ \ 53c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru .count = ATOMIC_INIT(n), \ 54c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru .sleepers = 0, \ 55c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ 56c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 57c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 58c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ 59c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) 60c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 61c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) 62c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 63c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline void sema_init (struct semaphore *sem, int val) 64c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 65c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru/* 66c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); 67c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * 68c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * i'd rather use the more flexible initialization above, but sadly 69c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * GCC 2.7.2.3 emits a bogus warning. EGCS doesn't. Oh well. 70c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru */ 71c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru atomic_set(&sem->count, val); 72c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru sem->sleepers = 0; 73c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru init_waitqueue_head(&sem->wait); 74c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 75c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 76c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline void init_MUTEX (struct semaphore *sem) 77c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 78c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru sema_init(sem, 1); 79c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 80c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 81c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline void init_MUTEX_LOCKED (struct semaphore *sem) 82c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 83c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru sema_init(sem, 0); 84c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 85c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 86c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querufastcall void __down_failed(void /* special register calling convention */); 87c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querufastcall int __down_failed_interruptible(void /* params in registers */); 88c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querufastcall int __down_failed_trylock(void /* params in registers */); 89c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querufastcall void __up_wakeup(void /* special register calling convention */); 90c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 91c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru/* 92c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * This is ugly, but we want the default case to fall through. 93c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * "__down_failed" is a special asm handler that calls the C 94c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * routine that actually waits. See arch/i386/kernel/semaphore.c 95c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru */ 96c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline void down(struct semaphore * sem) 97c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 98c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru might_sleep(); 99c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru __asm__ __volatile__( 100c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "# atomic down operation\n\t" 101c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru LOCK_PREFIX "decl %0\n\t" /* --sem->count */ 102c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "jns 2f\n" 103c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "\tlea %0,%%eax\n\t" 104c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "call __down_failed\n" 105c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "2:" 106c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"+m" (sem->count) 107c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru : 108c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"memory","ax"); 109c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 110c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 111c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru/* 112c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Interruptible try to acquire a semaphore. If we obtained 113c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * it, return zero. If we were interrupted, returns -EINTR 114c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru */ 115c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline int down_interruptible(struct semaphore * sem) 116c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 117c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru int result; 118c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 119c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru might_sleep(); 120c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru __asm__ __volatile__( 121c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "# atomic interruptible down operation\n\t" 122c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "xorl %0,%0\n\t" 123c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru LOCK_PREFIX "decl %1\n\t" /* --sem->count */ 124c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "jns 2f\n\t" 125c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "lea %1,%%eax\n\t" 126c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "call __down_failed_interruptible\n" 127c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "2:" 128c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"=&a" (result), "+m" (sem->count) 129c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru : 130c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"memory"); 131c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru return result; 132c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 133c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 134c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru/* 135c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Non-blockingly attempt to down() a semaphore. 136c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Returns zero if we acquired it 137c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru */ 138c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline int down_trylock(struct semaphore * sem) 139c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 140c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru int result; 141c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 142c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru __asm__ __volatile__( 143c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "# atomic interruptible down operation\n\t" 144c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "xorl %0,%0\n\t" 145c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru LOCK_PREFIX "decl %1\n\t" /* --sem->count */ 146c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "jns 2f\n\t" 147c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "lea %1,%%eax\n\t" 148c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "call __down_failed_trylock\n\t" 149c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "2:\n" 150c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"=&a" (result), "+m" (sem->count) 151c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru : 152c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"memory"); 153c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru return result; 154c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 155c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 156c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru/* 157c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * Note! This is subtle. We jump to wake people up only if 158c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru * the semaphore was negative (== somebody was waiting on it). 159c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru */ 160c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Querustatic inline void up(struct semaphore * sem) 161c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru{ 162c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru __asm__ __volatile__( 163c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "# atomic up operation\n\t" 164c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru LOCK_PREFIX "incl %0\n\t" /* ++sem->count */ 165c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "jg 1f\n\t" 166c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "lea %0,%%eax\n\t" 167c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "call __up_wakeup\n" 168c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru "1:" 169c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"+m" (sem->count) 170c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru : 171c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru :"memory","ax"); 172c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru} 173c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru 174c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#endif 175c559cd81139f97cecad1ad91a0b2e25a5936d53Jean-Baptiste Queru#endif 176