b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
8bc3bcc93a2b4 (Paul Gortmaker 2011-11-16 21:29:17 -0500 2) #include <linux/export.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) #include <linux/spinlock.h>
60063497a95e7 (Arun Sharma 2011-07-26 16:09:06 -0700 4) #include <linux/atomic.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5)
4db2ce0199f04 (David S. Miller 2005-09-14 21:47:01 -0700 6) /*
4db2ce0199f04 (David S. Miller 2005-09-14 21:47:01 -0700 7) * This is an implementation of the notion of "decrement a
4db2ce0199f04 (David S. Miller 2005-09-14 21:47:01 -0700 8) * reference count, and return locked if it decremented to zero".
4db2ce0199f04 (David S. Miller 2005-09-14 21:47:01 -0700 9) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) * NOTE NOTE NOTE! This is _not_ equivalent to
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) * if (atomic_dec_and_test(&atomic)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) * spin_lock(&lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) * return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) * }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) * return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) * because the spin-lock and the decrement must be
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) * "atomic".
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) {
a57004e1afb6e (Nicholas Piggin 2006-01-08 01:02:19 -0800 23) /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
a57004e1afb6e (Nicholas Piggin 2006-01-08 01:02:19 -0800 24) if (atomic_add_unless(atomic, -1, 1))
a57004e1afb6e (Nicholas Piggin 2006-01-08 01:02:19 -0800 25) return 0;
417dcdf99ec9f (Jan Blunck 2009-06-16 15:33:33 -0700 26)
a57004e1afb6e (Nicholas Piggin 2006-01-08 01:02:19 -0800 27) /* Otherwise do it the slow way */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) spin_lock(lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) if (atomic_dec_and_test(atomic))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) spin_unlock(lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) EXPORT_SYMBOL(_atomic_dec_and_lock);
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 36)
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 37) int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock,
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 38) unsigned long *flags)
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 39) {
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 40) /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 41) if (atomic_add_unless(atomic, -1, 1))
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 42) return 0;
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 43)
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 44) /* Otherwise do it the slow way */
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 45) spin_lock_irqsave(lock, *flags);
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 46) if (atomic_dec_and_test(atomic))
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 47) return 1;
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 48) spin_unlock_irqrestore(lock, *flags);
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 49) return 0;
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 50) }
ccfbb5bed4070 (Anna-Maria Gleixner 2018-06-12 18:16:20 +0200 51) EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave);