dec_and_lock.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/export.h>
  3. #include <linux/spinlock.h>
  4. #include <linux/atomic.h>
  5. /*
  6. * This is an implementation of the notion of "decrement a
  7. * reference count, and return locked if it decremented to zero".
  8. *
  9. * NOTE NOTE NOTE! This is _not_ equivalent to
  10. *
  11. * if (atomic_dec_and_test(&atomic)) {
  12. * spin_lock(&lock);
  13. * return 1;
  14. * }
  15. * return 0;
  16. *
  17. * because the spin-lock and the decrement must be
  18. * "atomic".
  19. */
  20. int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
  21. {
  22. /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
  23. if (atomic_add_unless(atomic, -1, 1))
  24. return 0;
  25. /* Otherwise do it the slow way */
  26. spin_lock(lock);
  27. if (atomic_dec_and_test(atomic))
  28. return 1;
  29. spin_unlock(lock);
  30. return 0;
  31. }
  32. EXPORT_SYMBOL(atomic_dec_and_lock);
  33. int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
  34. unsigned long *flags)
  35. {
  36. /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
  37. if (atomic_add_unless(atomic, -1, 1))
  38. return 0;
  39. /* Otherwise do it the slow way */
  40. spin_lock_irqsave(lock, *flags);
  41. if (atomic_dec_and_test(atomic))
  42. return 1;
  43. spin_unlock_irqrestore(lock, *flags);
  44. return 0;
  45. }
  46. EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave);
  47. int atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)
  48. {
  49. /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
  50. if (atomic_add_unless(atomic, -1, 1))
  51. return 0;
  52. /* Otherwise do it the slow way */
  53. raw_spin_lock(lock);
  54. if (atomic_dec_and_test(atomic))
  55. return 1;
  56. raw_spin_unlock(lock);
  57. return 0;
  58. }
  59. EXPORT_SYMBOL(atomic_dec_and_raw_lock);
  60. int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock_t *lock,
  61. unsigned long *flags)
  62. {
  63. /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
  64. if (atomic_add_unless(atomic, -1, 1))
  65. return 0;
  66. /* Otherwise do it the slow way */
  67. raw_spin_lock_irqsave(lock, *flags);
  68. if (atomic_dec_and_test(atomic))
  69. return 1;
  70. raw_spin_unlock_irqrestore(lock, *flags);
  71. return 0;
  72. }
  73. EXPORT_SYMBOL(_atomic_dec_and_raw_lock_irqsave);