Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

allocator.c 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Copyright © 2015 Intel Corporation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice (including the next
  12. * paragraph) shall be included in all copies or substantial portions of the
  13. * Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. * IN THE SOFTWARE.
  22. */
  23. #define _DEFAULT_SOURCE
  24. #include <stdint.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <values.h>
  28. #include <assert.h>
  29. #include <linux/futex.h>
  30. #include <linux/memfd.h>
  31. #include <sys/time.h>
  32. #include <sys/mman.h>
  33. #include <sys/syscall.h>
  34. #include "private.h"
  35. #ifdef HAVE_VALGRIND
  36. #define VG_NOACCESS_READ(__ptr) ({ \
  37. VALGRIND_MAKE_MEM_DEFINED((__ptr), sizeof(*(__ptr))); \
  38. __typeof(*(__ptr)) __val = *(__ptr); \
  39. VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr)));\
  40. __val; \
  41. })
  42. #define VG_NOACCESS_WRITE(__ptr, __val) ({ \
  43. VALGRIND_MAKE_MEM_UNDEFINED((__ptr), sizeof(*(__ptr))); \
  44. *(__ptr) = (__val); \
  45. VALGRIND_MAKE_MEM_NOACCESS((__ptr), sizeof(*(__ptr))); \
  46. })
  47. #else
  48. #define VG_NOACCESS_READ(__ptr) (*(__ptr))
  49. #define VG_NOACCESS_WRITE(__ptr, __val) (*(__ptr) = (__val))
  50. #endif
  51. /* Design goals:
  52. *
  53. * - Lock free (except when resizing underlying bos)
  54. *
  55. * - Constant time allocation with typically only one atomic
  56. *
  57. * - Multiple allocation sizes without fragmentation
  58. *
  59. * - Can grow while keeping addresses and offset of contents stable
  60. *
  61. * - All allocations within one bo so we can point one of the
  62. * STATE_BASE_ADDRESS pointers at it.
  63. *
  64. * The overall design is a two-level allocator: top level is a fixed size, big
  65. * block (8k) allocator, which operates out of a bo. Allocation is done by
  66. * either pulling a block from the free list or growing the used range of the
  67. * bo. Growing the range may run out of space in the bo which we then need to
  68. * grow. Growing the bo is tricky in a multi-threaded, lockless environment:
  69. * we need to keep all pointers and contents in the old map valid. GEM bos in
  70. * general can't grow, but we use a trick: we create a memfd and use ftruncate
  71. * to grow it as necessary. We mmap the new size and then create a gem bo for
  72. * it using the new gem userptr ioctl. Without heavy-handed locking around
  73. * our allocation fast-path, there isn't really a way to munmap the old mmap,
  74. * so we just keep it around until garbage collection time. While the block
  75. * allocator is lockless for normal operations, we block other threads trying
  76. * to allocate while we're growing the map. It sholdn't happen often, and
  77. * growing is fast anyway.
  78. *
  79. * At the next level we can use various sub-allocators. The state pool is a
  80. * pool of smaller, fixed size objects, which operates much like the block
  81. * pool. It uses a free list for freeing objects, but when it runs out of
  82. * space it just allocates a new block from the block pool. This allocator is
  83. * intended for longer lived state objects such as SURFACE_STATE and most
  84. * other persistent state objects in the API. We may need to track more info
  85. * with these object and a pointer back to the CPU object (eg VkImage). In
  86. * those cases we just allocate a slightly bigger object and put the extra
  87. * state after the GPU state object.
  88. *
  89. * The state stream allocator works similar to how the i965 DRI driver streams
  90. * all its state. Even with Vulkan, we need to emit transient state (whether
  91. * surface state base or dynamic state base), and for that we can just get a
  92. * block and fill it up. These cases are local to a command buffer and the
  93. * sub-allocator need not be thread safe. The streaming allocator gets a new
  94. * block when it runs out of space and chains them together so they can be
  95. * easily freed.
  96. */
  97. /* Allocations are always at least 64 byte aligned, so 1 is an invalid value.
  98. * We use it to indicate the free list is empty. */
  99. #define EMPTY 1
  100. struct anv_mmap_cleanup {
  101. void *map;
  102. size_t size;
  103. uint32_t gem_handle;
  104. };
  105. #define ANV_MMAP_CLEANUP_INIT ((struct anv_mmap_cleanup){0})
  106. static inline long
  107. sys_futex(void *addr1, int op, int val1,
  108. struct timespec *timeout, void *addr2, int val3)
  109. {
  110. return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
  111. }
  112. static inline int
  113. futex_wake(uint32_t *addr, int count)
  114. {
  115. return sys_futex(addr, FUTEX_WAKE, count, NULL, NULL, 0);
  116. }
  117. static inline int
  118. futex_wait(uint32_t *addr, int32_t value)
  119. {
  120. return sys_futex(addr, FUTEX_WAIT, value, NULL, NULL, 0);
  121. }
  122. static inline int
  123. memfd_create(const char *name, unsigned int flags)
  124. {
  125. return syscall(SYS_memfd_create, name, flags);
  126. }
  127. static inline uint32_t
  128. ilog2_round_up(uint32_t value)
  129. {
  130. assert(value != 0);
  131. return 32 - __builtin_clz(value - 1);
  132. }
  133. static inline uint32_t
  134. round_to_power_of_two(uint32_t value)
  135. {
  136. return 1 << ilog2_round_up(value);
  137. }
  138. static bool
  139. anv_free_list_pop(union anv_free_list *list, void **map, uint32_t *offset)
  140. {
  141. union anv_free_list current, next, old;
  142. current = *list;
  143. while (current.offset != EMPTY) {
  144. /* We have to add a memory barrier here so that the list head (and
  145. * offset) gets read before we read the map pointer. This way we
  146. * know that the map pointer is valid for the given offset at the
  147. * point where we read it.
  148. */
  149. __sync_synchronize();
  150. uint32_t *next_ptr = *map + current.offset;
  151. next.offset = VG_NOACCESS_READ(next_ptr);
  152. next.count = current.count + 1;
  153. old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, next.u64);
  154. if (old.u64 == current.u64) {
  155. *offset = current.offset;
  156. return true;
  157. }
  158. current = old;
  159. }
  160. return false;
  161. }
  162. static void
  163. anv_free_list_push(union anv_free_list *list, void *map, uint32_t offset)
  164. {
  165. union anv_free_list current, old, new;
  166. uint32_t *next_ptr = map + offset;
  167. old = *list;
  168. do {
  169. current = old;
  170. VG_NOACCESS_WRITE(next_ptr, current.offset);
  171. new.offset = offset;
  172. new.count = current.count + 1;
  173. old.u64 = __sync_val_compare_and_swap(&list->u64, current.u64, new.u64);
  174. } while (old.u64 != current.u64);
  175. }
  176. /* All pointers in the ptr_free_list are assumed to be page-aligned. This
  177. * means that the bottom 12 bits should all be zero.
  178. */
  179. #define PFL_COUNT(x) ((uintptr_t)(x) & 0xfff)
  180. #define PFL_PTR(x) ((void *)((uintptr_t)(x) & ~0xfff))
  181. #define PFL_PACK(ptr, count) ({ \
  182. assert(((uintptr_t)(ptr) & 0xfff) == 0); \
  183. (void *)((uintptr_t)(ptr) | (uintptr_t)((count) & 0xfff)); \
  184. })
  185. static bool
  186. anv_ptr_free_list_pop(void **list, void **elem)
  187. {
  188. void *current = *list;
  189. while (PFL_PTR(current) != NULL) {
  190. void **next_ptr = PFL_PTR(current);
  191. void *new_ptr = VG_NOACCESS_READ(next_ptr);
  192. unsigned new_count = PFL_COUNT(current) + 1;
  193. void *new = PFL_PACK(new_ptr, new_count);
  194. void *old = __sync_val_compare_and_swap(list, current, new);
  195. if (old == current) {
  196. *elem = PFL_PTR(current);
  197. return true;
  198. }
  199. current = old;
  200. }
  201. return false;
  202. }
  203. static void
  204. anv_ptr_free_list_push(void **list, void *elem)
  205. {
  206. void *old, *current;
  207. void **next_ptr = elem;
  208. old = *list;
  209. do {
  210. current = old;
  211. VG_NOACCESS_WRITE(next_ptr, PFL_PTR(current));
  212. unsigned new_count = PFL_COUNT(current) + 1;
  213. void *new = PFL_PACK(elem, new_count);
  214. old = __sync_val_compare_and_swap(list, current, new);
  215. } while (old != current);
  216. }
  217. static int
  218. anv_block_pool_grow(struct anv_block_pool *pool);
  219. void
  220. anv_block_pool_init(struct anv_block_pool *pool,
  221. struct anv_device *device, uint32_t block_size)
  222. {
  223. assert(is_power_of_two(block_size));
  224. pool->device = device;
  225. pool->bo.gem_handle = 0;
  226. pool->bo.offset = 0;
  227. pool->size = 0;
  228. pool->block_size = block_size;
  229. pool->next_block = 0;
  230. pool->free_list = ANV_FREE_LIST_EMPTY;
  231. anv_vector_init(&pool->mmap_cleanups,
  232. round_to_power_of_two(sizeof(struct anv_mmap_cleanup)), 128);
  233. /* Immediately grow the pool so we'll have a backing bo. */
  234. anv_block_pool_grow(pool);
  235. }
  236. void
  237. anv_block_pool_finish(struct anv_block_pool *pool)
  238. {
  239. struct anv_mmap_cleanup *cleanup;
  240. anv_vector_foreach(cleanup, &pool->mmap_cleanups) {
  241. if (cleanup->map)
  242. munmap(cleanup->map, cleanup->size);
  243. if (cleanup->gem_handle)
  244. anv_gem_close(pool->device, cleanup->gem_handle);
  245. }
  246. anv_vector_finish(&pool->mmap_cleanups);
  247. close(pool->fd);
  248. }
  249. static int
  250. anv_block_pool_grow(struct anv_block_pool *pool)
  251. {
  252. size_t size;
  253. void *map;
  254. int gem_handle;
  255. struct anv_mmap_cleanup *cleanup;
  256. if (pool->size == 0) {
  257. size = 32 * pool->block_size;
  258. } else {
  259. size = pool->size * 2;
  260. }
  261. cleanup = anv_vector_add(&pool->mmap_cleanups);
  262. if (!cleanup)
  263. return -1;
  264. *cleanup = ANV_MMAP_CLEANUP_INIT;
  265. if (pool->size == 0)
  266. pool->fd = memfd_create("block pool", MFD_CLOEXEC);
  267. if (pool->fd == -1)
  268. return -1;
  269. if (ftruncate(pool->fd, size) == -1)
  270. return -1;
  271. /* First try to see if mremap can grow the map in place. */
  272. map = MAP_FAILED;
  273. if (pool->size > 0)
  274. map = mremap(pool->map, pool->size, size, 0);
  275. if (map == MAP_FAILED) {
  276. /* Just leak the old map until we destroy the pool. We can't munmap it
  277. * without races or imposing locking on the block allocate fast path. On
  278. * the whole the leaked maps adds up to less than the size of the
  279. * current map. MAP_POPULATE seems like the right thing to do, but we
  280. * should try to get some numbers.
  281. */
  282. map = mmap(NULL, size, PROT_READ | PROT_WRITE,
  283. MAP_SHARED | MAP_POPULATE, pool->fd, 0);
  284. cleanup->map = map;
  285. cleanup->size = size;
  286. }
  287. if (map == MAP_FAILED)
  288. return -1;
  289. gem_handle = anv_gem_userptr(pool->device, map, size);
  290. if (gem_handle == 0)
  291. return -1;
  292. cleanup->gem_handle = gem_handle;
  293. /* Now that we successfull allocated everything, we can write the new
  294. * values back into pool. */
  295. pool->map = map;
  296. pool->bo.gem_handle = gem_handle;
  297. pool->bo.size = size;
  298. pool->bo.map = map;
  299. pool->bo.index = 0;
  300. /* Write size last and after the memory barrier here. We need the memory
  301. * barrier to make sure map and gem_handle are written before other threads
  302. * see the new size. A thread could allocate a block and then go try using
  303. * the old pool->map and access out of bounds. */
  304. __sync_synchronize();
  305. pool->size = size;
  306. return 0;
  307. }
  308. uint32_t
  309. anv_block_pool_alloc(struct anv_block_pool *pool)
  310. {
  311. uint32_t offset, block, size;
  312. /* Try free list first. */
  313. if (anv_free_list_pop(&pool->free_list, &pool->map, &offset)) {
  314. assert(pool->map);
  315. return offset;
  316. }
  317. restart:
  318. size = pool->size;
  319. block = __sync_fetch_and_add(&pool->next_block, pool->block_size);
  320. if (block < size) {
  321. assert(pool->map);
  322. return block;
  323. } else if (block == size) {
  324. /* We allocated the first block outside the pool, we have to grow it.
  325. * pool->next_block acts a mutex: threads who try to allocate now will
  326. * get block indexes above the current limit and hit futex_wait
  327. * below. */
  328. int err = anv_block_pool_grow(pool);
  329. assert(err == 0);
  330. (void) err;
  331. futex_wake(&pool->size, INT_MAX);
  332. } else {
  333. futex_wait(&pool->size, size);
  334. __sync_fetch_and_add(&pool->next_block, -pool->block_size);
  335. goto restart;
  336. }
  337. return block;
  338. }
  339. void
  340. anv_block_pool_free(struct anv_block_pool *pool, uint32_t offset)
  341. {
  342. anv_free_list_push(&pool->free_list, pool->map, offset);
  343. }
  344. static void
  345. anv_fixed_size_state_pool_init(struct anv_fixed_size_state_pool *pool,
  346. size_t state_size)
  347. {
  348. /* At least a cache line and must divide the block size. */
  349. assert(state_size >= 64 && is_power_of_two(state_size));
  350. pool->state_size = state_size;
  351. pool->free_list = ANV_FREE_LIST_EMPTY;
  352. pool->block.next = 0;
  353. pool->block.end = 0;
  354. }
  355. static uint32_t
  356. anv_fixed_size_state_pool_alloc(struct anv_fixed_size_state_pool *pool,
  357. struct anv_block_pool *block_pool)
  358. {
  359. uint32_t offset;
  360. struct anv_block_state block, old, new;
  361. /* Try free list first. */
  362. if (anv_free_list_pop(&pool->free_list, &block_pool->map, &offset))
  363. return offset;
  364. /* If free list was empty (or somebody raced us and took the items) we
  365. * allocate a new item from the end of the block */
  366. restart:
  367. block.u64 = __sync_fetch_and_add(&pool->block.u64, pool->state_size);
  368. if (block.next < block.end) {
  369. return block.next;
  370. } else if (block.next == block.end) {
  371. new.next = anv_block_pool_alloc(block_pool);
  372. new.end = new.next + block_pool->block_size;
  373. old.u64 = __sync_fetch_and_add(&pool->block.u64, new.u64 - block.u64);
  374. if (old.next != block.next)
  375. futex_wake(&pool->block.end, INT_MAX);
  376. return new.next;
  377. } else {
  378. futex_wait(&pool->block.end, block.end);
  379. __sync_fetch_and_add(&pool->block.u64, -pool->state_size);
  380. goto restart;
  381. }
  382. }
  383. static void
  384. anv_fixed_size_state_pool_free(struct anv_fixed_size_state_pool *pool,
  385. struct anv_block_pool *block_pool,
  386. uint32_t offset)
  387. {
  388. anv_free_list_push(&pool->free_list, block_pool->map, offset);
  389. }
  390. void
  391. anv_state_pool_init(struct anv_state_pool *pool,
  392. struct anv_block_pool *block_pool)
  393. {
  394. pool->block_pool = block_pool;
  395. for (unsigned i = 0; i < ANV_STATE_BUCKETS; i++) {
  396. size_t size = 1 << (ANV_MIN_STATE_SIZE_LOG2 + i);
  397. anv_fixed_size_state_pool_init(&pool->buckets[i], size);
  398. }
  399. }
  400. struct anv_state
  401. anv_state_pool_alloc(struct anv_state_pool *pool, size_t size, size_t align)
  402. {
  403. unsigned size_log2 = ilog2_round_up(size < align ? align : size);
  404. assert(size_log2 <= ANV_MAX_STATE_SIZE_LOG2);
  405. if (size_log2 < ANV_MIN_STATE_SIZE_LOG2)
  406. size_log2 = ANV_MIN_STATE_SIZE_LOG2;
  407. unsigned bucket = size_log2 - ANV_MIN_STATE_SIZE_LOG2;
  408. struct anv_state state;
  409. state.alloc_size = 1 << size_log2;
  410. state.offset = anv_fixed_size_state_pool_alloc(&pool->buckets[bucket],
  411. pool->block_pool);
  412. state.map = pool->block_pool->map + state.offset;
  413. VG(VALGRIND_MALLOCLIKE_BLOCK(state.map, size, 0, false));
  414. return state;
  415. }
  416. void
  417. anv_state_pool_free(struct anv_state_pool *pool, struct anv_state state)
  418. {
  419. assert(is_power_of_two(state.alloc_size));
  420. unsigned size_log2 = ilog2_round_up(state.alloc_size);
  421. assert(size_log2 >= ANV_MIN_STATE_SIZE_LOG2 &&
  422. size_log2 <= ANV_MAX_STATE_SIZE_LOG2);
  423. unsigned bucket = size_log2 - ANV_MIN_STATE_SIZE_LOG2;
  424. VG(VALGRIND_FREELIKE_BLOCK(state.map, 0));
  425. anv_fixed_size_state_pool_free(&pool->buckets[bucket],
  426. pool->block_pool, state.offset);
  427. }
  428. #define NULL_BLOCK 1
  429. struct stream_block {
  430. uint32_t next;
  431. /* The map for the BO at the time the block was givne to us */
  432. void *current_map;
  433. #ifdef HAVE_VALGRIND
  434. void *_vg_ptr;
  435. #endif
  436. };
  437. /* The state stream allocator is a one-shot, single threaded allocator for
  438. * variable sized blocks. We use it for allocating dynamic state.
  439. */
  440. void
  441. anv_state_stream_init(struct anv_state_stream *stream,
  442. struct anv_block_pool *block_pool)
  443. {
  444. stream->block_pool = block_pool;
  445. stream->next = 0;
  446. stream->end = 0;
  447. stream->current_block = NULL_BLOCK;
  448. }
  449. void
  450. anv_state_stream_finish(struct anv_state_stream *stream)
  451. {
  452. struct stream_block *sb;
  453. uint32_t block, next_block;
  454. block = stream->current_block;
  455. while (block != NULL_BLOCK) {
  456. sb = stream->block_pool->map + block;
  457. next_block = VG_NOACCESS_READ(&sb->next);
  458. VG(VALGRIND_FREELIKE_BLOCK(VG_NOACCESS_READ(&sb->_vg_ptr), 0));
  459. anv_block_pool_free(stream->block_pool, block);
  460. block = next_block;
  461. }
  462. }
  463. struct anv_state
  464. anv_state_stream_alloc(struct anv_state_stream *stream,
  465. uint32_t size, uint32_t alignment)
  466. {
  467. struct stream_block *sb;
  468. struct anv_state state;
  469. uint32_t block;
  470. state.offset = align_u32(stream->next, alignment);
  471. if (state.offset + size > stream->end) {
  472. block = anv_block_pool_alloc(stream->block_pool);
  473. void *current_map = stream->block_pool->map;
  474. sb = current_map + block;
  475. VG_NOACCESS_WRITE(&sb->current_map, current_map);
  476. VG_NOACCESS_WRITE(&sb->next, stream->current_block);
  477. VG(VG_NOACCESS_WRITE(&sb->_vg_ptr, 0));
  478. stream->current_block = block;
  479. stream->next = block + sizeof(*sb);
  480. stream->end = block + stream->block_pool->block_size;
  481. state.offset = align_u32(stream->next, alignment);
  482. assert(state.offset + size <= stream->end);
  483. }
  484. sb = stream->block_pool->map + stream->current_block;
  485. void *current_map = VG_NOACCESS_READ(&sb->current_map);
  486. state.map = current_map + state.offset;
  487. state.alloc_size = size;
  488. #ifdef HAVE_VALGRIND
  489. void *vg_ptr = VG_NOACCESS_READ(&sb->_vg_ptr);
  490. if (vg_ptr == NULL) {
  491. vg_ptr = state.map;
  492. VG_NOACCESS_WRITE(&sb->_vg_ptr, vg_ptr);
  493. VALGRIND_MALLOCLIKE_BLOCK(vg_ptr, size, 0, false);
  494. } else {
  495. ptrdiff_t vg_offset = vg_ptr - current_map;
  496. assert(vg_offset >= stream->current_block &&
  497. vg_offset < stream->end);
  498. VALGRIND_RESIZEINPLACE_BLOCK(vg_ptr,
  499. stream->next - vg_offset,
  500. (state.offset + size) - vg_offset,
  501. 0);
  502. }
  503. #endif
  504. stream->next = state.offset + size;
  505. return state;
  506. }
  507. struct bo_pool_bo_link {
  508. struct bo_pool_bo_link *next;
  509. struct anv_bo bo;
  510. };
  511. void
  512. anv_bo_pool_init(struct anv_bo_pool *pool,
  513. struct anv_device *device, uint32_t bo_size)
  514. {
  515. pool->device = device;
  516. pool->bo_size = bo_size;
  517. pool->free_list = NULL;
  518. }
  519. void
  520. anv_bo_pool_finish(struct anv_bo_pool *pool)
  521. {
  522. struct bo_pool_bo_link *link = PFL_PTR(pool->free_list);
  523. while (link != NULL) {
  524. struct bo_pool_bo_link link_copy = VG_NOACCESS_READ(link);
  525. /* The anv_gem_m[un]map() functions are also valgrind-safe so they
  526. * act as an alloc/free. In order to avoid a double-free warning, we
  527. * need to mark thiss as malloc'd before we unmap it.
  528. */
  529. VG(VALGRIND_MALLOCLIKE_BLOCK(link_copy.bo.map, pool->bo_size, 0, false));
  530. anv_gem_munmap(link_copy.bo.map, pool->bo_size);
  531. anv_gem_close(pool->device, link_copy.bo.gem_handle);
  532. link = link_copy.next;
  533. }
  534. }
  535. VkResult
  536. anv_bo_pool_alloc(struct anv_bo_pool *pool, struct anv_bo *bo)
  537. {
  538. VkResult result;
  539. void *next_free_void;
  540. if (anv_ptr_free_list_pop(&pool->free_list, &next_free_void)) {
  541. struct bo_pool_bo_link *next_free = next_free_void;
  542. *bo = VG_NOACCESS_READ(&next_free->bo);
  543. assert(bo->map == next_free);
  544. assert(bo->size == pool->bo_size);
  545. VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, pool->bo_size, 0, false));
  546. return VK_SUCCESS;
  547. }
  548. struct anv_bo new_bo;
  549. result = anv_bo_init_new(&new_bo, pool->device, pool->bo_size);
  550. if (result != VK_SUCCESS)
  551. return result;
  552. assert(new_bo.size == pool->bo_size);
  553. new_bo.map = anv_gem_mmap(pool->device, new_bo.gem_handle, 0, pool->bo_size);
  554. if (new_bo.map == NULL) {
  555. anv_gem_close(pool->device, new_bo.gem_handle);
  556. return vk_error(VK_ERROR_MEMORY_MAP_FAILED);
  557. }
  558. /* We don't need to call VALGRIND_MALLOCLIKE_BLOCK here because gem_mmap
  559. * calls it for us. If we really want to be pedantic we could do a
  560. * VALGRIND_FREELIKE_BLOCK right after the mmap, but there's no good
  561. * reason.
  562. */
  563. *bo = new_bo;
  564. return VK_SUCCESS;
  565. }
  566. void
  567. anv_bo_pool_free(struct anv_bo_pool *pool, const struct anv_bo *bo)
  568. {
  569. struct bo_pool_bo_link *link = bo->map;
  570. link->bo = *bo;
  571. VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0));
  572. anv_ptr_free_list_push(&pool->free_list, link);
  573. }