From ab9d2c6ca80bf1bc954899ef935a5e8f514c658e Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 8 Jan 2024 08:05:59 +0100 Subject: [PATCH] MINOR: applet: Add dedicated IN/OUT buffers for appctx It is the first patch of a series aimed to align applets on connections. Here, dedicated buffers are added for applets. For now, buffers are initialized and helpers function to deal with allocation are added. In addition, flags to report allocation failures or full buffers are also introduced. will be used to push data to the applet from the stream and will be used to push data from the applet to the stream. --- include/haproxy/applet-t.h | 8 ++++++++ include/haproxy/applet.h | 32 ++++++++++++++++++++++++++++++++ src/applet.c | 15 +++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/include/haproxy/applet-t.h b/include/haproxy/applet-t.h index bd96403c5..0ee4fbc34 100644 --- a/include/haproxy/applet-t.h +++ b/include/haproxy/applet-t.h @@ -31,6 +31,10 @@ /* flags for appctx->state */ #define APPLET_WANT_DIE 0x01 /* applet was running and requested to die */ +#define APPLET_INBLK_ALLOC 0x02 +#define APPLET_INBLK_FULL 0x04 +#define APPLET_OUTBLK_ALLOC 0x08 +#define APPLET_OUTBLK_FULL 0x10 /* Room for per-command context (mostly CLI commands but not only) */ #define APPLET_MAX_SVCCTX 88 @@ -60,6 +64,10 @@ struct appctx { unsigned short state; /* Internal appctx state */ unsigned int st0; /* CLI state for stats, session state for peers */ unsigned int st1; /* prompt/payload (bitwise OR of APPCTX_CLI_ST1_*) for stats, session error for peers */ + + struct buffer inbuf; + struct buffer outbuf; + struct buffer *chunk; /* used to store unfinished commands */ struct applet *applet; /* applet this context refers to */ struct session *sess; /* session for frontend applets (NULL for backend applets) */ diff --git a/include/haproxy/applet.h b/include/haproxy/applet.h index b04ffd95c..9cc50c305 100644 --- a/include/haproxy/applet.h +++ b/include/haproxy/applet.h @@ -58,6 +58,35 @@ static inline struct appctx *appctx_new_anywhere(struct applet *applet, struct s return appctx_new_on(applet, sedesc, -1); } + +/* + * Release a buffer, if any, and try to wake up entities waiting in the buffer + * wait queue. + */ +static inline void appctx_release_buf(struct appctx *appctx, struct buffer *bptr) +{ + if (bptr->size) { + b_free(bptr); + offer_buffers(appctx->buffer_wait.target, 1); + } +} + +/* + * Allocate a buffer. If if fails, it adds the appctx in buffer wait queue. + */ +static inline struct buffer *appctx_get_buf(struct appctx *appctx, struct buffer *bptr) +{ + struct buffer *buf = NULL; + + if (likely(!LIST_INLIST(&appctx->buffer_wait.list)) && + unlikely((buf = b_alloc(bptr)) == NULL)) { + appctx->buffer_wait.target = appctx; + appctx->buffer_wait.wakeup_cb = appctx_buf_available; + LIST_APPEND(&th_ctx->buffer_wq, &appctx->buffer_wait.list); + } + return buf; +} + /* Helper function to call .init applet callback function, if it exists. Returns 0 * on success and -1 on error. */ @@ -78,6 +107,9 @@ static inline int appctx_init(struct appctx *appctx) /* Releases an appctx previously allocated by appctx_new(). */ static inline void __appctx_free(struct appctx *appctx) { + appctx_release_buf(appctx, &appctx->inbuf); + appctx_release_buf(appctx, &appctx->outbuf); + task_destroy(appctx->t); if (LIST_INLIST(&appctx->buffer_wait.list)) LIST_DEL_INIT(&appctx->buffer_wait.list); diff --git a/src/applet.c b/src/applet.c index 5e6312efe..71e21c23d 100644 --- a/src/applet.c +++ b/src/applet.c @@ -232,6 +232,9 @@ struct appctx *appctx_new_on(struct applet *applet, struct sedesc *sedesc, int t appctx->t->process = task_run_applet; appctx->t->context = appctx; + appctx->inbuf = BUF_NULL; + appctx->outbuf = BUF_NULL; + LIST_INIT(&appctx->buffer_wait.list); appctx->buffer_wait.target = appctx; appctx->buffer_wait.wakeup_cb = appctx_buf_available; @@ -379,6 +382,18 @@ int appctx_buf_available(void *arg) struct appctx *appctx = arg; struct stconn *sc = appctx_sc(appctx); + if ((appctx->state & APPLET_INBLK_ALLOC) && b_alloc(&appctx->inbuf)) { + appctx->state &= ~APPLET_INBLK_ALLOC; + task_wakeup(appctx->t, TASK_WOKEN_RES); + return 1; + } + + if ((appctx->state & APPLET_OUTBLK_ALLOC) && b_alloc(&appctx->outbuf)) { + appctx->state &= ~APPLET_OUTBLK_ALLOC; + task_wakeup(appctx->t, TASK_WOKEN_RES); + return 1; + } + /* allocation requested ? */ if (!(sc->flags & SC_FL_NEED_BUFF)) return 0;