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