dec_and_lock.c 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. #include <linux/module.h>
  2. #include <linux/spinlock.h>
  3. #include <asm/atomic.h>
  4. #include <asm/system.h>
  5. #ifdef __HAVE_ARCH_CMPXCHG
  6. /*
  7. * This is an implementation of the notion of "decrement a
  8. * reference count, and return locked if it decremented to zero".
  9. *
  10. * This implementation can be used on any architecture that
  11. * has a cmpxchg, and where atomic->value is an int holding
  12. * the value of the atomic (i.e. the high bits aren't used
  13. * for a lock or anything like that).
  14. */
  15. int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
  16. {
  17. int counter;
  18. int newcount;
  19. for (;;) {
  20. counter = atomic_read(atomic);
  21. newcount = counter - 1;
  22. if (!newcount)
  23. break; /* do it the slow way */
  24. newcount = cmpxchg(&atomic->counter, counter, newcount);
  25. if (newcount == counter)
  26. return 0;
  27. }
  28. spin_lock(lock);
  29. if (atomic_dec_and_test(atomic))
  30. return 1;
  31. spin_unlock(lock);
  32. return 0;
  33. }
  34. #else
  35. /*
  36. * This is an architecture-neutral, but slow,
  37. * implementation of the notion of "decrement
  38. * a reference count, and return locked if it
  39. * decremented to zero".
  40. *
  41. * NOTE NOTE NOTE! This is _not_ equivalent to
  42. *
  43. * if (atomic_dec_and_test(&atomic)) {
  44. * spin_lock(&lock);
  45. * return 1;
  46. * }
  47. * return 0;
  48. *
  49. * because the spin-lock and the decrement must be
  50. * "atomic".
  51. *
  52. * This slow version gets the spinlock unconditionally,
  53. * and releases it if it isn't needed. Architectures
  54. * are encouraged to come up with better approaches,
  55. * this is trivially done efficiently using a load-locked
  56. * store-conditional approach, for example.
  57. */
  58. int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
  59. {
  60. spin_lock(lock);
  61. if (atomic_dec_and_test(atomic))
  62. return 1;
  63. spin_unlock(lock);
  64. return 0;
  65. }
  66. #endif
  67. EXPORT_SYMBOL(_atomic_dec_and_lock);