koliseo 0.6.0
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#include "koliseo.h"
19
21 .collect_stats = 0,
22 .verbose_lvl = 0,
23 .block_while_has_temp = 1,
24 .allow_zerocount_push = 0,
25 .log_fp = NULL,
26 .growable = 0,
27 .log_filepath = "",
28 .err_handlers = {
29#ifndef KOLISEO_HAS_LOCATE
30 .OOM_handler = &KLS_OOM_default_handler__,
31 .PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler__,
32 .ZEROCOUNT_handler = &KLS_ZEROCOUNT_default_handler__,
33#else
34 .OOM_handler = &KLS_OOM_default_handler_dbg__,
35 .PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler_dbg__,
36 .ZEROCOUNT_handler = &KLS_ZEROCOUNT_default_handler_dbg__,
37#endif // KOLISEO_HAS_LOCATE
38 },
39};
40
42 .tot_pushes = 0,
43 .tot_temp_pushes = 0,
44 .tot_pops = 0,
45 .tot_temp_pops = 0,
46 .tot_logcalls = 0,
47#ifdef KLS_DEBUG_CORE
48 .worst_pushcall_time = -1,
49#endif
50};
51
52static bool kls_set_conf(Koliseo * kls, KLS_Conf conf); //Declare function used internally by kls_new() and kls_new_conf()
53
58const char *string_koliseo_version(void)
59{
60 return KOLISEO_API_VERSION_STRING;
61}
62
68{
69 return KOLISEO_API_VERSION_INT;
70}
71
72#if defined(__SANITIZE_ADDRESS__)
73#include <sanitizer/asan_interface.h>
74#define KLS_ASAN_POISON(addr, size) __asan_poison_memory_region((addr), (size))
75#define KLS_ASAN_UNPOISON(addr, size) __asan_unpoison_memory_region((addr), (size))
76#else
77#define KLS_ASAN_POISON(addr, size) ((void)0)
78#define KLS_ASAN_UNPOISON(addr, size) ((void)0)
79#endif // __SANITIZE_ADDRESS__
80
90#ifndef KOLISEO_HAS_LOCATE
91void KLS_OOM_default_handler__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, ptrdiff_t count)
92#else
93void KLS_OOM_default_handler_dbg__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, ptrdiff_t count, Koliseo_Loc loc)
94#endif // KOLISEO_HAS_LOCATE
95{
96#ifndef KOLISEO_HAS_LOCATE
97 fprintf(stderr,
98 "[KLS] Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
99 size * count, available - padding);
100#else
101 fprintf(stderr,
102 "[KLS] " KLS_Loc_Fmt "Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
103 KLS_Loc_Arg(loc),
104 size * count, available - padding);
105#endif // KOLISEO_HAS_LOCATE
106 kls_free(kls); // Is it even worth it to try?
107 exit(EXIT_FAILURE); // Better than nothing. May change to return NULL instead? Requiring refactor of handler signature
108}
109
110#ifndef KOLISEO_HAS_LOCATE
111void KLS_PTRDIFF_MAX_default_handler__(struct Koliseo* kls, ptrdiff_t size, ptrdiff_t count)
112#else
113void KLS_PTRDIFF_MAX_default_handler_dbg__(struct Koliseo* kls, ptrdiff_t size, ptrdiff_t count, Koliseo_Loc loc)
114#endif
115{
116#ifndef _WIN32
117#ifndef KOLISEO_HAS_LOCATE
118 fprintf(stderr,
119 "[KLS] count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
120 count, PTRDIFF_MAX / size);
121#else
122 fprintf(stderr,
123 "[KLS] " KLS_Loc_Fmt "count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
124 KLS_Loc_Arg(loc),
125 count, PTRDIFF_MAX / size);
126#endif // KOLISEO_HAS_LOCATE
127#else
128#ifndef KOLISEO_HAS_LOCATE
129 fprintf(stderr,
130 "[KLS] count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
131 count, PTRDIFF_MAX / size);
132#else
133 fprintf(stderr,
134 "[KLS] " KLS_Loc_Fmt "count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
135 KLS_Loc_Arg(loc),
136 count, PTRDIFF_MAX / size);
137#endif // KOLISEO_HAS_LOCATE
138#endif // _WIN32
139 kls_free(kls);
140 exit(EXIT_FAILURE);
141}
142
152#ifndef KOLISEO_HAS_LOCATE
153void KLS_ZEROCOUNT_default_handler__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size)
154#else
155void KLS_ZEROCOUNT_default_handler_dbg__(Koliseo* kls, ptrdiff_t available, ptrdiff_t padding, ptrdiff_t size, Koliseo_Loc loc)
156#endif // KOLISEO_HAS_LOCATE
157{
158#ifndef KOLISEO_HAS_LOCATE
159 fprintf(stderr,
160 "[KLS] Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
161 size, padding, available);
162#else
163 fprintf(stderr,
164 "[KLS] " KLS_Loc_Fmt "Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
165 KLS_Loc_Arg(loc),
166 size, padding, available);
167#endif // KOLISEO_HAS_LOCATE
168 kls_free(kls);
169 exit(EXIT_FAILURE);
170}
171
177KLS_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)
178{
179 KLS_Conf res = {0};
180 res.collect_stats = collect_stats;
181 res.verbose_lvl = verbose_lvl;
182 res.block_while_has_temp = block_while_has_temp;
183 res.allow_zerocount_push = allow_zerocount_push;
184 res.growable = growable;
185 res.log_fp = log_fp;
186 res.log_filepath = log_filepath;
187
188 if (err_handlers.OOM_handler != NULL) {
189 res.err_handlers.OOM_handler = err_handlers.OOM_handler;
190 } else {
191#ifndef KOLISEO_HAS_LOCATE
193#else
194 res.err_handlers.OOM_handler = &KLS_OOM_default_handler_dbg__;
195#endif // KOLISEO_HAS_LOCATE
196 }
197
198 if (err_handlers.PTRDIFF_MAX_handler != NULL) {
200 } else {
201#ifndef KOLISEO_HAS_LOCATE
203#else
204 res.err_handlers.PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler_dbg__;
205#endif // KOLISEO_HAS_LOCATE
206 }
207
208 if (err_handlers.ZEROCOUNT_handler != NULL) {
210 } else {
211#ifndef KOLISEO_HAS_LOCATE
213#else
214 res.err_handlers.ZEROCOUNT_handler = &KLS_ZEROCOUNT_default_handler_dbg__;
215#endif // KOLISEO_HAS_LOCATE
216 }
217
218 return res;
219}
220
225KLS_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)
226{
228 return kls_conf_init_handled(collect_stats, verbose_lvl, block_while_has_temp, allow_zerocount_push, growable, log_fp, log_filepath, err_handlers);
229}
230
235{
236#ifdef KOLISEO_HAS_LOCATE
237 bool kls_locate = true;
238#else
239 bool kls_locate = false;
240#endif
241#ifdef KLS_DEBUG_CORE
242 bool kls_debug = true;
243#else
244 bool kls_debug = false;
245#endif
246#ifdef KOLISEO_HAS_EXPER
247 bool kls_exper = true;
248#else
249 bool kls_exper = false;
250#endif
251 bool features[3] = {
252 [0] = kls_debug,
253 [1] = kls_locate,
254 [2] = kls_exper,
255 };
256 int total_enabled = 0;
257 for (int i=0; i<3; i++) {
258 if (features[i]) {
259 total_enabled += 1;
260 }
261 }
262 fprintf(stderr, "[KLS] Enabled features: {");
263 if (total_enabled == 0) {
264 fprintf(stderr, "none}\n");
265 return;
266 } else {
267 if (kls_debug) {
268 fprintf(stderr, "debug%s", (total_enabled > 1 ? ", " : ""));
269 total_enabled -= 1;
270 }
271 if (kls_locate) {
272 fprintf(stderr, "locate%s", (total_enabled > 1 ? ", " : ""));
273 total_enabled -= 1;
274 }
275 if (kls_exper) {
276 fprintf(stderr, "exper");
277 }
278 fprintf(stderr, "}\n");
279 }
280}
281
287ptrdiff_t kls_get_pos(const Koliseo *kls)
288{
289 return kls->offset;
290}
291
304#ifndef KOLISEO_HAS_LOCATE
305void* 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)
306#else
307void* 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)
308#endif
309{
310 if (!kls) return NULL;
311 Koliseo* current = kls;
312 while (current->next != NULL) {
313 current = current->next;
314 }
315 if (r.error) {
316 const ptrdiff_t available = current->size - current->offset;
317 switch (r.error) {
318 case KLS_PUSH_OK: {
319 return r.p;
320 }
321 break;
322 case KLS_PUSH_SIZE_LT1: {
323#ifndef KOLISEO_HAS_LOCATE
324 fprintf(stderr,
325 "[KLS] %s(): size [%td] was < 1.\n",
326 caller_name,
327 size);
328#else
329 fprintf(stderr,
330 "[KLS] " KLS_Loc_Fmt "%s(): size [%td] was < 1.\n",
331 KLS_Loc_Arg(loc),
332 caller_name,
333 size);
334#endif // KOLISEO_HAS_LOCATE
335 }
336 break;
337 case KLS_PUSH_ALIGN_LT1: {
338#ifndef KOLISEO_HAS_LOCATE
339 fprintf(stderr,
340 "[KLS] %s(): align [%td] was < 1.\n",
341 caller_name,
342 align);
343#else
344 fprintf(stderr,
345 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was < 1.\n",
346 KLS_Loc_Arg(loc),
347 caller_name,
348 align);
349#endif // KOLISEO_HAS_LOCATE
350 }
351 break;
353#ifndef KOLISEO_HAS_LOCATE
354 fprintf(stderr,
355 "[KLS] %s(): align [%td] was not a power of 2.\n",
356 caller_name,
357 align);
358#else
359 fprintf(stderr,
360 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was not a power of 2.\n",
361 KLS_Loc_Arg(loc),
362 caller_name,
363 align);
364#endif // KOLISEO_HAS_LOCATE
365 }
366 break;
368#ifndef KOLISEO_HAS_LOCATE
369 fprintf(stderr,
370 "[KLS] %s(): count [%td] was < 0.\n",
371 caller_name,
372 count);
373#else
374 fprintf(stderr,
375 "[KLS] " KLS_Loc_Fmt "%s(): count [%td] was < 0.\n",
376 KLS_Loc_Arg(loc),
377 caller_name,
378 count);
379#endif // KOLISEO_HAS_LOCATE
380 }
381 break;
382 case KLS_PUSH_ZEROCOUNT: {
383 if (current->conf.err_handlers.ZEROCOUNT_handler != NULL) {
384#ifndef KOLISEO_HAS_LOCATE
385 current->conf.err_handlers.ZEROCOUNT_handler(current, available, padding, size);
386#else
387 current->conf.err_handlers.ZEROCOUNT_handler(current, available, padding, size, loc);
388#endif // KOLISEO_HAS_LOCATE
389 } else {
390#ifndef KOLISEO_HAS_LOCATE
391 fprintf(stderr,
392 "[KLS] %s(): Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
393 caller_name,
394 size, padding, available);
395#else
396 fprintf(stderr,
397 "[KLS] " KLS_Loc_Fmt "%s(): Doing a zero-count push. size [%td] padding [%td] available [%td].\n",
398 KLS_Loc_Arg(loc),
399 caller_name,
400 size, padding, available);
401#endif // KOLISEO_HAS_LOCATE
402 kls_free(kls);
403 exit(EXIT_FAILURE);
404 }
405 }
406 break;
408#ifndef KOLISEO_HAS_LOCATE
409 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo has an open Koliseo_Temp session.\n", caller_name);
410#else
411 fprintf(stderr, "[ERROR] " KLS_Loc_Fmt "[%s()]: Passed Koliseo has an open Koliseo_Temp session.\n", KLS_Loc_Arg(loc), caller_name);
412 kls_log(kls, "ERROR", KLS_Loc_Fmt "[%s()]: Passed Koliseo has an open Koliseo_Temp session.", KLS_Loc_Arg(loc), caller_name);
413 exit(EXIT_FAILURE);
414#endif // KOLISEO_HAS_LOCATE
415 }
416 break;
418 if (current->conf.err_handlers.PTRDIFF_MAX_handler != NULL) {
419#ifndef KOLISEO_HAS_LOCATE
420 current->conf.err_handlers.PTRDIFF_MAX_handler(current, size, count);
421#else
422 current->conf.err_handlers.PTRDIFF_MAX_handler(current, size, count, loc);
423#endif // KOLISEO_HAS_LOCATE
424 } else { // Let's keep this here for now? It's the original part before adding KLS_PTRDIFF_MAX_default_handler__()
425#ifndef _WIN32
426#ifndef KOLISEO_HAS_LOCATE
427 fprintf(stderr,
428 "[KLS] %s(): count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
429 caller_name,
430 count, PTRDIFF_MAX / size);
431#else
432 fprintf(stderr,
433 "[KLS] " KLS_Loc_Fmt "%s(): count [%td] was bigger than PTRDIFF_MAX/size [%li].\n",
434 KLS_Loc_Arg(loc),
435 caller_name,
436 count, PTRDIFF_MAX / size);
437#endif // KOLISEO_HAS_LOCATE
438#else
439#ifndef KOLISEO_HAS_LOCATE
440 fprintf(stderr,
441 "[KLS] %s(): count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
442 caller_name,
443 count, PTRDIFF_MAX / size);
444#else
445 fprintf(stderr,
446 "[KLS] " KLS_Loc_Fmt "%s(): count [%td] was bigger than PTRDIFF_MAX/size [%lli].\n",
447 KLS_Loc_Arg(loc),
448 caller_name,
449 count, PTRDIFF_MAX / size);
450#endif // KOLISEO_HAS_LOCATE
451#endif // _WIN32
452 }
453 }
454 break;
455 case KLS_PUSH_OOM: {
456 if (current->conf.err_handlers.OOM_handler != NULL) {
457#ifndef KOLISEO_HAS_LOCATE
458 current->conf.err_handlers.OOM_handler(current, available, padding, size, count);
459#else
460 current->conf.err_handlers.OOM_handler(current, available, padding, size, count, loc);
461#endif // KOLISEO_HAS_LOCATE
462 } else { // Let's keep this here for now? It's the original part before adding KLS_OOM_default_handler__()
463#ifndef KOLISEO_HAS_LOCATE
464 fprintf(stderr,
465 "[KLS] %s(): Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
466 caller_name,
467 size * count, available - padding);
468#else
469 fprintf(stderr,
470 "[KLS] " KLS_Loc_Fmt "%s(): Out of memory. size*count [%td] was bigger than available-padding [%td].\n",
471 KLS_Loc_Arg(loc),
472 caller_name,
473 size * count, available - padding);
474#endif // KOLISEO_HAS_LOCATE
475 }
476 }
477 break;
478 default: {
479 fprintf(stderr, "[KLS] %s(): unexpected error code [%i]\n", __func__, r.error);
480 return NULL;
481 }
482 break;
483 }
484 }
485 return r.p;
486}
487
494void kls_log(Koliseo *kls, const char *tag, const char *format, ...)
495{
496 if (kls == NULL) {
497 fprintf(stderr, "[KLS] %s(): Passed kls was NULL.\n", __func__);
498 return;
499 }
500 if (kls->conf.verbose_lvl > 0) {
501 va_list args;
502 FILE *fp = kls->conf.log_fp;
503 va_start(args, format);
504 if (fp == NULL) {
505 fprintf(stderr,
506 "[KLS] %s(): Failed opening file to print logs.\n",
507 __func__);
508 } else {
509 time_t now = time(0);
510 const struct tm *mytime = localtime(&now);
511 char timeheader[500];
512 if (strftime(timeheader, sizeof timeheader, "%X", mytime)) {
513 fprintf(fp, "[%-10.10s] [%s] [", tag, timeheader);
514 vfprintf(fp, format, args);
515 fprintf(fp, "]\n");
516 }
517 }
518 va_end(args);
519 }
520}
521
539#ifndef KOLISEO_HAS_LOCATE
540Koliseo *kls_new_alloc_ext(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Hooks ext_handlers, void* user)
541#else
542Koliseo *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)
543#endif // KOLISEO_HAS_LOCATE
544{
545 if (size < (ptrdiff_t)sizeof(Koliseo)) {
546#ifndef KOLISEO_HAS_LOCATE
547 fprintf(stderr,
548 "[ERROR] at %s(): invalid requested kls size (%td). Min accepted is: (%td).\n",
549 __func__, size, (ptrdiff_t)sizeof(Koliseo));
550#else
551 fprintf(stderr,
552 "[ERROR] " KLS_Loc_Fmt "%s(): invalid requested kls size (%td). Min accepted is: (%td).\n",
553 KLS_Loc_Arg(loc), __func__, size, (ptrdiff_t)sizeof(Koliseo));
554#endif // KOLISEO_HAS_LOCATE
555 //TODO Is it better to abort the program?
556 return NULL;
557 }
558 void *p = alloc_func(size);
559 if (p) {
560 //sprintf(msg,"Allocated (%li) for new KLS.",size);
561 //kls_log("KLS",msg);
562 char h_size[200];
563 kls_formatSize(size, h_size, sizeof(h_size));
564 Koliseo *kls = p;
565 kls->data = p;
566 kls->size = size;
567 kls->offset = sizeof(*kls);
568 kls->prev_offset = kls->offset;
569 kls->has_temp = 0;
570 kls->t_kls = NULL;
571 kls_set_conf(kls, KLS_DEFAULT_CONF);
573 kls->conf.log_fp = stderr;
574
575 KLS_ASAN_POISON(kls->data + kls->offset, kls->size - kls->offset);
576
577 kls->hooks = ext_handlers;
578 if (user) {
579 kls->extension_data = user;
580 } else {
581 kls->extension_data = NULL;
582 }
583 kls->free_func = free_func;
584 kls->next = NULL;
585#ifdef KLS_DEBUG_CORE
586 kls_log(kls, "KLS", "API Level { %i } -> Allocated (%s) for new KLS.",
587 int_koliseo_version(), h_size);
588 kls_log(kls, "KLS", "KLS offset: { %p }.", kls);
589 kls_log(kls, "KLS", "Allocation begin offset: { %p }.",
590 kls + kls->offset);
591#endif
592
593 if (kls->hooks.on_new_handler != NULL) {
594 // Call on_new extension
595 kls->hooks.on_new_handler(kls);
596 }
597 } else {
598#ifndef KOLISEO_HAS_LOCATE
599 fprintf(stderr, "[KLS] Failed %s() call.\n", __func__);
600#else
601 fprintf(stderr, "[KLS] " KLS_Loc_Fmt "Failed %s() call.\n", KLS_Loc_Arg(loc), __func__);
602#endif // KOLISEO_HAS_LOCATE
603 exit(EXIT_FAILURE);
604 }
605#ifdef KLS_DEBUG_CORE
606 Koliseo *kls_ref = p;
607 if (kls_ref->conf.verbose_lvl > 0) {
608 print_kls_2file(kls_ref->conf.log_fp, p);
609 }
610#endif
611 return p;
612}
613
629#ifndef KOLISEO_HAS_LOCATE
630Koliseo *kls_new_alloc(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func)
631#else
632Koliseo *kls_new_alloc_dbg(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, Koliseo_Loc loc)
633#endif // KOLISEO_HAS_LOCATE
634{
635#ifndef KOLISEO_HAS_LOCATE
636 return kls_new_alloc_ext(size, alloc_func, free_func, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
637#else
638 return kls_new_alloc_ext_dbg(size, alloc_func, free_func, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA, loc);
639#endif // KOLISEO_HAS_LOCATE
640}
641
654Koliseo *kls_new(ptrdiff_t size)
655{
657}
658
675Koliseo *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)
676{
677 Koliseo *k = kls_new_alloc_ext(size, alloc_func, free_func, ext_handlers, user);
678 bool conf_res = kls_set_conf(k, conf);
679 if (!conf_res) {
680 fprintf(stderr,
681 "[ERROR] [%s()]: Failed to set config for new Koliseo.\n",
682 __func__);
683 exit(EXIT_FAILURE);
684 }
685 return k;
686}
687
704Koliseo *kls_new_conf_alloc(ptrdiff_t size, KLS_Conf conf, kls_alloc_func alloc_func, kls_free_func free_func)
705{
706 return kls_new_conf_alloc_ext(size, conf, alloc_func, free_func, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
707}
708
721Koliseo *kls_new_conf_ext(ptrdiff_t size, KLS_Conf conf, KLS_Hooks ext_handlers, void* user)
722{
723 return kls_new_conf_alloc_ext(size, conf, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, ext_handlers, user);
724}
725
737Koliseo *kls_new_conf(ptrdiff_t size, KLS_Conf conf)
738{
740}
741
757Koliseo *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)
758{
759
760#ifndef KLS_DEBUG_CORE
761 fprintf(stderr,
762 "[WARN] %s(): KLS_DEBUG_CORE is not defined. No tracing allowed.\n",
763 __func__);
764#endif
765 KLS_Conf k = (KLS_Conf) {
766 .collect_stats = 1,.verbose_lvl =
767 1,.log_filepath = output_path,
768#ifndef KOLISEO_HAS_LOCATE
769 .err_handlers.OOM_handler = (err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler__),
770 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler__),
771#else
772 .err_handlers.OOM_handler = (err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler_dbg__),
773 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler_dbg__),
774#endif // KOLISEO_HAS_LOCATE
775 };
776 return kls_new_conf_alloc_ext(size, k, alloc_func, free_func, ext_handlers, user);
777}
778
793Koliseo *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)
794{
795 return kls_new_traced_alloc_handled_ext(size, output_path, alloc_func, free_func, err_handlers, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
796}
797
810Koliseo *kls_new_traced_ext(ptrdiff_t size, const char *output_path, KLS_Hooks ext_handlers, void* user)
811{
813 return kls_new_traced_alloc_handled_ext(size, output_path, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, err_handlers, ext_handlers, user);
814}
815
829Koliseo *kls_new_traced_alloc(ptrdiff_t size, const char *output_path, kls_alloc_func alloc_func, kls_free_func free_func)
830{
832 return kls_new_traced_alloc_handled(size, output_path, alloc_func, free_func, err_handlers);
833}
834
846Koliseo *kls_new_traced(ptrdiff_t size, const char *output_path)
847{
849}
850
863Koliseo *kls_new_traced_handled(ptrdiff_t size, const char *output_path, KLS_Err_Handlers err_handlers)
864{
865 return kls_new_traced_alloc_handled(size, output_path, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, err_handlers);
866}
867
881Koliseo *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)
882{
883#ifndef KLS_DEBUG_CORE
884 fprintf(stderr,
885 "[WARN] %s(): KLS_DEBUG_CORE is not defined. No debugging support.\n",
886 __func__);
887#endif
888 KLS_Conf k = (KLS_Conf) {
889 .collect_stats = 1,.verbose_lvl = 0,
890#ifndef KOLISEO_HAS_LOCATE
891 .err_handlers.OOM_handler = ( err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler__),
892 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler__),
893#else
894 .err_handlers.OOM_handler = ( err_handlers.OOM_handler != NULL ? err_handlers.OOM_handler : &KLS_OOM_default_handler_dbg__),
895 .err_handlers.PTRDIFF_MAX_handler = ( err_handlers.PTRDIFF_MAX_handler != NULL ? err_handlers.PTRDIFF_MAX_handler : &KLS_PTRDIFF_MAX_default_handler_dbg__),
896#endif // KOLIEO_HAS_LOCATE
897 };
898 Koliseo * kls = kls_new_conf_alloc_ext(size, k, alloc_func, free_func, ext_handlers, user);
899 kls->conf.verbose_lvl = 1;
900 return kls;
901}
902
915Koliseo *kls_new_dbg_alloc_handled(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func, KLS_Err_Handlers err_handlers)
916{
917 return kls_new_dbg_alloc_handled_ext(size, alloc_func, free_func, err_handlers, KLS_DEFAULT_HOOKS, KLS_DEFAULT_EXTENSION_DATA);
918}
919
930Koliseo *kls_new_dbg_ext(ptrdiff_t size, KLS_Hooks ext_handlers, void* user)
931{
933 return kls_new_dbg_alloc_handled_ext(size, KLS_DEFAULT_ALLOCF, KLS_DEFAULT_FREEF, err_handlers, ext_handlers, user);
934}
935
947Koliseo *kls_new_dbg_alloc(ptrdiff_t size, kls_alloc_func alloc_func, kls_free_func free_func)
948{
950 return kls_new_dbg_alloc_handled(size, alloc_func, free_func, err_handlers);
951}
952
962Koliseo *kls_new_dbg(ptrdiff_t size)
963{
965}
966
977Koliseo *kls_new_dbg_handled(ptrdiff_t size, KLS_Err_Handlers err_handlers)
978{
980}
981
988bool kls_set_conf(Koliseo *kls, KLS_Conf conf)
989{
990 if (kls == NULL) {
991 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
992 //TODO: is it better to exit() here?
993 return false;
994 }
995
996 kls->conf = conf;
997 if (kls->conf.log_fp == NULL) {
998 kls->conf.log_fp = stderr;
999#ifdef KLS_DEBUG_CORE
1000#ifdef KLS_SETCONF_DEBUG
1001 kls_log(kls, "KLS",
1002 "[%s()]: Preliminary set of conf.log_fp to stderr.",
1003 __func__);
1004#endif
1005#endif // KLS_DEBUG_CORE
1006 }
1007
1008 if (conf.err_handlers.OOM_handler == NULL) {
1009 fprintf(stderr,
1010 "[ERROR] at %s(): passed OOM_handler is NULL. Using default.\n",
1011 __func__);
1012#ifdef KLS_DEBUG_CORE
1013#ifdef KLS_SETCONF_DEBUG
1014 kls_log(kls, "KLS",
1015 "[%s()]: Passed OOM_handler was NULL, using default.",
1016 __func__);
1017#endif
1018#endif // KLS_DEBUG_CORE
1019#ifndef KOLISEO_HAS_LOCATE
1021#else
1022 kls->conf.err_handlers.OOM_handler = &KLS_OOM_default_handler_dbg__;
1023#endif
1024 }
1025
1026 if (conf.err_handlers.PTRDIFF_MAX_handler == NULL) {
1027 fprintf(stderr,
1028 "[ERROR] at %s(): passed PTRDIFF_MAX_handler is NULL. Using default.\n",
1029 __func__);
1030#ifdef KLS_DEBUG_CORE
1031#ifdef KLS_SETCONF_DEBUG
1032 kls_log(kls, "KLS",
1033 "[%s()]: Passed PTRDIFF_MAX_handler was NULL, using default.",
1034 __func__);
1035#endif
1036#endif // KLS_DEBUG_CORE
1037#ifndef KOLISEO_HAS_LOCATE
1039#else
1040 kls->conf.err_handlers.PTRDIFF_MAX_handler = &KLS_PTRDIFF_MAX_default_handler_dbg__;
1041#endif
1042 }
1043
1044#ifndef KLS_DEBUG_CORE
1045 if (kls->conf.collect_stats == 1) {
1046 fprintf(stderr,
1047 "[WARN] [%s()]: KLS_DEBUG_CORE is not defined. Stats may not be collected in full.\n",
1048 __func__);
1049 }
1050#endif
1051
1052 if (kls->conf.verbose_lvl > 0) {
1053 if (kls->conf.log_fp != NULL) {
1054#ifdef KLS_DEBUG_CORE
1055#ifdef KLS_SETCONF_DEBUG
1056 kls_log(kls, "WARN",
1057 "[%s()]: kls->conf.log_fp was not NULL. Overriding it.",
1058 __func__);
1059#endif
1060#endif
1061 }
1062
1063 FILE *log_fp = NULL;
1064 log_fp = fopen(kls->conf.log_filepath, "w");
1065 if (!log_fp) {
1066 fprintf(stderr,
1067 "[ERROR] [%s()]: Failed opening logfile at {\"%s\"} [write].\n",
1068 __func__, kls->conf.log_filepath);
1069 return false;
1070 } else {
1071 fprintf(log_fp, "%s", ""); //Reset log_fp
1072 fclose(log_fp);
1073 }
1074 log_fp = fopen(kls->conf.log_filepath, "a");
1075 if (!log_fp) {
1076 fprintf(stderr,
1077 "[ERROR] [%s()]: Failed opening logfile at {\"%s\"} [append].\n",
1078 __func__, kls->conf.log_filepath);
1079 return false;
1080 } else {
1081 kls->conf.log_fp = log_fp;
1082 }
1083 }
1084 return true;
1085}
1086
1087static bool kls__try_grow(Koliseo* kls, ptrdiff_t needed);
1088
1100#ifndef KOLISEO_HAS_LOCATE
1101KLS_Push_Result kls__advance(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, ptrdiff_t* padding, const char* caller_name)
1102#else
1103KLS_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)
1104#endif // KOLISEO_HAS_LOCATE
1105{
1106#ifdef KLS_DEBUG_CORE
1107#ifndef _WIN32
1108 struct timespec start_time, end_time;
1109 clock_gettime(CLOCK_MONOTONIC, &start_time);
1110#else
1111 LARGE_INTEGER start_time, end_time, frequency;
1112 QueryPerformanceFrequency(&frequency);
1113 QueryPerformanceCounter(&start_time);
1114#endif
1115#endif
1116
1117 if (kls == NULL) {
1118 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", caller_name);
1119 exit(EXIT_FAILURE);
1120 }
1121 if ((kls->has_temp == 1) && (kls->conf.block_while_has_temp == 1)) {
1122 return (KLS_Push_Result) {
1123 .p = NULL,
1125 };
1126 }
1127
1128#ifndef KOLISEO_HAS_LOCATE
1129 KLS_Push_Error res = kls__check_available(kls, size, align, count, __func__);
1130#else
1131 KLS_Push_Error res = kls__check_available_dbg(kls, size, align, count, __func__, loc);
1132#endif
1133 if (res != 0) {
1134 return (KLS_Push_Result) {
1135 .p = NULL,
1136 .error = res,
1137 };
1138 }
1139 Koliseo* current = kls;
1140 while (current->next != NULL) {
1141 current = current->next;
1142 }
1143 const ptrdiff_t pad = -current->offset & (align - 1);
1144 *padding = pad;
1145 char *p = current->data + current->offset + pad;
1146 current->prev_offset = current->offset;
1147 current->offset += pad + size * count;
1148
1149 KLS_ASAN_UNPOISON(p, size * count);
1150
1151 char h_size[200];
1152 kls_formatSize(size * count, h_size, sizeof(h_size));
1153 //sprintf(msg,"Pushed zeroes, size (%li) for KLS.",size);
1154 //kls_log("KLS",msg);
1155#ifdef KLS_DEBUG_CORE
1156 kls_log(current, "KLS", "Pushed zeroes on KLS, size (%s). Curr offset: { %p }.", h_size, current->data + current->offset);
1157 if (current->conf.collect_stats == 1) {
1158#ifndef _WIN32
1159 clock_gettime(CLOCK_MONOTONIC, &end_time); // %.9f
1160 double elapsed_time =
1161 (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec -
1162 start_time.tv_nsec) / 1e9;
1163#else
1164 QueryPerformanceCounter(&end_time); // %.7f
1165 double elapsed_time =
1166 (double)(end_time.QuadPart -
1167 start_time.QuadPart) / frequency.QuadPart;
1168#endif
1169 if (elapsed_time > current->stats.worst_pushcall_time) {
1170 current->stats.worst_pushcall_time = elapsed_time;
1171 }
1172 }
1173#endif
1174 if (current->conf.collect_stats == 1) {
1175 current->stats.tot_pushes += 1;
1176 }
1177 return (KLS_Push_Result) {
1178 .p = p,
1179 .error = KLS_PUSH_OK,
1180 };
1181}
1182
1195#ifndef KOLISEO_HAS_LOCATE
1196KLS_Push_Error kls__check_available(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, const char* caller_name)
1197#else
1198KLS_Push_Error kls__check_available_dbg(Koliseo* kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count, const char* caller_name, Koliseo_Loc loc)
1199#endif // KOLISEO_HAS_LOCATE
1200{
1201 assert(kls != NULL);
1202 assert(caller_name != NULL);
1203 if (count < 0) {
1205 }
1206 if (size < 1) {
1207 return KLS_PUSH_SIZE_LT1;
1208 }
1209 if (align < 1) {
1210 return KLS_PUSH_ALIGN_LT1;
1211 }
1212 if (! ((align & (align - 1)) == 0)) {
1214 }
1215 Koliseo* current = kls;
1216 while (current->next != NULL) {
1217 current = current->next;
1218 }
1219 const ptrdiff_t available = current->size - current->offset;
1220 const ptrdiff_t padding = -current->offset & (align - 1);
1221 if (count == 0) {
1222 if (current->conf.allow_zerocount_push != 1) {
1223 return KLS_PUSH_ZEROCOUNT;
1224 } else {
1225#ifdef KLS_DEBUG_CORE
1226 kls_log(current, "DEBUG", "Accepting zero-count push: conf.allow_zerocount_push was 1");
1227#endif // KLS_DEBUG_CORE
1228 }
1229 }
1230
1231 if (count > PTRDIFF_MAX / size || available - padding < size * count) {
1232 if (count > PTRDIFF_MAX / size) {
1233 return KLS_PUSH_PTRDIFF_MAX;
1234 } else {
1235 if (current->conf.growable == 1 && kls__try_grow(current, size + count + padding)) {
1236 return KLS_PUSH_OK;
1237 }
1238 return KLS_PUSH_OOM;
1239 }
1240 }
1241 return KLS_PUSH_OK;
1242}
1243
1255#ifndef KOLISEO_HAS_LOCATE
1256KLS_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)
1257#else
1258KLS_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)
1259#endif // KOLISEO_HAS_LOCATE
1260{
1261#ifdef KLS_DEBUG_CORE
1262#ifndef _WIN32
1263 struct timespec start_time, end_time;
1264 clock_gettime(CLOCK_MONOTONIC, &start_time);
1265#else
1266 LARGE_INTEGER start_time, end_time, frequency;
1267 QueryPerformanceFrequency(&frequency);
1268 QueryPerformanceCounter(&start_time);
1269#endif
1270#endif
1271
1272 if (kls_t == NULL) {
1273 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo_Temp was NULL.\n",
1274 __func__);
1275 exit(EXIT_FAILURE);
1276 }
1277 Koliseo *kls = kls_t->kls;
1278 if (kls == NULL) {
1279 fprintf(stderr, "[ERROR] [%s()]: Referred Koliseo was NULL.\n",
1280 __func__);
1281 exit(EXIT_FAILURE);
1282 }
1283#ifndef KOLISEO_HAS_LOCATE
1284 KLS_Push_Error res = kls__check_available(kls, size, align, count, __func__);
1285#else
1286 KLS_Push_Error res = kls__check_available_dbg(kls, size, align, count, __func__, loc);
1287#endif
1288 if (res != 0) {
1289 return (KLS_Push_Result) {
1290 .p = NULL,
1291 .error = res,
1292 };
1293 }
1294 Koliseo* current = kls;
1295 while (current->next != NULL) {
1296 current = current->next;
1297 }
1298 ptrdiff_t pad = -current->offset & (align - 1);
1299 char *p = current->data + current->offset + pad;
1300 *padding = pad;
1301 current->prev_offset = current->offset;
1302 current->offset += pad + size * count;
1303
1304 KLS_ASAN_UNPOISON(p, size * count);
1305
1306 char h_size[200];
1307 kls_formatSize(size * count, h_size, sizeof(h_size));
1308 //sprintf(msg,"Pushed zeroes, size (%li) for KLS.",size);
1309 //kls_log("KLS",msg);
1310#ifdef KLS_DEBUG_CORE
1311 if (current->conf.collect_stats == 1) {
1312#ifndef _WIN32
1313 clock_gettime(CLOCK_MONOTONIC, &end_time); // %.9f
1314 double elapsed_time =
1315 (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_nsec -
1316 start_time.tv_nsec) / 1e9;
1317#else
1318 QueryPerformanceCounter(&end_time); // %.7f
1319 double elapsed_time =
1320 (double)(end_time.QuadPart -
1321 start_time.QuadPart) / frequency.QuadPart;
1322#endif
1323 if (elapsed_time > current->stats.worst_pushcall_time) {
1324 current->stats.worst_pushcall_time = elapsed_time;
1325 }
1326 }
1327 kls_log(current, "KLS", "Pushed zeroes on Temp_KLS, size (%s). Curr offset: { %p }.", h_size, current->data + current->offset);
1328#endif
1329 if (current->conf.collect_stats == 1) {
1330 current->stats.tot_temp_pushes += 1;
1331 }
1332 return (KLS_Push_Result) {
1333 .p = p,
1334 .error = KLS_PUSH_OK,
1335 };
1336}
1337
1338bool kls__try_grow(Koliseo* kls, ptrdiff_t needed)
1339{
1340 assert(kls->next == NULL);
1341 ptrdiff_t new_size = KLS_MAX(kls->size * 2, needed);
1342 KLS_Hooks hooks = kls->hooks;
1343 hooks.on_new_handler = NULL; // We don't want the extension handler to run again on the tail
1344 // since the extension_data is shared
1346 kls_log(kls, "DEBUG", "%s(): growing Koliseo, new size: {%td}", __func__, new_size);
1347 if (!new_kls) return false;
1348 kls->next = new_kls;
1349 return true;
1350}
1351
1362void *kls_push(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
1363{
1364 ptrdiff_t padding = 0;
1365#ifndef KOLISEO_HAS_LOCATE
1366 KLS_Push_Result res = kls__advance(kls, size, align, count, &padding, __func__);
1367 return kls__handle_push_result(kls, res, size, align, count, padding, __func__);
1368#else
1369 KLS_Push_Result res = kls__advance_dbg(kls, size, align, count, &padding, __func__, KLS_HERE);
1370 return kls__handle_push_result_dbg(kls, res, size, align, count, padding, __func__, KLS_HERE);
1371#endif // KOLISEO_HAS_LOCATE
1372}
1373
1384#ifndef KOLISEO_HAS_LOCATE
1385void *kls_push_zero(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1386 ptrdiff_t count)
1387#else
1388void *kls_push_zero_dbg(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1389 ptrdiff_t count, Koliseo_Loc loc)
1390#endif // KOLISEO_HAS_LOCATE
1391{
1392 ptrdiff_t padding = 0;
1393#ifndef KOLISEO_HAS_LOCATE
1394 KLS_Push_Result res = kls__advance(kls, size, align, count, &padding, __func__);
1395 void* p = kls__handle_push_result(kls, res, size, align, count, padding, __func__);
1396#else
1397 KLS_Push_Result res = kls__advance_dbg(kls, size, align, count, &padding, __func__, loc);
1398 void* p = kls__handle_push_result_dbg(kls, res, size, align, count, padding, __func__, loc);
1399#endif // KOLISEO_HAS_LOCATE
1400 if (!p) return NULL;
1401 //Zero new area
1402 memset(p, 0, size * count);
1403 return p;
1404}
1405
1417#ifndef KOLISEO_HAS_LOCATE
1418void *kls_push_zero_ext(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1419 ptrdiff_t count)
1420#else
1421void *kls_push_zero_ext_dbg(Koliseo *kls, ptrdiff_t size, ptrdiff_t align,
1422 ptrdiff_t count, Koliseo_Loc loc)
1423#endif // KOLISEO_HAS_LOCATE
1424{
1425
1426 ptrdiff_t padding = 0;
1427#ifndef KOLISEO_HAS_LOCATE
1428 KLS_Push_Result res = kls__advance(kls, size, align, count, &padding, __func__);
1429 void* p = kls__handle_push_result(kls, res, size, align, count, padding, __func__);
1430#else
1431 KLS_Push_Result res = kls__advance_dbg(kls, size, align, count, &padding, __func__, loc);
1432 void* p = kls__handle_push_result_dbg(kls, res, size, align, count, padding, __func__, loc);
1433#endif // KOLISEO_HAS_LOCATE
1434 if (!p) return NULL;
1435 //Zero new area
1436 memset(p, 0, size * count);
1437
1438 Koliseo* current = kls;
1439 while (current->next != NULL) {
1440 current = current->next;
1441 }
1442
1443 if (current->hooks.on_push_handler != NULL) {
1444 /*
1445 struct KLS_EXTENSION_AR_DEFAULT_ARGS {
1446 const char* region_name;
1447 size_t region_name_len;
1448 const char* region_desc;
1449 size_t region_desc_len;
1450 int region_type;
1451 };
1452 struct KLS_EXTENSION_AR_DEFAULT_ARGS ar_args = {
1453 .region_name = KOLISEO_DEFAULT_REGION_NAME,
1454 .region_name_len = strlen(KOLISEO_DEFAULT_REGION_NAME),
1455 .region_desc = KOLISEO_DEFAULT_REGION_DESC,
1456 .region_desc_len = strlen(KOLISEO_DEFAULT_REGION_DESC),
1457 .region_type = KLS_None
1458 };
1459 kls->hooks.on_push_handler(kls, padding, (void*)&ar_args);
1460 */
1461 current->hooks.on_push_handler(current, padding, __func__, NULL);
1462 }
1463 return p;
1464}
1465
1466#ifndef KOLISEO_HAS_LOCATE
1467char* kls_vsprintf(Koliseo* kls, const char* fmt, va_list args)
1468#else
1469char* kls_vsprintf_dbg(Koliseo* kls, Koliseo_Loc loc, const char* fmt, va_list args)
1470#endif // KOLISEO_HAS_LOCATE
1471{
1472 va_list args_copy;
1473 va_copy(args_copy, args);
1474 int len = vsnprintf(NULL, 0, fmt, args);
1475#ifndef KOLISEO_HAS_LOCATE
1476 char* str = KLS_PUSH_ARR(kls, char, len+1);
1477#else
1478 char* str = kls_push_zero_ext_dbg(kls, sizeof(char), KLS_ALIGNOF(char), len+1, loc);
1479#endif // KOLISEO_HAS_LOCATE
1480 vsnprintf(str, len+1, fmt, args_copy);
1481 va_end(args_copy);
1482 return str;
1483}
1484
1491#ifndef KOLISEO_HAS_LOCATE
1492char* kls_sprintf(Koliseo* kls, const char* fmt, ...)
1493#else
1494char* kls_sprintf_dbg(Koliseo* kls, Koliseo_Loc loc, const char* fmt, ...)
1495#endif // KOLISEO_HAS_LOCATE
1496{
1497 va_list args;
1498 va_start(args, fmt);
1499#ifndef KOLISEO_HAS_LOCATE
1500 char* str = kls_vsprintf(kls, fmt, args);
1501#else
1502 char* str = kls_vsprintf_dbg(kls, loc, fmt, args);
1503#endif // KOLISEO_HAS_LOCATE
1504 va_end(args);
1505 return str;
1506}
1507
1519#ifndef KOLISEO_HAS_LOCATE
1520void *kls_temp_push_zero_ext(Koliseo_Temp *t_kls, ptrdiff_t size,
1521 ptrdiff_t align, ptrdiff_t count)
1522#else
1523void *kls_temp_push_zero_ext_dbg(Koliseo_Temp *t_kls, ptrdiff_t size,
1524 ptrdiff_t align, ptrdiff_t count, Koliseo_Loc loc)
1525#endif // KOLISEO_HAS_LOCATE
1526{
1527
1528 ptrdiff_t padding = 0;
1529
1530#ifndef KOLISEO_HAS_LOCATE
1531 KLS_Push_Result res = kls__temp_advance(t_kls, size, align, count, &padding, __func__);
1532#else
1533 KLS_Push_Result res = kls__temp_advance_dbg(t_kls, size, align, count, &padding, __func__, loc);
1534#endif // KOLISEO_HAS_LOCATE
1535 if (res.error) return NULL;
1536 //Zero new area
1537 memset(res.p, 0, size * count);
1538
1539 Koliseo* kls = t_kls->kls;
1540 Koliseo* current = kls;
1541 while (current->next != NULL) {
1542 current = current->next;
1543 }
1544
1545 if (current->hooks.on_temp_push_handler != NULL) {
1546 // Call on_temp_push extension with empty user arg
1547 current->hooks.on_temp_push_handler(t_kls, padding, __func__, NULL);
1548 }
1549 return res.p;
1550}
1551
1552#ifndef KOLISEO_HAS_LOCATE
1553char* kls_temp_vsprintf(Koliseo_Temp* kls_t, const char* fmt, va_list args)
1554#else
1555char* kls_temp_vsprintf_dbg(Koliseo_Temp* kls_t, Koliseo_Loc loc, const char* fmt, va_list args)
1556#endif // KOLISEO_HAS_LOCATE
1557{
1558 va_list args_copy;
1559 va_copy(args_copy, args);
1560 int len = vsnprintf(NULL, 0, fmt, args);
1561#ifndef KOLISEO_HAS_LOCATE
1562 char* str = KLS_PUSH_ARR_T(kls_t, char, len+1);
1563#else
1564 char* str = kls_temp_push_zero_ext_dbg(kls_t, sizeof(char), KLS_ALIGNOF(char), len+1, loc);
1565#endif // KOLISEO_HAS_LOCATE
1566 vsnprintf(str, len+1, fmt, args_copy);
1567 va_end(args_copy);
1568 return str;
1569}
1570
1571
1578#ifndef KOLISEO_HAS_LOCATE
1579char* kls_temp_sprintf(Koliseo_Temp* kls_t, const char* fmt, ...)
1580#else
1581char* kls_temp_sprintf_dbg(Koliseo_Temp* kls_t, Koliseo_Loc loc, const char* fmt, ...)
1582#endif // KOLISEO_HAS_LOCATE
1583{
1584 va_list args;
1585 va_start(args, fmt);
1586#ifndef KOLISEO_HAS_LOCATE
1587 char* str = kls_temp_vsprintf(kls_t, fmt, args);
1588#else
1589 char* str = kls_temp_vsprintf_dbg(kls_t, loc, fmt, args);
1590#endif // KOLISEO_HAS_LOCATE
1591 va_end(args);
1592 return str;
1593}
1594
1606#ifndef KOLISEO_HAS_LOCATE
1607void *kls_repush(Koliseo *kls, void* old, ptrdiff_t size, ptrdiff_t align,
1608 ptrdiff_t old_count, ptrdiff_t new_count)
1609#else
1610void *kls_repush_dbg(Koliseo *kls, void* old, ptrdiff_t size, ptrdiff_t align,
1611 ptrdiff_t old_count, ptrdiff_t new_count, Koliseo_Loc loc)
1612#endif // KOLISEO_HAS_LOCATE
1613{
1614 if (!old) {
1615#ifndef KOLISEO_HAS_LOCATE
1616 fprintf(stderr,
1617 "[KLS] %s(): old was NULL.\n",
1618 __func__);
1619#else
1620 fprintf(stderr,
1621 "[KLS] " KLS_Loc_Fmt "%s(): old was NULL.\n",
1622 KLS_Loc_Arg(loc),
1623 __func__);
1624#endif // KOLISEO_HAS_LOCATE
1625 return NULL;
1626 }
1627 if (old_count < 0) {
1628#ifndef KOLISEO_HAS_LOCATE
1629 fprintf(stderr,
1630 "[KLS] %s(): old_count [%td] was < 0.\n",
1631 __func__,
1632 old_count);
1633#else
1634 fprintf(stderr,
1635 "[KLS] " KLS_Loc_Fmt "%s(): old_count [%td] was < 0.\n",
1636 KLS_Loc_Arg(loc),
1637 __func__,
1638 old_count);
1639#endif // KOLISEO_HAS_LOCATE
1640 return NULL;
1641 }
1642 if (new_count < 0) {
1643#ifndef KOLISEO_HAS_LOCATE
1644 fprintf(stderr,
1645 "[KLS] %s(): new_count [%td] was < 0.\n",
1646 __func__,
1647 new_count);
1648#else
1649 fprintf(stderr,
1650 "[KLS] " KLS_Loc_Fmt "%s(): new_count [%td] was < 0.\n",
1651 KLS_Loc_Arg(loc),
1652 __func__,
1653 new_count);
1654#endif // KOLISEO_HAS_LOCATE
1655 return NULL;
1656 }
1657 if (size < 1) {
1658#ifndef KOLISEO_HAS_LOCATE
1659 fprintf(stderr,
1660 "[KLS] %s(): size [%td] was < 1.\n",
1661 __func__,
1662 size);
1663#else
1664 fprintf(stderr,
1665 "[KLS] " KLS_Loc_Fmt "%s(): size [%td] was < 1.\n",
1666 KLS_Loc_Arg(loc),
1667 __func__,
1668 size);
1669#endif // KOLISEO_HAS_LOCATE
1670 return NULL;
1671 }
1672 if (align < 1) {
1673#ifndef KOLISEO_HAS_LOCATE
1674 fprintf(stderr,
1675 "[KLS] %s(): align [%td] was < 1.\n",
1676 __func__,
1677 align);
1678#else
1679 fprintf(stderr,
1680 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was < 1.\n",
1681 KLS_Loc_Arg(loc),
1682 __func__,
1683 align);
1684#endif // KOLISEO_HAS_LOCATE
1685 return NULL;
1686 }
1687 if (! ((align & (align - 1)) == 0)) {
1688#ifndef KOLISEO_HAS_LOCATE
1689 fprintf(stderr,
1690 "[KLS] %s(): align [%td] was not a power of 2.\n",
1691 __func__,
1692 align);
1693#else
1694 fprintf(stderr,
1695 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was not a power of 2.\n",
1696 KLS_Loc_Arg(loc),
1697 __func__,
1698 align);
1699#endif // KOLISEO_HAS_LOCATE
1700 return NULL;
1701 }
1702 if (kls->has_temp == 1 && kls->conf.block_while_has_temp == 1) {
1703 fprintf(stderr, "%s(): kls has an active temp\n", __func__);
1704 return NULL;
1705 }
1706 size_t old_size = old_count * size;
1707 size_t new_size = new_count * size;
1708 void *new_ptr = kls_push_zero_ext(kls, size, align, new_count);
1709 if (new_ptr && old_size > 0) {
1710 memcpy(new_ptr, old, old_size < new_size ? old_size : new_size);
1711 }
1712 return new_ptr;
1713}
1714
1726#ifndef KOLISEO_HAS_LOCATE
1727void *kls_temp_repush(Koliseo_Temp *t_kls, void* old, ptrdiff_t size, ptrdiff_t align,
1728 ptrdiff_t old_count, ptrdiff_t new_count)
1729#else
1730void *kls_temp_repush_dbg(Koliseo_Temp *t_kls, void* old, ptrdiff_t size, ptrdiff_t align,
1731 ptrdiff_t old_count, ptrdiff_t new_count, Koliseo_Loc loc)
1732#endif // KOLISEO_HAS_LOCATE
1733{
1734 if (!old) {
1735#ifndef KOLISEO_HAS_LOCATE
1736 fprintf(stderr,
1737 "[KLS] %s(): old was NULL.\n",
1738 __func__);
1739#else
1740 fprintf(stderr,
1741 "[KLS] " KLS_Loc_Fmt "%s(): old was NULL.\n",
1742 KLS_Loc_Arg(loc),
1743 __func__);
1744#endif // KOLISEO_HAS_LOCATE
1745 return NULL;
1746 }
1747 if (old_count < 0) {
1748#ifndef KOLISEO_HAS_LOCATE
1749 fprintf(stderr,
1750 "[KLS] %s(): old_count [%td] was < 0.\n",
1751 __func__,
1752 old_count);
1753#else
1754 fprintf(stderr,
1755 "[KLS] " KLS_Loc_Fmt "%s(): old_count [%td] was < 0.\n",
1756 KLS_Loc_Arg(loc),
1757 __func__,
1758 old_count);
1759#endif // KOLISEO_HAS_LOCATE
1760 return NULL;
1761 }
1762 if (new_count < 0) {
1763#ifndef KOLISEO_HAS_LOCATE
1764 fprintf(stderr,
1765 "[KLS] %s(): new_count [%td] was < 0.\n",
1766 __func__,
1767 new_count);
1768#else
1769 fprintf(stderr,
1770 "[KLS] " KLS_Loc_Fmt "%s(): new_count [%td] was < 0.\n",
1771 KLS_Loc_Arg(loc),
1772 __func__,
1773 new_count);
1774#endif // KOLISEO_HAS_LOCATE
1775 return NULL;
1776 }
1777 if (size < 1) {
1778#ifndef KOLISEO_HAS_LOCATE
1779 fprintf(stderr,
1780 "[KLS] %s(): size [%td] was < 1.\n",
1781 __func__,
1782 size);
1783#else
1784 fprintf(stderr,
1785 "[KLS] " KLS_Loc_Fmt "%s(): size [%td] was < 1.\n",
1786 KLS_Loc_Arg(loc),
1787 __func__,
1788 size);
1789#endif // KOLISEO_HAS_LOCATE
1790 return NULL;
1791 }
1792 if (align < 1) {
1793#ifndef KOLISEO_HAS_LOCATE
1794 fprintf(stderr,
1795 "[KLS] %s(): align [%td] was < 1.\n",
1796 __func__,
1797 align);
1798#else
1799 fprintf(stderr,
1800 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was < 1.\n",
1801 KLS_Loc_Arg(loc),
1802 __func__,
1803 align);
1804#endif // KOLISEO_HAS_LOCATE
1805 return NULL;
1806 }
1807 if (! ((align & (align - 1)) == 0)) {
1808#ifndef KOLISEO_HAS_LOCATE
1809 fprintf(stderr,
1810 "[KLS] %s(): align [%td] was not a power of 2.\n",
1811 __func__,
1812 align);
1813#else
1814 fprintf(stderr,
1815 "[KLS] " KLS_Loc_Fmt "%s(): align [%td] was not a power of 2.\n",
1816 KLS_Loc_Arg(loc),
1817 __func__,
1818 align);
1819#endif // KOLISEO_HAS_LOCATE
1820 return NULL;
1821 }
1822 size_t old_size = old_count * size;
1823 size_t new_size = new_count * size;
1824 void *new_ptr = kls_temp_push_zero_ext(t_kls, size, align, new_count);
1825 if (new_ptr && old_size > 0) {
1826 memcpy(new_ptr, old, old_size < new_size ? old_size : new_size);
1827 }
1828 return new_ptr;
1829}
1830
1836void print_kls_2file(FILE *fp, const Koliseo *kls)
1837{
1838 if (fp == NULL) {
1839 fprintf(stderr, "print_kls_2file(): fp was NULL.\n");
1840 return;
1841 }
1842 if (kls == NULL) {
1843 fprintf(fp, "[KLS] kls was NULL.\n");
1844 } else {
1845 fprintf(fp, "\n[KLS] API Level: { %i }\n", int_koliseo_version());
1846 fprintf(fp, "\n[INFO] Conf: { " KLS_Conf_Fmt " }\n",
1847 KLS_Conf_Arg(kls->conf));
1848 fprintf(fp, "\n[INFO] Stats: { " KLS_Stats_Fmt " }\n",
1849 KLS_Stats_Arg(kls->stats));
1850 fprintf(fp, "\n[KLS] Size: { %td }\n", kls->size);
1851 char human_size[200];
1852 char curr_size[200];
1853 kls_formatSize(kls->size, human_size, sizeof(human_size));
1854 fprintf(fp, "[KLS] Size (Human): { %s }\n", human_size);
1855 kls_formatSize(kls->offset, curr_size, sizeof(curr_size));
1856 fprintf(fp, "[KLS] Used (Human): { %s }\n", curr_size);
1857 fprintf(fp, "[KLS] Offset: { %td }\n", kls->offset);
1858 fprintf(fp, "[KLS] Prev_Offset: { %td }\n", kls->prev_offset);
1859 fprintf(fp, "\n");
1860 }
1861}
1862
1867void print_dbg_kls(const Koliseo *kls)
1868{
1869 if (kls == NULL) {
1870 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
1871 exit(EXIT_FAILURE);
1872 }
1873 print_kls_2file(stderr, kls);
1874}
1875
1881void print_temp_kls_2file(FILE *fp, const Koliseo_Temp *t_kls)
1882{
1883 if (fp == NULL) {
1884 fprintf(stderr, "print_temp_kls_2file(): fp was NULL.\n");
1885 exit(EXIT_FAILURE);
1886 }
1887 if (t_kls == NULL) {
1888 fprintf(fp, "[KLS_T] t_kls was NULL.");
1889 } else if (t_kls->kls == NULL) {
1890 fprintf(fp, "[KLS_T] [%s()]: Referred Koliseo was NULL.\n", __func__);
1891 } else {
1892 const Koliseo *kls = t_kls->kls;
1893 fprintf(fp, "\n[KLS_T] API Level: { %i }\n", int_koliseo_version());
1894 fprintf(fp, "\n[KLS_T] Temp Size: { %td }\n",
1895 kls->size - t_kls->offset);
1896 fprintf(fp, "\n[KLS_T] Refer Size: { %td }\n", kls->size);
1897 char human_size[200];
1898 char curr_size[200];
1899 kls_formatSize(kls->size - t_kls->offset, human_size,
1900 sizeof(human_size));
1901 fprintf(fp, "[KLS_T] Temp Size Human: { %s }\n", human_size);
1902 kls_formatSize(kls->size, human_size, sizeof(human_size));
1903 fprintf(fp, "[KLS_T] Refer Size Human: { %s }\n", human_size);
1904 kls_formatSize(kls->offset, curr_size, sizeof(curr_size));
1905 fprintf(fp, "[KLS_T] Inner Used (Human): { %s }\n", curr_size);
1906 kls_formatSize(t_kls->offset, curr_size, sizeof(curr_size));
1907 fprintf(fp, "[KLS_T] Temp Used (Human): { %s }\n", curr_size);
1908 fprintf(fp, "[KLS_T] Inner Offset: { %td }\n", kls->offset);
1909 fprintf(fp, "[KLS_T] Temp Offset: { %td }\n", t_kls->offset);
1910 fprintf(fp, "[KLS_T] Inner Prev_Offset: { %td }\n", kls->prev_offset);
1911 fprintf(fp, "[KLS_T] Temp Prev_Offset: { %td }\n\n",
1912 t_kls->prev_offset);
1913 }
1914}
1915
1921{
1922 print_temp_kls_2file(stderr, t_kls);
1923}
1924
1932void kls_formatSize(ptrdiff_t size, char *outputBuffer, size_t bufferSize)
1933{
1934 const char *units[] =
1935 { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
1936 const int numUnits = sizeof(units) / sizeof(units[0]);
1937
1938 int unitIndex = 0;
1939 double sizeValue = (double)size;
1940
1941 while (sizeValue >= 1000 && unitIndex < numUnits - 1) {
1942 sizeValue /= 1000;
1943 unitIndex++;
1944 }
1945
1946 snprintf(outputBuffer, bufferSize, "%.2f %s", sizeValue, units[unitIndex]);
1947}
1948
1955{
1956 if (kls == NULL) {
1957 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
1958 exit(EXIT_FAILURE);
1959 }
1960 //Reset pointer
1961 kls->prev_offset = kls->offset;
1962 kls->offset = sizeof(*kls);
1963 if (kls->next) {
1964 Koliseo *chain = kls->next;
1965 kls->next = NULL;
1966 if (chain) {
1967 kls_free(chain);
1968 kls->extension_data = NULL; // The chain shares this pointer and we need to restore the extension data
1969 if (kls->hooks.on_new_handler) {
1970 kls->hooks.on_new_handler(kls);
1971 }
1972 }
1973 }
1974 KLS_ASAN_POISON(kls->data + kls->offset, kls->size - kls->offset);
1975#ifdef KLS_DEBUG_CORE
1976 kls_log(kls, "KLS", "API Level { %i } -> Cleared offsets for KLS.",
1978#endif
1979}
1980
1987{
1988 if (kls == NULL) {
1989 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
1990 exit(EXIT_FAILURE);
1991 }
1992 Koliseo* current = kls;
1993 while (current) {
1994 if (current->has_temp == 1) {
1995#ifdef KLS_DEBUG_CORE
1996 kls_log(current, "KLS",
1997 "API Level { %i } -> KLS had an active Koliseo_Temp.",
1999#endif
2000 kls_temp_end(current->t_kls);
2001 }
2002 if (current->hooks.on_free_handler != NULL) {
2003 // Call on_free() extension
2004 current->hooks.on_free_handler(current);
2005 for (Koliseo *k = current; k; k = k->next) {
2006 // We NULL all subsequent extension_data pointers, since the chain shares it
2007 // and it's freed in the first hook call
2008 k->extension_data = NULL;
2009 }
2010 }
2011 Koliseo* next = current->next;
2012 current->next = NULL;
2013 //kls_clear(current);
2014#ifdef KLS_DEBUG_CORE
2015 kls_log(current, "KLS", "API Level { %i } -> Freeing KLS.",
2017#endif
2018 if (current->conf.log_fp != NULL && current->conf.log_fp != stdout
2019 && current->conf.log_fp != stderr) {
2020#ifdef KLS_DEBUG_CORE
2021 kls_log(current, "KLS", "Closing kls log file. Path: {\"%s\"}.",
2022 kls->conf.log_filepath);
2023#endif
2024 int close_res = fclose(current->conf.log_fp);
2025 if (close_res != 0) {
2026 fprintf(stderr,
2027 "[ERROR] %s(): Failed fclose() on log_fp. Path: {\"%s\"}.",
2028 __func__, current->conf.log_filepath);
2029 }
2030 } else if (current->conf.log_fp == stdout || current->conf.log_fp == stderr) {
2031 if (current->conf.verbose_lvl > 1) {
2032 fprintf(stderr,
2033 "[INFO] %s(): kls->conf.log_fp is %s. Not closing it.\n",
2034 __func__,
2035 (current->conf.log_fp == stdout ? "stdout" : "stderr"));
2036 }
2037 }
2038 if (current->free_func == NULL) {
2039 fprintf(stderr,
2040 "[ERROR] %s(): free function was NULL.\n", __func__);
2041 return;
2042 }
2043 current->free_func(current);
2044 current = next;
2045 }
2046}
2047
2055#ifndef KOLISEO_HAS_LOCATE
2057#else
2058Koliseo_Temp *kls_temp_start_dbg(Koliseo *kls, Koliseo_Loc loc)
2059#endif // KOLISEO_HAS_LOCATE
2060{
2061 if (kls == NULL) {
2062 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
2063 exit(EXIT_FAILURE);
2064 }
2065 Koliseo* current = kls;
2066 while (current->next != NULL) {
2067 current = current->next;
2068 }
2069 if (current->has_temp != 0) {
2070 fprintf(stderr,
2071 "[ERROR] [%s()]: Passed Koliseo->has_temp is not 0. {%i}\n",
2072 __func__, current->has_temp);
2073#ifdef KLS_DEBUG_CORE
2074 kls_log(current, "ERROR", "[%s()]: Passed Koliseo->has_temp != 0 . {%i}",
2075 __func__, current->has_temp);
2076#endif
2077 return NULL;
2078 }
2079 ptrdiff_t prev = current->prev_offset;
2080 ptrdiff_t off = current->offset;
2081
2082 Koliseo_Temp *tmp = KLS_PUSH(current, Koliseo_Temp);
2083 tmp->kls = current;
2084 tmp->prev_offset = prev;
2085 tmp->offset = off;
2086#ifdef KLS_DEBUG_CORE
2087 kls_log(current, "INFO", "Passed kls conf: " KLS_Conf_Fmt "\n",
2088 KLS_Conf_Arg(current->conf));
2089#endif
2090
2091 current->has_temp = 1;
2092 current->t_kls = tmp;
2093 if (current->hooks.on_temp_start_handler != NULL) {
2094 // Call on_temp_start extension
2095 current->hooks.on_temp_start_handler(tmp);
2096 }
2097#ifdef KLS_DEBUG_CORE
2098 kls_log(current, "KLS", "Prepared new Temp KLS.");
2099#endif
2100 return tmp;
2101}
2102
2108{
2109 if (tmp_kls == NULL) {
2110 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo_Temp was NULL.\n",
2111 __func__);
2112 exit(EXIT_FAILURE);
2113 }
2114
2115 Koliseo *kls_ref = tmp_kls->kls;
2116 if (kls_ref == NULL) {
2117 fprintf(stderr, "[ERROR] [%s()]: Referred Koliseo was NULL.\n",
2118 __func__);
2119 exit(EXIT_FAILURE);
2120 }
2121
2122 if (kls_ref->hooks.on_temp_free_handler != NULL) {
2123 // Call on_temp_free() extension
2124 kls_ref->hooks.on_temp_free_handler(tmp_kls);
2125 }
2126
2127#ifdef KLS_DEBUG_CORE
2128 kls_log(kls_ref, "KLS", "Ended Temp KLS.");
2129#endif
2130 tmp_kls->kls->has_temp = 0;
2131 tmp_kls->kls->t_kls = NULL;
2132#if defined(__SANITIZE_ADDRESS__)
2133 ptrdiff_t old_offset = tmp_kls->kls->offset;
2134 ptrdiff_t new_offset = tmp_kls->offset;
2135#endif // __SANITIZE_ADDRESS__
2136 tmp_kls->kls->prev_offset = tmp_kls->prev_offset;
2137 tmp_kls->kls->offset = tmp_kls->offset;
2138
2139 // Free any Koliseo chained after the current one
2140 Koliseo* to_free = tmp_kls->kls->next;
2141 if (to_free != NULL) {
2142 kls_free(to_free);
2143 tmp_kls->kls->next = NULL;
2144 }
2145
2146 KLS_ASAN_POISON(tmp_kls->kls->data + new_offset, old_offset - new_offset);
2147 tmp_kls = NULL; // statement with no effect TODO: Clear tmp_kls from caller
2148 if (kls_ref->conf.collect_stats == 1) {
2149 kls_ref->stats.tot_temp_pushes = 0;
2150 kls_ref->stats.tot_temp_pops = 0;
2151 }
2152}
2153
2154#ifdef KOLISEO_HAS_EXPER
2163void *kls_pop(Koliseo *kls, ptrdiff_t size, ptrdiff_t align, ptrdiff_t count)
2164{
2165 if (kls == NULL) {
2166 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo was NULL.\n", __func__);
2167 exit(EXIT_FAILURE);
2168 }
2169 ptrdiff_t padding = -kls->offset & (align - 1);
2170 if (count > PTRDIFF_MAX / size
2171 || (kls->size + kls->offset) < (size * count)) {
2172 fprintf(stderr, "[KLS] Failed %s() call.\n", __func__);
2173 kls_free(kls);
2174 exit(EXIT_FAILURE);
2175 }
2176 char *p = kls->data + kls->offset - padding - size * count;
2177 kls->prev_offset = kls->offset;
2178 kls->offset -= padding + size * count;
2179#ifdef KLS_DEBUG_CORE
2180 kls_log(kls, "KLS", "Popped (%td) for KLS. Curr offset: { %p }",
2181 size, kls->data + kls->offset);
2182#endif
2183 if (kls->conf.collect_stats == 1) {
2184 kls->stats.tot_pops += 1;
2185 }
2186 return p;
2187}
2188
2197void *kls_temp_pop(Koliseo_Temp *t_kls, ptrdiff_t size, ptrdiff_t align,
2198 ptrdiff_t count)
2199{
2200 if (t_kls == NULL) {
2201 fprintf(stderr, "[ERROR] [%s()]: Passed Koliseo_Temp was NULL.\n",
2202 __func__);
2203 exit(EXIT_FAILURE);
2204 }
2205 Koliseo *kls = t_kls->kls;
2206 if (kls == NULL) {
2207 fprintf(stderr, "[ERROR] [%s()]: Referred Koliseo was NULL.\n",
2208 __func__);
2209 exit(EXIT_FAILURE);
2210 }
2211 ptrdiff_t padding = -kls->offset & (align - 1);
2212 if (count > PTRDIFF_MAX / size
2213 || (kls->size + kls->offset) < (size * count)) {
2214 fprintf(stderr, "[KLS] Failed %s() call.\n", __func__);
2215 kls_free(kls);
2216 exit(EXIT_FAILURE);
2217 }
2218 char *p = kls->data + kls->offset - padding - size * count;
2219 kls->prev_offset = kls->offset;
2220 kls->offset -= padding + size * count;
2221#ifdef KLS_DEBUG_CORE
2222 kls_log(kls, "KLS", "Popped (%td) for Temp_KLS. Curr offset: { %p }.", size, kls->data + kls->offset);
2223#endif
2224 if (kls->conf.collect_stats == 1) {
2225 kls->stats.tot_temp_pops += 1;
2226 }
2227 return p;
2228}
2229
2236char* kls_strdup(Koliseo* kls, char* source)
2237{
2238 char* dest = KLS_PUSH_STR(kls, source);
2239 KLS__STRCPY(dest, source);
2240 return dest;
2241}
2242
2249char** kls_strdup_arr(Koliseo* kls, size_t count, char** source)
2250{
2251 char** strings = NULL;
2252 strings = KLS_PUSH_ARR(kls, char*, count);
2253 for (int i=0; i < count; i++) {
2254 strings[i] = KLS_STRDUP(kls, source[i]);
2255 }
2256 return strings;
2257}
2258
2265char* kls_t_strdup(Koliseo_Temp* t_kls, char* source)
2266{
2267 char* dest = KLS_PUSH_STR_T(t_kls, source);
2268 KLS__STRCPY(dest, source);
2269 return dest;
2270}
2271
2278char** kls_t_strdup_arr(Koliseo_Temp* t_kls, size_t count, char** source)
2279{
2280 char** strings = NULL;
2281 strings = KLS_PUSH_ARR_T(t_kls, char*, count);
2282 for (int i=0; i < count; i++) {
2283 strings[i] = KLS_STRDUP_T(t_kls, source[i]);
2284 }
2285 return strings;
2286}
2287#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:846
Koliseo * kls_new(ptrdiff_t size)
Takes a ptrdiff_t size.
Definition koliseo.c:654
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:2236
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:2197
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:2056
void print_dbg_temp_kls(const Koliseo_Temp *t_kls)
Prints header fields from the passed Koliseo_Temp pointer, to stderr.
Definition koliseo.c:1920
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:1727
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:947
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:1881
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:2265
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:793
KLS_Stats KLS_STATS_DEFAULT
Default KLS_Stats values, used by kls_new().
Definition koliseo.c:41
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:494
char * kls_vsprintf(Koliseo *kls, const char *fmt, va_list args)
Definition koliseo.c:1467
void kls_temp_end(Koliseo_Temp *tmp_kls)
Ends passed Koliseo_Temp pointer.
Definition koliseo.c:2107
void kls_dbg_features(void)
Prints enabled Koliseo features to stderr.
Definition koliseo.c:234
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:2249
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:1520
void print_dbg_kls(const Koliseo *kls)
Prints header fields from the passed Koliseo pointer, to stderr.
Definition koliseo.c:1867
const char * string_koliseo_version(void)
Returns the constant string representing current version for Koliseo.
Definition koliseo.c:58
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:1607
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:1101
char * kls_temp_vsprintf(Koliseo_Temp *kls_t, const char *fmt, va_list args)
Definition koliseo.c:1553
ptrdiff_t kls_get_pos(const Koliseo *kls)
Returns the current offset (position of pointer bumper) for the passed Koliseo.
Definition koliseo.c:287
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:881
#define KLS_ASAN_UNPOISON(addr, size)
Definition koliseo.c:78
void kls_free(Koliseo *kls)
Calls kls_clear() on the passed Koliseo pointer and the frees the actual Koliseo.
Definition koliseo.c:1986
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:177
Koliseo * kls_new_dbg_ext(ptrdiff_t size, KLS_Hooks ext_handlers, void *user)
Takes a ptrdiff_t size.
Definition koliseo.c:930
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:1579
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:2278
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:1362
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:915
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:1196
#define KLS_ASAN_POISON(addr, size)
Definition koliseo.c:77
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:1385
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:630
Koliseo * kls_new_dbg(ptrdiff_t size)
Takes a ptrdiff_t size and returns a pointer to the prepared Koliseo.
Definition koliseo.c:962
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:829
char * kls_sprintf(Koliseo *kls, const char *fmt,...)
Takes a Koliseo pointer, and a format cstring, plus varargs.
Definition koliseo.c:1492
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:863
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:2163
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:675
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:111
KLS_Conf KLS_DEFAULT_CONF
Config used by any new Koliseo by default.
Definition koliseo.c:20
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:225
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:153
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:305
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:540
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:1836
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:757
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:977
void kls_clear(Koliseo *kls)
Resets the offset field for the passed Koliseo pointer.
Definition koliseo.c:1954
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:1418
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:1932
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:91
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:704
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:1256
int int_koliseo_version(void)
Returns the constant int representing current version for Koliseo.
Definition koliseo.c:67
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:810
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:737
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:721
void kls_free_func(void *)
Used to select a free function for the arena's backing memory.
Definition koliseo.h:96
#define KLS_PUSH_STR_T(kls_temp, cstr)
Macro to request memory for a C string from a Koliseo_Temp.
Definition koliseo.h:644
#define KLS_Stats_Fmt
Defines a format string for KLS_Stats.
Definition koliseo.h:294
#define KLS_PUSH_STR(kls, cstr)
Macro to request memory for a C string from a Koliseo.
Definition koliseo.h:527
#define KLS_Conf_Arg(conf)
Defines a format macro for KLS_Conf args.
Definition koliseo.h:287
#define KLS_DEFAULT_FREEF
Defines the default free function.
Definition koliseo.h:411
#define KLS_DEFAULT_ALLOCF
Defines the default allocation function.
Definition koliseo.h:407
#define KLS_PUSH(kls, type)
Macro used to request memory from a Koliseo.
Definition koliseo.h:564
#define KLS__STRCPY(dest, source)
Macro to copy a C string from a source buffer to a destination buffer.
Definition koliseo.h:748
#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:224
void * kls_alloc_func(size_t)
Used to select an allocation function for the arena's backing memory.
Definition koliseo.h:95
#define KLS_MAX(a, b)
Definition koliseo.h:102
#define KLS_STRDUP(kls, source)
Definition koliseo.h:757
KLS_Push_Error
Defines the result for kls__check_available().
Definition koliseo.h:367
@ KLS_PUSH_NEGATIVE_COUNT
Definition koliseo.h:372
@ KLS_PUSH_ZEROCOUNT
Definition koliseo.h:373
@ KLS_PUSH_ALIGN_NOT_POW2
Definition koliseo.h:371
@ KLS_PUSH_WITH_TEMP_ACTIVE
Definition koliseo.h:374
@ KLS_PUSH_OOM
Definition koliseo.h:376
@ KLS_PUSH_PTRDIFF_MAX
Definition koliseo.h:375
@ KLS_PUSH_SIZE_LT1
Definition koliseo.h:369
@ KLS_PUSH_ALIGN_LT1
Definition koliseo.h:370
@ KLS_PUSH_OK
Definition koliseo.h:368
#define KLS_Stats_Arg(stats)
Defines a format macro for KLS_Stats args.
Definition koliseo.h:304
#define KLS_Conf_Fmt
Defines a format string for KLS_Conf.
Definition koliseo.h:281
#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:632
#define KLS_STRDUP_T(t_kls, source)
Definition koliseo.h:767
#define KLS_DEFAULT_ERR_HANDLERS
Definition koliseo.h:182
#define KLS_PUSH_ARR(kls, type, count)
Macro used to request memory for an array of type values from a Koliseo.
Definition koliseo.h:515
Defines flags for Koliseo.
Definition koliseo.h:231
int growable
If set to 1, make the Koliseo grow when a out of memory for a push call.
Definition koliseo.h:238
int verbose_lvl
If > 0, makes the Koliseo try to acquire kls_log_fp from kls_log_filepath.
Definition koliseo.h:233
const char * log_filepath
String representing the path to the Koliseo logfile.
Definition koliseo.h:235
FILE * log_fp
FILE pointer used by the Koliseo to print its kls_log() output.
Definition koliseo.h:234
int allow_zerocount_push
If set to 1, make the Koliseo accept push calls with a count of 0.
Definition koliseo.h:237
int collect_stats
If set to 1, make the Koliseo collect performance stats.
Definition koliseo.h:232
KLS_Err_Handlers err_handlers
Used to pass custom error handlers for push calls.
Definition koliseo.h:239
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:236
Defines the handlers used for errors in push calls.
Definition koliseo.h:175
KLS_OOM_Handler * OOM_handler
Pointer to handler for Out-Of-Memory errors in push calls.
Definition koliseo.h:176
KLS_ZEROCOUNT_Handler * ZEROCOUNT_handler
Pointer to handler for zero-count errors in push calls.
Definition koliseo.h:178
KLS_PTRDIFF_MAX_Handler * PTRDIFF_MAX_handler
Pointer to handler for count > (PTRDIFF_MAX / size) errors in push calls.
Definition koliseo.h:177
Definition koliseo.h:199
KLS_hook_on_temp_start * on_temp_start_handler
Used to pass custom start handler for kls_temp_start calls.
Definition koliseo.h:203
KLS_hook_on_free * on_free_handler
Used to pass custom free handler for kls_free calls.
Definition koliseo.h:201
KLS_hook_on_temp_free * on_temp_free_handler
Used to pass custom free handler for kls_temp_end calls.
Definition koliseo.h:204
KLS_hook_on_push * on_push_handler
Used to pass custom push handler for kls_push calls.
Definition koliseo.h:202
KLS_hook_on_new * on_new_handler
Used to pass custom new handler for kls_new_alloc calls.
Definition koliseo.h:200
KLS_hook_on_temp_push * on_temp_push_handler
Used to pass custom push handler for kls_temp_push calls.
Definition koliseo.h:205
Defines the result for kls__advance() and kls__temp_advance().
Definition koliseo.h:384
KLS_Push_Error error
Definition koliseo.h:386
void * p
Definition koliseo.h:385
Defines a stat struct for Koliseo.
Definition koliseo.h:252
int tot_pops
Total POP calls done.
Definition koliseo.h:255
double worst_pushcall_time
Longest time taken by a PUSH call.
Definition koliseo.h:259
int tot_temp_pushes
Total PUSH_T calls done.
Definition koliseo.h:254
int tot_pushes
Total PUSH calls done.
Definition koliseo.h:253
int tot_temp_pops
Total POP_T calls done.
Definition koliseo.h:256
Represents a savestate for a Koliseo.
Definition koliseo.h:356
ptrdiff_t offset
Current position of memory pointer.
Definition koliseo.h:358
ptrdiff_t prev_offset
Previous position of memory pointer.
Definition koliseo.h:359
Koliseo * kls
Reference to the actual Koliseo we're saving.
Definition koliseo.h:357
Represents the initialised arena allocator struct.
Definition koliseo.h:317
ptrdiff_t size
Size of data field.
Definition koliseo.h:319
ptrdiff_t offset
Current position of memory pointer.
Definition koliseo.h:320
ptrdiff_t prev_offset
Previous position of memory pointer.
Definition koliseo.h:321
KLS_Conf conf
Contains flags to change the Koliseo behaviour.
Definition koliseo.h:323
struct Koliseo_Temp * t_kls
Points to related active Kolieo_Temp, when has_temp == 1.
Definition koliseo.h:325
KLS_Hooks hooks
Contains handlers for extensions.
Definition koliseo.h:326
char * data
Points to data field.
Definition koliseo.h:318
struct Koliseo * next
Points to the next Koliseo when conf.growable == 1.
Definition koliseo.h:330
void * extension_data
Points to data for extensions.
Definition koliseo.h:327
int has_temp
When == 1, a Koliseo_Temp is currently active on this Koliseo.
Definition koliseo.h:322
KLS_Stats stats
Contains stats for Koliseo performance analysis.
Definition koliseo.h:324
kls_free_func * free_func
Points to the free function for the arena's backing memory.
Definition koliseo.h:329