sref.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Copyright (c) 2014-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. *
  18. * Scalable reference counting.
  19. *
  20. * The purpose of this module is to reduce the amount of inter-processor
  21. * communication usually involved with reference counting. Scalable
  22. * reference counters should only be used when multiprocessor scalability
  23. * is important because of the costs they imply (increased memory usage
  24. * and latencies).
  25. *
  26. * When a counter drops to 0, the no-reference function associated with it
  27. * is called in work context. As a result, special care must be taken if
  28. * using sref counters in the work module itself.
  29. */
  30. #ifndef KERN_SREF_H
  31. #define KERN_SREF_H
  32. #include <stdint.h>
  33. #include <kern/init.h>
  34. #include <kern/slist.h>
  35. #include <kern/spinlock.h>
  36. #include <kern/work.h>
  37. struct sref_counter;
  38. // Type for no-reference functions.
  39. typedef void (*sref_noref_fn_t) (struct sref_counter *);
  40. #ifdef CONFIG_SREF_DEBUG
  41. #define SREF_VERIFY
  42. #endif
  43. /*
  44. * Weak reference.
  45. *
  46. * A weak reference is a pointer to a reference counter in which the
  47. * least-significant bit is used to indicate whether the counter is
  48. * "dying", i.e. about to be destroyed.
  49. *
  50. * It must be accessed with atomic instructions. There is no need to
  51. * enforce memory order on access since the only data that depends on
  52. * the weak reference are cpu-local deltas.
  53. */
  54. struct sref_weakref
  55. {
  56. uintptr_t addr;
  57. };
  58. /*
  59. * Scalable reference counter.
  60. *
  61. * It's tempting to merge the flags into the node member, but since they're
  62. * not protected by the same lock, store them separately.
  63. *
  64. * Locking keys :
  65. * (c) sref_counter
  66. * (g) sref_data
  67. *
  68. * Interrupts must be disabled when accessing a global counter.
  69. */
  70. struct sref_counter
  71. {
  72. sref_noref_fn_t noref_fn;
  73. #ifdef SREF_VERIFY
  74. struct
  75. #else
  76. union
  77. #endif
  78. {
  79. struct
  80. {
  81. struct slist_node node; // (g)
  82. struct spinlock lock;
  83. int flags; // (c)
  84. unsigned long value; // (c)
  85. struct sref_weakref *weakref;
  86. };
  87. struct work work;
  88. };
  89. };
  90. /*
  91. * Report a periodic event (normally the periodic timer interrupt) on the
  92. * current processor.
  93. *
  94. * Interrupts and preemption must be disabled when calling this function.
  95. */
  96. void sref_report_periodic_event (void);
  97. /*
  98. * Initialize a scalable reference counter.
  99. *
  100. * The no-reference function is called (from thread context) when it is
  101. * certain that the true number of references is 0.
  102. */
  103. void sref_counter_init (struct sref_counter *counter,
  104. unsigned long init_value,
  105. struct sref_weakref *weakref,
  106. sref_noref_fn_t noref_fn);
  107. /*
  108. * Counter operations.
  109. *
  110. * These functions may safely be called in interrupt context.
  111. *
  112. * These functions imply a compiler barrier.
  113. */
  114. void sref_counter_inc (struct sref_counter *counter);
  115. void sref_counter_dec (struct sref_counter *counter);
  116. /*
  117. * Attempt to get a reference from a weak reference.
  118. *
  119. * If successful, increment the reference counter before returning it.
  120. * Otherwise return NULL.
  121. *
  122. * This function may safely be called in interrupt context.
  123. */
  124. struct sref_counter* sref_weakref_get (struct sref_weakref *weakref);
  125. /*
  126. * This init operation provides :
  127. * - sref counter and weakref initialization and usage
  128. */
  129. INIT_OP_DECLARE (sref_bootstrap);
  130. #endif