koliseo 0.6.1
Loading...
Searching...
No Matches
koliseo.c
Go to the documentation of this file.
1// jgabaut @ github.com/jgabaut
2// SPDX-License-Identifier: GPL-3.0-only
3/*
4 Copyright (C) 2023-2026 jgabaut
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3 of the License.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18#ifndef _WIN32
19#ifndef _POSIX_C_SOURCE
20#define _POSIX_C_SOURCE 200809L
21#endif
22#endif
23#include "koliseo.h"
24
26 .collect_stats = 0,
27 .verbose_lvl = 0,
28 .block_while_has_temp = 1,
29 .allow_zerocount_push = 0,
30 .log_fp = NULL,
31 .growable = 0,
32 .log_filepath = "",
33 .err_handlers = {
34#ifndef KOLISEO_HAS_LOCATE
35 .OOM_handler = &KLS_OOM_default_handler__,
36 .PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler__,
37 .ZEROCOUNT_handler = &KLS_ZEROCOUNT_default_handler__,
38#else
39 .OOM_handler = &KLS_OOM_default_handler_dbg__,
40 .PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler_dbg__,
41 .ZEROCOUNT_handler = &KLS_ZEROCOUNT_default_handler_dbg__,
42#endif // KOLISEO_HAS_LOCATE
43 },
44};
45
47 .tot_pushes = 0,
48 .tot_temp_pushes = 0,
49 .tot_pops = 0,
50 .tot_temp_pops = 0,
51 .tot_logcalls = 0,
52#ifdef KLS_DEBUG_CORE
53 .worst_pushcall_time = -1,
54#endif
55};
56
57static bool kls_set_conf(Koliseo * kls, KLS_Conf conf); //Declare function used internally by kls_new() and kls_new_conf()
58
63const char *string_koliseo_version(void)
64{
65 return KOLISEO_API_VERSION_STRING;
66}
67
73{
74 return KOLISEO_API_VERSION_INT;
75}
76
77#if defined(__SANITIZE_ADDRESS__)
78#include <sanitizer/asan_interface.h>
79#define KLS_ASAN_POISON(addr, size) __asan_poison_memory_region((addr), (size))
80#define KLS_ASAN_UNPOISON(addr, size) __asan_unpoison_memory_region((addr), (size))
81#else
82#define KLS_ASAN_POISON(addr, size) ((void)0)
83#define KLS_ASAN_UNPOISON(addr, size) ((void)0)
84#endif // __SANITIZE_ADDRESS__
85
95#ifndef KOLISEO_HAS_LOCATE
96void KLS_OOM_default_handler__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, ptrdiff_t count)
97#else
98void KLS_OOM_default_handler_dbg__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, ptrdiff_t count, Koliseo_Loc loc)
99#endif // KOLISEO_HAS_LOCATE
100{
101#ifndef KOLISEO_HAS_LOCATE
102 fprintf(stderr,
103 "[KLS] Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
104 size * count, available - padding);
105#else
106 fprintf(stderr,
107 "[KLS] " KLS_Loc_Fmt "Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
108 KLS_Loc_Arg(loc),
109 size * count, available - padding);
110#endif // KOLISEO_HAS_LOCATE
111 kls_free(kls); // Is it even worth it to try?
112 exit(EXIT_FAILURE); // Better than nothing. May change to return NULL instead? Requiring refactor of handler signature
113}
114
115#ifndef KOLISEO_HAS_LOCATE
116void KLS_PTRDIFF_MAX_default_handler__(struct Koliseo* kls, ptrdiff_t size, ptrdiff_t count)
117#else
118void KLS_PTRDIFF_MAX_default_handler_dbg__(struct Koliseo* kls, ptrdiff_t size, ptrdiff_t count, Koliseo_Loc loc)
119#endif
120{
121#ifndef _WIN32
122#ifndef KOLISEO_HAS_LOCATE
123 fprintf(stderr,
124 "[KLS] count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
125 count, PTRDIFF_MAX / size);
126#else
127 fprintf(stderr,
128 "[KLS] " KLS_Loc_Fmt "count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
129 KLS_Loc_Arg(loc),
130 count, PTRDIFF_MAX / size);
131#endif // KOLISEO_HAS_LOCATE
132#else
133#ifndef KOLISEO_HAS_LOCATE
134 fprintf(stderr,
135 "[KLS] count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
136 count, PTRDIFF_MAX / size);
137#else
138 fprintf(stderr,
139 "[KLS] " KLS_Loc_Fmt "count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
140 KLS_Loc_Arg(loc),
141 count, PTRDIFF_MAX / size);
142#endif // KOLISEO_HAS_LOCATE
143#endif // _WIN32
144 kls_free(kls);
145 exit(EXIT_FAILURE);
146}
147
157#ifndef KOLISEO_HAS_LOCATE
158void KLS_ZEROCOUNT_default_handler__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size)
159#else
160void KLS_ZEROCOUNT_default_handler_dbg__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, Koliseo_Loc loc)
161#endif // KOLISEO_HAS_LOCATE
162{
163#ifndef KOLISEO_HAS_LOCATE
164 fprintf(stderr,
165 "[KLS] Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
166 size, padding, available);
167#else
168 fprintf(stderr,
169 "[KLS] " KLS_Loc_Fmt "Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
170 KLS_Loc_Arg(loc),
171 size, padding, available);
172#endif // KOLISEO_HAS_LOCATE
173 kls_free(kls);
174 exit(EXIT_FAILURE);
175}
176
182KLS_Conf kls_conf_init_handled(int collect_stats, int verbose_lvl, int block_while_has_temp, int allow_zerocount_push, int growable, FILE* log_fp, const char* log_filepath, KLS_Err_Handlers err_handlers)
183{
184 KLS_Conf res = {0};
185 res.collect_stats = collect_stats;
186 res.verbose_lvl = verbose_lvl;
187 res.block_while_has_temp = block_while_has_temp;
188 res.allow_zerocount_push = allow_zerocount_push;
189 res.growable = growable;
190 res.log_fp = log_fp;
191 res.log_filepath = log_filepath;
192
193 if (err_handlers.OOM_handler != NULL) {
194 res.err_handlers.OOM_handler = err_handlers.OOM_handler;
195 } else {
196#ifndef KOLISEO_HAS_LOCATE
198#else
199 res.err_handlers.OOM_handler = &KLS_OOM_default_handler_dbg__;
200#endif // KOLISEO_HAS_LOCATE
201 }
202
203 if (err_handlers.PTRDIFF_MAX_handler != NULL) {
205 } else {
206#ifndef KOLISEO_HAS_LOCATE
208#else
209 res.err_handlers.PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler_dbg__;
210#endif // KOLISEO_HAS_LOCATE
211 }
212
213 if (err_handlers.ZEROCOUNT_handler != NULL) {
215 } else {
216#ifndef KOLISEO_HAS_LOCATE
218#else
219 res.err_handlers.ZEROCOUNT_handler = &KLS_ZEROCOUNT_default_handler_dbg__;
220#endif // KOLISEO_HAS_LOCATE
221 }
222
223 return res;
224}
225
230KLS_Conf kls_conf_init(int collect_stats, int verbose_lvl, int block_while_has_temp, int allow_zerocount_push, int growable, FILE* log_fp, const char* log_filepath)
231{
233 return kls_conf_init_handled(collect_stats, verbose_lvl, block_while_has_temp, allow_zerocount_push, growable, log_fp, log_filepath, err_handlers);
234}
235
240{
241#ifdef KOLISEO_HAS_LOCATE
242 bool kls_locate = true;
243#else
244 bool kls_locate = false;
245#endif
246#ifdef KLS_DEBUG_CORE
247 bool kls_debug = true;
248#else
249 bool kls_debug = false;
250#endif
251#ifdef KOLISEO_HAS_EXPER
252 bool kls_exper = true;
253#else
254 bool kls_exper = false;
255#endif
256 bool features[3] = {
257 [0] = kls_debug,
258 [1] = kls_locate,
259 [2] = kls_exper,
260 };
261 int total_enabled = 0;
262 for (int i=0; i<3; i++) {
263 if (features[i]) {
264 total_enabled += 1;
265 }
266 }
267 fprintf(stderr, "[KLS] Enabled features: {");
268 if (total_enabled == 0) {
269 fprintf(stderr, "none}\n");
270 return;
271 } else {
272 if (kls_debug) {
273 fprintf(stderr, "debug%s", (total_enabled > 1 ? ", " : ""));
274 total_enabled -= 1;
275 }
276 if (kls_locate) {
277 fprintf(stderr, "locate%s", (total_enabled > 1 ? ", " : ""));
278 total_enabled -= 1;
279 }
280 if (kls_exper) {
281 fprintf(stderr, "exper");
282 }
283 fprintf(stderr, "}\n");
284 }
285}
286
292ptrdiff_t kls_get_pos(const Koliseo *kls)
293{
294 return kls->offset;
295}
296
309#ifndef KOLISEO_HAS_LOCATE
310void* kls__handle_push_result(Koliseo* kls, KLS_Push_Result r, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t padding, const char* caller_name)
311#else
312void* kls__handle_push_result_dbg(Koliseo* kls, KLS_Push_Result r, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t padding, const char* caller_name, Koliseo_Loc loc)
313#endif
314{
315 if (!kls) return NULL;
316 Koliseo* current = kls;
317 while (current->next != NULL) {
318 current = current->next;
319 }
320 if (r.error) {
321 const ptrdiff_t available = current->size - current->offset;
322 switch (r.error) {
323 case KLS_PUSH_OK: {
324 return r.p;
325 }
326 break;
327 case KLS_PUSH_SIZE_LT1: {
328#ifndef KOLISEO_HAS_LOCATE
329 fprintf(stderr,
330 "[KLS] %s(): size [%td] was < 1.\n",
331 caller_name,
332 size);
333#else
334 fprintf(stderr,
335 "[KLS] " KLS_Loc_Fmt "%s(): size [%td] was < 1.\n",
336 KLS_Loc_Arg(loc),
337 caller_name,
338 size);
339#endif // KOLISEO_HAS_LOCATE
340 }
341 break;
342 case KLS_PUSH_ALIGN_LT1: {
343#ifndef KOLISEO_HAS_LOCATE
344 fprintf(stderr,
345 "[KLS] %s(): align [%td] was < 1.\n",
346 caller_name,
347 align);
348#else
349 fprintf(stderr,
350 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was < 1.\n",
351 KLS_Loc_Arg(loc),
352 caller_name,
353 align);
354#endif // KOLISEO_HAS_LOCATE
355 }
356 break;
358#ifndef KOLISEO_HAS_LOCATE
359 fprintf(stderr,
360 "[KLS] %s(): align [%td] was not a power of 2.\n",
361 caller_name,
362 align);
363#else
364 fprintf(stderr,
365 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was not a power of 2.\n",
366 KLS_Loc_Arg(loc),
367 caller_name,
368 align);
369#endif // KOLISEO_HAS_LOCATE
370 }
371 break;
373#ifndef KOLISEO_HAS_LOCATE
374 fprintf(stderr,
375 "[KLS] %s(): count [%td] was < 0.\n",
376 caller_name,
377 count);
378#else
379 fprintf(stderr,
380 "[KLS] " KLS_Loc_Fmt "%s(): count [%td] was < 0.\n",
381 KLS_Loc_Arg(loc),
382 caller_name,
383 count);
384#endif // KOLISEO_HAS_LOCATE
385 }
386 break;
387 case KLS_PUSH_ZEROCOUNT: {
388 if (current->conf.err_handlers.ZEROCOUNT_handler != NULL) {
389#ifndef KOLISEO_HAS_LOCATE
390 current->conf.err_handlers.ZEROCOUNT_handler(current, available, padding, size);
391#else
392 current->conf.err_handlers.ZEROCOUNT_handler(current, available, padding, size, loc);
393#endif // KOLISEO_HAS_LOCATE
394 } else {
395#ifndef KOLISEO_HAS_LOCATE
396 fprintf(stderr,
397 "[KLS] %s(): Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
398 caller_name,
399 size, padding, available);
400#else
401 fprintf(stderr,
402 "[KLS] " KLS_Loc_Fmt "%s(): Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
403 KLS_Loc_Arg(loc),
404 caller_name,
405 size, padding, available);
406#endif // KOLISEO_HAS_LOCATE
407 kls_free(kls);
408 exit(EXIT_FAILURE);
409 }
410 }
411 break;
413#ifndef KOLISEO_HAS_LOCATE
414 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo has an open Koliseo_Temp session.\n", caller_name);
415#else
416 fprintf(stderr, "[ERROR] " KLS_Loc_Fmt "[%s()]: Passed Koliseo has an open Koliseo_Temp session.\n", KLS_Loc_Arg(loc), caller_name);
417 kls_log(kls, "ERROR", KLS_Loc_Fmt "[%s()]: Passed Koliseo has an open Koliseo_Temp session.", KLS_Loc_Arg(loc), caller_name);
418 exit(EXIT_FAILURE);
419#endif // KOLISEO_HAS_LOCATE
420 }
421 break;
423 if (current->conf.err_handlers.PTRDIFF_MAX_handler != NULL) {
424#ifndef KOLISEO_HAS_LOCATE
425 current->conf.err_handlers.PTRDIFF_MAX_handler(current, size, count);
426#else
427 current->conf.err_handlers.PTRDIFF_MAX_handler(current, size, count, loc);
428#endif // KOLISEO_HAS_LOCATE
429 } else { // Let's keep this here for now? It's the original part before adding KLS_PTRDIFF_MAX_default_handler__()
430#ifndef _WIN32
431#ifndef KOLISEO_HAS_LOCATE
432 fprintf(stderr,
433 "[KLS] %s(): count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
434 caller_name,
435 count, PTRDIFF_MAX / size);
436#else
437 fprintf(stderr,
438 "[KLS] " KLS_Loc_Fmt "%s(): count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
439 KLS_Loc_Arg(loc),
440 caller_name,
441 count, PTRDIFF_MAX / size);
442#endif // KOLISEO_HAS_LOCATE
443#else
444#ifndef KOLISEO_HAS_LOCATE
445 fprintf(stderr,
446 "[KLS] %s(): count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
447 caller_name,
448 count, PTRDIFF_MAX / size);
449#else
450 fprintf(stderr,
451 "[KLS] " KLS_Loc_Fmt "%s(): count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
452 KLS_Loc_Arg(loc),
453 caller_name,
454 count, PTRDIFF_MAX / size);
455#endif // KOLISEO_HAS_LOCATE
456#endif // _WIN32
457 }
458 }
459 break;
460 case KLS_PUSH_OOM: {
461 if (current->conf.err_handlers.OOM_handler != NULL) {
462#ifndef KOLISEO_HAS_LOCATE
463 current->conf.err_handlers.OOM_handler(current, available, padding, size, count);
464#else
465 current->conf.err_handlers.OOM_handler(current, available, padding, size, count, loc);
466#endif // KOLISEO_HAS_LOCATE
467 } else { // Let's keep this here for now? It's the original part before adding KLS_OOM_default_handler__()
468#ifndef KOLISEO_HAS_LOCATE
469 fprintf(stderr,
470 "[KLS] %s(): Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
471 caller_name,
472 size * count, available - padding);
473#else
474 fprintf(stderr,
475 "[KLS] " KLS_Loc_Fmt "%s(): Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
476 KLS_Loc_Arg(loc),
477 caller_name,
478 size * count, available - padding);
479#endif // KOLISEO_HAS_LOCATE
480 }
481 }
482 break;
483 default: {
484 fprintf(stderr, "[KLS] %s(): unexpected error code [%i]\n", __func__, r.error);
485 return NULL;
486 }
487 break;
488 }
489 }
490 return r.p;
491}
492
499void kls_log(Koliseo *kls, const char *tag, const char *format, ...)
500{
501 if (kls == NULL) {
502 fprintf(stderr, "[KLS] %s(): Passed kls was NULL.\n", __func__);
503 return;
504 }
505 if (kls->conf.verbose_lvl > 0) {
506 va_list args;
507 FILE *fp = kls->conf.log_fp;
508 va_start(args, format);
509 if (fp == NULL) {
510 fprintf(stderr,
511 "[KLS] %s(): Failed opening file to print logs.\n",
512 __func__);
513 } else {
514 time_t now = time(0);
515 const struct tm *mytime = localtime(&now);
516 char timeheader[500];
517 if (strftime(timeheader, sizeof timeheader, "%X", mytime)) {
518 fprintf(fp, "[%-10.10s] [%s] [", tag, timeheader);
519 vfprintf(fp, format, args);
520 fprintf(fp, "]\n");
521 }
522 }
523 va_end(args);
524 }
525}
526
544#ifndef KOLISEO_HAS_LOCATE
545Koliseo *kls_new_alloc_ext(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Hooks ext_handlers, void* user)
546#else
547Koliseo *kls_new_alloc_ext_dbg(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Hooks ext_handlers, void* user, Koliseo_Loc loc)
548#endif // KOLISEO_HAS_LOCATE
549{
550 if (size < (ptrdiff_t)sizeof(Koliseo)) {
551#ifndef KOLISEO_HAS_LOCATE
552 fprintf(stderr,
553 "[ERROR] at %s(): invalid requested kls size (%td). Min accepted is: (%td).\n",
554 __func__, size, (ptrdiff_t)sizeof(Koliseo));
555#else
556 fprintf(stderr,
557 "[ERROR] " KLS_Loc_Fmt "%s(): invalid requested kls size (%td). Min accepted is: (%td).\n",
558 KLS_Loc_Arg(loc), __func__, size, (ptrdiff_t)sizeof(Koliseo));
559#endif // KOLISEO_HAS_LOCATE
560 //TODO Is it better to abort the program?
561 return NULL;
562 }
563 void *p = alloc_func(size);
564 if (p) {
565 //sprintf(msg,"Allocated (%li) for new KLS.",size);
566 //kls_log("KLS",msg);
567 char h_size[200];
568 kls_formatSize(size, h_size, sizeof(h_size));
569 Koliseo *kls = p;
570 kls->data = p;
571 kls->size = size;
572 kls->offset = sizeof(*kls);
573 kls->prev_offset = kls->offset;
574 kls->has_temp = 0;
575 kls->t_kls = NULL;
576 kls_set_conf(kls, KLS_DEFAULT_CONF);
578 kls->conf.log_fp = stderr;
579
580 KLS_ASAN_POISON(kls->data + kls->offset, kls->size - kls->offset);
581
582 kls->hooks = ext_handlers;
583 if (user) {
584 kls->extension_data = user;
585 } else {
586 kls->extension_data = NULL;
587 }
588 kls->free_func = free_func;
589 kls->next = NULL;
590#ifdef KLS_DEBUG_CORE
591 kls_log(kls, "KLS", "API Level { %i } -> Allocated (%s) for new KLS.",
592 int_koliseo_version(), h_size);
593 kls_log(kls, "KLS", "KLS offset: { %p }.", kls);
594 kls_log(kls, "KLS", "Allocation begin offset: { %p }.",
595 kls + kls->offset);
596#endif
597
598 if (kls->hooks.on_new_handler != NULL) {
599 // Call on_new extension
600 kls->hooks.on_new_handler(kls);
601 }
602 } else {
603#ifndef KOLISEO_HAS_LOCATE
604 fprintf(stderr, "[KLS] Failed %s() call.\n", __func__);
605#else
606 fprintf(stderr, "[KLS] " KLS_Loc_Fmt "Failed %s() call.\n", KLS_Loc_Arg(loc), __func__);
607#endif // KOLISEO_HAS_LOCATE
608 exit(EXIT_FAILURE);
609 }
610#ifdef KLS_DEBUG_CORE
611 Koliseo *kls_ref = p;
612 if (kls_ref->conf.verbose_lvl > 0) {
613 print_kls_2file(kls_ref->conf.log_fp, p);
614 }
615#endif
616 return p;
617}
618
634#ifndef KOLISEO_HAS_LOCATE
635Koliseo *kls_new_alloc(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func)
636#else
637Koliseo *kls_new_alloc_dbg(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, Koliseo_Loc loc)
638#endif // KOLISEO_HAS_LOCATE
639{
640#ifndef KOLISEO_HAS_LOCATE
641 return kls_new_alloc_ext(size, alloc_func, free_func, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
642#else
643 return kls_new_alloc_ext_dbg(size, alloc_func, free_func, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA, loc);
644#endif // KOLISEO_HAS_LOCATE
645}
646
659Koliseo *kls_new(ptrdiff_t size)
660{
662}
663
680Koliseo *kls_new_conf_alloc_ext(ptrdiff_t size, KLS_Conf conf, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Hooks ext_handlers, void* user)
681{
682 Koliseo *k = kls_new_alloc_ext(size, alloc_func, free_func, ext_handlers, user);
683 bool conf_res = kls_set_conf(k, conf);
684 if (!conf_res) {
685 fprintf(stderr,
686 "[ERROR] [%s()]: Failed to set config for new Koliseo.\n",
687 __func__);
688 exit(EXIT_FAILURE);
689 }
690 return k;
691}
692
709Koliseo *kls_new_conf_alloc(ptrdiff_t size, KLS_Conf conf, kls_alloc_func alloc_func, kls_free_func free_func)
710{
711 return kls_new_conf_alloc_ext(size, conf, alloc_func, free_func, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
712}
713
726Koliseo *kls_new_conf_ext(ptrdiff_t size, KLS_Conf conf, KLS_Hooks ext_handlers, void* user)
727{
728 return kls_new_conf_alloc_ext(size, conf, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, ext_handlers, user);
729}
730
742Koliseo *kls_new_conf(ptrdiff_t size, KLS_Conf conf)
743{
745}
746
762Koliseo *kls_new_traced_alloc_handled_ext(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers, KLS_Hooks ext_handlers, void* user)
763{
764
765#ifndef KLS_DEBUG_CORE
766 fprintf(stderr,
767 "[WARN] %s(): KLS_DEBUG_CORE is not defined. No tracing allowed.\n",
768 __func__);
769#endif
770 KLS_Conf k = (KLS_Conf) {
771 .collect_stats = 1,.verbose_lvl =
772 1,.log_filepath = output_path,
773#ifndef KOLISEO_HAS_LOCATE
774 .err_handlers.OOM_handler = (err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler__),
775 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler__),
776#else
777 .err_handlers.OOM_handler = (err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler_dbg__),
778 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler_dbg__),
779#endif // KOLISEO_HAS_LOCATE
780 };
781 return kls_new_conf_alloc_ext(size, k, alloc_func, free_func, ext_handlers, user);
782}
783
798Koliseo *kls_new_traced_alloc_handled(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers)
799{
800 return kls_new_traced_alloc_handled_ext(size, output_path, alloc_func, free_func, err_handlers, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
801}
802
815Koliseo *kls_new_traced_ext(ptrdiff_t size, const char *output_path, KLS_Hooks ext_handlers, void* user)
816{
818 return kls_new_traced_alloc_handled_ext(size, output_path, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, err_handlers, ext_handlers, user);
819}
820
834Koliseo *kls_new_traced_alloc(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func)
835{
837 return kls_new_traced_alloc_handled(size, output_path, alloc_func, free_func, err_handlers);
838}
839
851Koliseo *kls_new_traced(ptrdiff_t size, const char *output_path)
852{
854}
855
868Koliseo *kls_new_traced_handled(ptrdiff_t size, const char *output_path, KLS_Err_Handlers err_handlers)
869{
870 return kls_new_traced_alloc_handled(size, output_path, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, err_handlers);
871}
872
886Koliseo *kls_new_dbg_alloc_handled_ext(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers, KLS_Hooks ext_handlers, void* user)
887{
888#ifndef KLS_DEBUG_CORE
889 fprintf(stderr,
890 "[WARN] %s(): KLS_DEBUG_CORE is not defined. No debugging support.\n",
891 __func__);
892#endif
893 KLS_Conf k = (KLS_Conf) {
894 .collect_stats = 1,.verbose_lvl = 0,
895#ifndef KOLISEO_HAS_LOCATE
896 .err_handlers.OOM_handler = ( err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler__),
897 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler__),
898#else
899 .err_handlers.OOM_handler = ( err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler_dbg__),
900 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler_dbg__),
901#endif // KOLIEO_HAS_LOCATE
902 };
903 Koliseo * kls = kls_new_conf_alloc_ext(size, k, alloc_func, free_func, ext_handlers, user);
904 kls->conf.verbose_lvl = 1;
905 return kls;
906}
907
920Koliseo *kls_new_dbg_alloc_handled(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers)
921{
922 return kls_new_dbg_alloc_handled_ext(size, alloc_func, free_func, err_handlers, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
923}
924
935Koliseo *kls_new_dbg_ext(ptrdiff_t size, KLS_Hooks ext_handlers, void* user)
936{
938 return kls_new_dbg_alloc_handled_ext(size, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, err_handlers, ext_handlers, user);
939}
940
952Koliseo *kls_new_dbg_alloc(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func)
953{
955 return kls_new_dbg_alloc_handled(size, alloc_func, free_func, err_handlers);
956}
957
967Koliseo *kls_new_dbg(ptrdiff_t size)
968{
970}
971
982Koliseo *kls_new_dbg_handled(ptrdiff_t size, KLS_Err_Handlers err_handlers)
983{
985}
986
993bool kls_set_conf(Koliseo *kls, KLS_Conf conf)
994{
995 if (kls == NULL) {
996 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
997 //TODO: is it better to exit() here?
998 return false;
999 }
1000
1001 kls->conf = conf;
1002 if (kls->conf.log_fp == NULL) {
1003 kls->conf.log_fp = stderr;
1004#ifdef KLS_DEBUG_CORE
1005#ifdef KLS_SETCONF_DEBUG
1006 kls_log(kls, "KLS",
1007 "[%s()]: Preliminary set of conf.log_fp to stderr.",
1008 __func__);
1009#endif
1010#endif // KLS_DEBUG_CORE
1011 }
1012
1013 if (conf.err_handlers.OOM_handler == NULL) {
1014 fprintf(stderr,
1015 "[ERROR] at %s(): passed OOM_handler is NULL. Using default.\n",
1016 __func__);
1017#ifdef KLS_DEBUG_CORE
1018#ifdef KLS_SETCONF_DEBUG
1019 kls_log(kls, "KLS",
1020 "[%s()]: Passed OOM_handler was NULL, using default.",
1021 __func__);
1022#endif
1023#endif // KLS_DEBUG_CORE
1024#ifndef KOLISEO_HAS_LOCATE
1026#else
1027 kls->conf.err_handlers.OOM_handler = &KLS_OOM_default_handler_dbg__;
1028#endif
1029 }
1030
1031 if (conf.err_handlers.PTRDIFF_MAX_handler == NULL) {
1032 fprintf(stderr,
1033 "[ERROR] at %s(): passed PTRDIFF_MAX_handler is NULL. Using default.\n",
1034 __func__);
1035#ifdef KLS_DEBUG_CORE
1036#ifdef KLS_SETCONF_DEBUG
1037 kls_log(kls, "KLS",
1038 "[%s()]: Passed PTRDIFF_MAX_handler was NULL, using default.",
1039 __func__);
1040#endif
1041#endif // KLS_DEBUG_CORE
1042#ifndef KOLISEO_HAS_LOCATE
1044#else
1045 kls->conf.err_handlers.PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler_dbg__;
1046#endif
1047 }
1048
1049#ifndef KLS_DEBUG_CORE
1050 if (kls->conf.collect_stats == 1) {
1051 fprintf(stderr,
1052 "[WARN] [%s()]: KLS_DEBUG_CORE is not defined. Stats may not be collected in full.\n",
1053 __func__);
1054 }
1055#endif
1056
1057 if (kls->conf.verbose_lvl > 0) {
1058 if (kls->conf.log_fp != NULL) {
1059#ifdef KLS_DEBUG_CORE
1060#ifdef KLS_SETCONF_DEBUG
1061 kls_log(kls, "WARN",
1062 "[%s()]: kls->conf.log_fp was not NULL. Overriding it.",
1063 __func__);
1064#endif
1065#endif
1066 }
1067
1068 FILE *log_fp = NULL;
1069 log_fp = fopen(kls->conf.log_filepath, "w");
1070 if (!log_fp) {
1071 fprintf(stderr,
1072 "[ERROR] [%s()]: Failed opening logfile at {\"%s\"} [write].\n",
1073 __func__, kls->conf.log_filepath);
1074 return false;
1075 } else {
1076 fprintf(log_fp, "%s", ""); //Reset log_fp
1077 fclose(log_fp);
1078 }
1079 log_fp = fopen(kls->conf.log_filepath, "a");
1080 if (!log_fp) {
1081 fprintf(stderr,
1082 "[ERROR] [%s()]: Failed opening logfile at {\"%s\"} [append].\n",
1083 __func__, kls->conf.log_filepath);
1084 return false;
1085 } else {
1086 kls->conf.log_fp = log_fp;
1087 }
1088 }
1089 return true;
1090}
1091
1092static bool kls__try_grow(Koliseo* kls, ptrdiff_t needed);
1093
1105#ifndef KOLISEO_HAS_LOCATE
1106KLS_Push_Result kls__advance(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t* padding, const char* caller_name)
1107#else
1108KLS_Push_Result kls__advance_dbg(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t* padding, const char* caller_name, Koliseo_Loc loc)
1109#endif // KOLISEO_HAS_LOCATE
1110{
1111#ifdef KLS_DEBUG_CORE
1112#ifndef _WIN32
1113 struct timespec start_time, end_time;
1114 clock_gettime(CLOCK_MONOTONIC, &start_time);
1115#else
1116 LARGE_INTEGER start_time, end_time, frequency;
1117 QueryPerformanceFrequency(&frequency);
1118 QueryPerformanceCounter(&start_time);
1119#endif
1120#endif
1121
1122 if (kls == NULL) {
1123 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", caller_name);
1124 exit(EXIT_FAILURE);
1125 }
1126 if ((kls->has_temp == 1) && (kls->conf.block_while_has_temp == 1)) {
1127 return (KLS_Push_Result) {
1128 .p = NULL,
1130 };
1131 }
1132
1133#ifndef KOLISEO_HAS_LOCATE
1134 KLS_Push_Error res = kls__check_available(kls, size, align, count, __func__);
1135#else
1136 KLS_Push_Error res = kls__check_available_dbg(kls, size, align, count, __func__, loc);
1137#endif
1138 if (res != 0) {
1139 return (KLS_Push_Result) {
1140 .p = NULL,
1141 .error = res,
1142 };
1143 }
1144 Koliseo* current = kls;
1145 while (current->next != NULL) {
1146 current = current->next;
1147 }
1148 const ptrdiff_t pad = -current->offset & (align - 1);
1149 *padding = pad;
1150 char *p = current->data + current->offset + pad;
1151 current->prev_offset = current->offset;
1152 current->offset += pad + size * count;
1153
1154 KLS_ASAN_UNPOISON(p, size * count);
1155
1156 char h_size[200];
1157 kls_formatSize(size * count, h_size, sizeof(h_size));
1158 //sprintf(msg,"Pushed zeroes, size (%li) for KLS.",size);
1159 //kls_log("KLS",msg);
1160#ifdef KLS_DEBUG_CORE
1161 kls_log(current, "KLS", "Pushed zeroes on KLS, size (%s). Curr offset: { %p }.", h_size, current->data + current->offset);
1162 if (current->conf.collect_stats == 1) {
1163#ifndef _WIN32
1164 clock_gettime(CLOCK_MONOTONIC, &end_time); // %.9f
1165 double elapsed_time =
1166 (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec -
1167 start_time.tv_nsec) / 1e9;
1168#else
1169 QueryPerformanceCounter(&end_time); // %.7f
1170 double elapsed_time =
1171 (double)(end_time.QuadPart -
1172 start_time.QuadPart) / frequency.QuadPart;
1173#endif
1174 if (elapsed_time > current->stats.worst_pushcall_time) {
1175 current->stats.worst_pushcall_time = elapsed_time;
1176 }
1177 }
1178#endif
1179 if (current->conf.collect_stats == 1) {
1180 current->stats.tot_pushes += 1;
1181 }
1182 return (KLS_Push_Result) {
1183 .p = p,
1184 .error = KLS_PUSH_OK,
1185 };
1186}
1187
1200#ifndef KOLISEO_HAS_LOCATE
1201KLS_Push_Error kls__check_available(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, const char* caller_name)
1202#else
1203KLS_Push_Error kls__check_available_dbg(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, const char* caller_name, Koliseo_Loc loc)
1204#endif // KOLISEO_HAS_LOCATE
1205{
1206 assert(kls != NULL);
1207 assert(caller_name != NULL);
1208 if (count < 0) {
1210 }
1211 if (size < 1) {
1212 return KLS_PUSH_SIZE_LT1;
1213 }
1214 if (align < 1) {
1215 return KLS_PUSH_ALIGN_LT1;
1216 }
1217 if (! ((align & (align - 1)) == 0)) {
1219 }
1220 Koliseo* current = kls;
1221 while (current->next != NULL) {
1222 current = current->next;
1223 }
1224 const ptrdiff_t available = current->size - current->offset;
1225 const ptrdiff_t padding = -current->offset & (align - 1);
1226 if (count == 0) {
1227 if (current->conf.allow_zerocount_push != 1) {
1228 return KLS_PUSH_ZEROCOUNT;
1229 } else {
1230#ifdef KLS_DEBUG_CORE
1231 kls_log(current, "DEBUG", "Accepting zero-count push: conf.allow_zerocount_push was 1");
1232#endif // KLS_DEBUG_CORE
1233 }
1234 }
1235
1236 if (count > PTRDIFF_MAX / size || available - padding < size * count) {
1237 if (count > PTRDIFF_MAX / size) {
1238 return KLS_PUSH_PTRDIFF_MAX;
1239 } else {
1240 if (current->conf.growable == 1 && kls__try_grow(current, size + count + padding)) {
1241 return KLS_PUSH_OK;
1242 }
1243 return KLS_PUSH_OOM;
1244 }
1245 }
1246 return KLS_PUSH_OK;
1247}
1248
1260#ifndef KOLISEO_HAS_LOCATE
1261KLS_Push_Result kls__temp_advance(Koliseo_Temp* kls_t, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t* padding, const char* caller_name)
1262#else
1263KLS_Push_Result kls__temp_advance_dbg(Koliseo_Temp* kls_t, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t* padding, const char* caller_name, Koliseo_Loc loc)
1264#endif // KOLISEO_HAS_LOCATE
1265{
1266#ifdef KLS_DEBUG_CORE
1267#ifndef _WIN32
1268 struct timespec start_time, end_time;
1269 clock_gettime(CLOCK_MONOTONIC, &start_time);
1270#else
1271 LARGE_INTEGER start_time, end_time, frequency;
1272 QueryPerformanceFrequency(&frequency);
1273 QueryPerformanceCounter(&start_time);
1274#endif
1275#endif
1276
1277 if (kls_t == NULL) {
1278 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo_Temp was NULL.\n",
1279 __func__);
1280 exit(EXIT_FAILURE);
1281 }
1282 Koliseo *kls = kls_t->kls;
1283 if (kls == NULL) {
1284 fprintf(stderr, "[ERROR] [%s()]: Referred Koliseo was NULL.\n",
1285 __func__);
1286 exit(EXIT_FAILURE);
1287 }
1288#ifndef KOLISEO_HAS_LOCATE
1289 KLS_Push_Error res = kls__check_available(kls, size, align, count, __func__);
1290#else
1291 KLS_Push_Error res = kls__check_available_dbg(kls, size, align, count, __func__, loc);
1292#endif
1293 if (res != 0) {
1294 return (KLS_Push_Result) {
1295 .p = NULL,
1296 .error = res,
1297 };
1298 }
1299 Koliseo* current = kls;
1300 while (current->next != NULL) {
1301 current = current->next;
1302 }
1303 ptrdiff_t pad = -current->offset & (align - 1);
1304 char *p = current->data + current->offset + pad;
1305 *padding = pad;
1306 current->prev_offset = current->offset;
1307 current->offset += pad + size * count;
1308
1309 KLS_ASAN_UNPOISON(p, size * count);
1310
1311 char h_size[200];
1312 kls_formatSize(size * count, h_size, sizeof(h_size));
1313 //sprintf(msg,"Pushed zeroes, size (%li) for KLS.",size);
1314 //kls_log("KLS",msg);
1315#ifdef KLS_DEBUG_CORE
1316 if (current->conf.collect_stats == 1) {
1317#ifndef _WIN32
1318 clock_gettime(CLOCK_MONOTONIC, &end_time); // %.9f
1319 double elapsed_time =
1320 (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec -
1321 start_time.tv_nsec) / 1e9;
1322#else
1323 QueryPerformanceCounter(&end_time); // %.7f
1324 double elapsed_time =
1325 (double)(end_time.QuadPart -
1326 start_time.QuadPart) / frequency.QuadPart;
1327#endif
1328 if (elapsed_time > current->stats.worst_pushcall_time) {
1329 current->stats.worst_pushcall_time = elapsed_time;
1330 }
1331 }
1332 kls_log(current, "KLS", "Pushed zeroes on Temp_KLS, size (%s). Curr offset: { %p }.", h_size, current->data + current->offset);
1333#endif
1334 if (current->conf.collect_stats == 1) {
1335 current->stats.tot_temp_pushes += 1;
1336 }
1337 return (KLS_Push_Result) {
1338 .p = p,
1339 .error = KLS_PUSH_OK,
1340 };
1341}
1342
1343bool kls__try_grow(Koliseo* kls, ptrdiff_t needed)
1344{
1345 assert(kls->next == NULL);
1346 ptrdiff_t new_size = KLS_MAX(kls->size * 2, needed);
1347 KLS_Hooks hooks = kls->hooks;
1348 hooks.on_new_handler = NULL; // We don't want the extension handler to run again on the tail
1349 // since the extension_data is shared
1351 kls_log(kls, "DEBUG", "%s(): growing Koliseo, new size: {%td}", __func__, new_size);
1352 if (!new_kls) return false;
1353 kls->next = new_kls;
1354 return true;
1355}
1356
1367void *kls_push(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
1368{
1369 ptrdiff_t padding = 0;
1370#ifndef KOLISEO_HAS_LOCATE
1371 KLS_Push_Result res = kls__advance(kls, size, align, count, &padding, __func__);
1372 return kls__handle_push_result(kls, res, size, align, count, padding, __func__);
1373#else
1374 KLS_Push_Result res = kls__advance_dbg(kls, size, align, count, &padding, __func__, KLS_HERE);
1375 return kls__handle_push_result_dbg(kls, res, size, align, count, padding, __func__, KLS_HERE);
1376#endif // KOLISEO_HAS_LOCATE
1377}
1378
1389#ifndef KOLISEO_HAS_LOCATE
1390void *kls_push_zero(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1391 ptrdiff_t count)
1392#else
1393void *kls_push_zero_dbg(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1394 ptrdiff_t count, Koliseo_Loc loc)
1395#endif // KOLISEO_HAS_LOCATE
1396{
1397 ptrdiff_t padding = 0;
1398#ifndef KOLISEO_HAS_LOCATE
1399 KLS_Push_Result res = kls__advance(kls, size, align, count, &padding, __func__);
1400 void* p = kls__handle_push_result(kls, res, size, align, count, padding, __func__);
1401#else
1402 KLS_Push_Result res = kls__advance_dbg(kls, size, align, count, &padding, __func__, loc);
1403 void* p = kls__handle_push_result_dbg(kls, res, size, align, count, padding, __func__, loc);
1404#endif // KOLISEO_HAS_LOCATE
1405 if (!p) return NULL;
1406 //Zero new area
1407 memset(p, 0, size * count);
1408 return p;
1409}
1410
1422#ifndef KOLISEO_HAS_LOCATE
1423void *kls_push_zero_ext(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1424 ptrdiff_t count)
1425#else
1426void *kls_push_zero_ext_dbg(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1427 ptrdiff_t count, Koliseo_Loc loc)
1428#endif // KOLISEO_HAS_LOCATE
1429{
1430
1431 ptrdiff_t padding = 0;
1432#ifndef KOLISEO_HAS_LOCATE
1433 KLS_Push_Result res = kls__advance(kls, size, align, count, &padding, __func__);
1434 void* p = kls__handle_push_result(kls, res, size, align, count, padding, __func__);
1435#else
1436 KLS_Push_Result res = kls__advance_dbg(kls, size, align, count, &padding, __func__, loc);
1437 void* p = kls__handle_push_result_dbg(kls, res, size, align, count, padding, __func__, loc);
1438#endif // KOLISEO_HAS_LOCATE
1439 if (!p) return NULL;
1440 //Zero new area
1441 memset(p, 0, size * count);
1442
1443 Koliseo* current = kls;
1444 while (current->next != NULL) {
1445 current = current->next;
1446 }
1447
1448 if (current->hooks.on_push_handler != NULL) {
1449 /*
1450 struct KLS_EXTENSION_AR_DEFAULT_ARGS {
1451 const char* region_name;
1452 size_t region_name_len;
1453 const char* region_desc;
1454 size_t region_desc_len;
1455 int region_type;
1456 };
1457 struct KLS_EXTENSION_AR_DEFAULT_ARGS ar_args = {
1458 .region_name = KOLISEO_DEFAULT_REGION_NAME,
1459 .region_name_len = strlen(KOLISEO_DEFAULT_REGION_NAME),
1460 .region_desc = KOLISEO_DEFAULT_REGION_DESC,
1461 .region_desc_len = strlen(KOLISEO_DEFAULT_REGION_DESC),
1462 .region_type = KLS_None
1463 };
1464 kls->hooks.on_push_handler(kls, padding, (void*)&ar_args);
1465 */
1466 current->hooks.on_push_handler(current, padding, __func__, NULL);
1467 }
1468 return p;
1469}
1470
1471#ifndef KOLISEO_HAS_LOCATE
1472char* kls_vsprintf(Koliseo* kls, const char* fmt, va_list args)
1473#else
1474char* kls_vsprintf_dbg(Koliseo* kls, Koliseo_Loc loc, const char* fmt, va_list args)
1475#endif // KOLISEO_HAS_LOCATE
1476{
1477 va_list args_copy;
1478 va_copy(args_copy, args);
1479 int len = vsnprintf(NULL, 0, fmt, args);
1480#ifndef KOLISEO_HAS_LOCATE
1481 char* str = KLS_PUSH_ARR(kls, char, len+1);
1482#else
1483 char* str = kls_push_zero_ext_dbg(kls, sizeof(char), KLS_ALIGNOF(char), len+1, loc);
1484#endif // KOLISEO_HAS_LOCATE
1485 vsnprintf(str, len+1, fmt, args_copy);
1486 va_end(args_copy);
1487 return str;
1488}
1489
1496#ifndef KOLISEO_HAS_LOCATE
1497char* kls_sprintf(Koliseo* kls, const char* fmt, ...)
1498#else
1499char* kls_sprintf_dbg(Koliseo* kls, Koliseo_Loc loc, const char* fmt, ...)
1500#endif // KOLISEO_HAS_LOCATE
1501{
1502 va_list args;
1503 va_start(args, fmt);
1504#ifndef KOLISEO_HAS_LOCATE
1505 char* str = kls_vsprintf(kls, fmt, args);
1506#else
1507 char* str = kls_vsprintf_dbg(kls, loc, fmt, args);
1508#endif // KOLISEO_HAS_LOCATE
1509 va_end(args);
1510 return str;
1511}
1512
1524#ifndef KOLISEO_HAS_LOCATE
1525void *kls_temp_push_zero_ext(Koliseo_Temp *t_kls, ptrdiff_t size,
1526 ptrdiff_t align, ptrdiff_t count)
1527#else
1528void *kls_temp_push_zero_ext_dbg(Koliseo_Temp *t_kls, ptrdiff_t size,
1529 ptrdiff_t align, ptrdiff_t count, Koliseo_Loc loc)
1530#endif // KOLISEO_HAS_LOCATE
1531{
1532
1533 ptrdiff_t padding = 0;
1534
1535#ifndef KOLISEO_HAS_LOCATE
1536 KLS_Push_Result res = kls__temp_advance(t_kls, size, align, count, &padding, __func__);
1537#else
1538 KLS_Push_Result res = kls__temp_advance_dbg(t_kls, size, align, count, &padding, __func__, loc);
1539#endif // KOLISEO_HAS_LOCATE
1540 if (res.error) return NULL;
1541 //Zero new area
1542 memset(res.p, 0, size * count);
1543
1544 Koliseo* kls = t_kls->kls;
1545 Koliseo* current = kls;
1546 while (current->next != NULL) {
1547 current = current->next;
1548 }
1549
1550 if (current->hooks.on_temp_push_handler != NULL) {
1551 // Call on_temp_push extension with empty user arg
1552 current->hooks.on_temp_push_handler(t_kls, padding, __func__, NULL);
1553 }
1554 return res.p;
1555}
1556
1557#ifndef KOLISEO_HAS_LOCATE
1558char* kls_temp_vsprintf(Koliseo_Temp* kls_t, const char* fmt, va_list args)
1559#else
1560char* kls_temp_vsprintf_dbg(Koliseo_Temp* kls_t, Koliseo_Loc loc, const char* fmt, va_list args)
1561#endif // KOLISEO_HAS_LOCATE
1562{
1563 va_list args_copy;
1564 va_copy(args_copy, args);
1565 int len = vsnprintf(NULL, 0, fmt, args);
1566#ifndef KOLISEO_HAS_LOCATE
1567 char* str = KLS_PUSH_ARR_T(kls_t, char, len+1);
1568#else
1569 char* str = kls_temp_push_zero_ext_dbg(kls_t, sizeof(char), KLS_ALIGNOF(char), len+1, loc);
1570#endif // KOLISEO_HAS_LOCATE
1571 vsnprintf(str, len+1, fmt, args_copy);
1572 va_end(args_copy);
1573 return str;
1574}
1575
1576
1583#ifndef KOLISEO_HAS_LOCATE
1584char* kls_temp_sprintf(Koliseo_Temp* kls_t, const char* fmt, ...)
1585#else
1586char* kls_temp_sprintf_dbg(Koliseo_Temp* kls_t, Koliseo_Loc loc, const char* fmt, ...)
1587#endif // KOLISEO_HAS_LOCATE
1588{
1589 va_list args;
1590 va_start(args, fmt);
1591#ifndef KOLISEO_HAS_LOCATE
1592 char* str = kls_temp_vsprintf(kls_t, fmt, args);
1593#else
1594 char* str = kls_temp_vsprintf_dbg(kls_t, loc, fmt, args);
1595#endif // KOLISEO_HAS_LOCATE
1596 va_end(args);
1597 return str;
1598}
1599
1611#ifndef KOLISEO_HAS_LOCATE
1612void *kls_repush(Koliseo *kls, void* old, ptrdiff_t size, ptrdiff_t align,
1613 ptrdiff_t old_count, ptrdiff_t new_count)
1614#else
1615void *kls_repush_dbg(Koliseo *kls, void* old, ptrdiff_t size, ptrdiff_t align,
1616 ptrdiff_t old_count, ptrdiff_t new_count, Koliseo_Loc loc)
1617#endif // KOLISEO_HAS_LOCATE
1618{
1619 if (!old) {
1620#ifndef KOLISEO_HAS_LOCATE
1621 fprintf(stderr,
1622 "[KLS] %s(): old was NULL.\n",
1623 __func__);
1624#else
1625 fprintf(stderr,
1626 "[KLS] " KLS_Loc_Fmt "%s(): old was NULL.\n",
1627 KLS_Loc_Arg(loc),
1628 __func__);
1629#endif // KOLISEO_HAS_LOCATE
1630 return NULL;
1631 }
1632 if (old_count < 0) {
1633#ifndef KOLISEO_HAS_LOCATE
1634 fprintf(stderr,
1635 "[KLS] %s(): old_count [%td] was < 0.\n",
1636 __func__,
1637 old_count);
1638#else
1639 fprintf(stderr,
1640 "[KLS] " KLS_Loc_Fmt "%s(): old_count [%td] was < 0.\n",
1641 KLS_Loc_Arg(loc),
1642 __func__,
1643 old_count);
1644#endif // KOLISEO_HAS_LOCATE
1645 return NULL;
1646 }
1647 if (new_count < 0) {
1648#ifndef KOLISEO_HAS_LOCATE
1649 fprintf(stderr,
1650 "[KLS] %s(): new_count [%td] was < 0.\n",
1651 __func__,
1652 new_count);
1653#else
1654 fprintf(stderr,
1655 "[KLS] " KLS_Loc_Fmt "%s(): new_count [%td] was < 0.\n",
1656 KLS_Loc_Arg(loc),
1657 __func__,
1658 new_count);
1659#endif // KOLISEO_HAS_LOCATE
1660 return NULL;
1661 }
1662 if (size < 1) {
1663#ifndef KOLISEO_HAS_LOCATE
1664 fprintf(stderr,
1665 "[KLS] %s(): size [%td] was < 1.\n",
1666 __func__,
1667 size);
1668#else
1669 fprintf(stderr,
1670 "[KLS] " KLS_Loc_Fmt "%s(): size [%td] was < 1.\n",
1671 KLS_Loc_Arg(loc),
1672 __func__,
1673 size);
1674#endif // KOLISEO_HAS_LOCATE
1675 return NULL;
1676 }
1677 if (align < 1) {
1678#ifndef KOLISEO_HAS_LOCATE
1679 fprintf(stderr,
1680 "[KLS] %s(): align [%td] was < 1.\n",
1681 __func__,
1682 align);
1683#else
1684 fprintf(stderr,
1685 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was < 1.\n",
1686 KLS_Loc_Arg(loc),
1687 __func__,
1688 align);
1689#endif // KOLISEO_HAS_LOCATE
1690 return NULL;
1691 }
1692 if (! ((align & (align - 1)) == 0)) {
1693#ifndef KOLISEO_HAS_LOCATE
1694 fprintf(stderr,
1695 "[KLS] %s(): align [%td] was not a power of 2.\n",
1696 __func__,
1697 align);
1698#else
1699 fprintf(stderr,
1700 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was not a power of 2.\n",
1701 KLS_Loc_Arg(loc),
1702 __func__,
1703 align);
1704#endif // KOLISEO_HAS_LOCATE
1705 return NULL;
1706 }
1707 if (kls->has_temp == 1 && kls->conf.block_while_has_temp == 1) {
1708 fprintf(stderr, "%s(): kls has an active temp\n", __func__);
1709 return NULL;
1710 }
1711 size_t old_size = old_count * size;
1712 size_t new_size = new_count * size;
1713 void *new_ptr = kls_push_zero_ext(kls, size, align, new_count);
1714 if (new_ptr && old_size > 0) {
1715 memcpy(new_ptr, old, old_size < new_size ? old_size : new_size);
1716 }
1717 return new_ptr;
1718}
1719
1731#ifndef KOLISEO_HAS_LOCATE
1732void *kls_temp_repush(Koliseo_Temp *t_kls, void* old, ptrdiff_t size, ptrdiff_t align,
1733 ptrdiff_t old_count, ptrdiff_t new_count)
1734#else
1735void *kls_temp_repush_dbg(Koliseo_Temp *t_kls, void* old, ptrdiff_t size, ptrdiff_t align,
1736 ptrdiff_t old_count, ptrdiff_t new_count, Koliseo_Loc loc)
1737#endif // KOLISEO_HAS_LOCATE
1738{
1739 if (!old) {
1740#ifndef KOLISEO_HAS_LOCATE
1741 fprintf(stderr,
1742 "[KLS] %s(): old was NULL.\n",
1743 __func__);
1744#else
1745 fprintf(stderr,
1746 "[KLS] " KLS_Loc_Fmt "%s(): old was NULL.\n",
1747 KLS_Loc_Arg(loc),
1748 __func__);
1749#endif // KOLISEO_HAS_LOCATE
1750 return NULL;
1751 }
1752 if (old_count < 0) {
1753#ifndef KOLISEO_HAS_LOCATE
1754 fprintf(stderr,
1755 "[KLS] %s(): old_count [%td] was < 0.\n",
1756 __func__,
1757 old_count);
1758#else
1759 fprintf(stderr,
1760 "[KLS] " KLS_Loc_Fmt "%s(): old_count [%td] was < 0.\n",
1761 KLS_Loc_Arg(loc),
1762 __func__,
1763 old_count);
1764#endif // KOLISEO_HAS_LOCATE
1765 return NULL;
1766 }
1767 if (new_count < 0) {
1768#ifndef KOLISEO_HAS_LOCATE
1769 fprintf(stderr,
1770 "[KLS] %s(): new_count [%td] was < 0.\n",
1771 __func__,
1772 new_count);
1773#else
1774 fprintf(stderr,
1775 "[KLS] " KLS_Loc_Fmt "%s(): new_count [%td] was < 0.\n",
1776 KLS_Loc_Arg(loc),
1777 __func__,
1778 new_count);
1779#endif // KOLISEO_HAS_LOCATE
1780 return NULL;
1781 }
1782 if (size < 1) {
1783#ifndef KOLISEO_HAS_LOCATE
1784 fprintf(stderr,
1785 "[KLS] %s(): size [%td] was < 1.\n",
1786 __func__,
1787 size);
1788#else
1789 fprintf(stderr,
1790 "[KLS] " KLS_Loc_Fmt "%s(): size [%td] was < 1.\n",
1791 KLS_Loc_Arg(loc),
1792 __func__,
1793 size);
1794#endif // KOLISEO_HAS_LOCATE
1795 return NULL;
1796 }
1797 if (align < 1) {
1798#ifndef KOLISEO_HAS_LOCATE
1799 fprintf(stderr,
1800 "[KLS] %s(): align [%td] was < 1.\n",
1801 __func__,
1802 align);
1803#else
1804 fprintf(stderr,
1805 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was < 1.\n",
1806 KLS_Loc_Arg(loc),
1807 __func__,
1808 align);
1809#endif // KOLISEO_HAS_LOCATE
1810 return NULL;
1811 }
1812 if (! ((align & (align - 1)) == 0)) {
1813#ifndef KOLISEO_HAS_LOCATE
1814 fprintf(stderr,
1815 "[KLS] %s(): align [%td] was not a power of 2.\n",
1816 __func__,
1817 align);
1818#else
1819 fprintf(stderr,
1820 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was not a power of 2.\n",
1821 KLS_Loc_Arg(loc),
1822 __func__,
1823 align);
1824#endif // KOLISEO_HAS_LOCATE
1825 return NULL;
1826 }
1827 size_t old_size = old_count * size;
1828 size_t new_size = new_count * size;
1829 void *new_ptr = kls_temp_push_zero_ext(t_kls, size, align, new_count);
1830 if (new_ptr && old_size > 0) {
1831 memcpy(new_ptr, old, old_size < new_size ? old_size : new_size);
1832 }
1833 return new_ptr;
1834}
1835
1841void print_kls_2file(FILE *fp, const Koliseo *kls)
1842{
1843 if (fp == NULL) {
1844 fprintf(stderr, "print_kls_2file(): fp was NULL.\n");
1845 return;
1846 }
1847 if (kls == NULL) {
1848 fprintf(fp, "[KLS] kls was NULL.\n");
1849 } else {
1850 fprintf(fp, "\n[KLS] API Level: { %i }\n", int_koliseo_version());
1851 fprintf(fp, "\n[INFO] Conf: { " KLS_Conf_Fmt " }\n",
1852 KLS_Conf_Arg(kls->conf));
1853 fprintf(fp, "\n[INFO] Stats: { " KLS_Stats_Fmt " }\n",
1854 KLS_Stats_Arg(kls->stats));
1855 fprintf(fp, "\n[KLS] Size: { %td }\n", kls->size);
1856 char human_size[200];
1857 char curr_size[200];
1858 kls_formatSize(kls->size, human_size, sizeof(human_size));
1859 fprintf(fp, "[KLS] Size (Human): { %s }\n", human_size);
1860 kls_formatSize(kls->offset, curr_size, sizeof(curr_size));
1861 fprintf(fp, "[KLS] Used (Human): { %s }\n", curr_size);
1862 fprintf(fp, "[KLS] Offset: { %td }\n", kls->offset);
1863 fprintf(fp, "[KLS] Prev_Offset: { %td }\n", kls->prev_offset);
1864 fprintf(fp, "\n");
1865 }
1866}
1867
1872void print_dbg_kls(const Koliseo *kls)
1873{
1874 if (kls == NULL) {
1875 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
1876 exit(EXIT_FAILURE);
1877 }
1878 print_kls_2file(stderr, kls);
1879}
1880
1886void print_temp_kls_2file(FILE *fp, const Koliseo_Temp *t_kls)
1887{
1888 if (fp == NULL) {
1889 fprintf(stderr, "print_temp_kls_2file(): fp was NULL.\n");
1890 exit(EXIT_FAILURE);
1891 }
1892 if (t_kls == NULL) {
1893 fprintf(fp, "[KLS_T] t_kls was NULL.");
1894 } else if (t_kls->kls == NULL) {
1895 fprintf(fp, "[KLS_T] [%s()]: Referred Koliseo was NULL.\n", __func__);
1896 } else {
1897 const Koliseo *kls = t_kls->kls;
1898 fprintf(fp, "\n[KLS_T] API Level: { %i }\n", int_koliseo_version());
1899 fprintf(fp, "\n[KLS_T] Temp Size: { %td }\n",
1900 kls->size - t_kls->offset);
1901 fprintf(fp, "\n[KLS_T] Refer Size: { %td }\n", kls->size);
1902 char human_size[200];
1903 char curr_size[200];
1904 kls_formatSize(kls->size - t_kls->offset, human_size,
1905 sizeof(human_size));
1906 fprintf(fp, "[KLS_T] Temp Size Human: { %s }\n", human_size);
1907 kls_formatSize(kls->size, human_size, sizeof(human_size));
1908 fprintf(fp, "[KLS_T] Refer Size Human: { %s }\n", human_size);
1909 kls_formatSize(kls->offset, curr_size, sizeof(curr_size));
1910 fprintf(fp, "[KLS_T] Inner Used (Human): { %s }\n", curr_size);
1911 kls_formatSize(t_kls->offset, curr_size, sizeof(curr_size));
1912 fprintf(fp, "[KLS_T] Temp Used (Human): { %s }\n", curr_size);
1913 fprintf(fp, "[KLS_T] Inner Offset: { %td }\n", kls->offset);
1914 fprintf(fp, "[KLS_T] Temp Offset: { %td }\n", t_kls->offset);
1915 fprintf(fp, "[KLS_T] Inner Prev_Offset: { %td }\n", kls->prev_offset);
1916 fprintf(fp, "[KLS_T] Temp Prev_Offset: { %td }\n\n",
1917 t_kls->prev_offset);
1918 }
1919}
1920
1926{
1927 print_temp_kls_2file(stderr, t_kls);
1928}
1929
1937void kls_formatSize(ptrdiff_t size, char *outputBuffer, size_t bufferSize)
1938{
1939 const char *units[] =
1940 { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
1941 const int numUnits = sizeof(units) / sizeof(units[0]);
1942
1943 int unitIndex = 0;
1944 double sizeValue = (double)size;
1945
1946 while (sizeValue >= 1000 && unitIndex < numUnits - 1) {
1947 sizeValue /= 1000;
1948 unitIndex++;
1949 }
1950
1951 snprintf(outputBuffer, bufferSize, "%.2f %s", sizeValue, units[unitIndex]);
1952}
1953
1960{
1961 if (kls == NULL) {
1962 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
1963 exit(EXIT_FAILURE);
1964 }
1965 //Reset pointer
1966 kls->prev_offset = kls->offset;
1967 kls->offset = sizeof(*kls);
1968 if (kls->next) {
1969 Koliseo *chain = kls->next;
1970 kls->next = NULL;
1971 if (chain) {
1972 kls_free(chain);
1973 kls->extension_data = NULL; // The chain shares this pointer and we need to restore the extension data
1974 if (kls->hooks.on_new_handler) {
1975 kls->hooks.on_new_handler(kls);
1976 }
1977 }
1978 }
1979 KLS_ASAN_POISON(kls->data + kls->offset, kls->size - kls->offset);
1980#ifdef KLS_DEBUG_CORE
1981 kls_log(kls, "KLS", "API Level { %i } -> Cleared offsets for KLS.",
1983#endif
1984}
1985
1992{
1993 if (kls == NULL) {
1994 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
1995 exit(EXIT_FAILURE);
1996 }
1997 Koliseo* current = kls;
1998 while (current) {
1999 if (current->has_temp == 1) {
2000#ifdef KLS_DEBUG_CORE
2001 kls_log(current, "KLS",
2002 "API Level { %i } -> KLS had an active Koliseo_Temp.",
2004#endif
2005 kls_temp_end(current->t_kls);
2006 }
2007 if (current->hooks.on_free_handler != NULL) {
2008 // Call on_free() extension
2009 current->hooks.on_free_handler(current);
2010 for (Koliseo *k = current; k; k = k->next) {
2011 // We NULL all subsequent extension_data pointers, since the chain shares it
2012 // and it's freed in the first hook call
2013 k->extension_data = NULL;
2014 }
2015 }
2016 Koliseo* next = current->next;
2017 current->next = NULL;
2018 //kls_clear(current);
2019#ifdef KLS_DEBUG_CORE
2020 kls_log(current, "KLS", "API Level { %i } -> Freeing KLS.",
2022#endif
2023 if (current->conf.log_fp != NULL && current->conf.log_fp != stdout
2024 && current->conf.log_fp != stderr) {
2025#ifdef KLS_DEBUG_CORE
2026 kls_log(current, "KLS", "Closing kls log file. Path: {\"%s\"}.",
2027 kls->conf.log_filepath);
2028#endif
2029 int close_res = fclose(current->conf.log_fp);
2030 if (close_res != 0) {
2031 fprintf(stderr,
2032 "[ERROR] %s(): Failed fclose() on log_fp. Path: {\"%s\"}.",
2033 __func__, current->conf.log_filepath);
2034 }
2035 } else if (current->conf.log_fp == stdout || current->conf.log_fp == stderr) {
2036 if (current->conf.verbose_lvl > 1) {
2037 fprintf(stderr,
2038 "[INFO] %s(): kls->conf.log_fp is %s. Not closing it.\n",
2039 __func__,
2040 (current->conf.log_fp == stdout ? "stdout" : "stderr"));
2041 }
2042 }
2043 if (current->free_func == NULL) {
2044 fprintf(stderr,
2045 "[ERROR] %s(): free function was NULL.\n", __func__);
2046 return;
2047 }
2048 current->free_func(current);
2049 current = next;
2050 }
2051}
2052
2060#ifndef KOLISEO_HAS_LOCATE
2062#else
2063Koliseo_Temp *kls_temp_start_dbg(Koliseo *kls, Koliseo_Loc loc)
2064#endif // KOLISEO_HAS_LOCATE
2065{
2066 if (kls == NULL) {
2067 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
2068 exit(EXIT_FAILURE);
2069 }
2070 Koliseo* current = kls;
2071 while (current->next != NULL) {
2072 current = current->next;
2073 }
2074 if (current->has_temp != 0) {
2075 fprintf(stderr,
2076 "[ERROR] [%s()]: Passed Koliseo->has_temp is not 0. {%i}\n",
2077 __func__, current->has_temp);
2078#ifdef KLS_DEBUG_CORE
2079 kls_log(current, "ERROR", "[%s()]: Passed Koliseo->has_temp != 0 . {%i}",
2080 __func__, current->has_temp);
2081#endif
2082 return NULL;
2083 }
2084 ptrdiff_t prev = current->prev_offset;
2085 ptrdiff_t off = current->offset;
2086
2087 Koliseo_Temp *tmp = KLS_PUSH(current, Koliseo_Temp);
2088 tmp->kls = current;
2089 tmp->prev_offset = prev;
2090 tmp->offset = off;
2091#ifdef KLS_DEBUG_CORE
2092 kls_log(current, "INFO", "Passed kls conf: " KLS_Conf_Fmt "\n",
2093 KLS_Conf_Arg(current->conf));
2094#endif
2095
2096 current->has_temp = 1;
2097 current->t_kls = tmp;
2098 if (current->hooks.on_temp_start_handler != NULL) {
2099 // Call on_temp_start extension
2100 current->hooks.on_temp_start_handler(tmp);
2101 }
2102#ifdef KLS_DEBUG_CORE
2103 kls_log(current, "KLS", "Prepared new Temp KLS.");
2104#endif
2105 return tmp;
2106}
2107
2113{
2114 if (tmp_kls == NULL) {
2115 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo_Temp was NULL.\n",
2116 __func__);
2117 exit(EXIT_FAILURE);
2118 }
2119
2120 Koliseo *kls_ref = tmp_kls->kls;
2121 if (kls_ref == NULL) {
2122 fprintf(stderr, "[ERROR] [%s()]: Referred Koliseo was NULL.\n",
2123 __func__);
2124 exit(EXIT_FAILURE);
2125 }
2126
2127 if (kls_ref->hooks.on_temp_free_handler != NULL) {
2128 // Call on_temp_free() extension
2129 kls_ref->hooks.on_temp_free_handler(tmp_kls);
2130 }
2131
2132#ifdef KLS_DEBUG_CORE
2133 kls_log(kls_ref, "KLS", "Ended Temp KLS.");
2134#endif
2135 tmp_kls->kls->has_temp = 0;
2136 tmp_kls->kls->t_kls = NULL;
2137#if defined(__SANITIZE_ADDRESS__)
2138 ptrdiff_t old_offset = tmp_kls->kls->offset;
2139 ptrdiff_t new_offset = tmp_kls->offset;
2140#endif // __SANITIZE_ADDRESS__
2141 tmp_kls->kls->prev_offset = tmp_kls->prev_offset;
2142 tmp_kls->kls->offset = tmp_kls->offset;
2143
2144 // Free any Koliseo chained after the current one
2145 Koliseo* to_free = tmp_kls->kls->next;
2146 if (to_free != NULL) {
2147 kls_free(to_free);
2148 tmp_kls->kls->next = NULL;
2149 }
2150
2151 KLS_ASAN_POISON(tmp_kls->kls->data + new_offset, old_offset - new_offset);
2152 tmp_kls = NULL; // statement with no effect TODO: Clear tmp_kls from caller
2153 if (kls_ref->conf.collect_stats == 1) {
2154 kls_ref->stats.tot_temp_pushes = 0;
2155 kls_ref->stats.tot_temp_pops = 0;
2156 }
2157}
2158
2159#ifdef KOLISEO_HAS_EXPER
2168void *kls_pop(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
2169{
2170 if (kls == NULL) {
2171 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
2172 exit(EXIT_FAILURE);
2173 }
2174 ptrdiff_t padding = -kls->offset & (align - 1);
2175 if (count > PTRDIFF_MAX / size
2176 || (kls->size + kls->offset) < (size * count)) {
2177 fprintf(stderr, "[KLS] Failed %s() call.\n", __func__);
2178 kls_free(kls);
2179 exit(EXIT_FAILURE);
2180 }
2181 char *p = kls->data + kls->offset - padding - size * count;
2182 kls->prev_offset = kls->offset;
2183 kls->offset -= padding + size * count;
2184#ifdef KLS_DEBUG_CORE
2185 kls_log(kls, "KLS", "Popped (%td) for KLS. Curr offset: { %p }",
2186 size, kls->data + kls->offset);
2187#endif
2188 if (kls->conf.collect_stats == 1) {
2189 kls->stats.tot_pops += 1;
2190 }
2191 return p;
2192}
2193
2202void *kls_temp_pop(Koliseo_Temp *t_kls, ptrdiff_t size, ptrdiff_t align,
2203 ptrdiff_t count)
2204{
2205 if (t_kls == NULL) {
2206 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo_Temp was NULL.\n",
2207 __func__);
2208 exit(EXIT_FAILURE);
2209 }
2210 Koliseo *kls = t_kls->kls;
2211 if (kls == NULL) {
2212 fprintf(stderr, "[ERROR] [%s()]: Referred Koliseo was NULL.\n",
2213 __func__);
2214 exit(EXIT_FAILURE);
2215 }
2216 ptrdiff_t padding = -kls->offset & (align - 1);
2217 if (count > PTRDIFF_MAX / size
2218 || (kls->size + kls->offset) < (size * count)) {
2219 fprintf(stderr, "[KLS] Failed %s() call.\n", __func__);
2220 kls_free(kls);
2221 exit(EXIT_FAILURE);
2222 }
2223 char *p = kls->data + kls->offset - padding - size * count;
2224 kls->prev_offset = kls->offset;
2225 kls->offset -= padding + size * count;
2226#ifdef KLS_DEBUG_CORE
2227 kls_log(kls, "KLS", "Popped (%td) for Temp_KLS. Curr offset: { %p }.", size, kls->data + kls->offset);
2228#endif
2229 if (kls->conf.collect_stats == 1) {
2230 kls->stats.tot_temp_pops += 1;
2231 }
2232 return p;
2233}
2234
2241char* kls_strdup(Koliseo* kls, char* source)
2242{
2243 char* dest = KLS_PUSH_STR(kls, source);
2244 KLS__STRCPY(dest, source);
2245 return dest;
2246}
2247
2254char** kls_strdup_arr(Koliseo* kls, size_t count, char** source)
2255{
2256 char** strings = NULL;
2257 strings = KLS_PUSH_ARR(kls, char*, count);
2258 for (int i=0; i < count; i++) {
2259 strings[i] = KLS_STRDUP(kls, source[i]);
2260 }
2261 return strings;
2262}
2263
2270char* kls_t_strdup(Koliseo_Temp* t_kls, char* source)
2271{
2272 char* dest = KLS_PUSH_STR_T(t_kls, source);
2273 KLS__STRCPY(dest, source);
2274 return dest;
2275}
2276
2283char** kls_t_strdup_arr(Koliseo_Temp* t_kls, size_t count, char** source)
2284{
2285 char** strings = NULL;
2286 strings = KLS_PUSH_ARR_T(t_kls, char*, count);
2287 for (int i=0; i < count; i++) {
2288 strings[i] = KLS_STRDUP_T(t_kls, source[i]);
2289 }
2290 return strings;
2291}
2292#endif // KOLISEO_HAS_EXPER
#define KLS_DEFAULT_HOOKS
Definition kls_region.h:162
Koliseo * kls_new_traced(ptrdiff_t size, const char *output_path)
Takes a ptrdiff_t size and a filepath for the trace output file.
Definition koliseo.c:851
Koliseo * kls_new(ptrdiff_t size)
Takes a ptrdiff_t size.
Definition koliseo.c:659
char * kls_strdup(Koliseo *kls, char *source)
Function to dupe a C string to a Koliseo, and return a pointer to the allocated string.
Definition koliseo.c:2241
void * kls_temp_pop(Koliseo_Temp *t_kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
Takes a Koliseo_Temp, and ptrdiff_t values for size, align and count.
Definition koliseo.c:2202
Koliseo_Temp * kls_temp_start(Koliseo *kls)
Starts a new savestate for the passed Koliseo pointer, by initialising its Koliseo_Temp pointer and r...
Definition koliseo.c:2061
void print_dbg_temp_kls(const Koliseo_Temp *t_kls)
Prints header fields from the passed Koliseo_Temp pointer, to stderr.
Definition koliseo.c:1925
void * kls_temp_repush(Koliseo_Temp *t_kls, void *old, ptrdiff_t size, ptrdiff_t align, ptrdiff_t old_count, ptrdiff_t new_count)
Takes a Koliseo_Temp pointer, and a void pointer to the old allocation, ptrdiff_t values for size,...
Definition koliseo.c:1732
Koliseo * kls_new_dbg_alloc(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func)
Takes a ptrdiff_t size, an allocation function pointer and a free function pointer,...
Definition koliseo.c:952
void print_temp_kls_2file(FILE *fp, const Koliseo_Temp *t_kls)
Prints header fields from the passed Koliseo_Temp pointer, to the passed FILE pointer.
Definition koliseo.c:1886
char * kls_t_strdup(Koliseo_Temp *t_kls, char *source)
Function to dupe a C string to a Koliseo_Temp, and return a pointer to the allocated string.
Definition koliseo.c:2270
Koliseo * kls_new_traced_alloc_handled(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers)
Takes a ptrdiff_t size, a filepath for the trace output file, an allocation function pointer and a fr...
Definition koliseo.c:798
KLS_Stats KLS_STATS_DEFAULT
Default KLS_Stats values, used by kls_new().
Definition koliseo.c:46
void kls_log(Koliseo *kls, const char *tag, const char *format,...)
Logs a message to the log_fp FILE field of the passed Koliseo pointer, if its conf....
Definition koliseo.c:499
char * kls_vsprintf(Koliseo *kls, const char *fmt, va_list args)
Definition koliseo.c:1472
void kls_temp_end(Koliseo_Temp *tmp_kls)
Ends passed Koliseo_Temp pointer.
Definition koliseo.c:2112
void kls_dbg_features(void)
Prints enabled Koliseo features to stderr.
Definition koliseo.c:239
char ** kls_strdup_arr(Koliseo *kls, size_t count, char **source)
Function to dupe a C string array to a Koliseo, and return a pointer to the allocated array.
Definition koliseo.c:2254
void * kls_temp_push_zero_ext(Koliseo_Temp *t_kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
Takes a Koliseo_Temp, and ptrdiff_t values for size, align and count.
Definition koliseo.c:1525
void print_dbg_kls(const Koliseo *kls)
Prints header fields from the passed Koliseo pointer, to stderr.
Definition koliseo.c:1872
const char * string_koliseo_version(void)
Returns the constant string representing current version for Koliseo.
Definition koliseo.c:63
void * kls_repush(Koliseo *kls, void *old, ptrdiff_t size, ptrdiff_t align, ptrdiff_t old_count, ptrdiff_t new_count)
Takes a Koliseo pointer, and a void pointer to the old allocation, ptrdiff_t values for size,...
Definition koliseo.c:1612
KLS_Push_Result kls__advance(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t *padding, const char *caller_name)
Takes a Koliseo pointer, and ptrdiff_t values for size, align and count.
Definition koliseo.c:1106
char * kls_temp_vsprintf(Koliseo_Temp *kls_t, const char *fmt, va_list args)
Definition koliseo.c:1558
ptrdiff_t kls_get_pos(const Koliseo *kls)
Returns the current offset (position of pointer bumper) for the passed Koliseo.
Definition koliseo.c:292
Koliseo * kls_new_dbg_alloc_handled_ext(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size, an allocation function pointer and a free function pointer,...
Definition koliseo.c:886
#define KLS_ASAN_UNPOISON(addr, size)
Definition koliseo.c:83
void kls_free(Koliseo *kls)
Calls kls_clear() on the passed Koliseo pointer and the frees the actual Koliseo.
Definition koliseo.c:1991
KLS_Conf kls_conf_init_handled(int collect_stats, int verbose_lvl, int block_while_has_temp, int allow_zerocount_push, int growable, FILE *log_fp, const char *log_filepath, KLS_Err_Handlers err_handlers)
Used to prepare a KLS_Conf without caring about KOLISEO_HAS_REGIONS.
Definition koliseo.c:182
Koliseo * kls_new_dbg_ext(ptrdiff_t size, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size.
Definition koliseo.c:935
char * kls_temp_sprintf(Koliseo_Temp *kls_t, const char *fmt,...)
Takes a Koliseo_Temp pointer, and a format cstring, plus varargs.
Definition koliseo.c:1584
char ** kls_t_strdup_arr(Koliseo_Temp *t_kls, size_t count, char **source)
Function to dupe a C string array to a Koliseo_Temp, and return a pointer to the allocated array.
Definition koliseo.c:2283
void * kls_push(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
Takes a Koliseo pointer, and ptrdiff_t values for size, align and count.
Definition koliseo.c:1367
Koliseo * kls_new_dbg_alloc_handled(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers)
Takes a ptrdiff_t size, an allocation function pointer and a free function pointer,...
Definition koliseo.c:920
KLS_Push_Error kls__check_available(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, const char *caller_name)
Takes a Koliseo, a ptrdiff_t size, align and count, and a caller name.
Definition koliseo.c:1201
#define KLS_ASAN_POISON(addr, size)
Definition koliseo.c:82
void * kls_push_zero(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
Takes a Koliseo pointer, and ptrdiff_t values for size, align and count.
Definition koliseo.c:1390
Koliseo * kls_new_alloc(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func)
Takes a ptrdiff_t size and a function pointer to the allocation function.
Definition koliseo.c:635
Koliseo * kls_new_dbg(ptrdiff_t size)
Takes a ptrdiff_t size and returns a pointer to the prepared Koliseo.
Definition koliseo.c:967
Koliseo * kls_new_traced_alloc(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func)
Takes a ptrdiff_t size, a filepath for the trace output file, an allocation function pointer and a fr...
Definition koliseo.c:834
char * kls_sprintf(Koliseo *kls, const char *fmt,...)
Takes a Koliseo pointer, and a format cstring, plus varargs.
Definition koliseo.c:1497
Koliseo * kls_new_traced_handled(ptrdiff_t size, const char *output_path, KLS_Err_Handlers err_handlers)
Takes a ptrdiff_t size and a filepath for the trace output file.
Definition koliseo.c:868
void * kls_pop(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
Takes a Koliseo pointer, and ptrdiff_t values for size, align and count.
Definition koliseo.c:2168
Koliseo * kls_new_conf_alloc_ext(ptrdiff_t size, KLS_Conf conf, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size, a KLS_Conf to configure the new Koliseo, an allocation function pointer and a...
Definition koliseo.c:680
void KLS_PTRDIFF_MAX_default_handler__(struct Koliseo *kls, ptrdiff_t size, ptrdiff_t count)
Used by default when no handler is passed.
Definition koliseo.c:116
KLS_Conf KLS_DEFAULT_CONF
Config used by any new Koliseo by default.
Definition koliseo.c:25
KLS_Conf kls_conf_init(int collect_stats, int verbose_lvl, int block_while_has_temp, int allow_zerocount_push, int growable, FILE *log_fp, const char *log_filepath)
Used to prepare a KLS_Conf without caring about KOLISEO_HAS_REGIONS.
Definition koliseo.c:230
void KLS_ZEROCOUNT_default_handler__(Koliseo *kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size)
Used internally for handling zero-count in push calls when no user handler is provided.
Definition koliseo.c:158
void * kls__handle_push_result(Koliseo *kls, KLS_Push_Result r, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t padding, const char *caller_name)
Handles a KLS_Push_Result.
Definition koliseo.c:310
Koliseo * kls_new_alloc_ext(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size and a function pointer to the allocation function.
Definition koliseo.c:545
void print_kls_2file(FILE *fp, const Koliseo *kls)
Prints header fields from the passed Koliseo pointer, to the passed FILE pointer.
Definition koliseo.c:1841
Koliseo * kls_new_traced_alloc_handled_ext(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size, a filepath for the trace output file, an allocation function pointer and a fr...
Definition koliseo.c:762
Koliseo * kls_new_dbg_handled(ptrdiff_t size, KLS_Err_Handlers err_handlers)
Takes a ptrdiff_t size and returns a pointer to the prepared Koliseo.
Definition koliseo.c:982
void kls_clear(Koliseo *kls)
Resets the offset field for the passed Koliseo pointer.
Definition koliseo.c:1959
void * kls_push_zero_ext(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
Takes a Koliseo pointer, and ptrdiff_t values for size, align and count.
Definition koliseo.c:1423
void kls_formatSize(ptrdiff_t size, char *outputBuffer, size_t bufferSize)
Converts a ptrdiff_t size to human-readable SI units (modulo 1000).
Definition koliseo.c:1937
void KLS_OOM_default_handler__(Koliseo *kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, ptrdiff_t count)
Used internally for handling Out-Of-Memory in push calls when no user handler is provided.
Definition koliseo.c:96
Koliseo * kls_new_conf_alloc(ptrdiff_t size, KLS_Conf conf, kls_alloc_func alloc_func, kls_free_func free_func)
Takes a ptrdiff_t size, a KLS_Conf to configure the new Koliseo, an allocation function pointer and a...
Definition koliseo.c:709
KLS_Push_Result kls__temp_advance(Koliseo_Temp *kls_t, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t *padding, const char *caller_name)
Takes a Koliseo_Temp, and ptrdiff_t values for size, align and count.
Definition koliseo.c:1261
int int_koliseo_version(void)
Returns the constant int representing current version for Koliseo.
Definition koliseo.c:72
Koliseo * kls_new_traced_ext(ptrdiff_t size, const char *output_path, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size and a filepath for the trace output file.
Definition koliseo.c:815
Koliseo * kls_new_conf(ptrdiff_t size, KLS_Conf conf)
Takes a ptrdiff_t size and a KLS_Conf to configure the new Koliseo.
Definition koliseo.c:742
Koliseo * kls_new_conf_ext(ptrdiff_t size, KLS_Conf conf, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size and a KLS_Conf to configure the new Koliseo.
Definition koliseo.c:726
void kls_free_func(void *)
Used to select a free function for the arena's backing memory.
Definition koliseo.h:92
#define KLS_PUSH_STR_T(kls_temp, cstr)
Macro to request memory for a C string from a Koliseo_Temp.
Definition koliseo.h:643
#define KLS_Stats_Fmt
Defines a format string for KLS_Stats.
Definition koliseo.h:293
#define KLS_PUSH_STR(kls, cstr)
Macro to request memory for a C string from a Koliseo.
Definition koliseo.h:526
#define KLS_Conf_Arg(conf)
Defines a format macro for KLS_Conf args.
Definition koliseo.h:286
#define KLS_DEFAULT_FREEF
Defines the default free function.
Definition koliseo.h:410
#define KLS_DEFAULT_ALLOCF
Defines the default allocation function.
Definition koliseo.h:406
#define KLS_PUSH(kls, type)
Macro used to request memory from a Koliseo.
Definition koliseo.h:563
#define KLS__STRCPY(dest, source)
Macro to copy a C string from a source buffer to a destination buffer.
Definition koliseo.h:747
#define KLS_ALIGNOF
Definition koliseo.h:24
#define KLS_DEFAULT_EXTENSION_DATA
Defines default hooks that are loaded on kls_new() variants lacking explicit set of KLS_Hooks.
Definition koliseo.h:220
void * kls_alloc_func(size_t)
Used to select an allocation function for the arena's backing memory.
Definition koliseo.h:91
#define KLS_MAX(a, b)
Definition koliseo.h:98
#define KLS_STRDUP(kls, source)
Definition koliseo.h:756
KLS_Push_Error
Defines the result for kls__check_available().
Definition koliseo.h:366
@ KLS_PUSH_NEGATIVE_COUNT
Definition koliseo.h:371
@ KLS_PUSH_ZEROCOUNT
Definition koliseo.h:372
@ KLS_PUSH_ALIGN_NOT_POW2
Definition koliseo.h:370
@ KLS_PUSH_WITH_TEMP_ACTIVE
Definition koliseo.h:373
@ KLS_PUSH_OOM
Definition koliseo.h:375
@ KLS_PUSH_PTRDIFF_MAX
Definition koliseo.h:374
@ KLS_PUSH_SIZE_LT1
Definition koliseo.h:368
@ KLS_PUSH_ALIGN_LT1
Definition koliseo.h:369
@ KLS_PUSH_OK
Definition koliseo.h:367
#define KLS_Stats_Arg(stats)
Defines a format macro for KLS_Stats args.
Definition koliseo.h:303
#define KLS_Conf_Fmt
Defines a format string for KLS_Conf.
Definition koliseo.h:280
#define KLS_PUSH_ARR_T(kls_temp, type, count)
Macro used to request memory for an array of type values from a Koliseo_Temp.
Definition koliseo.h:631
#define KLS_STRDUP_T(t_kls, source)
Definition koliseo.h:766
#define KLS_DEFAULT_ERR_HANDLERS
Definition koliseo.h:178
#define KLS_PUSH_ARR(kls, type, count)
Macro used to request memory for an array of type values from a Koliseo.
Definition koliseo.h:514
Defines flags for Koliseo.
Definition koliseo.h:227
int growable
If set to 1, make the Koliseo grow when a out of memory for a push call.
Definition koliseo.h:234
int verbose_lvl
If > 0, makes the Koliseo try to acquire kls_log_fp from kls_log_filepath.
Definition koliseo.h:229
const char * log_filepath
String representing the path to the Koliseo logfile.
Definition koliseo.h:231
FILE * log_fp
FILE pointer used by the Koliseo to print its kls_log() output.
Definition koliseo.h:230
int allow_zerocount_push
If set to 1, make the Koliseo accept push calls with a count of 0.
Definition koliseo.h:233
int collect_stats
If set to 1, make the Koliseo collect performance stats.
Definition koliseo.h:228
KLS_Err_Handlers err_handlers
Used to pass custom error handlers for push calls.
Definition koliseo.h:235
int block_while_has_temp
If set to 1, make the Koliseo reject push calls while it has an open Koliseo_Temp.
Definition koliseo.h:232
Defines the handlers used for errors in push calls.
Definition koliseo.h:171
KLS_OOM_Handler * OOM_handler
Pointer to handler for Out-Of-Memory errors in push calls.
Definition koliseo.h:172
KLS_ZEROCOUNT_Handler * ZEROCOUNT_handler
Pointer to handler for zero-count errors in push calls.
Definition koliseo.h:174
KLS_PTRDIFF_MAX_Handler * PTRDIFF_MAX_handler
Pointer to handler for count > (PTRDIFF_MAX / size) errors in push calls.
Definition koliseo.h:173
Definition koliseo.h:195
KLS_hook_on_temp_start * on_temp_start_handler
Used to pass custom start handler for kls_temp_start calls.
Definition koliseo.h:199
KLS_hook_on_free * on_free_handler
Used to pass custom free handler for kls_free calls.
Definition koliseo.h:197
KLS_hook_on_temp_free * on_temp_free_handler
Used to pass custom free handler for kls_temp_end calls.
Definition koliseo.h:200
KLS_hook_on_push * on_push_handler
Used to pass custom push handler for kls_push calls.
Definition koliseo.h:198
KLS_hook_on_new * on_new_handler
Used to pass custom new handler for kls_new_alloc calls.
Definition koliseo.h:196
KLS_hook_on_temp_push * on_temp_push_handler
Used to pass custom push handler for kls_temp_push calls.
Definition koliseo.h:201
Defines the result for kls__advance() and kls__temp_advance().
Definition koliseo.h:383
KLS_Push_Error error
Definition koliseo.h:385
void * p
Definition koliseo.h:384
Defines a stat struct for Koliseo.
Definition koliseo.h:248
int tot_pops
Total POP calls done.
Definition koliseo.h:251
double worst_pushcall_time
DEPRECATED: support for timing will be dropped in the next release.
Definition koliseo.h:258
int tot_temp_pushes
Total PUSH_T calls done.
Definition koliseo.h:250
int tot_pushes
Total PUSH calls done.
Definition koliseo.h:249
int tot_temp_pops
Total POP_T calls done.
Definition koliseo.h:252
Represents a savestate for a Koliseo.
Definition koliseo.h:355
ptrdiff_t offset
Current position of memory pointer.
Definition koliseo.h:357
ptrdiff_t prev_offset
Previous position of memory pointer.
Definition koliseo.h:358
Koliseo * kls
Reference to the actual Koliseo we're saving.
Definition koliseo.h:356
Represents the initialised arena allocator struct.
Definition koliseo.h:316
ptrdiff_t size
Size of data field.
Definition koliseo.h:318
ptrdiff_t offset
Current position of memory pointer.
Definition koliseo.h:319
ptrdiff_t prev_offset
Previous position of memory pointer.
Definition koliseo.h:320
KLS_Conf conf
Contains flags to change the Koliseo behaviour.
Definition koliseo.h:322
struct Koliseo_Temp * t_kls
Points to related active Kolieo_Temp, when has_temp == 1.
Definition koliseo.h:324
KLS_Hooks hooks
Contains handlers for extensions.
Definition koliseo.h:325
char * data
Points to data field.
Definition koliseo.h:317
struct Koliseo * next
Points to the next Koliseo when conf.growable == 1.
Definition koliseo.h:329
void * extension_data
Points to data for extensions.
Definition koliseo.h:326
int has_temp
When == 1, a Koliseo_Temp is currently active on this Koliseo.
Definition koliseo.h:321
KLS_Stats stats
Contains stats for Koliseo performance analysis.
Definition koliseo.h:323
kls_free_func * free_func
Points to the free function for the arena's backing memory.
Definition koliseo.h:328