semaphore.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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