sref.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  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. * This implementation is based on the paper "RadixVM: Scalable address
  19. * spaces for multithreaded applications" by Austin T. Clements,
  20. * M. Frans Kaashoek, and Nickolai Zeldovich. Specifically, it implements
  21. * the Refcache component described in the paper, with a few differences
  22. * outlined below.
  23. *
  24. * Refcache flushes delta caches directly from an interrupt handler, and
  25. * disables interrupts and preemption on cache access. That behavior is
  26. * realtime-unfriendly because of the potentially large number of deltas
  27. * in a cache. This module uses dedicated manager threads to perform
  28. * cache flushes and queue reviews, and only disables preemption on
  29. * individual delta access.
  30. *
  31. * Locking protocol : cache -> counter -> global data
  32. */
  33. #include <assert.h>
  34. #include <errno.h>
  35. #include <stdbool.h>
  36. #include <stddef.h>
  37. #include <stdint.h>
  38. #include <stdio.h>
  39. #include <kern/atomic.h>
  40. #include <kern/clock.h>
  41. #include <kern/cpumap.h>
  42. #include <kern/init.h>
  43. #include <kern/list.h>
  44. #include <kern/log.h>
  45. #include <kern/macros.h>
  46. #include <kern/panic.h>
  47. #include <kern/percpu.h>
  48. #include <kern/slist.h>
  49. #include <kern/spinlock.h>
  50. #include <kern/sref.h>
  51. #include <kern/syscnt.h>
  52. #include <kern/thread.h>
  53. #include <machine/cpu.h>
  54. // Counter flags.
  55. #define SREF_CNTF_QUEUED 0x1 // Queued for review
  56. #define SREF_CNTF_DIRTY 0x2 // Dirty zero seen
  57. #define SREF_CNTF_UNREF 0x4 // Unreferenced, for debugging only
  58. // Per-cache delta table size.
  59. #define SREF_CACHE_DELTA_TABLE_SIZE 4096
  60. #if !ISP2 (SREF_CACHE_DELTA_TABLE_SIZE)
  61. #error "delta table size must be a power-of-two"
  62. #endif
  63. #ifdef __LP64__
  64. #define SREF_HASH_SHIFT 3
  65. #else
  66. #define SREF_HASH_SHIFT 2
  67. #endif
  68. // Negative close to 0 so that an overflow occurs early.
  69. #define SREF_EPOCH_ID_INIT_VALUE ((uint32_t)-500)
  70. // Weakref flags.
  71. #define SREF_WEAKREF_DYING ((uintptr_t)1)
  72. #define SREF_WEAKREF_MASK (~SREF_WEAKREF_DYING)
  73. /*
  74. * Since review queues are processor-local, at least two local epochs
  75. * must have passed before a zero is considered a true zero. As a result,
  76. * three queues are required, one for the current epoch, and two more.
  77. * The queues are stored in an array used as a ring buffer that moves
  78. * forward with each new local epoch. Indexing in this array is done
  79. * with a binary mask instead of a modulo, for performance reasons, and
  80. * consequently, the array size must be at least the nearest power-of-two
  81. * above three.
  82. */
  83. #define SREF_NR_QUEUES P2ROUND (3, 2)
  84. // Number of counters in review queue beyond which to issue a warning.
  85. #define SREF_NR_COUNTERS_WARN 10000
  86. /*
  87. * Global data.
  88. *
  89. * Processors regularly check the global epoch ID against their own,
  90. * locally cached epoch ID. If they're the same, a processor flushes
  91. * its cached deltas, acknowledges its flush by decrementing the number
  92. * of pending acknowledgment counter, and increments its local epoch ID,
  93. * preventing additional flushes during the same epoch.
  94. *
  95. * The last processor to acknowledge starts the next epoch.
  96. *
  97. * The epoch ID and the pending acknowledgments counter fill an entire
  98. * cache line each in order to avoid false sharing on SMP. Whenever
  99. * multiple processors may access them, they must use atomic operations
  100. * to avoid data races.
  101. *
  102. * Atomic operations on the pending acknowledgments counter are done
  103. * with acquire-release ordering to enforce the memory ordering
  104. * guarantees required by both the implementation and the interface.
  105. */
  106. struct sref_data
  107. {
  108. __cacheline_aligned uint32_t epoch_id;
  109. __cacheline_aligned uint32_t nr_pending_acks;
  110. uint64_t start_ts;
  111. struct syscnt sc_epochs;
  112. struct syscnt sc_dirty_zeroes;
  113. struct syscnt sc_true_zeroes;
  114. struct syscnt sc_revives;
  115. struct syscnt sc_last_epoch_ms;
  116. struct syscnt sc_longest_epoch_ms;
  117. };
  118. /*
  119. * Temporary difference to apply on a reference counter.
  120. *
  121. * Deltas are stored in per-processor caches and added to their global
  122. * counter when flushed. A delta is valid if and only if the counter it
  123. * points to isn't NULL.
  124. *
  125. * On cache flush, if a delta is valid, it must be flushed whatever its
  126. * value because a delta can be a dirty zero too. By flushing all valid
  127. * deltas, and clearing them all after a flush, activity on a counter is
  128. * reliably reported.
  129. */
  130. struct sref_delta
  131. {
  132. struct list node;
  133. struct sref_counter *counter;
  134. unsigned long value;
  135. };
  136. struct sref_queue
  137. {
  138. struct slist counters;
  139. unsigned long size;
  140. };
  141. /*
  142. * Per-processor cache of deltas.
  143. *
  144. * A cache is dirty if there is at least one delta that requires flushing.
  145. * It may only be flushed once per epoch.
  146. *
  147. * Delta caches are implemented with hash tables for quick ref count to
  148. * delta lookups. For now, a very simple replacement policy, similar to
  149. * that described in the RadixVM paper, is used. Improve with an LRU-like
  150. * algorithm if this turns out to be a problem.
  151. *
  152. * Periodic events (normally the system timer tick) trigger cache checks.
  153. * A cache check may wake up the manager thread if the cache needs management,
  154. * i.e. if it's dirty or if there are counters to review. Otherwise, the
  155. * flush acknowledgment is done directly to avoid the cost of a thread
  156. * wake-up.
  157. *
  158. * Interrupts and preemption must be disabled when accessing a delta cache.
  159. */
  160. struct sref_cache
  161. {
  162. struct sref_data *data;
  163. bool dirty;
  164. bool flushed;
  165. uint32_t epoch_id;
  166. struct sref_delta deltas[SREF_CACHE_DELTA_TABLE_SIZE];
  167. struct list valid_deltas;
  168. struct sref_queue queues[SREF_NR_QUEUES];
  169. struct thread *manager;
  170. struct syscnt sc_collisions;
  171. struct syscnt sc_flushes;
  172. };
  173. static struct sref_data sref_data;
  174. static struct sref_cache sref_cache __percpu;
  175. static uint32_t
  176. sref_data_get_epoch_id (const struct sref_data *data)
  177. {
  178. return (data->epoch_id);
  179. }
  180. static bool
  181. sref_data_check_epoch_id (const struct sref_data *data, uint32_t epoch_id)
  182. {
  183. if (likely (atomic_load_rlx (&data->epoch_id) != epoch_id))
  184. return (false);
  185. atomic_fence_acq ();
  186. return (true);
  187. }
  188. static void
  189. sref_data_start_epoch (struct sref_data *data)
  190. {
  191. uint64_t now = clock_get_time (),
  192. duration = clock_ticks_to_ms (now - data->start_ts);
  193. syscnt_set (&data->sc_last_epoch_ms, duration);
  194. if (duration > syscnt_read (&data->sc_longest_epoch_ms))
  195. syscnt_set (&data->sc_longest_epoch_ms, duration);
  196. assert (data->nr_pending_acks == 0);
  197. data->nr_pending_acks = cpu_count();
  198. data->start_ts = now;
  199. uint32_t epoch_id = atomic_load_rlx (&data->epoch_id);
  200. atomic_store_rel (&data->epoch_id, epoch_id + 1);
  201. }
  202. static void
  203. sref_data_ack_cpu (struct sref_data *data)
  204. {
  205. uint32_t prev = atomic_sub_acq_rel (&data->nr_pending_acks, 1);
  206. if (prev != 1)
  207. {
  208. assert (prev != 0);
  209. return;
  210. }
  211. syscnt_inc (&data->sc_epochs);
  212. sref_data_start_epoch (data);
  213. }
  214. static void
  215. sref_data_update_stats (struct sref_data *data, int64_t nr_dirty_zeroes,
  216. int64_t nr_true_zeroes, int64_t nr_revives)
  217. {
  218. syscnt_add (&data->sc_dirty_zeroes, nr_dirty_zeroes);
  219. syscnt_add (&data->sc_true_zeroes, nr_true_zeroes);
  220. syscnt_add (&data->sc_revives, nr_revives);
  221. }
  222. static bool
  223. sref_counter_aligned (const struct sref_counter *counter)
  224. {
  225. return (((uintptr_t)counter & ~SREF_WEAKREF_MASK) == 0);
  226. }
  227. static void
  228. sref_weakref_init (struct sref_weakref *weakref, struct sref_counter *counter)
  229. {
  230. assert (sref_counter_aligned (counter));
  231. weakref->addr = (uintptr_t)counter;
  232. }
  233. static void
  234. sref_weakref_mark_dying (struct sref_weakref *weakref)
  235. {
  236. atomic_or_rlx (&weakref->addr, SREF_WEAKREF_DYING);
  237. }
  238. static void
  239. sref_weakref_clear_dying (struct sref_weakref *weakref)
  240. {
  241. atomic_and_rlx (&weakref->addr, SREF_WEAKREF_MASK);
  242. }
  243. static int
  244. sref_weakref_kill (struct sref_weakref *weakref)
  245. {
  246. uintptr_t addr = atomic_load_rlx (&weakref->addr) | SREF_WEAKREF_DYING,
  247. oldval = atomic_cas_rlx (&weakref->addr, addr, 0);
  248. if (oldval == addr)
  249. return (0);
  250. assert ((oldval & SREF_WEAKREF_MASK) == (addr & SREF_WEAKREF_MASK));
  251. return (EBUSY);
  252. }
  253. static struct sref_counter*
  254. sref_weakref_tryget (struct sref_weakref *weakref)
  255. {
  256. uintptr_t prev = atomic_and_rlx (&weakref->addr, SREF_WEAKREF_MASK);
  257. return ((struct sref_counter *)(prev & SREF_WEAKREF_MASK));
  258. }
  259. static uintptr_t
  260. sref_counter_hash (const struct sref_counter *counter)
  261. {
  262. uintptr_t va = (uintptr_t) counter;
  263. assert (P2ALIGNED (va, 1UL << SREF_HASH_SHIFT));
  264. return (va >> SREF_HASH_SHIFT);
  265. }
  266. static bool
  267. sref_counter_is_queued (const struct sref_counter *counter)
  268. {
  269. return ((counter->flags & SREF_CNTF_QUEUED) != 0);
  270. }
  271. static void
  272. sref_counter_mark_queued (struct sref_counter *counter)
  273. {
  274. counter->flags |= SREF_CNTF_QUEUED;
  275. }
  276. static void
  277. sref_counter_clear_queued (struct sref_counter *counter)
  278. {
  279. counter->flags &= ~SREF_CNTF_QUEUED;
  280. }
  281. static bool
  282. sref_counter_is_dirty (const struct sref_counter *counter)
  283. {
  284. return ((counter->flags & SREF_CNTF_DIRTY) != 0);
  285. }
  286. static void
  287. sref_counter_mark_dirty (struct sref_counter *counter)
  288. {
  289. counter->flags |= SREF_CNTF_DIRTY;
  290. }
  291. static void
  292. sref_counter_clear_dirty (struct sref_counter *counter)
  293. {
  294. counter->flags &= ~SREF_CNTF_DIRTY;
  295. }
  296. #ifdef SREF_VERIFY
  297. static bool
  298. sref_counter_is_unreferenced (const struct sref_counter *counter)
  299. {
  300. return ((counter->flags & SREF_CNTF_UNREF) != 0);
  301. }
  302. static void
  303. sref_counter_mark_unreferenced (struct sref_counter *counter)
  304. {
  305. counter->flags |= SREF_CNTF_UNREF;
  306. }
  307. #endif
  308. static void
  309. sref_counter_mark_dying (struct sref_counter *counter)
  310. {
  311. if (counter->weakref)
  312. sref_weakref_mark_dying (counter->weakref);
  313. }
  314. static void
  315. sref_counter_clear_dying (struct sref_counter *counter)
  316. {
  317. if (counter->weakref)
  318. sref_weakref_clear_dying (counter->weakref);
  319. }
  320. static int
  321. sref_counter_kill_weakref (struct sref_counter *counter)
  322. {
  323. return (counter->weakref ? sref_weakref_kill (counter->weakref) : 0);
  324. }
  325. static void __init
  326. sref_queue_init (struct sref_queue *queue)
  327. {
  328. slist_init (&queue->counters);
  329. queue->size = 0;
  330. }
  331. static bool
  332. sref_queue_empty (const struct sref_queue *queue)
  333. {
  334. return (queue->size == 0);
  335. }
  336. static void
  337. sref_queue_push (struct sref_queue *queue, struct sref_counter *counter)
  338. {
  339. slist_insert_tail (&queue->counters, &counter->node);
  340. ++queue->size;
  341. }
  342. static struct sref_counter*
  343. sref_queue_pop (struct sref_queue *queue)
  344. {
  345. _Auto counter = slist_pop_entry (&queue->counters,
  346. struct sref_counter, node);
  347. --queue->size;
  348. return (counter);
  349. }
  350. static void
  351. sref_queue_move (struct sref_queue *dest, const struct sref_queue *src)
  352. {
  353. slist_set_head (&dest->counters, &src->counters);
  354. dest->size = src->size;
  355. }
  356. static struct sref_queue*
  357. sref_cache_get_queue (struct sref_cache *cache, size_t index)
  358. {
  359. assert (index < ARRAY_SIZE (cache->queues));
  360. return (&cache->queues[index]);
  361. }
  362. static struct sref_queue*
  363. sref_cache_get_queue_by_epoch_id (struct sref_cache *cache, uint32_t epoch_id)
  364. {
  365. size_t mask = ARRAY_SIZE (cache->queues) - 1;
  366. return (sref_cache_get_queue (cache, epoch_id & mask));
  367. }
  368. static void
  369. sref_cache_schedule_review (struct sref_cache *cache,
  370. struct sref_counter *counter)
  371. {
  372. assert (!sref_counter_is_queued (counter));
  373. assert (!sref_counter_is_dirty (counter));
  374. sref_counter_mark_queued (counter);
  375. sref_counter_mark_dying (counter);
  376. _Auto queue = sref_cache_get_queue_by_epoch_id (cache, cache->epoch_id);
  377. sref_queue_push (queue, counter);
  378. }
  379. static void
  380. sref_counter_add (struct sref_counter *counter, unsigned long delta,
  381. struct sref_cache *cache)
  382. {
  383. assert (!cpu_intr_enabled ());
  384. SPINLOCK_GUARD (&counter->lock);
  385. counter->value += delta;
  386. if (counter->value)
  387. ;
  388. else if (sref_counter_is_queued (counter))
  389. sref_counter_mark_dirty (counter);
  390. else
  391. sref_cache_schedule_review (cache, counter);
  392. }
  393. static void
  394. sref_counter_noref (struct work *work)
  395. {
  396. _Auto counter = structof (work, struct sref_counter, work);
  397. counter->noref_fn (counter);
  398. }
  399. static void __init
  400. sref_delta_init (struct sref_delta *delta)
  401. {
  402. delta->counter = NULL;
  403. delta->value = 0;
  404. }
  405. static struct sref_counter*
  406. sref_delta_counter (struct sref_delta *delta)
  407. {
  408. return (delta->counter);
  409. }
  410. static void
  411. sref_delta_set_counter (struct sref_delta *delta, struct sref_counter *counter)
  412. {
  413. assert (!delta->value);
  414. delta->counter = counter;
  415. }
  416. static void
  417. sref_delta_clear (struct sref_delta *delta)
  418. {
  419. assert (!delta->value);
  420. delta->counter = NULL;
  421. }
  422. static void
  423. sref_delta_inc (struct sref_delta *delta)
  424. {
  425. ++delta->value;
  426. }
  427. static void
  428. sref_delta_dec (struct sref_delta *delta)
  429. {
  430. --delta->value;
  431. }
  432. static bool
  433. sref_delta_is_valid (const struct sref_delta *delta)
  434. {
  435. return (delta->counter != 0);
  436. }
  437. static void
  438. sref_delta_flush (struct sref_delta *delta, struct sref_cache *cache)
  439. {
  440. sref_counter_add (delta->counter, delta->value, cache);
  441. delta->value = 0;
  442. }
  443. static void
  444. sref_delta_evict (struct sref_delta *delta, struct sref_cache *cache)
  445. {
  446. sref_delta_flush (delta, cache);
  447. sref_delta_clear (delta);
  448. }
  449. static struct sref_cache*
  450. sref_get_local_cache (void)
  451. {
  452. return (cpu_local_ptr (sref_cache));
  453. }
  454. static uintptr_t
  455. sref_cache_compute_counter_index (const struct sref_cache *cache,
  456. const struct sref_counter *counter)
  457. {
  458. return (sref_counter_hash (counter) & (ARRAY_SIZE (cache->deltas) - 1));
  459. }
  460. static struct sref_delta*
  461. sref_cache_get_delta (struct sref_cache *cache, size_t index)
  462. {
  463. assert (index < ARRAY_SIZE (cache->deltas));
  464. return (&cache->deltas[index]);
  465. }
  466. static struct sref_cache*
  467. sref_cache_acquire (cpu_flags_t *flags)
  468. {
  469. thread_preempt_disable_intr_save (flags);
  470. return (sref_get_local_cache ());
  471. }
  472. static void
  473. sref_cache_release (cpu_flags_t flags)
  474. {
  475. thread_preempt_enable_intr_restore (flags);
  476. }
  477. static bool
  478. sref_cache_is_dirty (const struct sref_cache *cache)
  479. {
  480. return (cache->dirty);
  481. }
  482. static void
  483. sref_cache_set_dirty (struct sref_cache *cache)
  484. {
  485. cache->dirty = true;
  486. }
  487. static void
  488. sref_cache_clear_dirty (struct sref_cache *cache)
  489. {
  490. cache->dirty = false;
  491. }
  492. static bool
  493. sref_cache_is_flushed (const struct sref_cache *cache)
  494. {
  495. return (cache->flushed);
  496. }
  497. static void
  498. sref_cache_set_flushed (struct sref_cache *cache)
  499. {
  500. cache->flushed = true;
  501. }
  502. static void
  503. sref_cache_clear_flushed (struct sref_cache *cache)
  504. {
  505. cache->flushed = false;
  506. }
  507. static void
  508. sref_cache_add_delta (struct sref_cache *cache, struct sref_delta *delta,
  509. struct sref_counter *counter)
  510. {
  511. assert (!sref_delta_is_valid (delta));
  512. assert (counter);
  513. sref_delta_set_counter (delta, counter);
  514. list_insert_tail (&cache->valid_deltas, &delta->node);
  515. }
  516. static void
  517. sref_cache_remove_delta (struct sref_cache *cache, struct sref_delta *delta)
  518. {
  519. assert (sref_delta_is_valid (delta));
  520. sref_delta_evict (delta, cache);
  521. list_remove (&delta->node);
  522. }
  523. static struct sref_delta*
  524. sref_cache_take_delta (struct sref_cache *cache, struct sref_counter *counter)
  525. {
  526. size_t index = sref_cache_compute_counter_index (cache, counter);
  527. _Auto delta = sref_cache_get_delta (cache, index);
  528. if (!sref_delta_is_valid (delta))
  529. sref_cache_add_delta (cache, delta, counter);
  530. else if (sref_delta_counter (delta) != counter)
  531. {
  532. sref_cache_remove_delta (cache, delta);
  533. sref_cache_add_delta (cache, delta, counter);
  534. syscnt_inc (&cache->sc_collisions);
  535. }
  536. return (delta);
  537. }
  538. static bool
  539. sref_cache_needs_management (struct sref_cache *cache)
  540. {
  541. assert (!cpu_intr_enabled ());
  542. assert (!thread_preempt_enabled ());
  543. const _Auto queue =
  544. sref_cache_get_queue_by_epoch_id (cache, cache->epoch_id - 2);
  545. return (sref_cache_is_dirty (cache) || !sref_queue_empty (queue));
  546. }
  547. static void
  548. sref_cache_end_epoch (struct sref_cache *cache)
  549. {
  550. assert (!sref_cache_needs_management (cache));
  551. sref_data_ack_cpu (cache->data);
  552. ++cache->epoch_id;
  553. }
  554. static void
  555. sref_cache_flush (struct sref_cache *cache, struct sref_queue *queue)
  556. {
  557. cpu_flags_t flags;
  558. while (1)
  559. {
  560. thread_preempt_disable_intr_save (&flags);
  561. if (list_empty (&cache->valid_deltas))
  562. break;
  563. struct sref_delta *delta = list_first_entry (&cache->valid_deltas,
  564. typeof (*delta), node);
  565. sref_cache_remove_delta (cache, delta);
  566. thread_preempt_enable_intr_restore (flags);
  567. }
  568. sref_cache_clear_dirty (cache);
  569. sref_cache_set_flushed (cache);
  570. _Auto prev_queue =
  571. sref_cache_get_queue_by_epoch_id (cache, cache->epoch_id - 2);
  572. sref_queue_move (queue, prev_queue);
  573. sref_queue_init (prev_queue);
  574. sref_cache_end_epoch (cache);
  575. thread_preempt_enable_intr_restore (flags);
  576. syscnt_inc (&cache->sc_flushes);
  577. }
  578. static void
  579. sref_queue_review (struct sref_queue *queue, struct sref_cache *cache)
  580. {
  581. int64_t nr_dirty_zeroes = 0, nr_true_zeroes = 0, nr_revives = 0;
  582. struct work_queue works;
  583. work_queue_init (&works);
  584. while (!sref_queue_empty (queue))
  585. {
  586. _Auto counter = sref_queue_pop (queue);
  587. cpu_flags_t flags;
  588. spinlock_lock_intr_save (&counter->lock, &flags);
  589. #ifdef SREF_VERIFY
  590. assert (!sref_counter_is_unreferenced (counter));
  591. #endif
  592. assert (sref_counter_is_queued (counter));
  593. sref_counter_clear_queued (counter);
  594. bool requeue;
  595. if (counter->value)
  596. {
  597. sref_counter_clear_dirty (counter);
  598. sref_counter_clear_dying (counter);
  599. spinlock_unlock_intr_restore (&counter->lock, flags);
  600. continue;
  601. }
  602. else if (sref_counter_is_dirty (counter))
  603. {
  604. requeue = true;
  605. ++nr_dirty_zeroes;
  606. sref_counter_clear_dirty (counter);
  607. }
  608. else if (sref_counter_kill_weakref (counter) == 0)
  609. requeue = false;
  610. else
  611. {
  612. requeue = true;
  613. ++nr_revives;
  614. }
  615. if (requeue)
  616. {
  617. sref_cache_schedule_review (cache, counter);
  618. spinlock_unlock_intr_restore (&counter->lock, flags);
  619. }
  620. else
  621. {
  622. /*
  623. * Keep in mind that the work structure shares memory with
  624. * the counter data.
  625. */
  626. #ifdef SREF_VERIFY
  627. sref_counter_mark_unreferenced (counter);
  628. #endif
  629. /*
  630. * Unlocking isn't needed here, since this counter is now
  631. * really at 0, but do it for consistency.
  632. */
  633. spinlock_unlock_intr_restore (&counter->lock, flags);
  634. ++nr_true_zeroes;
  635. work_init (&counter->work, sref_counter_noref);
  636. work_queue_push (&works, &counter->work);
  637. }
  638. }
  639. if (work_queue_nr_works (&works) != 0)
  640. work_queue_schedule (&works, WORK_HIGHPRIO);
  641. sref_data_update_stats (cache->data, nr_dirty_zeroes,
  642. nr_true_zeroes, nr_revives);
  643. }
  644. static void
  645. sref_cache_manage (void *arg)
  646. {
  647. struct sref_cache *cache = arg;
  648. cpu_flags_t flags;
  649. thread_preempt_disable_intr_save (&flags);
  650. while (1)
  651. {
  652. while (sref_cache_is_flushed (cache))
  653. thread_sleep (NULL, cache, "sref");
  654. thread_preempt_enable_intr_restore (flags);
  655. struct sref_queue queue;
  656. sref_cache_flush (cache, &queue);
  657. sref_queue_review (&queue, cache);
  658. thread_preempt_disable_intr_save (&flags);
  659. }
  660. }
  661. static void
  662. sref_cache_check (struct sref_cache *cache)
  663. {
  664. if (!sref_data_check_epoch_id (&sref_data, cache->epoch_id))
  665. return;
  666. else if (!sref_cache_needs_management (cache))
  667. {
  668. sref_cache_end_epoch (cache);
  669. return;
  670. }
  671. sref_cache_clear_flushed (cache);
  672. thread_wakeup (cache->manager);
  673. }
  674. static void __init
  675. sref_cache_init (struct sref_cache *cache, uint32_t cpu,
  676. struct sref_data *data)
  677. {
  678. cache->data = data;
  679. cache->dirty = false;
  680. cache->flushed = true;
  681. cache->epoch_id = sref_data_get_epoch_id (&sref_data) + 1;
  682. for (size_t i = 0; i < ARRAY_SIZE (cache->deltas); i++)
  683. sref_delta_init (sref_cache_get_delta (cache, i));
  684. list_init (&cache->valid_deltas);
  685. for (size_t i = 0; i < ARRAY_SIZE (cache->queues); i++)
  686. sref_queue_init (sref_cache_get_queue (cache, i));
  687. char name[SYSCNT_NAME_SIZE];
  688. snprintf (name, sizeof (name), "sref_collisions/%u", cpu);
  689. syscnt_register (&cache->sc_collisions, name);
  690. snprintf (name, sizeof (name), "sref_flushes/%u", cpu);
  691. syscnt_register (&cache->sc_flushes, name);
  692. cache->manager = NULL;
  693. }
  694. static void __init
  695. sref_cache_init_manager (struct sref_cache *cache, uint32_t cpu)
  696. {
  697. struct cpumap *cpumap;
  698. int error = cpumap_create (&cpumap);
  699. if (error)
  700. panic ("sref: unable to create manager thread CPU map");
  701. cpumap_zero (cpumap);
  702. cpumap_set (cpumap, cpu);
  703. char name[THREAD_NAME_SIZE];
  704. snprintf (name, sizeof (name),
  705. THREAD_KERNEL_PREFIX "sref_cache_manage/%u", cpu);
  706. struct thread_attr attr;
  707. thread_attr_init (&attr, name);
  708. thread_attr_set_cpumap (&attr, cpumap);
  709. thread_attr_set_priority (&attr, THREAD_SCHED_FS_PRIO_MAX);
  710. struct thread *manager;
  711. error = thread_create (&manager, &attr, sref_cache_manage, cache);
  712. cpumap_destroy (cpumap);
  713. if (error)
  714. panic ("sref: unable to create manager thread");
  715. cache->manager = manager;
  716. }
  717. static void __init
  718. sref_data_init (struct sref_data *data)
  719. {
  720. data->epoch_id = SREF_EPOCH_ID_INIT_VALUE;
  721. data->nr_pending_acks = 0;
  722. data->start_ts = clock_get_time ();
  723. syscnt_register (&data->sc_epochs, "sref_epochs");
  724. syscnt_register (&data->sc_dirty_zeroes, "sref_dirty_zeroes");
  725. syscnt_register (&data->sc_true_zeroes, "sref_true_zeroes");
  726. syscnt_register (&data->sc_revives, "sref_revives");
  727. syscnt_register (&data->sc_last_epoch_ms, "sref_last_epoch_ms");
  728. syscnt_register (&data->sc_longest_epoch_ms, "sref_longest_epoch_ms");
  729. }
  730. static int __init
  731. sref_bootstrap (void)
  732. {
  733. sref_data_init (&sref_data);
  734. sref_cache_init (sref_get_local_cache (), 0, &sref_data);
  735. return (0);
  736. }
  737. INIT_OP_DEFINE (sref_bootstrap,
  738. INIT_OP_DEP (cpu_setup, true),
  739. INIT_OP_DEP (spinlock_setup, true),
  740. INIT_OP_DEP (syscnt_setup, true),
  741. INIT_OP_DEP (thread_bootstrap, true));
  742. static int __init
  743. sref_setup (void)
  744. {
  745. for (uint32_t i = 1; i < cpu_count (); i++)
  746. sref_cache_init (percpu_ptr (sref_cache, i), i, &sref_data);
  747. for (uint32_t i = 0; i < cpu_count (); i++)
  748. sref_cache_init_manager (percpu_ptr (sref_cache, i), i);
  749. sref_data_start_epoch (&sref_data);
  750. return (0);
  751. }
  752. INIT_OP_DEFINE (sref_setup,
  753. INIT_OP_DEP (cpu_mp_probe, true),
  754. INIT_OP_DEP (cpumap_setup, true),
  755. INIT_OP_DEP (log_setup, true),
  756. INIT_OP_DEP (sref_bootstrap, true),
  757. INIT_OP_DEP (thread_setup, true));
  758. void
  759. sref_report_periodic_event (void)
  760. {
  761. sref_cache_check (sref_get_local_cache ());
  762. }
  763. void
  764. sref_counter_init (struct sref_counter *counter,
  765. unsigned long init_value,
  766. struct sref_weakref *weakref,
  767. sref_noref_fn_t noref_fn)
  768. {
  769. assert (init_value);
  770. counter->noref_fn = noref_fn;
  771. spinlock_init (&counter->lock);
  772. counter->flags = 0;
  773. counter->value = init_value;
  774. counter->weakref = weakref;
  775. if (weakref)
  776. sref_weakref_init (weakref, counter);
  777. }
  778. static void
  779. sref_counter_inc_common (struct sref_counter *counter, struct sref_cache *cache)
  780. {
  781. sref_cache_set_dirty (cache);
  782. sref_delta_inc (sref_cache_take_delta (cache, counter));
  783. }
  784. void
  785. sref_counter_inc (struct sref_counter *counter)
  786. {
  787. cpu_flags_t flags;
  788. _Auto cache = sref_cache_acquire (&flags);
  789. sref_counter_inc_common (counter, cache);
  790. sref_cache_release (flags);
  791. }
  792. void
  793. sref_counter_dec (struct sref_counter *counter)
  794. {
  795. cpu_flags_t flags;
  796. _Auto cache = sref_cache_acquire (&flags);
  797. sref_cache_set_dirty (cache);
  798. sref_delta_dec (sref_cache_take_delta (cache, counter));
  799. sref_cache_release (flags);
  800. }
  801. struct sref_counter*
  802. sref_weakref_get (struct sref_weakref *weakref)
  803. {
  804. cpu_flags_t flags;
  805. _Auto cache = sref_cache_acquire (&flags);
  806. _Auto counter = sref_weakref_tryget (weakref);
  807. if (counter)
  808. sref_counter_inc_common (counter, cache);
  809. sref_cache_release (flags);
  810. return (counter);
  811. }