diff options
author | Ian Moffett <ian@osmora.org> | 2025-08-04 01:03:43 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-08-04 01:14:14 -0400 |
commit | 14b9fc0a5f3dfb22adae90dd61961682eaf50931 (patch) | |
tree | 6ba51157affea23daa5243071bd1de3fb1e09ae8 /lib/liboda/src | |
parent | c416178fb23943c35e0f32f7447ab4c59b4f6a70 (diff) |
liboda: Add window cache
Implement a window cache to avoid the overhead of back-to-back calls for
malloc() and free. This commit additionally introduces a new
oda_shutdown() function for cleaning up the library.
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'lib/liboda/src')
-rw-r--r-- | lib/liboda/src/window.c | 150 |
1 files changed, 147 insertions, 3 deletions
diff --git a/lib/liboda/src/window.c b/lib/liboda/src/window.c index 9a8b799..8e91fac 100644 --- a/lib/liboda/src/window.c +++ b/lib/liboda/src/window.c @@ -28,6 +28,7 @@ */ #include <sys/errno.h> +#include <sys/queue.h> #include <stdlib.h> #include <string.h> #include <liboda/oda.h> @@ -36,6 +37,113 @@ #include <libgfx/gfx.h> /* + * The window cache is used to reduce how many + * calls to malloc() and free() are made during + * window creation and destruction. + */ +static TAILQ_HEAD(, oda_window) wcache; +static uint32_t wcache_cookie = 0; +static odawid_t next_wid = 1; + +/* + * Pop a window from the window cache. + * Returns NULL there are no more windows. + */ +static struct oda_window * +oda_window_pop(void) +{ + struct oda_window *wdp; + + if (wcache_cookie != ODA_COOKIE) { + TAILQ_INIT(&wcache); + wcache_cookie = ODA_COOKIE; + return NULL; + } + + wdp = TAILQ_FIRST(&wcache); + TAILQ_REMOVE(&wcache, wdp, link); + return wdp; +} + +/* + * Place a window into the window cache. + */ +static void +oda_window_cache(struct oda_window *wdp) +{ + /* Ensure arg is valid */ + if (wdp == NULL) { + return; + } + + if (wcache_cookie != ODA_COOKIE) { + TAILQ_INIT(&wcache); + wcache_cookie = ODA_COOKIE; + } + + TAILQ_INSERT_TAIL(&wcache, wdp, link); +} + +/* + * Allocate an ODP window + * + * Returns NULL on failure + */ +static struct oda_window * +oda_window_alloc(void) +{ + struct oda_window *wdp; + + /* + * First check if there are any entries + * we can grab from the window cache. + */ + wdp = oda_window_pop(); + if (wdp != NULL) { + return wdp; + } + + /* Allocate a new window */ + wdp = malloc(sizeof(*wdp)); + if (wdp == NULL) { + return NULL; + } + + memset(wdp, 0, sizeof(*wdp)); + wdp->wid = next_wid++; + return wdp; +} + +/* + * Release a given ODA window descriptor + * + * @wdp: Window to free + */ +static void +oda_window_release(struct oda_state *state, struct oda_window *wdp) +{ + if (wdp == NULL) { + return; + } + + /* + * It is probably a good idea to ensure previous + * state other than the old window ID is reset + * and zeroed. + */ + wdp->session = NULL; + memset(&wdp->surface, 0, sizeof(wdp->surface)); + + /* + * Now we can remove this window from the list + * of windows we are tracking and add it to the + * cache. + */ + TAILQ_REMOVE(&state->winq, wdp, link); + oda_window_cache(wdp); +} + +/* * Check if a point is within the bounds of * a surface. * @@ -78,6 +186,34 @@ oda_check_point(struct oda_window *wp, struct oda_point *point) } /* + * Clean up after ourselves and release + * each entry of the wcache. + * + * Returns 0 on success. + */ +static int +oda_free_wcache(void) +{ + struct oda_window *wdp, *next; + + if (wcache_cookie != ODA_COOKIE) { + return -1; + } + + /* + * Go through each entry and call free() + * on them. + */ + wdp = TAILQ_FIRST(&wcache); + while (wdp != NULL) { + next = TAILQ_NEXT(wdp, link); + free(wdp); + wdp = next; + } + return 0; +} + +/* * Plot a pixel onto a window * * @state: ODA state pointer @@ -176,7 +312,7 @@ oda_reqwin(struct oda_wattr *params, struct oda_window **res) } /* Allocate a new window */ - wp = malloc(sizeof(*wp)); + wp = oda_window_alloc(); if (wp == NULL) { return -ENOMEM; } @@ -255,7 +391,15 @@ oda_termwin(struct oda_state *state, struct oda_window *win) return error; } - TAILQ_REMOVE(&state->winq, win, link); - free(win); + oda_window_release(state, win); return 0; } + +/* + * Shutdown the ODA library + */ +int +oda_shutdown(struct oda_state *state) +{ + return oda_free_wcache(); +} |