mcs_spinlock.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include <linux/percpu.h>
  2. #include <linux/mutex.h>
  3. #include <linux/sched.h>
  4. #include "mcs_spinlock.h"
  5. #ifdef CONFIG_SMP
  6. /*
  7. * An MCS like lock especially tailored for optimistic spinning for sleeping
  8. * lock implementations (mutex, rwsem, etc).
  9. *
  10. * Using a single mcs node per CPU is safe because sleeping locks should not be
  11. * called from interrupt context and we have preemption disabled while
  12. * spinning.
  13. */
  14. static DEFINE_PER_CPU_SHARED_ALIGNED(struct optimistic_spin_queue, osq_node);
  15. /*
  16. * Get a stable @node->next pointer, either for unlock() or unqueue() purposes.
  17. * Can return NULL in case we were the last queued and we updated @lock instead.
  18. */
  19. static inline struct optimistic_spin_queue *
  20. osq_wait_next(struct optimistic_spin_queue **lock,
  21. struct optimistic_spin_queue *node,
  22. struct optimistic_spin_queue *prev)
  23. {
  24. struct optimistic_spin_queue *next = NULL;
  25. for (;;) {
  26. if (*lock == node && cmpxchg(lock, node, prev) == node) {
  27. /*
  28. * We were the last queued, we moved @lock back. @prev
  29. * will now observe @lock and will complete its
  30. * unlock()/unqueue().
  31. */
  32. break;
  33. }
  34. /*
  35. * We must xchg() the @node->next value, because if we were to
  36. * leave it in, a concurrent unlock()/unqueue() from
  37. * @node->next might complete Step-A and think its @prev is
  38. * still valid.
  39. *
  40. * If the concurrent unlock()/unqueue() wins the race, we'll
  41. * wait for either @lock to point to us, through its Step-B, or
  42. * wait for a new @node->next from its Step-C.
  43. */
  44. if (node->next) {
  45. next = xchg(&node->next, NULL);
  46. if (next)
  47. break;
  48. }
  49. arch_mutex_cpu_relax();
  50. }
  51. return next;
  52. }
  53. bool osq_lock(struct optimistic_spin_queue **lock)
  54. {
  55. struct optimistic_spin_queue *node = this_cpu_ptr(&osq_node);
  56. struct optimistic_spin_queue *prev, *next;
  57. node->locked = 0;
  58. node->next = NULL;
  59. node->prev = prev = xchg(lock, node);
  60. if (likely(prev == NULL))
  61. return true;
  62. ACCESS_ONCE(prev->next) = node;
  63. /*
  64. * Normally @prev is untouchable after the above store; because at that
  65. * moment unlock can proceed and wipe the node element from stack.
  66. *
  67. * However, since our nodes are static per-cpu storage, we're
  68. * guaranteed their existence -- this allows us to apply
  69. * cmpxchg in an attempt to undo our queueing.
  70. */
  71. while (!smp_load_acquire(&node->locked)) {
  72. /*
  73. * If we need to reschedule bail... so we can block.
  74. */
  75. if (need_resched())
  76. goto unqueue;
  77. arch_mutex_cpu_relax();
  78. }
  79. return true;
  80. unqueue:
  81. /*
  82. * Step - A -- stabilize @prev
  83. *
  84. * Undo our @prev->next assignment; this will make @prev's
  85. * unlock()/unqueue() wait for a next pointer since @lock points to us
  86. * (or later).
  87. */
  88. for (;;) {
  89. if (prev->next == node &&
  90. cmpxchg(&prev->next, node, NULL) == node)
  91. break;
  92. /*
  93. * We can only fail the cmpxchg() racing against an unlock(),
  94. * in which case we should observe @node->locked becomming
  95. * true.
  96. */
  97. if (smp_load_acquire(&node->locked))
  98. return true;
  99. arch_mutex_cpu_relax();
  100. /*
  101. * Or we race against a concurrent unqueue()'s step-B, in which
  102. * case its step-C will write us a new @node->prev pointer.
  103. */
  104. prev = ACCESS_ONCE(node->prev);
  105. }
  106. /*
  107. * Step - B -- stabilize @next
  108. *
  109. * Similar to unlock(), wait for @node->next or move @lock from @node
  110. * back to @prev.
  111. */
  112. next = osq_wait_next(lock, node, prev);
  113. if (!next)
  114. return false;
  115. /*
  116. * Step - C -- unlink
  117. *
  118. * @prev is stable because its still waiting for a new @prev->next
  119. * pointer, @next is stable because our @node->next pointer is NULL and
  120. * it will wait in Step-A.
  121. */
  122. ACCESS_ONCE(next->prev) = prev;
  123. ACCESS_ONCE(prev->next) = next;
  124. return false;
  125. }
  126. void osq_unlock(struct optimistic_spin_queue **lock)
  127. {
  128. struct optimistic_spin_queue *node = this_cpu_ptr(&osq_node);
  129. struct optimistic_spin_queue *next;
  130. /*
  131. * Fast path for the uncontended case.
  132. */
  133. if (likely(cmpxchg(lock, node, NULL) == node))
  134. return;
  135. /*
  136. * Second most likely case.
  137. */
  138. next = xchg(&node->next, NULL);
  139. if (next) {
  140. ACCESS_ONCE(next->locked) = 1;
  141. return;
  142. }
  143. next = osq_wait_next(lock, node, NULL);
  144. if (next)
  145. ACCESS_ONCE(next->locked) = 1;
  146. }
  147. #endif