dec_and_lock.c 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  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);