The applet ops provide callbacks for the applet lifecycle: an init callback
called before the applet starts processing, a shut callback called when one
side of the applet endpoint is shut, and a release callback called when both
sides are shut. But there is no callback called when the applet context is
destroyed, when its last user is released: the release callback may run long
before, while the stream attached to the applet is still alive, so the
applets holding references on objects used by their stream have no way to
know when to drop them.
Add a destroy callback to the applet ops, called by __appctx_free() when the
applet context is destroyed. It happens during the teardown of the stream
attached to the applet (from sc_destroy(), inside stream_free()). So this is
guaranteed to be after the last run of the stream, even if it was requeued
instead of being immediately freed.
size_t (*fastfwd)(struct appctx *appctx, struct buffer *buf, size_t count, unsigned int flags); /* Callback to fast-forward data */
void (*shut)(struct appctx *appctx, unsigned int mode, struct se_abort_info *reason); /* shutdown function */
void (*release)(struct appctx *); /* callback to release resources, may be NULL */
+ void (*destroy)(struct appctx *); /* callback called when the appctx is destroyed,
+ may be NULL. Called by __appctx_free(),
+ after the last stream using this applet was
+ released. */
unsigned int timeout; /* execution timeout. */
};
/* Releases an appctx previously allocated by appctx_new(). */
static inline void __appctx_free(struct appctx *appctx)
{
+ /* Let the applet release the resources bound to the applet context,
+ * before it is released.
+ */
+ if (appctx->applet->destroy)
+ CALL_APPLET_NO_RET(appctx->applet, destroy(appctx));
+
appctx_release_buf(appctx, &appctx->inbuf);
appctx_release_buf(appctx, &appctx->outbuf);