[master] 4e441176c Improve vmod developer docs for private pointers

Nils Goroll nils.goroll at uplex.de
Wed Jan 13 18:27:09 UTC 2021


commit 4e441176c6d27974ae21d8c41633c77b88b76a86
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Wed Jan 13 19:25:11 2021 +0100

    Improve vmod developer docs for private pointers
    
    See #3498 for an unresolved issue noticed on the way.

diff --git a/doc/sphinx/reference/vmod.rst b/doc/sphinx/reference/vmod.rst
index ee9d4f991..5e65edf16 100644
--- a/doc/sphinx/reference/vmod.rst
+++ b/doc/sphinx/reference/vmod.rst
@@ -492,6 +492,8 @@ The VCL compiler supports the following private pointers:
   These private pointers live only for the duration of their top
   level request
 
+  .. XXX BROKEN https://github.com/varnishcache/varnish-cache/issues/3498
+
 * ``PRIV_VCL`` "per vcl" private pointers are useful for such global
   state that applies to all calls in this VCL, for instance flags that
   determine if regular expressions are case-sensitive in this vmod or
@@ -499,6 +501,8 @@ The VCL compiler supports the following private pointers:
   to the VMOD's event function.
   This private pointer lives for the duration of the loaded VCL.
 
+  The ``PRIV_CALL`` vmod_privs are finalized before ``PRIV_VCL``.
+
 The way it works in the vmod code, is that a ``struct vmod_priv *`` is
 passed to the functions where one of the ``PRIV_*`` argument types is
 specified.
@@ -532,7 +536,7 @@ help debugging.
 vmod_priv`` when the scope ends with that ``.priv`` pointer as its
 only argument.
 
-In the common case where a private data structure is allocated with
+The common case where a private data structure is allocated with
 malloc(3) would look like this::
 
 	static const struct vmod_priv_methods mymethods[1] = {{
@@ -557,21 +561,88 @@ malloc(3) would look like this::
 		...
 	}
 
-Note on use with objects:
+Private Pointers Memory Management
+----------------------------------
+
+The generic malloc(3) / free(3) approach documented above works for
+all private pointers. It is the simplest and less error prone (as long
+as allocated memory is properly freed though the fini callback), but
+comes at the cost of calling into the heap memory allocator.
+
+Per-vmod constant data structures can be assigned to any private
+pointer type, but, obviously, free(3) must not be used on them.
+
+Dynamic data stored in ``PRIV_TASK`` and ``PRIV_TOP`` pointers can
+also come from the workspace:
+
+* For ``PRIV_TASK``, any allocation from ``ctx->ws`` works, like so::
+
+	if (priv->priv == NULL) {
+		priv->priv = WS_Alloc(ctx->ws, sizeof(struct myfoo));
+		if (priv->priv == NULL) {
+			VRT_fail(ctx, "WS_Alloc failed");
+			return (...);
+		}
+		priv->methods = mymethods;
+		mystate = priv->priv;
+		mystate->foo = 21;
+		...
+
+* For ``PRIV_TOP``, first of all keep in mind that it must only be
+  used from the client context, so vmod code should error out for
+  ``ctx->req == NULL``.
+
+  For dynamic data, the *top request's* workspace must be used, which
+  complicates things a bit::
+
+	if (priv->priv == NULL) {
+		struct ws *ws;
+
+		CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
+		CHECK_OBJ_NOTNULL(ctx->req->top, REQTOP_MAGIC);
+		CHECK_OBJ_NOTNULL(ctx->req->top->topreq, REQ_MAGIC);
+		ws = ctx->req->top->topreq->ws;
+
+		priv->priv = WS_Alloc(ws, sizeof(struct myfoo));
+		// ... same as above for PRIV_TASK
+
+Notice that allocations on the workspace do not need to be freed,
+their lifetime is the respective task.
 
-The per-call vmod_privs are freed before the per-vcl vmod_priv.
+Private Pointers and Objects
+----------------------------
 
-``PRIV_TASK`` and ``PRIV_TOP`` arguments are not per object instance,
-but still per vmod as for ordinary vmod functions. Thus, vmods
+``PRIV_TASK`` and ``PRIV_TOP`` arguments to methods are not per object
+instance, but per vmod as for ordinary vmod functions. Thus, vmods
 requiring per-task / per top-request state for object instances need
 to implement other means to associate storage with object instances.
 
-Using ``VRT_priv_task()`` to maintain per object instance state is a
-convenient yet unofficial interface which was not originally intended
-for this purpose and will likely be replaced with a more suitable
-interface.
+This is what ``VRT_priv_task()`` / ``VRT_priv_task_get()`` and
+``VRT_priv_top()`` / ``VRT_priv_top_get()`` are for:
+
+The non-get functions either return an existing ``PRIV_TASK`` /
+``PRIV_TOP`` for a given ``void *`` argument or create one. They
+return ``NULL`` in case of an allocation failure.
+
+The ``_get()`` functions do not create a ``PRIV_*``, but return either
+an existing one or ``NULL``.
+
+By convention, private pointers for object instance are created on the
+address of the object, as in this example for a ``PRIV_TASK``::
+
+  VCL_VOID
+  myvmod_obj_method(VRT_CTX, struct myvmod_obj *o)
+  {
+      struct vmod_priv *p;
+
+      p = VRT_priv_task(ctx, o);
+
+      // ... see above
 
-.. XXX add VRT_priv_task_get() and make it official?
+The ``PRIV_TOP`` case looks identical except for calling
+``VRT_priv_top(ctx, o)`` in place of ``VRT_priv_task(ctx, o)``, but be
+reminded that the ``VRT_priv_top*()`` functions must only be called
+from client context (if ``ctx->req != NULL``).
 
 .. _ref-vmod-event-functions:
 


More information about the varnish-commit mailing list