[master] c1f19f9 Add an offline, default-off lock-order "Witness" facility, to make sure I have not added any other lock-order reversals.

Poul-Henning Kamp phk at FreeBSD.org
Tue Jul 7 11:41:13 CEST 2015


commit c1f19f98c37f878a1846b6209c358f22e7eb5118
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Tue Jul 7 09:36:17 2015 +0000

    Add an offline, default-off lock-order "Witness" facility, to make sure
    I have not added any other lock-order reversals.

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index b96d765..522fad2 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -849,6 +849,7 @@ unsigned HTTP1_Write(const struct worker *w, const struct http *hp, const int*);
 #define VXID(u) ((u) & VSL_IDENTMASK)
 uint32_t VXID_Get(struct worker *, uint32_t marker);
 extern volatile struct params * cache_param;
+extern pthread_key_t witness_key;
 void THR_SetName(const char *name);
 const char* THR_GetName(void);
 void THR_SetBusyobj(const struct busyobj *);
@@ -859,9 +860,9 @@ struct req * THR_GetRequest(void);
 /* cache_lck.c */
 
 /* Internal functions, call only through macros below */
-void Lck__Lock(struct lock *lck, const char *p, const char *f, int l);
-void Lck__Unlock(struct lock *lck, const char *p, const char *f, int l);
-int Lck__Trylock(struct lock *lck, const char *p, const char *f, int l);
+void Lck__Lock(struct lock *lck, const char *p,  int l);
+void Lck__Unlock(struct lock *lck, const char *p,  int l);
+int Lck__Trylock(struct lock *lck, const char *p,  int l);
 void Lck__New(struct lock *lck, struct VSC_C_lck *, const char *);
 void Lck__Assert(const struct lock *lck, int held);
 
@@ -871,9 +872,9 @@ void Lck_Delete(struct lock *lck);
 int Lck_CondWait(pthread_cond_t *cond, struct lock *lck, double);
 
 #define Lck_New(a, b) Lck__New(a, b, #b)
-#define Lck_Lock(a) Lck__Lock(a, __func__, __FILE__, __LINE__)
-#define Lck_Unlock(a) Lck__Unlock(a, __func__, __FILE__, __LINE__)
-#define Lck_Trylock(a) Lck__Trylock(a, __func__, __FILE__, __LINE__)
+#define Lck_Lock(a) Lck__Lock(a, __func__, __LINE__)
+#define Lck_Unlock(a) Lck__Unlock(a, __func__, __LINE__)
+#define Lck_Trylock(a) Lck__Trylock(a, __func__, __LINE__)
 #define Lck_AssertHeld(a) Lck__Assert(a, 1)
 
 #define LOCK(nam) extern struct VSC_C_lck *lck_##nam;
diff --git a/bin/varnishd/cache/cache_lck.c b/bin/varnishd/cache/cache_lck.c
index caac924..c623ab7 100644
--- a/bin/varnishd/cache/cache_lck.c
+++ b/bin/varnishd/cache/cache_lck.c
@@ -37,6 +37,7 @@
 
 #include <errno.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "cache.h"
 
@@ -59,16 +60,63 @@ static VTAILQ_HEAD(, ilck)	ilck_head = VTAILQ_HEAD_INITIALIZER(ilck_head);
 
 static pthread_mutex_t		lck_mtx;
 
+/*--------------------------------------------------------------------*/
+
+static void
+Lck_Witness_Lock(const struct ilck *il, const char *p, int l, const char *try)
+{
+	char *q, t[10];
+	int emit;
+
+	AN(p);
+	q = pthread_getspecific(witness_key);
+	if (q == NULL) {
+		q = calloc(1, 1024);
+		AN(q);
+		AZ(pthread_setspecific(witness_key, q));
+	}
+	emit = *q != '\0';
+	strcat(q, " ");
+	strcat(q, il->w);
+	strcat(q, try);
+	strcat(q, ",");
+	strcat(q, p);
+	strcat(q, ",");
+	bprintf(t, "%d", l);
+	strcat(q, t);
+	if (emit)
+		VSL(SLT_Witness, 0, "%s", q);
+}
+
+static void
+Lck_Witness_Unlock(const struct ilck *il)
+{
+	char *q, *r;
+
+	q = pthread_getspecific(witness_key);
+	if (q == NULL)
+		return;
+	r = strrchr(q, ' ');
+	if (r == NULL)
+		r = q;
+	else
+		*r++ = '\0';
+	if (memcmp(r, il->w, strlen(il->w)))
+		VSL(SLT_Witness, 0, "Unlock %s @ %s <%s>", il->w, r, q);
+	else
+		*r = '\0';
+}
+
+/*--------------------------------------------------------------------*/
+
 void __match_proto__()
-Lck__Lock(struct lock *lck, const char *p, const char *f, int l)
+Lck__Lock(struct lock *lck, const char *p, int l)
 {
 	struct ilck *ilck;
 
-	(void)p;
-	(void)f;
-	(void)l;
-
 	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	if (DO_DEBUG(DBG_WITNESS))
+		Lck_Witness_Lock(ilck, p, l, "");
 	AZ(pthread_mutex_lock(&ilck->mtx));
 	AZ(ilck->held);
 	ilck->stat->locks++;
@@ -77,12 +125,11 @@ Lck__Lock(struct lock *lck, const char *p, const char *f, int l)
 }
 
 void __match_proto__()
-Lck__Unlock(struct lock *lck, const char *p, const char *f, int l)
+Lck__Unlock(struct lock *lck, const char *p, int l)
 {
 	struct ilck *ilck;
 
 	(void)p;
-	(void)f;
 	(void)l;
 
 	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
@@ -101,19 +148,19 @@ Lck__Unlock(struct lock *lck, const char *p, const char *f, int l)
 	 */
 	memset(&ilck->owner, 0, sizeof ilck->owner);
 	AZ(pthread_mutex_unlock(&ilck->mtx));
+	if (DO_DEBUG(DBG_WITNESS))
+		Lck_Witness_Unlock(ilck);
 }
 
 int __match_proto__()
-Lck__Trylock(struct lock *lck, const char *p, const char *f, int l)
+Lck__Trylock(struct lock *lck, const char *p, int l)
 {
 	struct ilck *ilck;
 	int r;
 
-	(void)p;
-	(void)f;
-	(void)l;
-
 	CAST_OBJ_NOTNULL(ilck, lck->priv, ILCK_MAGIC);
+	if (DO_DEBUG(DBG_WITNESS))
+		Lck_Witness_Lock(ilck, p, l, "?");
 	r = pthread_mutex_trylock(&ilck->mtx);
 	assert(r == 0 || r == EBUSY);
 	if (r == 0) {
diff --git a/bin/varnishd/cache/cache_main.c b/bin/varnishd/cache/cache_main.c
index cb5175a..f95bc77 100644
--- a/bin/varnishd/cache/cache_main.c
+++ b/bin/varnishd/cache/cache_main.c
@@ -51,6 +51,7 @@ volatile struct params	*cache_param;
 
 static pthread_key_t req_key;
 static pthread_key_t bo_key;
+pthread_key_t witness_key;
 
 void
 THR_SetBusyobj(const struct busyobj *bo)
@@ -199,6 +200,7 @@ child_main(void)
 
 	AZ(pthread_key_create(&req_key, NULL));
 	AZ(pthread_key_create(&bo_key, NULL));
+	AZ(pthread_key_create(&witness_key, NULL));
 	AZ(pthread_key_create(&name_key, NULL));
 
 	THR_SetName("cache-main");
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index 17b5790..f2817d8 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -70,6 +70,7 @@ extern int vtc_stop;		/* Abandon current test, no error */
 extern pthread_t	vtc_thread;
 extern int iflg;
 extern unsigned vtc_maxdur;
+extern int vtc_witness;
 
 void init_sema(void);
 void init_server(void);
diff --git a/bin/varnishtest/vtc_main.c b/bin/varnishtest/vtc_main.c
index a2b34e0..ce50c6b 100644
--- a/bin/varnishtest/vtc_main.c
+++ b/bin/varnishtest/vtc_main.c
@@ -88,6 +88,7 @@ static int vtc_fail;
 static int leave_temp;
 static char *tmppath;
 static char *cwd = NULL;
+int vtc_witness = 0;
 
 /**********************************************************************
  * Parse a -D option argument into a name/val pair, and insert
@@ -414,7 +415,7 @@ main(int argc, char * const *argv)
 
 	setbuf(stdout, NULL);
 	setbuf(stderr, NULL);
-	while ((ch = getopt(argc, argv, "D:ij:klLn:qt:v")) != -1) {
+	while ((ch = getopt(argc, argv, "D:ij:klLn:qt:vW")) != -1) {
 		switch (ch) {
 		case 'D':
 			if (!parse_D_opt(optarg)) {
@@ -452,6 +453,9 @@ main(int argc, char * const *argv)
 			if (vtc_verbosity < 2)
 				vtc_verbosity++;
 			break;
+		case 'W':
+			vtc_witness++;
+			break;
 		default:
 			usage();
 		}
diff --git a/bin/varnishtest/vtc_varnish.c b/bin/varnishtest/vtc_varnish.c
index c6cb52f..ce666e3 100644
--- a/bin/varnishtest/vtc_varnish.c
+++ b/bin/varnishtest/vtc_varnish.c
@@ -394,6 +394,8 @@ varnish_launch(struct varnish *v)
 	VSB_printf(vsb, "cd ${pwd} &&");
 	VSB_printf(vsb, " exec ${varnishd} %s -d -n %s",
 	    v->jail, v->workdir);
+	if (vtc_witness)
+		VSB_cat(vsb, " -p debug=+witness");
 	VSB_printf(vsb, " -l 2m,1m,-");
 	VSB_printf(vsb, " -p auto_restart=off");
 	VSB_printf(vsb, " -p syslog_cli_traffic=off");
diff --git a/bin/varnishtest/witness.py b/bin/varnishtest/witness.py
new file mode 100644
index 0000000..081429e
--- /dev/null
+++ b/bin/varnishtest/witness.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+#
+# This script is in the public domain
+#
+# Run instructions:
+#	varnishtest -W -iv -j <pick_a_number> > _.w
+#	python witness.py
+#	dot -Tpng /tmp/_.dot > /tmp/_.png
+
+from __future__ import print_function
+
+d = dict()
+a = dict()
+
+fi = open("_w")
+fo = open("/tmp/_.dot", "w")
+
+fo.write('''digraph {
+	#rotate="90"
+	#page="8.2,11.7"
+	size="8.2,11.7"
+	rankdir="LR"
+	node [fontname="Inconsolata", fontsize="10"]
+	edge [fontname="Inconsolata", fontsize="10"]
+''')
+
+for i in fi:
+	l = "ROOT"
+	j = i.split()
+	if len(j) < 8:
+		continue
+	if j[1][0] != 'v':
+		continue
+	if j[3] != "vsl|":
+		continue
+	if j[5] != "Witness":
+		continue
+	t = j[7:]
+	tt = str(t)
+	if tt in d:
+		continue
+	d[tt] = True
+	for e in t:
+		f = e.split(",")
+		x = '"%s" -> "%s" [label="%s(%s)"]\n' % (l, f[0], f[1], f[2])
+		if not x in a:
+			a[x] = True
+			fo.write(x)
+		l = f[0]
+
+fo.write("}\n")
+	
diff --git a/doc/sphinx/phk/brinch-hansens-arrows.rst b/doc/sphinx/phk/brinch-hansens-arrows.rst
new file mode 100644
index 0000000..cba1f44
--- /dev/null
+++ b/doc/sphinx/phk/brinch-hansens-arrows.rst
@@ -0,0 +1,60 @@
+.. _phk_brinch_hansens_arrows:
+
+=====================
+Brinch-Hansens Arrows
+=====================
+
+As you may have noticed, I am a bit of a IT-history nerd, and we do have
+some rather important early IT history in Denmark.
+
+If you have a solid CS background, you have undoubtedly heard about
+both dining philosophers and Brinch-Hansens work in multiprogramming.
+
+Multiprogramming is fundamentally hard, because you cannot have one
+thread holding lock A trying to get lock B, while another holds
+lock B trying to get lock A.
+
+Brinch-Hansen did a lot of both theoretical and practical work in the
+area of multiprogramming and being both good at it and one of the
+pioneers, he was awardede the ACM Turing Prize for it.
+
+You can read more about him here:
+`Brinch-Hansen Archive <http://brinch-hansen.net/>`_
+
+Along the way he came up with a trivial and practical way to guarantee
+that a given multiprogramming system was free of deadlocks:  Draw
+the locking order and make sure all the arrows point to the right.
+
+When we started working with multi-core systems in FreeBSD, we were
+sure to have deadlocks in our future, and we adobted and expanded
+a facility called "WITNESS" originally written for BSDI, which
+keeps an eye on Brinch-Hansens arrows in real time.
+
+Historically I have been pretty good at avoiding deadlocks, it seems
+to come natural to me to think about locking order, but not everybody
+feels that way about them, and WITNESS have caught a lot of "Ohh,
+didn't think about *that*" situations over the years.
+
+It is no accident that Varnish has a very simple locking structure,
+but as we add more and more flexibility and extensibility to Varnish
+it grows a little here and there, and I managed to introduce a
+lock-order reversal the other day - my first in about five years I
+think.
+
+Since I'm obviously getting old and slipping up here, I though it
+was about time I carried out the Brinch-Hansen check on Varnish.
+
+I briefly pondered porting WITNESS into Varnish, but it's 3k lines
+and we have extremely good code coverage in our regression tests
+so I decided to KISS and do it as post-processing.
+
+I have added default-off debug code to emit VSL "Witness" records,
+taught varnishtest how to enable that code, and added a small python
+script to process the records into a nice plot:
+
+.. image:: brinch_hansens_arrows_1.svg
+
+And yo and behold:  All the arrows point to the right.
+
+*phk*
+
diff --git a/doc/sphinx/phk/brinch_hansens_arrows_1.svg b/doc/sphinx/phk/brinch_hansens_arrows_1.svg
new file mode 100644
index 0000000..86e47e5
--- /dev/null
+++ b/doc/sphinx/phk/brinch_hansens_arrows_1.svg
@@ -0,0 +1,381 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: %3 Pages: 1 -->
+<svg width="590pt" height="621pt"
+ viewBox="0.00 0.00 590.00 621.05" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(0.548343 0.548343) rotate(0) translate(4 1128.59)">
+<title>%3</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-1128.59 1071.97,-1128.59 1071.97,4 -4,4"/>
+<!-- ROOT -->
+<g id="node1" class="node"><title>ROOT</title>
+<ellipse fill="none" stroke="black" cx="27" cy="-776.588" rx="27" ry="18"/>
+<text text-anchor="middle" x="27" y="-774.088" font-family="Inconsolata" font-size="10.00">ROOT</text>
+</g>
+<!-- lck_cli -->
+<g id="node2" class="node"><title>lck_cli</title>
+<ellipse fill="none" stroke="black" cx="251" cy="-446.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="251" y="-444.088" font-family="Inconsolata" font-size="10.00">lck_cli</text>
+</g>
+<!-- ROOT->lck_cli -->
+<g id="edge1" class="edge"><title>ROOT->lck_cli</title>
+<path fill="none" stroke="black" d="M35.1396,-759.108C43.1387,-740.2 56.9688,-709.431 72,-684.588 122.333,-601.401 195.011,-511.726 229.867,-470.187"/>
+<polygon fill="black" stroke="black" points="232.547,-472.439 236.316,-462.537 227.195,-467.927 232.547,-472.439"/>
+<text text-anchor="middle" x="127.5" y="-687.588" font-family="Inconsolata" font-size="10.00">cli_cb_before(81)</text>
+</g>
+<!-- lck_vbe -->
+<g id="node3" class="node"><title>lck_vbe</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-174.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="522" y="-172.088" font-family="Inconsolata" font-size="10.00">lck_vbe</text>
+</g>
+<!-- ROOT->lck_vbe -->
+<g id="edge48" class="edge"><title>ROOT->lck_vbe</title>
+<path fill="none" stroke="black" d="M28.1836,-758.48C29.3313,-658.683 36.6691,-178.292 72,-123.588 164.89,20.2365 302.534,30.6867 451,-54.5879 485.274,-74.2736 504.352,-117.929 513.645,-146.8"/>
+<polygon fill="black" stroke="black" points="510.392,-148.136 516.635,-156.696 517.093,-146.111 510.392,-148.136"/>
+<text text-anchor="middle" x="251" y="-16.5879" font-family="Inconsolata" font-size="10.00">VBE_Delete(172)</text>
+</g>
+<!-- lck_exp -->
+<g id="node5" class="node"><title>lck_exp</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-1079.59" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="522" y="-1077.09" font-family="Inconsolata" font-size="10.00">lck_exp</text>
+</g>
+<!-- ROOT->lck_exp -->
+<g id="edge5" class="edge"><title>ROOT->lck_exp</title>
+<path fill="none" stroke="black" d="M28.32,-794.654C29.6706,-848.534 36.6296,-1006.48 72,-1040.59 185.387,-1149.93 398.108,-1111.42 483.812,-1089.98"/>
+<polygon fill="black" stroke="black" points="484.804,-1093.34 493.619,-1087.46 483.063,-1086.56 484.804,-1093.34"/>
+<text text-anchor="middle" x="251" y="-1116.59" font-family="Inconsolata" font-size="10.00">exp_thread(588)</text>
+</g>
+<!-- lck_backend -->
+<g id="node7" class="node"><title>lck_backend</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-242.588" rx="43.6222" ry="18"/>
+<text text-anchor="middle" x="522" y="-240.088" font-family="Inconsolata" font-size="10.00">lck_backend</text>
+</g>
+<!-- ROOT->lck_backend -->
+<g id="edge8" class="edge"><title>ROOT->lck_backend</title>
+<path fill="none" stroke="black" d="M28.8689,-758.589C34.3585,-667.862 72.5475,-259.596 319,-121.588 370.187,-92.9241 405.189,-84.9392 451,-121.588 479.458,-144.355 449.573,-170.753 469,-201.588 473.801,-209.208 480.534,-216.004 487.566,-221.767"/>
+<polygon fill="black" stroke="black" points="485.775,-224.801 495.861,-228.045 489.999,-219.219 485.775,-224.801"/>
+<text text-anchor="middle" x="251" y="-219.588" font-family="Inconsolata" font-size="10.00">vbe_dir_finish(185)</text>
+</g>
+<!-- ROOT->lck_backend -->
+<g id="edge26" class="edge"><title>ROOT->lck_backend</title>
+<path fill="none" stroke="black" d="M27.8413,-758.449C27.3726,-676.363 28.1992,-339.605 72,-245.588 106.108,-172.375 129.315,-154.8 201,-117.588 299.963,-66.2157 365.755,-24.7127 451,-96.5879 487.198,-127.108 444.801,-160.892 469,-201.588 473.603,-209.329 480.259,-216.173 487.28,-221.942"/>
+<polygon fill="black" stroke="black" points="485.498,-224.982 495.589,-228.211 489.714,-219.394 485.498,-224.982"/>
+<text text-anchor="middle" x="251" y="-120.588" font-family="Inconsolata" font-size="10.00">vbp_thread(361)</text>
+</g>
+<!-- lck_objhdr -->
+<g id="node10" class="node"><title>lck_objhdr</title>
+<ellipse fill="none" stroke="black" cx="251" cy="-838.588" rx="40.7358" ry="18"/>
+<text text-anchor="middle" x="251" y="-836.088" font-family="Inconsolata" font-size="10.00">lck_objhdr</text>
+</g>
+<!-- ROOT->lck_objhdr -->
+<g id="edge14" class="edge"><title>ROOT->lck_objhdr</title>
+<path fill="none" stroke="black" d="M39.0133,-793.137C46.886,-803.494 58.4576,-816.069 72,-822.588 112.376,-842.024 163.847,-844.622 201.044,-843.195"/>
+<polygon fill="black" stroke="black" points="201.321,-846.686 211.136,-842.697 200.975,-839.695 201.321,-846.686"/>
+<text text-anchor="middle" x="127.5" y="-845.588" font-family="Inconsolata" font-size="10.00">hcb_deref(401)</text>
+</g>
+<!-- ROOT->lck_objhdr -->
+<g id="edge18" class="edge"><title>ROOT->lck_objhdr</title>
+<path fill="none" stroke="black" d="M52.1201,-783.536C58.5539,-785.288 65.519,-787.094 72,-788.588 120.925,-799.869 135.001,-794.859 183,-809.588 193.284,-812.744 204.114,-816.995 213.997,-821.268"/>
+<polygon fill="black" stroke="black" points="212.575,-824.466 223.134,-825.336 215.422,-818.071 212.575,-824.466"/>
+<text text-anchor="middle" x="127.5" y="-812.588" font-family="Inconsolata" font-size="10.00">hcl_lookup(141)</text>
+</g>
+<!-- ROOT->lck_objhdr -->
+<g id="edge23" class="edge"><title>ROOT->lck_objhdr</title>
+<path fill="none" stroke="black" d="M52.6661,-770.932C84.1502,-764.923 139.72,-758.436 183,-775.588 202.357,-783.259 219.379,-799.463 231.421,-813.515"/>
+<polygon fill="black" stroke="black" points="228.877,-815.933 237.917,-821.46 234.297,-811.503 228.877,-815.933"/>
+<text text-anchor="middle" x="127.5" y="-778.588" font-family="Inconsolata" font-size="10.00">hcb_lookup(438)</text>
+</g>
+<!-- ROOT->lck_objhdr -->
+<g id="edge44" class="edge"><title>ROOT->lck_objhdr</title>
+<path fill="none" stroke="black" d="M44.8614,-762.668C52.6245,-757.137 62.2634,-751.423 72,-748.588 119.366,-734.795 138.914,-726.447 183,-748.588 208.964,-761.628 227.417,-790.025 238.298,-811.457"/>
+<polygon fill="black" stroke="black" points="235.272,-813.242 242.764,-820.734 241.58,-810.206 235.272,-813.242"/>
+<text text-anchor="middle" x="127.5" y="-751.588" font-family="Inconsolata" font-size="10.00">HSH_Unbusy(702)</text>
+</g>
+<!-- ROOT->lck_objhdr -->
+<g id="edge47" class="edge"><title>ROOT->lck_objhdr</title>
+<path fill="none" stroke="black" d="M32.0927,-794.333C37.5737,-813.534 49.3503,-843.196 72,-856.588 114.951,-881.983 174.089,-868.419 212.186,-854.79"/>
+<polygon fill="black" stroke="black" points="213.732,-857.948 221.869,-851.163 211.277,-851.393 213.732,-857.948"/>
+<text text-anchor="middle" x="127.5" y="-873.588" font-family="Inconsolata" font-size="10.00">HSH_DerefObjCore(778)</text>
+</g>
+<!-- lck_ban -->
+<g id="node12" class="node"><title>lck_ban</title>
+<ellipse fill="none" stroke="black" cx="756.923" cy="-825.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="756.923" y="-823.088" font-family="Inconsolata" font-size="10.00">lck_ban</text>
+</g>
+<!-- ROOT->lck_ban -->
+<g id="edge37" class="edge"><title>ROOT->lck_ban</title>
+<path fill="none" stroke="black" d="M28.5225,-795.048C30.3463,-826.565 38.2603,-891.249 72,-931.588 112.936,-980.531 139.2,-978.717 201,-994.588 304.759,-1021.24 598.951,-1053.01 683,-986.588 725.18,-953.254 743.781,-890.136 751.321,-853.615"/>
+<polygon fill="black" stroke="black" points="754.79,-854.113 753.243,-843.631 747.916,-852.789 754.79,-854.113"/>
+<text text-anchor="middle" x="385" y="-1027.59" font-family="Inconsolata" font-size="10.00">ban_lurker_getfirst(1019)</text>
+</g>
+<!-- lck_lru -->
+<g id="node13" class="node"><title>lck_lru</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-778.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="522" y="-776.088" font-family="Inconsolata" font-size="10.00">lck_lru</text>
+</g>
+<!-- ROOT->lck_lru -->
+<g id="edge34" class="edge"><title>ROOT->lck_lru</title>
+<path fill="none" stroke="black" d="M38.4883,-760.097C46.2856,-749.479 57.9758,-736.58 72,-730.588 117.366,-711.204 133.72,-728.294 183,-730.588 302.499,-736.149 333.882,-731.208 451,-755.588 462.602,-758.003 474.974,-761.682 486.039,-765.394"/>
+<polygon fill="black" stroke="black" points="485.179,-768.801 495.774,-768.777 487.477,-762.189 485.179,-768.801"/>
+<text text-anchor="middle" x="251" y="-737.588" font-family="Inconsolata" font-size="10.00">EXP_NukeOne(333)</text>
+</g>
+<!-- lck_smp -->
+<g id="node16" class="node"><title>lck_smp</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-980.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="522" y="-978.088" font-family="Inconsolata" font-size="10.00">lck_smp</text>
+</g>
+<!-- ROOT->lck_smp -->
+<g id="edge40" class="edge"><title>ROOT->lck_smp</title>
+<path fill="none" stroke="black" d="M30.5203,-794.681C34.8089,-818.734 45.7693,-861.053 72,-885.588 187.63,-993.743 394.281,-991.233 480.98,-984.693"/>
+<polygon fill="black" stroke="black" points="481.504,-988.162 491.187,-983.862 480.936,-981.186 481.504,-988.162"/>
+<text text-anchor="middle" x="251" y="-982.588" font-family="Inconsolata" font-size="10.00">smp_open(328)</text>
+</g>
+<!-- lck_cli->lck_vbe -->
+<g id="edge2" class="edge"><title>lck_cli->lck_vbe</title>
+<path fill="none" stroke="black" d="M253.11,-428.434C257.195,-368.415 273.584,-178.111 319,-141.588 368.791,-101.548 448.29,-134.033 491.202,-156.917"/>
+<polygon fill="black" stroke="black" points="489.581,-160.02 500.031,-161.767 492.951,-153.885 489.581,-160.02"/>
+<text text-anchor="middle" x="385" y="-144.588" font-family="Inconsolata" font-size="10.00">VRT_new_backend(100)</text>
+</g>
+<!-- lck_cli->lck_vbe -->
+<g id="edge12" class="edge"><title>lck_cli->lck_vbe</title>
+<path fill="none" stroke="black" d="M251.409,-428.369C251.055,-384.62 256.653,-273.018 319,-215.588 324.993,-210.067 424.736,-191.644 481.776,-181.475"/>
+<polygon fill="black" stroke="black" points="482.663,-184.872 491.897,-179.677 481.439,-177.98 482.663,-184.872"/>
+<text text-anchor="middle" x="385" y="-218.588" font-family="Inconsolata" font-size="10.00">backend_find(243)</text>
+</g>
+<!-- lck_cli->lck_vbe -->
+<g id="edge30" class="edge"><title>lck_cli->lck_vbe</title>
+<path fill="none" stroke="black" d="M253.612,-428.391C258.969,-372.568 278.199,-205.587 319,-173.588 343.333,-154.505 429.999,-162.188 481.572,-168.816"/>
+<polygon fill="black" stroke="black" points="481.326,-172.314 491.7,-170.162 482.248,-165.375 481.326,-172.314"/>
+<text text-anchor="middle" x="385" y="-176.588" font-family="Inconsolata" font-size="10.00">VBE_Delete(172)</text>
+</g>
+<!-- lck_vcl -->
+<g id="node4" class="node"><title>lck_vcl</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-427.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="522" y="-425.088" font-family="Inconsolata" font-size="10.00">lck_vcl</text>
+</g>
+<!-- lck_cli->lck_vcl -->
+<g id="edge3" class="edge"><title>lck_cli->lck_vcl</title>
+<path fill="none" stroke="black" d="M262.941,-429.638C274.591,-413.314 294.683,-389.66 319,-379.588 373.201,-357.137 394.963,-362.221 451,-379.588 467.972,-384.848 484.487,-395.803 497.209,-405.92"/>
+<polygon fill="black" stroke="black" points="495.059,-408.684 504.989,-412.38 499.531,-403.299 495.059,-408.684"/>
+<text text-anchor="middle" x="385" y="-382.588" font-family="Inconsolata" font-size="10.00">VCL_AddBackend(195)</text>
+</g>
+<!-- lck_cli->lck_vcl -->
+<g id="edge4" class="edge"><title>lck_cli->lck_vcl</title>
+<path fill="none" stroke="black" d="M258.194,-428.993C267.395,-405.895 287.102,-366.323 319,-349.588 370.951,-322.332 397.425,-325.682 451,-349.588 474.847,-360.229 493.956,-383.453 506.145,-401.807"/>
+<polygon fill="black" stroke="black" points="503.251,-403.78 511.563,-410.35 509.162,-400.031 503.251,-403.78"/>
+<text text-anchor="middle" x="385" y="-352.588" font-family="Inconsolata" font-size="10.00">VCL_Load(466)</text>
+</g>
+<!-- lck_cli->lck_vcl -->
+<g id="edge7" class="edge"><title>lck_cli->lck_vcl</title>
+<path fill="none" stroke="black" d="M268.109,-461.841C280.821,-472.765 299.595,-486.568 319,-492.588 375.032,-509.971 396.799,-515.039 451,-492.588 461.453,-488.258 460.801,-482.384 469,-474.588 477.778,-466.242 487.59,-457.282 496.306,-449.446"/>
+<polygon fill="black" stroke="black" points="498.822,-451.891 503.941,-442.615 494.155,-446.674 498.822,-451.891"/>
+<text text-anchor="middle" x="385" y="-509.588" font-family="Inconsolata" font-size="10.00">ccf_config_use(617)</text>
+</g>
+<!-- lck_cli->lck_vcl -->
+<g id="edge11" class="edge"><title>lck_cli->lck_vcl</title>
+<path fill="none" stroke="black" d="M280.363,-452.999C319.286,-460.736 391.233,-471.23 451,-458.588 464.339,-455.767 478.227,-450.229 490.083,-444.605"/>
+<polygon fill="black" stroke="black" points="491.704,-447.707 499.106,-440.126 488.592,-441.437 491.704,-447.707"/>
+<text text-anchor="middle" x="385" y="-466.588" font-family="Inconsolata" font-size="10.00">VCL_Get(134)</text>
+</g>
+<!-- lck_cli->lck_vcl -->
+<g id="edge13" class="edge"><title>lck_cli->lck_vcl</title>
+<path fill="none" stroke="black" d="M282.075,-444.464C330.632,-441.034 426.339,-434.274 480.73,-430.432"/>
+<polygon fill="black" stroke="black" points="480.979,-433.924 490.707,-429.728 480.486,-426.941 480.979,-433.924"/>
+<text text-anchor="middle" x="385" y="-443.588" font-family="Inconsolata" font-size="10.00">VCL_Rel(177)</text>
+</g>
+<!-- lck_cli->lck_vcl -->
+<g id="edge29" class="edge"><title>lck_cli->lck_vcl</title>
+<path fill="none" stroke="black" d="M274.187,-434.254C286.887,-427.903 303.362,-420.827 319,-417.588 374.826,-406.025 441.095,-413.152 482.103,-419.912"/>
+<polygon fill="black" stroke="black" points="481.765,-423.406 492.214,-421.657 482.955,-416.508 481.765,-423.406"/>
+<text text-anchor="middle" x="385" y="-420.588" font-family="Inconsolata" font-size="10.00">ccf_config_discard(579)</text>
+</g>
+<!-- lck_cli->lck_backend -->
+<g id="edge24" class="edge"><title>lck_cli->lck_backend</title>
+<path fill="none" stroke="black" d="M253.525,-428.447C257.508,-393.347 271.484,-316.206 319,-277.588 319.373,-277.285 411.483,-261.409 471.177,-251.145"/>
+<polygon fill="black" stroke="black" points="471.925,-254.568 481.188,-249.425 470.739,-247.669 471.925,-254.568"/>
+<text text-anchor="middle" x="385" y="-280.588" font-family="Inconsolata" font-size="10.00">vbp_update_backend(158)</text>
+</g>
+<!-- lck_cli->lck_backend -->
+<g id="edge25" class="edge"><title>lck_cli->lck_backend</title>
+<path fill="none" stroke="black" d="M251.512,-428.385C251.518,-386.95 258.075,-285.772 319,-241.588 342.289,-224.698 418.691,-229.868 470.565,-235.759"/>
+<polygon fill="black" stroke="black" points="470.249,-239.246 480.59,-236.94 471.068,-232.294 470.249,-239.246"/>
+<text text-anchor="middle" x="385" y="-244.588" font-family="Inconsolata" font-size="10.00">VBP_Control(525)</text>
+</g>
+<!-- lck_cli->lck_backend -->
+<g id="edge33" class="edge"><title>lck_cli->lck_backend</title>
+<path fill="none" stroke="black" d="M255.853,-428.38C262.981,-399.436 281.087,-343.278 319,-314.588 366.681,-278.507 395.649,-311.206 451,-288.588 465.732,-282.568 480.661,-273.289 492.926,-264.637"/>
+<polygon fill="black" stroke="black" points="495.323,-267.22 501.345,-258.503 491.201,-261.562 495.323,-267.22"/>
+<text text-anchor="middle" x="385" y="-317.588" font-family="Inconsolata" font-size="10.00">VBP_Remove(578)</text>
+</g>
+<!-- lck_cli->lck_ban -->
+<g id="edge16" class="edge"><title>lck_cli->lck_ban</title>
+<path fill="none" stroke="black" d="M261.411,-463.82C272.473,-482.064 292.705,-509.819 319,-521.588 372.548,-545.555 394.526,-537.478 451,-521.588 460.025,-519.049 459.975,-513.127 469,-510.588 514.35,-497.828 528.067,-506.491 575,-510.588 623.553,-514.826 650.453,-493.311 683,-529.588 723.601,-574.843 665.673,-753.106 701,-802.588 705.157,-808.41 711.08,-812.765 717.51,-816.021"/>
+<polygon fill="black" stroke="black" points="716.572,-819.422 727.148,-820.048 719.27,-812.963 716.572,-819.422"/>
+<text text-anchor="middle" x="522" y="-513.588" font-family="Inconsolata" font-size="10.00">BAN_Insert(533)</text>
+</g>
+<!-- lck_cli->lck_ban -->
+<g id="edge17" class="edge"><title>lck_cli->lck_ban</title>
+<path fill="none" stroke="black" d="M252.121,-464.651C253.437,-504.906 262.614,-602.308 319,-651.588 406.102,-727.712 470.133,-649.755 575,-698.588 640.825,-729.24 638.844,-765.05 701,-802.588 707.005,-806.214 713.685,-809.535 720.262,-812.456"/>
+<polygon fill="black" stroke="black" points="719.156,-815.788 729.731,-816.439 721.87,-809.335 719.156,-815.788"/>
+<text text-anchor="middle" x="522" y="-701.588" font-family="Inconsolata" font-size="10.00">BAN_Insert(572)</text>
+</g>
+<!-- lck_cli->lck_ban -->
+<g id="edge31" class="edge"><title>lck_cli->lck_ban</title>
+<path fill="none" stroke="black" d="M254.318,-464.608C259.552,-497.613 275.427,-567.751 319,-604.588 447.121,-712.903 574.54,-576.589 683,-704.588 711.629,-738.374 673.226,-768.096 701,-802.588 705.443,-808.106 711.444,-812.318 717.849,-815.527"/>
+<polygon fill="black" stroke="black" points="716.815,-818.89 727.389,-819.548 719.533,-812.439 716.815,-818.89"/>
+<text text-anchor="middle" x="522" y="-652.588" font-family="Inconsolata" font-size="10.00">BAN_TailRef(210)</text>
+</g>
+<!-- lck_cli->lck_ban -->
+<g id="edge32" class="edge"><title>lck_cli->lck_ban</title>
+<path fill="none" stroke="black" d="M255.915,-464.557C263.129,-493.114 281.355,-548.494 319,-576.588 384.981,-625.829 626.953,-585.281 683,-645.588 730.813,-697.035 658.821,-746.429 701,-802.588 705.255,-808.253 711.167,-812.533 717.545,-815.763"/>
+<polygon fill="black" stroke="black" points="716.51,-819.125 727.084,-819.785 719.229,-812.675 716.51,-819.125"/>
+<text text-anchor="middle" x="522" y="-613.588" font-family="Inconsolata" font-size="10.00">BAN_TailDeref(225)</text>
+</g>
+<!-- lck_cli->lck_ban -->
+<g id="edge36" class="edge"><title>lck_cli->lck_ban</title>
+<path fill="none" stroke="black" d="M259.236,-464.321C269.226,-486.414 289.427,-523.569 319,-542.588 457.354,-631.565 572.041,-488.151 683,-609.588 712.056,-641.388 675.497,-767.874 701,-802.588 705.236,-808.353 711.195,-812.682 717.636,-815.93"/>
+<polygon fill="black" stroke="black" points="716.697,-819.331 727.274,-819.957 719.396,-812.872 716.697,-819.331"/>
+<text text-anchor="middle" x="522" y="-572.588" font-family="Inconsolata" font-size="10.00">ccf_ban_list(1312)</text>
+</g>
+<!-- lck_cli->lck_smp -->
+<g id="edge46" class="edge"><title>lck_cli->lck_smp</title>
+<path fill="none" stroke="black" d="M255.731,-464.405C264.066,-504.32 284.743,-603.974 301,-687.588 309.368,-730.629 295.423,-747.619 319,-784.588 357.728,-845.311 410.705,-818.893 451,-878.588 470.179,-907.001 447.882,-926.585 469,-953.588 473.337,-959.133 479.129,-963.653 485.272,-967.297"/>
+<polygon fill="black" stroke="black" points="483.907,-970.532 494.396,-972.027 487.129,-964.317 483.907,-970.532"/>
+<text text-anchor="middle" x="385" y="-881.588" font-family="Inconsolata" font-size="10.00">debug_persistent(653)</text>
+</g>
+<!-- lck_backend_tcp -->
+<g id="node8" class="node"><title>lck_backend_tcp</title>
+<ellipse fill="none" stroke="black" cx="756.923" cy="-191.588" rx="55.8461" ry="18"/>
+<text text-anchor="middle" x="756.923" y="-189.088" font-family="Inconsolata" font-size="10.00">lck_backend_tcp</text>
+</g>
+<!-- lck_vbe->lck_backend_tcp -->
+<g id="edge39" class="edge"><title>lck_vbe->lck_backend_tcp</title>
+<path fill="none" stroke="black" d="M553.189,-172.9C585.439,-171.534 638.001,-170.567 683,-175.588 689.34,-176.295 695.938,-177.322 702.46,-178.519"/>
+<polygon fill="black" stroke="black" points="702.11,-182.018 712.598,-180.52 703.465,-175.15 702.11,-182.018"/>
+<text text-anchor="middle" x="638" y="-178.588" font-family="Inconsolata" font-size="10.00">VBT_Rel(193)</text>
+</g>
+<!-- lck_wstat -->
+<g id="node6" class="node"><title>lck_wstat</title>
+<ellipse fill="none" stroke="black" cx="756.923" cy="-1079.59" rx="37.8497" ry="18"/>
+<text text-anchor="middle" x="756.923" y="-1077.09" font-family="Inconsolata" font-size="10.00">lck_wstat</text>
+</g>
+<!-- lck_exp->lck_wstat -->
+<g id="edge6" class="edge"><title>lck_exp->lck_wstat</title>
+<path fill="none" stroke="black" d="M553.451,-1079.59C593.002,-1079.59 662.458,-1079.59 708.829,-1079.59"/>
+<polygon fill="black" stroke="black" points="708.931,-1083.09 718.931,-1079.59 708.931,-1076.09 708.931,-1083.09"/>
+<text text-anchor="middle" x="638" y="-1082.59" font-family="Inconsolata" font-size="10.00">Pool_Sumstat(72)</text>
+</g>
+<!-- lck_backend->lck_backend_tcp -->
+<g id="edge9" class="edge"><title>lck_backend->lck_backend_tcp</title>
+<path fill="none" stroke="black" d="M556.976,-231.581C568.356,-228.112 581.159,-224.445 593,-221.588 626.785,-213.436 664.976,-206.295 695.886,-201.028"/>
+<polygon fill="black" stroke="black" points="696.792,-204.425 706.073,-199.315 695.631,-197.522 696.792,-204.425"/>
+<text text-anchor="middle" x="638" y="-224.588" font-family="Inconsolata" font-size="10.00">VBT_Recycle(264)</text>
+</g>
+<!-- lck_wq -->
+<g id="node14" class="node"><title>lck_wq</title>
+<ellipse fill="none" stroke="black" cx="756.923" cy="-276.588" rx="28.0137" ry="18"/>
+<text text-anchor="middle" x="756.923" y="-274.088" font-family="Inconsolata" font-size="10.00">lck_wq</text>
+</g>
+<!-- lck_backend->lck_wq -->
+<g id="edge27" class="edge"><title>lck_backend->lck_wq</title>
+<path fill="none" stroke="black" d="M564.292,-238.177C596.913,-235.806 643.383,-234.911 683,-243.588 698.074,-246.889 713.792,-253.536 726.759,-260.004"/>
+<polygon fill="black" stroke="black" points="725.178,-263.127 735.666,-264.633 728.406,-256.916 725.178,-263.127"/>
+<text text-anchor="middle" x="638" y="-246.588" font-family="Inconsolata" font-size="10.00">Pool_Task_Any(98)</text>
+</g>
+<!-- lck_backend->lck_wq -->
+<g id="edge28" class="edge"><title>lck_backend->lck_wq</title>
+<path fill="none" stroke="black" d="M562.204,-249.561C572.232,-251.276 583.006,-253.057 593,-254.588 636.151,-261.198 685.896,-267.762 718.953,-271.976"/>
+<polygon fill="black" stroke="black" points="718.709,-275.473 729.069,-273.259 719.589,-268.529 718.709,-275.473"/>
+<text text-anchor="middle" x="638" y="-270.588" font-family="Inconsolata" font-size="10.00">Pool_Task(231)</text>
+</g>
+<!-- lck_waiter -->
+<g id="node9" class="node"><title>lck_waiter</title>
+<ellipse fill="none" stroke="black" cx="1024.41" cy="-191.588" rx="40.7358" ry="18"/>
+<text text-anchor="middle" x="1024.41" y="-189.088" font-family="Inconsolata" font-size="10.00">lck_waiter</text>
+</g>
+<!-- lck_backend_tcp->lck_waiter -->
+<g id="edge10" class="edge"><title>lck_backend_tcp->lck_waiter</title>
+<path fill="none" stroke="black" d="M812.931,-191.588C860.134,-191.588 927.584,-191.588 973.309,-191.588"/>
+<polygon fill="black" stroke="black" points="973.578,-195.088 983.578,-191.588 973.578,-188.088 973.578,-195.088"/>
+<text text-anchor="middle" x="896.846" y="-194.588" font-family="Inconsolata" font-size="10.00">vwk_enter(147)</text>
+</g>
+<!-- lck_objhdr->lck_exp -->
+<g id="edge22" class="edge"><title>lck_objhdr->lck_exp</title>
+<path fill="none" stroke="black" d="M260.248,-856.139C270.843,-879.221 289.261,-921.233 301,-958.588 311.926,-993.356 292.609,-1013.45 319,-1038.59 362.124,-1079.66 392.784,-1049.05 451,-1061.59 461.69,-1063.89 473.215,-1066.71 483.766,-1069.43"/>
+<polygon fill="black" stroke="black" points="482.964,-1072.84 493.525,-1071.99 484.738,-1066.07 482.964,-1072.84"/>
+<text text-anchor="middle" x="385" y="-1064.59" font-family="Inconsolata" font-size="10.00">exp_mail_it(145)</text>
+</g>
+<!-- lck_hcb -->
+<g id="node11" class="node"><title>lck_hcb</title>
+<ellipse fill="none" stroke="black" cx="522" cy="-926.588" rx="31.3996" ry="18"/>
+<text text-anchor="middle" x="522" y="-924.088" font-family="Inconsolata" font-size="10.00">lck_hcb</text>
+</g>
+<!-- lck_objhdr->lck_hcb -->
+<g id="edge15" class="edge"><title>lck_objhdr->lck_hcb</title>
+<path fill="none" stroke="black" d="M267.391,-855.311C280.003,-867.919 298.98,-884.536 319,-893.588 347.188,-906.333 430.475,-917.007 480.872,-922.531"/>
+<polygon fill="black" stroke="black" points="480.778,-926.041 491.095,-923.63 481.527,-919.081 480.778,-926.041"/>
+<text text-anchor="middle" x="385" y="-921.588" font-family="Inconsolata" font-size="10.00">hcb_deref(405)</text>
+</g>
+<!-- lck_objhdr->lck_ban -->
+<g id="edge19" class="edge"><title>lck_objhdr->lck_ban</title>
+<path fill="none" stroke="black" d="M289.846,-843.858C299.345,-844.973 309.53,-845.993 319,-846.588 480.459,-856.733 522.916,-869.935 683,-846.588 695.301,-844.794 708.442,-841.469 720.131,-837.986"/>
+<polygon fill="black" stroke="black" points="721.467,-841.236 729.973,-834.919 719.384,-834.553 721.467,-841.236"/>
+<text text-anchor="middle" x="522" y="-862.588" font-family="Inconsolata" font-size="10.00">BAN_CheckObject(927)</text>
+</g>
+<!-- lck_objhdr->lck_ban -->
+<g id="edge20" class="edge"><title>lck_objhdr->lck_ban</title>
+<path fill="none" stroke="black" d="M291.963,-837.557C386.09,-835.129 620.907,-829.071 715.495,-826.631"/>
+<polygon fill="black" stroke="black" points="715.62,-830.129 725.527,-826.372 715.44,-823.131 715.62,-830.129"/>
+<text text-anchor="middle" x="522" y="-835.588" font-family="Inconsolata" font-size="10.00">BAN_CheckObject(948)</text>
+</g>
+<!-- lck_objhdr->lck_lru -->
+<g id="edge21" class="edge"><title>lck_objhdr->lck_lru</title>
+<path fill="none" stroke="black" d="M263.731,-821.232C275.562,-805.428 295.42,-783.147 319,-773.588 372.797,-751.78 441.447,-760.254 483.27,-768.974"/>
+<polygon fill="black" stroke="black" points="482.781,-772.45 493.299,-771.178 484.284,-765.613 482.781,-772.45"/>
+<text text-anchor="middle" x="385" y="-776.588" font-family="Inconsolata" font-size="10.00">EXP_Rearm(299)</text>
+</g>
+<!-- lck_objhdr->lck_wq -->
+<g id="edge45" class="edge"><title>lck_objhdr->lck_wq</title>
+<path fill="none" stroke="black" d="M261.213,-820.834C272.231,-801.502 292.55,-771.254 319,-755.588 368.732,-726.133 529.926,-745.77 575,-709.588 707.586,-603.158 744.236,-382.513 753.254,-304.588"/>
+<polygon fill="black" stroke="black" points="756.742,-304.887 754.35,-294.566 749.784,-304.126 756.742,-304.887"/>
+<text text-anchor="middle" x="522" y="-736.588" font-family="Inconsolata" font-size="10.00">Pool_Task(231)</text>
+</g>
+<!-- lck_objhdr->lck_smp -->
+<g id="edge43" class="edge"><title>lck_objhdr->lck_smp</title>
+<path fill="none" stroke="black" d="M259.486,-856.375C269.614,-878.1 289.833,-914.219 319,-932.588 369.39,-964.323 393.417,-940.407 451,-955.588 462.774,-958.692 475.379,-962.904 486.602,-966.986"/>
+<polygon fill="black" stroke="black" points="485.461,-970.296 496.054,-970.509 487.906,-963.737 485.461,-970.296"/>
+<text text-anchor="middle" x="385" y="-958.588" font-family="Inconsolata" font-size="10.00">smp_oc_getobj(425)</text>
+</g>
+<!-- lck_objhdr? -->
+<g id="node15" class="node"><title>lck_objhdr?</title>
+<ellipse fill="none" stroke="black" cx="1024.41" cy="-794.588" rx="43.6222" ry="18"/>
+<text text-anchor="middle" x="1024.41" y="-792.088" font-family="Inconsolata" font-size="10.00">lck_objhdr?</text>
+</g>
+<!-- lck_ban->lck_objhdr? -->
+<g id="edge38" class="edge"><title>lck_ban->lck_objhdr?</title>
+<path fill="none" stroke="black" d="M787.605,-822.122C832.222,-816.912 917.176,-806.992 972.004,-800.59"/>
+<polygon fill="black" stroke="black" points="972.684,-804.035 982.21,-799.398 971.872,-797.082 972.684,-804.035"/>
+<text text-anchor="middle" x="896.846" y="-818.588" font-family="Inconsolata" font-size="10.00">ban_lurker_getfirst(1029)</text>
+</g>
+<!-- lck_lru->lck_objhdr? -->
+<g id="edge35" class="edge"><title>lck_lru->lck_objhdr?</title>
+<path fill="none" stroke="black" d="M553.464,-779.512C606.274,-781.119 718.247,-784.547 812.846,-787.588 866.544,-789.314 927.943,-791.364 970.526,-792.798"/>
+<polygon fill="black" stroke="black" points="970.548,-796.3 980.66,-793.139 970.784,-789.304 970.548,-796.3"/>
+<text text-anchor="middle" x="756.923" y="-790.588" font-family="Inconsolata" font-size="10.00">EXP_NukeOne(352)</text>
+</g>
+<!-- lck_smp->lck_ban -->
+<g id="edge41" class="edge"><title>lck_smp->lck_ban</title>
+<path fill="none" stroke="black" d="M553.154,-978.626C587.524,-975.052 643.979,-964.976 683,-936.588 712.464,-915.153 733.339,-877.886 745.002,-852.5"/>
+<polygon fill="black" stroke="black" points="748.322,-853.645 749.158,-843.083 741.918,-850.819 748.322,-853.645"/>
+<text text-anchor="middle" x="638" y="-974.588" font-family="Inconsolata" font-size="10.00">BAN_Reload(773)</text>
+</g>
+<!-- lck_smp->lck_ban -->
+<g id="edge42" class="edge"><title>lck_smp->lck_ban</title>
+<path fill="none" stroke="black" d="M548.45,-970.988C557.58,-966.665 567.468,-960.871 575,-953.588 586.73,-942.244 580.312,-931.849 593,-921.588 625.573,-895.247 646.773,-914.622 683,-893.588 702.957,-882 721.904,-864.041 735.481,-849.488"/>
+<polygon fill="black" stroke="black" points="738.315,-851.573 742.444,-841.816 733.132,-846.869 738.315,-851.573"/>
+<text text-anchor="middle" x="638" y="-924.588" font-family="Inconsolata" font-size="10.00">BAN_TailRef(210)</text>
+</g>
+</g>
+</svg>
diff --git a/doc/sphinx/phk/index.rst b/doc/sphinx/phk/index.rst
index 425d4e5..7dae4e4 100644
--- a/doc/sphinx/phk/index.rst
+++ b/doc/sphinx/phk/index.rst
@@ -8,6 +8,7 @@ You may or may not want to know what Poul-Henning thinks.
 .. toctree::
 	:maxdepth: 1
 
+	brinch-hansens-arrows.rst
 	ssl_again.rst
 	persistent.rst
 	dough.rst
diff --git a/include/tbl/debug_bits.h b/include/tbl/debug_bits.h
index 31eef0c..9e5b684 100644
--- a/include/tbl/debug_bits.h
+++ b/include/tbl/debug_bits.h
@@ -41,4 +41,5 @@ DEBUG_BIT(LURKER,		lurker,		"VSL Ban lurker")
 DEBUG_BIT(ESI_CHOP,		esi_chop,	"Chop ESI fetch to bits")
 DEBUG_BIT(FLUSH_HEAD,		flush_head,	"Flush after http1 head")
 DEBUG_BIT(VTC_MODE,		vtc_mode,	"Varnishtest Mode")
+DEBUG_BIT(WITNESS,		witness,	"Emit WITNESS lock records")
 /*lint -restore */
diff --git a/include/tbl/vsl_tags.h b/include/tbl/vsl_tags.h
index fff29d5..d592016 100644
--- a/include/tbl/vsl_tags.h
+++ b/include/tbl/vsl_tags.h
@@ -518,5 +518,9 @@ SLTM(VfpAcct, 0, "Fetch filter accounting",
 	NODEF_NOTICE
 )
 
+SLTM(Witness, 0, "Lock order witness records",
+	"Diagnostic recording of locking order.\n"
+)
+
 #undef NODEF_NOTICE
 /*lint -restore */



More information about the varnish-commit mailing list