diff --git a/include/haproxy/applet.h b/include/haproxy/applet.h index 0bba054df..937fdbc75 100644 --- a/include/haproxy/applet.h +++ b/include/haproxy/applet.h @@ -64,6 +64,13 @@ static inline struct appctx *appctx_new_anywhere(struct applet *applet, struct c */ static inline int appctx_init(struct appctx *appctx) { + /* Set appctx affinity to the current thread. Because, after this call, + * the appctx will be fully initialized. The session and the stream will + * eventually be created. The affinity must be set now ! + */ + BUG_ON((appctx->t->thread_mask & tid_bit) == 0); + task_set_affinity(appctx->t, tid_bit); + if (appctx->applet->init) return appctx->applet->init(appctx); return 0; diff --git a/src/applet.c b/src/applet.c index 3c5ffb256..42d46f83f 100644 --- a/src/applet.c +++ b/src/applet.c @@ -35,8 +35,8 @@ struct appctx *appctx_new(struct applet *applet, struct cs_endpoint *endp, unsig { struct appctx *appctx; - /* Disable the feature for now ! */ - BUG_ON(thread_mask != tid_bit); + /* Backend appctx cannot be started on another thread than the local one */ + BUG_ON(thread_mask != tid_bit && endp); appctx = pool_zalloc(pool_head_appctx); if (unlikely(!appctx)) @@ -91,7 +91,10 @@ int appctx_finalize_startup(struct appctx *appctx, struct proxy *px, struct buff { struct session *sess; - BUG_ON(appctx->sess || !(appctx->endp->flags & CS_EP_ORPHAN)); + /* async startup is only possible for frontend appctx. Thus for orphan + * appctx. Because no backend appctx can be orphan. + */ + BUG_ON(!(appctx->endp->flags & CS_EP_ORPHAN)); sess = session_new(px, NULL, &appctx->obj_type); if (!sess) @@ -188,7 +191,7 @@ int appctx_buf_available(void *arg) struct task *task_run_applet(struct task *t, void *context, unsigned int state) { struct appctx *app = context; - struct conn_stream *cs = appctx_cs(app); + struct conn_stream *cs; unsigned int rate; size_t count; @@ -197,6 +200,21 @@ struct task *task_run_applet(struct task *t, void *context, unsigned int state) return NULL; } + if (app->endp->flags & CS_EP_ORPHAN) { + /* Finalize init of orphan appctx. .init callback function must + * be defined and it must finalize appctx startup. + */ + BUG_ON(!app->applet->init); + + if (appctx_init(app) == -1) { + appctx_free_on_early_error(app); + return NULL; + } + BUG_ON(!app->sess || !appctx_cs(app) || !appctx_strm(app)); + } + + cs = appctx_cs(app); + /* We always pretend the applet can't get and doesn't want to * put, it's up to it to change this if needed. This ensures * that one applet which ignores any event will not spin.