summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dc/dc_memory_pool.h
blob: 0ec305813d66b6c01f380a72e77a83e33222171b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
 * Copyright (C) Advanced Micro Devices, Inc. All rights reserved.
 *
 * You may not use this software and documentation (if any) (collectively, the
 * "Materials") except in compliance with the terms and conditions of the
 * Software License Agreement included with the Materials or otherwise as set
 * forth in writing and signed by you and an authorized signatory of AMD.
 *
 * If you do not have a copy of the Software License Agreement, contact your AMD
 * representative for a copy. You agree that you will not reverse engineer or
 * decompile the Materials, in whole or in part, except as allowed by applicable
 * law.
 *
 * THE MATERIALS ARE DISTRIBUTED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
 * REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 */
#ifndef DC_MEMORY_POOL_H
#define DC_MEMORY_POOL_H

#include "os_types.h"

/**
 * Non-resizable lock-free memory pool with fixed capacity.
 *
 * Custom implementation is used over Linux llist, as llist requires external
 * locking if more than one thread pops from the list.
 *
 * Emplace and erase operations do not use any mutexes or spinlocks, which
 * guarantees forward progress even if another thread
 * has been suspended in the middle of the call. High contention might result
 * in multiple internal retries, but will eventually either succeed once other
 * threads stop actively modifying the pool, or fail if the pool is empty.
 *
 * Implemented as Treiber stack using indexed free list and head with generation
 * counter to solve ABA problem, as each modification of the head increments
 * the generation, preventing issue of `push(A)` being indistinguishable from
 * `push(A); { push(B); pop(B); }` to another thread, corrupting data structure.
 */
struct dc_memory_pool;

/**
 * Create dc_memory_pool.
 *
 * @param size Non-zero pool block size, all acquires will be of this size.
 * @param capacity Non-zero number of blocks that can be acquired from the pool.
 * @return Pointer to the pool if succeeded, null if failed.
 */
__must_check struct dc_memory_pool *dc_memory_pool_create(size_t size,
							  size_t capacity);

/**
 * Destroy given pool and free all allocated memory, invalidating any pointers.
 *
 * This operation is not synchronized, calling any other operation on the pool
 * while it is being destroyed results in Undefined Behavior.
 *
 * @param pool Can be null to support common destruction patterns.
 */
void dc_memory_pool_destroy(struct dc_memory_pool *pool);

/**
 * Acquire single block from pool.
 *
 * @param pool Cannot be null.
 * @return Pointer to block if succeeded, null if empty.
 */
__must_check void *dc_memory_pool_acquire(struct dc_memory_pool *pool);

/**
 * Release previously acquired block, freeing it for others to acquire.
 *
 * @param pool Cannot be null.
 * @param memory Cannot be null, has to be owned by the pool.
 */
void dc_memory_pool_release(struct dc_memory_pool *pool, void *memory);

/**
 * Check if given memory is owned by the pool to facilitate arenas.
 *
 * @warning if (owns(pool, p)) release(pool, p);` pattern is not safe
 * if used with same `p` from multiple unsynchronized threads.
 * If multiple owning threads are desired, use krefs to assure single release.
 *
 * @param pool Cannot be null.
 * @param memory Cannot be null.
 * @return True if the memory was previously acquired from the pool.
 */
__must_check bool dc_memory_pool_owns(const struct dc_memory_pool *pool,
				      const void *memory);

/**
 * Get pool block size.
 *
 * @param pool Cannot be null.
 * @return Pool block size as given to dc_memory_pool_create().
 */
__must_check size_t dc_memory_pool_size(const struct dc_memory_pool *pool);

/**
 * Get pool block count.
 *
 * @param pool Cannot be null.
 * @return Pool block count as given to dc_memory_pool_create().
 */
__must_check size_t dc_memory_pool_capacity(const struct dc_memory_pool *pool);

#endif // Header guard