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 | |
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')
-rw-r--r-- | lib/liboda/include/liboda/oda.h | 6 | ||||
-rw-r--r-- | lib/liboda/include/liboda/types.h | 1 | ||||
-rw-r--r-- | lib/liboda/src/window.c | 150 |
3 files changed, 153 insertions, 4 deletions
diff --git a/lib/liboda/include/liboda/oda.h b/lib/liboda/include/liboda/oda.h index 10738a9..13474d5 100644 --- a/lib/liboda/include/liboda/oda.h +++ b/lib/liboda/include/liboda/oda.h @@ -40,10 +40,12 @@ /* * ODA representation of a window. * + * @wid: Window ID (identifies the window) * @surface: Window surface descriptor * @session: Session this window belongs to */ struct oda_window { + odawid_t wid; struct gfx_shape surface; struct oda_state *session; TAILQ_ENTRY(oda_window) link; @@ -99,9 +101,11 @@ struct oda_point { int oda_reqwin(struct oda_wattr *params, struct oda_window **res); int oda_termwin(struct oda_state *state, struct oda_window *win); -int oda_plotwin(struct oda_state *state, const struct oda_point *point); +int oda_plotwin(struct oda_state *state, const struct oda_point *point); int oda_start_win(struct oda_state *state, struct oda_window *win); + int oda_init(struct oda_state *res); +int oda_shutdown(struct oda_state *state); #endif /* !LIBODA_ODA_H */ diff --git a/lib/liboda/include/liboda/types.h b/lib/liboda/include/liboda/types.h index 8b77aa7..ec12330 100644 --- a/lib/liboda/include/liboda/types.h +++ b/lib/liboda/include/liboda/types.h @@ -36,5 +36,6 @@ typedef uint32_t odapos_t; /* X/Y positions */ typedef uint32_t odapix_t; /* RGB pixel */ typedef odapix_t odacolor_t; /* RGB color */ typedef uint32_t odadimm_t; /* Dimensions */ +typedef uint32_t odawid_t; /* Window ID */ #endif /* !LIBODA_TYPE_H */ 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(); +} |