/src/librabbitmq/librabbitmq/amqp_mem.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2007 - 2021, Alan Antonuk and the rabbitmq-c contributors. |
2 | | // SPDX-License-Identifier: mit |
3 | | |
4 | | #ifdef HAVE_CONFIG_H |
5 | | #include "config.h" |
6 | | #endif |
7 | | |
8 | | #include "amqp_private.h" |
9 | | #include <assert.h> |
10 | | #include <stdint.h> |
11 | | #include <stdio.h> |
12 | | #include <stdlib.h> |
13 | | #include <string.h> |
14 | | #include <sys/types.h> |
15 | | |
16 | 0 | char const *amqp_version(void) { return AMQP_VERSION_STRING; } |
17 | | |
18 | 0 | uint32_t amqp_version_number(void) { return AMQP_VERSION; } |
19 | | |
20 | 1.06k | void init_amqp_pool(amqp_pool_t *pool, size_t pagesize) { |
21 | 1.06k | pool->pagesize = pagesize ? pagesize : 4096; |
22 | | |
23 | 1.06k | pool->pages.num_blocks = 0; |
24 | 1.06k | pool->pages.blocklist = NULL; |
25 | | |
26 | 1.06k | pool->large_blocks.num_blocks = 0; |
27 | 1.06k | pool->large_blocks.blocklist = NULL; |
28 | | |
29 | 1.06k | pool->next_page = 0; |
30 | 1.06k | pool->alloc_block = NULL; |
31 | 1.06k | pool->alloc_used = 0; |
32 | 1.06k | } |
33 | | |
34 | 2.13k | static void empty_blocklist(amqp_pool_blocklist_t *x) { |
35 | 2.13k | int i; |
36 | | |
37 | 2.13k | if (x->blocklist != NULL) { |
38 | 46.4k | for (i = 0; i < x->num_blocks; i++) { |
39 | 45.6k | free(x->blocklist[i]); |
40 | 45.6k | } |
41 | 725 | free(x->blocklist); |
42 | 725 | } |
43 | 2.13k | x->num_blocks = 0; |
44 | 2.13k | x->blocklist = NULL; |
45 | 2.13k | } |
46 | | |
47 | 1.06k | void recycle_amqp_pool(amqp_pool_t *pool) { |
48 | 1.06k | empty_blocklist(&pool->large_blocks); |
49 | 1.06k | pool->next_page = 0; |
50 | 1.06k | pool->alloc_block = NULL; |
51 | 1.06k | pool->alloc_used = 0; |
52 | 1.06k | } |
53 | | |
54 | 1.06k | void empty_amqp_pool(amqp_pool_t *pool) { |
55 | 1.06k | recycle_amqp_pool(pool); |
56 | 1.06k | empty_blocklist(&pool->pages); |
57 | 1.06k | } |
58 | | |
59 | | /* Returns 1 on success, 0 on failure */ |
60 | 45.6k | static int record_pool_block(amqp_pool_blocklist_t *x, void *block) { |
61 | 45.6k | size_t blocklistlength = sizeof(void *) * (x->num_blocks + 1); |
62 | | |
63 | 45.6k | if (x->blocklist == NULL) { |
64 | 725 | x->blocklist = malloc(blocklistlength); |
65 | 725 | if (x->blocklist == NULL) { |
66 | 0 | return 0; |
67 | 0 | } |
68 | 44.9k | } else { |
69 | 44.9k | void *newbl = realloc(x->blocklist, blocklistlength); |
70 | 44.9k | if (newbl == NULL) { |
71 | 0 | return 0; |
72 | 0 | } |
73 | 44.9k | x->blocklist = newbl; |
74 | 44.9k | } |
75 | | |
76 | 45.6k | x->blocklist[x->num_blocks] = block; |
77 | 45.6k | x->num_blocks++; |
78 | 45.6k | return 1; |
79 | 45.6k | } |
80 | | |
81 | 105k | void *amqp_pool_alloc(amqp_pool_t *pool, size_t amount) { |
82 | 105k | if (amount == 0) { |
83 | 7.87k | return NULL; |
84 | 7.87k | } |
85 | | |
86 | 97.6k | amount = (amount + 7) & (~7); /* round up to nearest 8-byte boundary */ |
87 | | |
88 | 97.6k | if (amount > pool->pagesize) { |
89 | 9.92k | void *result = calloc(1, amount); |
90 | 9.92k | if (result == NULL) { |
91 | 0 | return NULL; |
92 | 0 | } |
93 | 9.92k | if (!record_pool_block(&pool->large_blocks, result)) { |
94 | 0 | free(result); |
95 | 0 | return NULL; |
96 | 0 | } |
97 | 9.92k | return result; |
98 | 9.92k | } |
99 | | |
100 | 87.7k | if (pool->alloc_block != NULL) { |
101 | 87.1k | assert(pool->alloc_used <= pool->pagesize); |
102 | | |
103 | 87.1k | if (pool->alloc_used + amount <= pool->pagesize) { |
104 | 51.9k | void *result = pool->alloc_block + pool->alloc_used; |
105 | 51.9k | pool->alloc_used += amount; |
106 | 51.9k | return result; |
107 | 51.9k | } |
108 | 87.1k | } |
109 | | |
110 | 35.7k | if (pool->next_page >= pool->pages.num_blocks) { |
111 | 35.7k | pool->alloc_block = calloc(1, pool->pagesize); |
112 | 35.7k | if (pool->alloc_block == NULL) { |
113 | 0 | return NULL; |
114 | 0 | } |
115 | 35.7k | if (!record_pool_block(&pool->pages, pool->alloc_block)) { |
116 | 0 | return NULL; |
117 | 0 | } |
118 | 35.7k | pool->next_page = pool->pages.num_blocks; |
119 | 35.7k | } else { |
120 | 0 | pool->alloc_block = pool->pages.blocklist[pool->next_page]; |
121 | 0 | pool->next_page++; |
122 | 0 | } |
123 | | |
124 | 35.7k | pool->alloc_used = amount; |
125 | | |
126 | 35.7k | return pool->alloc_block; |
127 | 35.7k | } |
128 | | |
129 | | void amqp_pool_alloc_bytes(amqp_pool_t *pool, size_t amount, |
130 | 0 | amqp_bytes_t *output) { |
131 | 0 | output->len = amount; |
132 | 0 | output->bytes = amqp_pool_alloc(pool, amount); |
133 | 0 | } |
134 | | |
135 | 0 | amqp_bytes_t amqp_cstring_bytes(char const *cstr) { |
136 | 0 | amqp_bytes_t result; |
137 | 0 | result.len = strlen(cstr); |
138 | 0 | result.bytes = (void *)cstr; |
139 | 0 | return result; |
140 | 0 | } |
141 | | |
142 | 0 | amqp_bytes_t amqp_bytes_malloc_dup(amqp_bytes_t src) { |
143 | 0 | amqp_bytes_t result; |
144 | 0 | result.len = src.len; |
145 | 0 | result.bytes = malloc(src.len); |
146 | 0 | if (result.bytes != NULL) { |
147 | 0 | memcpy(result.bytes, src.bytes, src.len); |
148 | 0 | } |
149 | 0 | return result; |
150 | 0 | } |
151 | | |
152 | 0 | amqp_bytes_t amqp_bytes_malloc(size_t amount) { |
153 | 0 | amqp_bytes_t result; |
154 | 0 | result.len = amount; |
155 | 0 | result.bytes = malloc(amount); /* will return NULL if it fails */ |
156 | 0 | return result; |
157 | 0 | } |
158 | | |
159 | 0 | void amqp_bytes_free(amqp_bytes_t bytes) { free(bytes.bytes); } |
160 | | |
161 | | amqp_pool_t *amqp_get_or_create_channel_pool(amqp_connection_state_t state, |
162 | 0 | amqp_channel_t channel) { |
163 | 0 | amqp_pool_table_entry_t *entry; |
164 | 0 | size_t index = channel % POOL_TABLE_SIZE; |
165 | |
|
166 | 0 | entry = state->pool_table[index]; |
167 | |
|
168 | 0 | for (; NULL != entry; entry = entry->next) { |
169 | 0 | if (channel == entry->channel) { |
170 | 0 | return &entry->pool; |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | 0 | entry = malloc(sizeof(amqp_pool_table_entry_t)); |
175 | 0 | if (NULL == entry) { |
176 | 0 | return NULL; |
177 | 0 | } |
178 | | |
179 | 0 | entry->channel = channel; |
180 | 0 | entry->next = state->pool_table[index]; |
181 | 0 | state->pool_table[index] = entry; |
182 | |
|
183 | 0 | init_amqp_pool(&entry->pool, state->frame_max); |
184 | |
|
185 | 0 | return &entry->pool; |
186 | 0 | } |
187 | | |
188 | | amqp_pool_t *amqp_get_channel_pool(amqp_connection_state_t state, |
189 | 0 | amqp_channel_t channel) { |
190 | 0 | amqp_pool_table_entry_t *entry; |
191 | 0 | size_t index = channel % POOL_TABLE_SIZE; |
192 | |
|
193 | 0 | entry = state->pool_table[index]; |
194 | |
|
195 | 0 | for (; NULL != entry; entry = entry->next) { |
196 | 0 | if (channel == entry->channel) { |
197 | 0 | return &entry->pool; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | 0 | return NULL; |
202 | 0 | } |
203 | | |
204 | 0 | int amqp_bytes_equal(amqp_bytes_t r, amqp_bytes_t l) { |
205 | 0 | if (r.len == l.len && |
206 | 0 | (r.bytes == l.bytes || 0 == memcmp(r.bytes, l.bytes, r.len))) { |
207 | 0 | return 1; |
208 | 0 | } |
209 | 0 | return 0; |
210 | 0 | } |