resource.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. // Copyright © 2019 Ariadne Devos
  3. /* sHT -- fixed-size memory allocation */
  4. #ifndef _sHT_RESOURCE_H
  5. #define _sHT_RESOURCE_H
  6. #include <stddef.h>
  7. /** Object caches
  8. s2's object caches allocate pre-allocated objects of fixed size. They
  9. are akin to slabs and object pools, but subtly different.
  10. A slab's memory is allocated on-demand[SLAB], whereas in a cache, it
  11. is done in advance, when s2 boots or loads a module. That seems to
  12. be the only conceptual difference, although this causes many
  13. repercussions in the implementation.
  14. Why this inflexibility? If s2 is the only application, it can allocate
  15. as it pleases. If there are other applications that allocate memory
  16. on-demand, s2 services could be unpredictably unavailable, which is not
  17. reliable -- but s2 must be, up to a configurable value of load.
  18. (This could be less rigid. E.g., the object cache may be grown
  19. opportunistically for non-critical tasks. But s2 allows for spawning
  20. new, independent but cooperating processes, so this is not a problem.
  21. In fact, this forms automatic tests.)
  22. [SLAB]: The Slab Allocator: An Object-Caching Kernel Memory Allocator
  23. by Jeff Bonwick, Sun Microsystems.
  24. It is assumed that there is no shortage of virtual memory.
  25. * Usage
  26. Caches are initialised with @var{sHT_objcache_bless_batch}. It does not
  27. allocate memory itself, rather, it takes a block of memory to use.
  28. @var{sHT_objcache_size_batch} calculates how large the blocks must be.
  29. @var{sHT_alloc} tries to allocates an object from a cache.
  30. @var{sHT_free} frees the object, making it available for later operations.
  31. Caches do not have to be freed. While in use, however, they require the
  32. block to remain available. In particular, the objects are allocated from
  33. the block. */
  34. struct sHT_objcache;
  35. /** Calculate the size of the memory blocks the object caches need
  36. @var{n}: the number of caches to calculate the size for, positive
  37. @var{size}: an writable array to put the calculated cache size in, in the
  38. same order as @var{capacity} and @var{elem_size}, of length @var{n} and
  39. not accessed concurrently
  40. @var{capacity}: an array of the numbers of distinct objects that can be
  41. allocated from the cache, of length @var{n}, readable and unchanging
  42. @var{elem_size}: an array of the sizes of each object that can be
  43. allocated from the cache, of length @var{n}, readable and unchanging
  44. The return value is non-negative and less than or equal to @var{n}. Name
  45. it @var{i}. At least @var{i} elements of @var{size} are set, although they
  46. may speculatively be incorrect. On a non-speculative execution, @var{i}
  47. being less than @var{n} signifies an overflow condition, implying the
  48. hypothetical memory block isn't allocatable.
  49. Once @var{i} is despeculated, if it is equal to @var{n}, the elements of
  50. @var{size} are correct.
  51. (Strictly speaking, a memory block could span multiple caches. Would that
  52. be a good idea? Less syscalls, less TLB pressure, less padding overhead,
  53. higher portability, but also less bug detection and more predictability
  54. for attackers.) */
  55. size_t
  56. sHT_objcache_size_batch(size_t n, size_t size[], const size_t capacity[], const size_t elem_size[]);
  57. /** Bless some memory blocks into caches
  58. @var{n}: the number of blocks to bless into caches, positive
  59. @var{cache}: a readable, unchanging array of distinct memory blocks
  60. / caches-to-be, in the same order as @var{capacity} and @var{elem_size},
  61. that can be written to, read from after writing, and are not accessed
  62. concurrently, of size returned by @var{sHT_objcache_size_batch}...
  63. @var{capacity}: the capacity of each cache, unchanging and readable
  64. for the duration of this call, disjoint from @var{cache}
  65. @var{elem_size}: the size of an element in each cache, unchanging and
  66. readable for the duration of this call, disjoint from @var{cache}
  67. The return value is non-negative and less than or equal to @var{n}. Name
  68. it @var{i}. At least @var{i} elements of @var{cache} are set, although they
  69. may speculatively be incorrect. On a non-speculative execution, @var{i} is
  70. @var{n}. */
  71. size_t
  72. sHT_objcache_bless_batch(size_t n, void *cache[], const size_t capacity[], const size_t elem_size[]);
  73. /** Try to allocate a fresh object from an object cache.
  74. @var{cache}: the object cache to utilise
  75. The object will have the size specified by @var{sHT_alloc_cache},
  76. and at least standard alignment (i.e. @code{_Alignof(max_align_t)}}.
  77. This procedure does not know about signals or POSIX asynchronuous
  78. cancellation.
  79. This may fail by returning @code{NULL} if the object cache is exhausted.
  80. Else, return a fresh object. On a speculative execution, the object may
  81. not be fresh: it may share memory with an already-allocated object of the
  82. cache. If this is a problem in your use cache, you can use
  83. @var{sHT_despeculate}. */
  84. __attribute__((warn_unused_result))
  85. __attribute__((nonnull (1)))
  86. void *
  87. sHT_alloc(struct sHT_objcache *cache);
  88. /** Free an object that belongs to a certain cache.
  89. @var{cache}: the object cache @var{object} was allocated from
  90. @var{object}: the object to free
  91. The object must have been allocated by @var{sHT_alloc} with the same
  92. cache argument. The object will become dangling.
  93. @var{object} speculatively being NULL is also allowed, although that
  94. speculatively messes up statistics.
  95. This procedure does not know about signals or POSIX asynchronuous
  96. cancellation.
  97. This cannot fail in any way. */
  98. __attribute__((nonnull (1)))
  99. void
  100. sHT_free(struct sHT_objcache *cache, void *object);
  101. /** Test if a cache is exhausted.
  102. @var{cache}: the object cache to test
  103. This does not mutate anything.
  104. This procedure does not know about signals or POSIX asynchronuous
  105. cancellation.
  106. This cannot fail in any way. Return 1 if exhausted, 0 otherwise.
  107. An incorrect boolean may be returned on a speculative execution. */
  108. __attribute__((nonnull (1)))
  109. __attribute__((pure))
  110. _Bool
  111. sHT_cache_exhausted_p(struct sHT_objcache *cache);
  112. #endif