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. <inbuf> will be used to push data to the applet from the stream
and <outbuf> will be used to push data from the applet to the stream.
/* 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
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) */
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.
*/
/* 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);
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;
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;