File Coverage

third_party/modest/source/mycore/utils/mcobject_async.c
Criterion Covered Total %
statement 134 252 53.1
branch 53 134 39.5
condition n/a
subroutine n/a
pod n/a
total 187 386 48.4


line stmt bran cond sub pod time code
1             /*
2             Copyright (C) 2015-2017 Alexander Borisov
3            
4             This library is free software; you can redistribute it and/or
5             modify it under the terms of the GNU Lesser General Public
6             License as published by the Free Software Foundation; either
7             version 2.1 of the License, or (at your option) any later version.
8            
9             This library 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 GNU
12             Lesser General Public License for more details.
13            
14             You should have received a copy of the GNU Lesser General Public
15             License along with this library; if not, write to the Free Software
16             Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17            
18             Author: lex.borisov@gmail.com (Alexander Borisov)
19             */
20              
21             #include "mycore/utils/mcobject_async.h"
22              
23 435           mcobject_async_t * mcobject_async_create(void)
24             {
25 435           return (mcobject_async_t*)mycore_calloc(1, sizeof(mcobject_async_t));
26             }
27              
28 435           mcobject_async_status_t mcobject_async_chunk_up(mcobject_async_t *mcobj_async)
29             {
30 435           mcobj_async->chunks_length = 0;
31            
32 435 50         if(mcobj_async->chunks[ mcobj_async->chunks_pos_length ] == NULL) {
33 435           mcobj_async->chunks[ mcobj_async->chunks_pos_length ] = (mcobject_async_chunk_t*)mycore_calloc(mcobj_async->chunks_size, sizeof(mcobject_async_chunk_t));
34            
35 435 50         if(mcobj_async->chunks[ mcobj_async->chunks_pos_length ] == NULL)
36 0           return MCOBJECT_ASYNC_STATUS_CHUNK_ERROR_MEMORY_ALLOCATION;
37             }
38            
39 435           return MCOBJECT_ASYNC_STATUS_OK;
40             }
41              
42 435           mcobject_async_status_t mcobject_async_init(mcobject_async_t *mcobj_async, size_t chunk_len, size_t obj_size_by_one_chunk, size_t struct_size)
43             {
44 435           mcobj_async->origin_size = obj_size_by_one_chunk;
45 435           mcobj_async->struct_size = struct_size;
46 435           mcobj_async->struct_size_sn = struct_size + sizeof(size_t);
47            
48 435           mcobj_async->chunks_pos_length = 0;
49 435           mcobj_async->chunks_pos_size = 128;
50 435           mcobj_async->chunks_size = chunk_len;
51 435           mcobj_async->chunks = (mcobject_async_chunk_t**)mycore_calloc(mcobj_async->chunks_pos_size, sizeof(mcobject_async_chunk_t*));
52            
53 435 50         if(mcobj_async->chunks == NULL)
54 0           return MCOBJECT_ASYNC_STATUS_CHUNK_ERROR_MEMORY_ALLOCATION;
55            
56 435           mcobject_async_chunk_up(mcobj_async);
57            
58 435           mcobj_async->chunk_cache_size = mcobj_async->chunks_size;
59 435           mcobj_async->chunk_cache = (mcobject_async_chunk_t**)mycore_calloc(mcobj_async->chunk_cache_size, sizeof(mcobject_async_chunk_t*));
60            
61 435 50         if(mcobj_async->chunk_cache == NULL)
62 0           return MCOBJECT_ASYNC_STATUS_CHUNK_CACHE_ERROR_MEMORY_ALLOCATION;
63            
64 435           mcobj_async->nodes_length = 0;
65 435           mcobj_async->nodes_size = 64;
66 435           mcobj_async->nodes = (mcobject_async_node_t*)mycore_calloc(mcobj_async->nodes_size, sizeof(mcobject_async_node_t));
67            
68 435 50         if(mcobj_async->nodes == NULL)
69 0           return MCOBJECT_ASYNC_STATUS_NODES_ERROR_MEMORY_ALLOCATION;
70            
71 435           mcobj_async->nodes_cache_length = 0;
72 435           mcobj_async->nodes_cache_size = mcobj_async->nodes_size;
73 435           mcobj_async->nodes_cache = (size_t*)mycore_malloc(mcobj_async->nodes_cache_size * sizeof(size_t));
74            
75 435 50         if(mcobj_async->nodes_cache == NULL)
76 0           return MCOBJECT_ASYNC_STATUS_NODES_ERROR_MEMORY_ALLOCATION;
77            
78 435           mcobject_async_clean(mcobj_async);
79            
80 435           mcobj_async->mcsync = mcsync_create();
81 435 50         if(mcobj_async->mcsync == NULL)
82 0           return MCOBJECT_ASYNC_STATUS_ERROR_MEMORY_ALLOCATION;
83            
84 435 50         if(mcsync_init(mcobj_async->mcsync))
85 0           return MCOBJECT_ASYNC_STATUS_ERROR_MEMORY_ALLOCATION;
86            
87 435           return MCOBJECT_ASYNC_STATUS_OK;
88             }
89              
90 435           void mcobject_async_clean(mcobject_async_t *mcobj_async)
91             {
92 435 50         if(mcobj_async->chunks[0] != NULL)
93 435           mcobj_async->chunks_pos_length = 1;
94             else
95 0           mcobj_async->chunks_pos_length = 0;
96            
97 435           mcobj_async->chunks_length = 0;
98 435           mcobj_async->chunk_cache_length = 0;
99            
100             size_t node_idx;
101 435 50         for (node_idx = 0; node_idx < mcobj_async->nodes_length; node_idx++)
102             {
103 0           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
104 0           node->cache_length = 0;
105            
106 0 0         if(node->chunk) {
107 0           node->chunk = mcobject_async_chunk_malloc(mcobj_async, mcobj_async->origin_size, NULL);
108             }
109             }
110 435           }
111              
112 432           mcobject_async_t * mcobject_async_destroy(mcobject_async_t *mcobj_async, int destroy_self)
113             {
114 432 50         if(mcobj_async == NULL)
115 0           return NULL;
116            
117 432 50         if(mcobj_async->nodes)
118             {
119 1152 100         for (size_t node_idx = 0; node_idx < mcobj_async->nodes_length; node_idx++)
120             {
121 720           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
122            
123 720 50         if(node->cache)
124 720           mycore_free(node->cache);
125             }
126            
127 432           mycore_free(mcobj_async->nodes);
128             }
129            
130 432 50         if(mcobj_async->nodes_cache) {
131 432           mycore_free(mcobj_async->nodes_cache);
132             }
133            
134 432 50         if(mcobj_async->chunks) {
135 864 100         for (size_t pos_idx = 0; pos_idx < mcobj_async->chunks_pos_length; pos_idx++) {
136 432 50         if(mcobj_async->chunks[pos_idx])
137             {
138 55728 100         for (size_t idx = 0; idx < mcobj_async->chunks_size; idx++) {
139 55296 100         if(mcobj_async->chunks[pos_idx][idx].begin)
140 720           mycore_free(mcobj_async->chunks[pos_idx][idx].begin);
141             }
142            
143 432           mycore_free(mcobj_async->chunks[pos_idx]);
144             }
145             }
146            
147 432           mycore_free(mcobj_async->chunks);
148             }
149            
150 432 50         if(mcobj_async->chunk_cache) {
151 432           mycore_free(mcobj_async->chunk_cache);
152             }
153            
154 432           mcobj_async->mcsync = mcsync_destroy(mcobj_async->mcsync, 1);
155            
156 432           memset(mcobj_async, 0, sizeof(mcobject_async_t));
157            
158 432 50         if(destroy_self)
159 432           mycore_free(mcobj_async);
160             else
161 0           return mcobj_async;
162            
163 432           return NULL;
164             }
165              
166 725           mcobject_async_status_t mcobject_async_mem_malloc(mcobject_async_t *mcobj_async, mcobject_async_chunk_t *chunk, size_t length)
167             {
168 725 50         if(chunk->begin) {
169 0 0         if(length > chunk->size) {
170 0           mycore_free(chunk->begin);
171            
172 0           chunk->size = length + mcobj_async->origin_size;
173 0           chunk->begin = (unsigned char*)mycore_malloc(chunk->size * mcobj_async->struct_size_sn);
174             }
175             }
176             else {
177 725           chunk->size = mcobj_async->origin_size;
178            
179 725 50         if(length > chunk->size)
180 0           chunk->size += length;
181            
182 725           chunk->begin = (unsigned char*)mycore_malloc(chunk->size * mcobj_async->struct_size_sn);
183             }
184            
185 725           chunk->length = 0;
186            
187 725 50         if(chunk->begin == NULL)
188 0           return MCOBJECT_ASYNC_STATUS_CHUNK_ERROR_MEMORY_ALLOCATION;
189            
190 725           return MCOBJECT_ASYNC_STATUS_OK;
191             }
192              
193 725           mcobject_async_chunk_t * mcobject_async_chunk_malloc_without_lock(mcobject_async_t *mcobj_async, size_t length, mcobject_async_status_t *status)
194             {
195 725 100         if(status)
196 435           *status = MCOBJECT_ASYNC_STATUS_OK;
197            
198 725 50         if(mcobj_async->chunk_cache_length)
199             {
200 0           mcobj_async->chunk_cache_length--;
201            
202 0           mcobj_async->chunk_cache[ mcobj_async->chunk_cache_length ]->length = 0;
203 0           mcobj_async->chunk_cache[ mcobj_async->chunk_cache_length ]->next = NULL;
204 0           mcobj_async->chunk_cache[ mcobj_async->chunk_cache_length ]->prev = NULL;
205            
206 0           return mcobj_async->chunk_cache[ mcobj_async->chunk_cache_length ];
207             }
208            
209 725 50         if(mcobj_async->chunks_length >= mcobj_async->chunks_size)
210             {
211 0 0         if(mcobj_async->chunks_pos_length >= mcobj_async->chunks_pos_size)
212             {
213 0           size_t tmp_pos_size = mcobj_async->chunks_pos_size << 1;
214 0           mcobject_async_chunk_t **tmp_pos = mycore_realloc(mcobj_async->chunks,
215             sizeof(mcobject_async_chunk_t*) * tmp_pos_size);
216            
217 0 0         if(tmp_pos)
218             {
219 0           memset(&tmp_pos[mcobj_async->chunks_pos_length], 0, (tmp_pos_size - mcobj_async->chunks_pos_length)
220             * sizeof(mcobject_async_chunk_t*));
221            
222 0           mcobj_async->chunks_pos_size = tmp_pos_size;
223 0           mcobj_async->chunks = tmp_pos;
224             }
225             else {
226 0 0         if(status)
227 0           *status = MCOBJECT_ASYNC_STATUS_CHUNK_ERROR_MEMORY_ALLOCATION;
228            
229 0           return NULL;
230             }
231             }
232            
233 0 0         if(mcobject_async_chunk_up(mcobj_async)) {
234 0 0         if(status)
235 0           *status = MCOBJECT_ASYNC_STATUS_CHUNK_ERROR_MEMORY_ALLOCATION;
236            
237 0           return NULL;
238             }
239            
240 0           mcobj_async->chunks_pos_length++;
241             }
242            
243 725           mcobject_async_chunk_t* chunk = &mcobj_async->chunks[mcobj_async->chunks_pos_length - 1][mcobj_async->chunks_length];
244 725           mcobj_async->chunks_length++;
245            
246 725           chunk->next = NULL;
247 725           chunk->prev = NULL;
248            
249 725 100         if(status)
250 435           *status = mcobject_async_mem_malloc(mcobj_async, chunk, length);
251             else
252 290           mcobject_async_mem_malloc(mcobj_async, chunk, length);
253            
254 725           return chunk;
255             }
256              
257 0           mcobject_async_chunk_t * mcobject_async_chunk_malloc(mcobject_async_t *mcobj_async, size_t length, mcobject_async_status_t *status)
258             {
259 0 0         if(mcsync_lock(mcobj_async->mcsync)) {
260 0 0         if(status)
261 0           *status = MCOBJECT_ASYNC_STATUS_ERROR_MEMORY_ALLOCATION;
262            
263 0           return NULL;
264             }
265            
266 0           mcobject_async_chunk_t* chunk = mcobject_async_chunk_malloc_without_lock(mcobj_async, length, status);
267 0           mcsync_unlock(mcobj_async->mcsync);
268            
269 0           return chunk;
270             }
271              
272 725           size_t mcobject_async_node_add(mcobject_async_t *mcobj_async, mcobject_async_status_t *status)
273             {
274 725           mcsync_lock(mcobj_async->mcsync);
275            
276 725 100         if(status)
277 435           *status = MCOBJECT_ASYNC_STATUS_OK;
278            
279             size_t node_idx;
280            
281 725 50         if(mcobj_async->nodes_cache_length) {
282 0           mcobj_async->nodes_cache_length--;
283            
284 0           node_idx = mcobj_async->nodes_cache[ mcobj_async->nodes_cache_length ];
285             }
286             else {
287 725 50         if(mcobj_async->nodes_length >= mcobj_async->nodes_size) {
288 0           mcsync_unlock(mcobj_async->mcsync);
289 0           return 0;
290             }
291            
292 725           node_idx = mcobj_async->nodes_length;
293 725           mcobj_async->nodes_length++;
294             }
295            
296 725           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
297            
298 725           node->chunk = mcobject_async_chunk_malloc_without_lock(mcobj_async, mcobj_async->origin_size, status);
299            
300 725 100         if(status && *status) {
    50          
301 0           mcsync_unlock(mcobj_async->mcsync);
302 0           return 0;
303             }
304            
305 725           node->chunk->next = NULL;
306 725           node->chunk->prev = NULL;
307            
308 725           node->cache_length = 0;
309 725           node->cache_size = mcobj_async->origin_size;
310 725           node->cache = (void**)mycore_malloc(sizeof(void*) * node->cache_size);
311            
312 725 50         if(node->cache == NULL) {
313 0 0         if(status)
314 0           *status = MCOBJECT_ASYNC_STATUS_CHUNK_CACHE_ERROR_MEMORY_ALLOCATION;
315            
316 0           mcsync_unlock(mcobj_async->mcsync);
317 0           return 0;
318             }
319            
320 725           mcsync_unlock(mcobj_async->mcsync);
321            
322 725           return node_idx;
323             }
324              
325 725           void mcobject_async_node_clean(mcobject_async_t *mcobj_async, size_t node_idx)
326             {
327 725 50         if(mcobj_async->nodes_length <= node_idx)
328 0           return;
329            
330 725           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
331 725           node->cache_length = 0;
332            
333 725 50         if(node->chunk == NULL)
334 0           return;
335            
336 725 50         while (node->chunk->prev)
337 0           node->chunk = node->chunk->prev;
338            
339 725           node->chunk->length = 0;
340 725           node->cache_length = 0;
341             }
342              
343 0           void mcobject_async_node_all_clean(mcobject_async_t *mcobj_async)
344             {
345 0 0         for (size_t node_idx = 0; node_idx < mcobj_async->nodes_length; node_idx++) {
346 0           mcobject_async_node_clean(mcobj_async, node_idx);
347             }
348 0           }
349              
350 0           void mcobject_async_node_delete(mcobject_async_t *mcobj_async, size_t node_idx)
351             {
352 0           mcsync_lock(mcobj_async->mcsync);
353            
354 0 0         if(mcobj_async->nodes_length <= node_idx) {
355 0           mcsync_unlock(mcobj_async->mcsync);
356 0           return;
357             }
358            
359 0           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
360 0           mcobject_async_chunk_t *chunk = node->chunk;
361            
362 0 0         while (chunk->next)
363 0           chunk = chunk->next;
364            
365 0 0         while (chunk)
366             {
367 0 0         if(mcobj_async->chunk_cache_length >= mcobj_async->chunk_cache_size) {
368 0           size_t new_size = mcobj_async->chunk_cache_size << 1;
369            
370 0           mcobject_async_chunk_t **tmp = (mcobject_async_chunk_t**)mycore_realloc(mcobj_async->chunk_cache,
371             sizeof(mcobject_async_chunk_t*) * new_size);
372            
373 0 0         if(tmp) {
374 0           mcobj_async->chunk_cache_size = new_size;
375 0           mcobj_async->chunk_cache = tmp;
376             }
377             else {
378             // TODO: add return status
379 0           mcsync_unlock(mcobj_async->mcsync);
380 0           return;
381             }
382             }
383            
384 0           mcobj_async->chunk_cache[ mcobj_async->chunk_cache_length ] = chunk;
385 0           mcobj_async->chunk_cache_length++;
386            
387 0           chunk = chunk->prev;
388             }
389            
390 0 0         if(node->cache)
391 0           mycore_free(node->cache);
392            
393 0           memset(node, 0, sizeof(mcobject_async_node_t));
394            
395 0 0         if(mcobj_async->nodes_cache_length >= mcobj_async->nodes_cache_size) {
396 0           size_t new_size = mcobj_async->nodes_cache_size << 1;
397            
398 0           size_t *tmp = (size_t*)mycore_realloc(mcobj_async->nodes_cache, sizeof(size_t) * mcobj_async->nodes_cache_size);
399            
400 0 0         if(tmp) {
401 0           mcobj_async->nodes_cache = tmp;
402 0           mcobj_async->nodes_cache_size = new_size;
403             }
404             }
405            
406 0           mcobj_async->nodes_cache[ mcobj_async->nodes_cache_length ] = node_idx;
407 0           mcobj_async->nodes_cache_length++;
408            
409 0           mcsync_unlock(mcobj_async->mcsync);
410             }
411              
412 4527           void * mcobject_async_malloc(mcobject_async_t *mcobj_async, size_t node_idx, mcobject_async_status_t *status)
413             {
414 4527           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
415            
416 4527 100         if(node->cache_length) {
417 105 50         if(status)
418 0           *status = MCOBJECT_ASYNC_STATUS_OK;
419            
420 105           node->cache_length--;
421 105           return node->cache[ node->cache_length ];
422             }
423            
424 4422 50         if(node->chunk->length >= node->chunk->size)
425             {
426 0 0         if(node->chunk->next) {
427 0           node->chunk = node->chunk->next;
428 0           node->chunk->length = 0;
429             }
430             else {
431             mcobject_async_status_t mystatus;
432 0           mcobject_async_chunk_t *chunk = mcobject_async_chunk_malloc(mcobj_async, mcobj_async->origin_size, &mystatus);
433            
434 0 0         if(mystatus) {
435 0 0         if(status)
436 0           *status = mystatus;
437            
438 0           return NULL;
439             }
440            
441 0           chunk->prev = node->chunk;
442 0           node->chunk->next = chunk;
443            
444 0           node->chunk = chunk;
445             }
446             }
447            
448 4422 50         if(status)
449 0           *status = MCOBJECT_ASYNC_STATUS_OK;
450            
451 4422           size_t offset = node->chunk->length * mcobj_async->struct_size_sn;
452 4422           *((size_t*)(&node->chunk->begin[offset])) = node_idx;
453            
454 4422           node->chunk->length++;
455 4422           return &node->chunk->begin[(offset + sizeof(size_t))];
456             }
457              
458 342           mcobject_async_status_t mcobject_async_free(mcobject_async_t *mcobj_async, void *entry)
459             {
460 342           size_t node_idx = *((size_t*)((unsigned char*)entry - sizeof(size_t)));
461            
462 342 50         if(node_idx >= mcobj_async->nodes_length)
463 0           return MCOBJECT_ASYNC_STATUS_NODES_ERROR_BAD_NODE_ID;
464            
465 342           mcobject_async_node_t *node = &mcobj_async->nodes[node_idx];
466            
467 342 50         if(node->cache_length >= node->cache_size) {
468 0           size_t new_size = node->cache_size << 1;
469            
470 0           void **tmp = (void**)mycore_realloc(node->cache, sizeof(void*) * new_size);
471            
472 0 0         if(tmp) {
473 0           node->cache = tmp;
474 0           node->cache_size = new_size;
475             }
476             else
477 0           return MCOBJECT_ASYNC_STATUS_CACHE_ERROR_MEMORY_REALLOC;
478             }
479            
480 342           node->cache[ node->cache_length ] = entry;
481 342           node->cache_length++;
482            
483 342           return MCOBJECT_ASYNC_STATUS_OK;
484             }
485              
486