mwrap (Perl version) user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
* [PATCH 0/3] fleshing out some things...
@ 2022-12-16 14:39 Eric Wong
  2022-12-16 14:39 ` [PATCH 1/3] support changing bt_req_depth dynamically Eric Wong
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Eric Wong @ 2022-12-16 14:39 UTC (permalink / raw)
  To: mwrap-perl

Eric Wong (3):
  support changing bt_req_depth dynamically
  support symlink install
  various documentation updates

 .gitignore          |  1 +
 INSTALL             | 44 ++++++++++++++++++++
 MANIFEST            |  2 +
 Makefile.PL         | 12 ++++++
 Mwrap.xs            | 16 ++++++++
 README              | 10 ++---
 exe.sh              |  8 ++++
 httpd.h             | 99 ++++++++++++++++++++++++++++++++++++++-------
 mwrap_core.h        | 11 ++---
 script/mwrap-perl   | 78 +++++++++++++++++++++++++++++++++++
 script/mwrap-rproxy | 84 +++++++++++++++++++++++++++++++++++---
 t/httpd.t           |  4 ++
 t/mwrap.t           |  8 ++++
 13 files changed, 347 insertions(+), 30 deletions(-)
 create mode 100644 INSTALL
 create mode 100755 exe.sh

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] support changing bt_req_depth dynamically
  2022-12-16 14:39 [PATCH 0/3] fleshing out some things Eric Wong
@ 2022-12-16 14:39 ` Eric Wong
  2022-12-16 14:39 ` [PATCH 2/3] support symlink install Eric Wong
  2022-12-16 14:39 ` [PATCH 3/3] various documentation updates Eric Wong
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2022-12-16 14:39 UTC (permalink / raw)
  To: mwrap-perl

This is a valuable tuning knob and allows users to forgo
restarting an app to change backtrace depth.  A /reset is
recommended.
---
 Mwrap.xs     | 16 ++++++++++++
 httpd.h      | 70 +++++++++++++++++++++++++++++++++++++++++++++-------
 mwrap_core.h | 11 +++++----
 t/httpd.t    |  4 +++
 t/mwrap.t    |  8 ++++++
 5 files changed, 95 insertions(+), 14 deletions(-)

diff --git a/Mwrap.xs b/Mwrap.xs
index 568ec2b..846d89d 100644
--- a/Mwrap.xs
+++ b/Mwrap.xs
@@ -132,6 +132,22 @@ mwrap_reset()
 CODE:
 	mwrap_reset();
 
+unsigned
+mwrap_bt_depth(arg = &PL_sv_undef)
+	SV *arg;
+CODE:
+	if (SvOK(arg)) {
+		UV n = SvUVx(arg);
+		if (n > MWRAP_BT_MAX)
+			n = MWRAP_BT_MAX;
+		CMM_STORE_SHARED(bt_req_depth, (uint32_t)n);
+		RETVAL = n;
+	} else {
+		RETVAL = CMM_LOAD_SHARED(bt_req_depth);
+	}
+OUTPUT:
+	RETVAL
+
 Devel::Mwrap::SrcLoc
 mwrap_get(loc)
 	SV *loc;
diff --git a/httpd.h b/httpd.h
index 9b4ebe7..fc7b873 100644
--- a/httpd.h
+++ b/httpd.h
@@ -41,6 +41,7 @@
 #define URL "https://80x24.org/mwrap-perl.git/about"
 #define TYPE_HTML "text/html; charset=UTF-8"
 #define TYPE_CSV "text/csv"
+#define TYPE_PLAIN "text/plain"
 
 enum mw_qev {
 	MW_QEV_IGNORE = 0,
@@ -341,6 +342,15 @@ static enum mw_qev h1_do_trim(struct mw_h1 *h1)
 	return h1_res_oneshot(h1, r200, sizeof(r200) - 1);
 }
 
+static enum mw_qev h1_do_ctl_finish(struct mw_h1 *h1)
+{
+	struct mw_fbuf plain;
+	FILE *fp = wbuf_init(&plain);
+	if (!fp) return h1_close(h1);
+	fprintf(fp, "MWRAP=bt:%u\n", (unsigned)CMM_LOAD_SHARED(bt_req_depth));
+	return h1_200(h1, &plain, TYPE_PLAIN);
+}
+
 #define PATH_SKIP(h1r, pfx) path_skip(h1r, pfx, sizeof(pfx) - 1)
 static const char *path_skip(struct mw_h1req *h1r, const char *pfx, size_t len)
 {
@@ -570,7 +580,7 @@ static enum mw_qev each_at(struct mw_h1 *h1, struct mw_h1req *h1r)
 	FPUTS("<html><head><title>", fp);
 	write_html(fp, lb.ptr, lb.len);
 	FPUTS("</title></head><body><p>live allocations at:", fp);
-	if (bt_req_depth) FPUTS("<br/>", fp);
+	if (l->bt_len > 1 || (l->bt_len == 1 && l->f)) FPUTS("<br/>", fp);
 	else fputc(' ', fp);
 	write_html(fp, lb.ptr, lb.len);
 
@@ -627,13 +637,14 @@ static enum mw_qev each_gt(struct mw_h1 *h1, struct mw_h1req *h1r,
 	if (!fp) return h1_close(h1);
 
 	if (!csv) {
+		unsigned depth = (unsigned)CMM_LOAD_SHARED(bt_req_depth);
 		fprintf(fp, "<html><head><title>mwrap each &gt;%lu"
 			"</title></head><body><p>mwrap each &gt;%lu "
 			"(change `%lu' in URL to adjust filtering) - "
-			"MWRAP=bt:%u", min, min, min, (unsigned)bt_req_depth);
+			"MWRAP=bt:%u", min, min, min, depth);
 		show_stats(fp);
 		/* need borders to distinguish multi-level traces */
-		if (bt_req_depth)
+		if (depth)
 			FPUTS("<table\nborder=1><tr>", fp);
 		else /* save screen space if only tracing one line */
 			FPUTS("<table><tr>", fp);
@@ -757,6 +768,8 @@ static enum mw_qev h1_dispatch(struct mw_h1 *h1, struct mw_h1req *h1r)
 			return h1_do_reset(h1);
 		if (h1r->path_len == 5 && !memcmp(h1r->path, "/trim", 5))
 			return h1_do_trim(h1);
+		if (h1r->path_len == 4 && !memcmp(h1r->path, "/ctl", 4))
+			return h1_do_ctl_finish(h1);
 	}
 	return h1_404(h1);
 }
@@ -816,12 +829,31 @@ static enum mw_qev h1_drain_input(struct mw_h1 *h1, struct mw_h1req *h1r)
 	return h1_dispatch(h1, h1r);
 }
 
+static bool valid_end(const char *end)
+{
+	switch (*end) {
+	case '\r': case ' ': case '\t': case '\n': return true;
+	default: return false;
+	}
+}
+
+/* no error reporting, too much code */
+static void ctl_set(struct mw_h1 *h1, long n)
+{
+	if (n >= 0) {
+		if (n > MWRAP_BT_MAX)
+			n = MWRAP_BT_MAX;
+		CMM_STORE_SHARED(bt_req_depth, (uint32_t)n);
+	}
+}
+
 static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
 {
 	enum { HDR_IGN, HDR_CONN, HDR_XENC, HDR_CLEN } cur = HDR_IGN;
 	bool conn_set = false;
 	char *end;
 	struct phr_header *hdr = h1r->hdr;
+	long depth = -1;
 
 	h1->prev_len = 0;
 	h1->has_input = 0;
@@ -837,8 +869,21 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
 			cur = HDR_CONN;
 		else if (NAME_EQ(hdr, "Trailer"))
 			return h1_400(h1);
-		else if (hdr->name)
+		else if (hdr->name) {
 			cur = HDR_IGN;
+			/*
+			 * don't want to increase code to deal with POST
+			 * request bodies, so let pico handle parameters in
+			 * HTTP request headers, instead.
+			 */
+			if (NAME_EQ(hdr, "X-Mwrap-BT-Depth")) {
+				errno = 0;
+				depth = strtol(hdr->value, &end, 10);
+				if (errno || !valid_end(end))
+					depth = -1;
+			}
+		}
+
 		/* else: continuation line */
 		if (!hdr->value_len)
 			continue;
@@ -860,12 +905,8 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
 			h1->has_input = 1;
 			errno = 0;
 			h1->in_len = strtoul(hdr->value, &end, 10);
-			if (errno)
+			if (errno || !valid_end(end))
 				return h1_400(h1);
-			switch (*end) {
-			case '\r': case ' ': case '\t': case '\n': break;
-			default: return h1_400(h1);
-			}
 			break;
 		case HDR_IGN:
 			break;
@@ -883,6 +924,17 @@ static enum mw_qev h1_parse_harder(struct mw_h1 *h1, struct mw_h1req *h1r)
 	} else {
 		return h1_404(h1);
 	}
+
+	/*
+	 * special case for /ctl, since I don't feel like parsing queries
+	 * in the request body (ensure no query string, too)
+	 */
+	if (h1r->method_len == 4 && !memcmp(h1r->method, "POST", 4)) {
+		if (h1r->path_len == 4 && !memcmp(h1r->path, "/ctl", 4))
+			ctl_set(h1, depth);
+	}
+
+	/* break off QUERY_STRING */
 	h1r->qstr = memchr(h1r->path, '?', h1r->path_len);
 	if (h1r->qstr) {
 		++h1r->qstr; /* ignore '?' */
diff --git a/mwrap_core.h b/mwrap_core.h
index 3fd67f1..9e4f065 100644
--- a/mwrap_core.h
+++ b/mwrap_core.h
@@ -13,6 +13,7 @@
 typedef void COP;
 #endif
 
+/* set a sensible max to avoid stack overflows */
 #ifndef MWRAP_BT_MAX
 #	define	MWRAP_BT_MAX 32
 #endif
@@ -136,14 +137,14 @@ static void *my_mempcpy(void *dest, const void *src, size_t n)
 
 
 #define SRC_LOC_BT(bt) union stk_bt bt; do { \
-	uint32_t depth = locating ? 1 : bt_req_depth; \
+	uint32_t depth = locating ? 1 : CMM_LOAD_SHARED(bt_req_depth); \
 	switch (depth) { \
 	case 0: \
 	case 1: bt.sl.bt_len = 1; bt.sl.bt[0] = RETURN_ADDRESS(0); break; \
 	default: /* skip 1st level of BT since thats our function */ \
-		mwrap_assert(bt_req_depth <= MWRAP_BT_MAX); \
+		mwrap_assert(depth <= MWRAP_BT_MAX); \
 		++locating; \
-		long n = (long)backtrace(bt_dst(&bt), bt_req_depth); \
+		long n = (long)backtrace(bt_dst(&bt), depth); \
 		--locating; \
 		bt.sl.bt_len = n <= 1 ? 0 : (uint32_t)n - 1; \
 		if (n > 1) mwrap_assert(bt.sl.bt[0] == RETURN_ADDRESS(0)); \
@@ -1026,9 +1027,9 @@ __attribute__((constructor)) static void mwrap_ctor(void)
 			char *end;
 			unsigned long n = strtoul(bt, &end, 10);
 			if (n && !errno && (*end == ',' || *end == 0)) {
-				if (n >= MWRAP_BT_MAX)
+				if (n > MWRAP_BT_MAX)
 					n = MWRAP_BT_MAX;
-				bt_req_depth = (uint32_t)n;
+				CMM_STORE_SHARED(bt_req_depth, (uint32_t)n);
 			}
 		}
 	}
diff --git a/t/httpd.t b/t/httpd.t
index 176c6ed..3fe9c1f 100644
--- a/t/httpd.t
+++ b/t/httpd.t
@@ -157,6 +157,10 @@ SKIP: {
 	$rc = system(qw(curl -vsSf --unix-socket), $sock, '-o', $cout,
 		'-d', 'x=y', "http://0/$pid/reset");
 	is($rc, 0, 'curl /reset');
+	$rc = system(qw(curl -vsSf --unix-socket), $sock, '-o', $cout,
+		'-HX-Mwrap-BT-Depth:10', '-XPOST', "http://0/$pid/ctl");
+	is($rc, 0, 'curl /ctl (X-Mwrap-BT-Depth)');
+	like(slurp($cout), qr/\bMWRAP=bt:10\b/, 'changed bt depth');
 };
 
 
diff --git a/t/mwrap.t b/t/mwrap.t
index bf6ae6e..76a2366 100644
--- a/t/mwrap.t
+++ b/t/mwrap.t
@@ -166,4 +166,12 @@ EOM
 		'aligned_alloc + cfree function ran w/o crashing');
 };
 
+is(Devel::Mwrap::bt_depth(), 0, 'default bt depth is zero');
+is(Devel::Mwrap::bt_depth(5), 5, 'set depth to reasonable level');
+is(Devel::Mwrap::bt_depth(), 5, 'depth stays at 5');
+is(Devel::Mwrap::bt_depth(500), 32, 'depth clamped to 32 when 500 attempted');
+is(Devel::Mwrap::bt_depth(), 32, 'depth stayed clamped at 32');
+is(Devel::Mwrap::bt_depth(undef), 32, 'depth stayed clamped at 32');
+is(Devel::Mwrap::bt_depth(-1), 32, 'depth stayed clamped at 32');
+
 done_testing;

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] support symlink install
  2022-12-16 14:39 [PATCH 0/3] fleshing out some things Eric Wong
  2022-12-16 14:39 ` [PATCH 1/3] support changing bt_req_depth dynamically Eric Wong
@ 2022-12-16 14:39 ` Eric Wong
  2022-12-16 14:39 ` [PATCH 3/3] various documentation updates Eric Wong
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2022-12-16 14:39 UTC (permalink / raw)
  To: mwrap-perl

This is useful for users w/o root permissions.
---
 .gitignore  |  1 +
 INSTALL     | 44 ++++++++++++++++++++++++++++++++++++++++++++
 MANIFEST    |  2 ++
 Makefile.PL | 12 ++++++++++++
 README      | 10 +++++-----
 exe.sh      |  8 ++++++++
 6 files changed, 72 insertions(+), 5 deletions(-)
 create mode 100644 INSTALL
 create mode 100755 exe.sh

diff --git a/.gitignore b/.gitignore
index 71cb379..a89b4a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 /MYMETA.
 /MYMETA.*
 /MANIFEST.gen
+/Makefile.old
 /Makefile
 /Mwrap.bs
 /Mwrap.c
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..80ff748
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,44 @@
+Dependencies: liburcu (Userspace RCU) is required at runtime.
+
+`pkg-config', GNU make, and standard Perl build tools are also required.
+
+             FreeBSD:	pkg install pkg-config liburcu
+Debian-based systems:	apt-get install pkg-config liburcu-dev
+
+
+Newer versions of xxhash can unlock a small bit of performance:
+
+	pkg install xxhash
+	apt-get install libxxhash-dev
+
+
+If using mwrap-rproxy, Plack is also required:
+
+	pkg install p5-Plack p5-Plack-Middleware-Deflater
+	apt-get install libplack-perl libplack-middleware-deflater-perl
+
+symlink-install
+---------------
+
+For users who lack permissions and/or wish to minimize their
+installation footprint, the "symlink-install" target is available.
+The following commands installs symlinks to $HOME/bin
+pointing to the source tree:
+
+	perl Makefile.PL
+	make symlink-install prefix=$HOME
+
+standard MakeMaker installation (Perl)
+--------------------------------------
+
+To use MakeMaker, you need to ensure ExtUtils::MakeMaker is available.
+This is typically installed with Perl, but RPM-based systems will likely
+need to install the `perl-ExtUtils-MakeMaker' package.
+
+Once the dependencies are installed, you should be able to build and
+install the system (into /usr/local) with:
+
+        perl Makefile.PL
+        make
+        make check
+        make install # root permissions may be needed
diff --git a/MANIFEST b/MANIFEST
index 4e3c487..096cec9 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,5 +1,6 @@
 .gitignore
 COPYING
+INSTALL
 MANIFEST
 Makefile.PL
 Mwrap.xs
@@ -7,6 +8,7 @@ README
 check.h
 dlmalloc_c.h
 examples/mwrap.psgi
+exe.sh
 gcc.h
 httpd.h
 jhash.h
diff --git a/Makefile.PL b/Makefile.PL
index e7e24cf..f953d51 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -123,5 +123,17 @@ pure_all :: build.env
 
 check:: all check-manifest
 	prove -bvw -j\$(N)
+
+# Install symlinks to ~/bin (which is hopefuly in PATH) which point to
+# this source tree.
+# prefix + bindir matches git.git Makefile:
+prefix = \$(HOME)
+bindir = \$(prefix)/bin
+symlink-install : all
+	mkdir -p \$(bindir)
+	exe=\$\$(realpath exe.sh) && cd \$(bindir) && \\
+	for x in \$(EXE_FILES); do \\
+		ln -sf "\$\$exe" \$\$(basename "\$\$x"); \\
+	done
 EOF
 }
diff --git a/README b/README
index e7375b0..ba95d47 100644
--- a/README
+++ b/README
@@ -19,15 +19,15 @@ require rebuilding Perl.
 
 Tested on the `perl' package distributed with:
 
-* Debian GNU/Linux 10
+* Debian GNU/Linux 10 and 11
 
-It may work on FreeBSD, NetBSD, OpenBSD and DragonFly BSD.
+* FreeBSD 12.x
 
-== Install
+It may work on NetBSD, OpenBSD and DragonFly BSD.
 
-	# FreeBSD: pkg install pkg-config liburcu
+== Install
 
-	# Debian-based systems: apt-get install pkg-config liburcu-dev
+See `INSTALL' document
 
 == Usage
 
diff --git a/exe.sh b/exe.sh
new file mode 100755
index 0000000..c3ee2d3
--- /dev/null
+++ b/exe.sh
@@ -0,0 +1,8 @@
+#!/bin/sh -e
+# symlink this file to a directory in PATH to run anything in script/*
+# without needing perms to install globally.  Used by "make symlink-install"
+p=$(realpath "$0" || readlink "$0") # neither is POSIX, but common
+p=$(dirname "$p") c=$(basename "$0") # both are POSIX
+exec ${PERL-perl} -w -I"$p"/blib/lib -I"$p"/blib/arch \
+	"$p"/script/"${c%.sh}" "$@"
+: this script is too short to copyright

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] various documentation updates
  2022-12-16 14:39 [PATCH 0/3] fleshing out some things Eric Wong
  2022-12-16 14:39 ` [PATCH 1/3] support changing bt_req_depth dynamically Eric Wong
  2022-12-16 14:39 ` [PATCH 2/3] support symlink install Eric Wong
@ 2022-12-16 14:39 ` Eric Wong
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Wong @ 2022-12-16 14:39 UTC (permalink / raw)
  To: mwrap-perl

mwrap_httpd will have online help :>
---
 httpd.h             | 29 ++++++++++++----
 script/mwrap-perl   | 78 +++++++++++++++++++++++++++++++++++++++++
 script/mwrap-rproxy | 84 ++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 180 insertions(+), 11 deletions(-)

diff --git a/httpd.h b/httpd.h
index fc7b873..afce2a1 100644
--- a/httpd.h
+++ b/httpd.h
@@ -483,7 +483,7 @@ static off_t write_loc_name(FILE *fp, const struct src_loc *l)
 		if (!s) return -1;
 		if (l->f) fputc('\n', fp);
 
-		/* omit local " [$ADDRESS]" if doing deep backtraces */
+		/* omit local " [RETURN_ADDRESS]" if doing deep backtraces */
 		for (uint32_t i = 0; i < l->bt_len; ++i) {
 			char *c = memrchr(s[i], '[', strlen(s[i]));
 			if (c && c > (s[i] + 2) && c[-1] == ' ')
@@ -723,12 +723,29 @@ static enum mw_qev pid_root(struct mw_h1 *h1, struct mw_h1req *h1r)
 	if (!fp) return h1_close(h1);
 #define default_min "2000"
 
-	FPUTS("<html><head><title>mwrap demo</title></head><body>"
-		"<p>mwrap demo", fp);
+	int pid = (int)getpid();
+	fprintf(fp, "<html><head><title>mwrap PID:%d</title></head><body>"
+		"<pre>mwrap PID:%d", pid, pid);
 	show_stats(fp);
-	FPUTS("<p><a\nhref=\"each/" default_min "\">allocations &gt;"
-		default_min " bytes</a>"
-		"<p><a\nhref=\"" URL "\">" URL "</a></body></html>", fp);
+	FPUTS("\n\n<a\nhref=\"each/" default_min "\">allocations &gt;"
+		default_min " bytes</a>""</pre><pre\nid=help>"
+"To get source file and line info for native backtraces, consult your\n"
+"distro for -dbg, -dbgsym, or -debug packages.\n"
+"And/or rebuild your code with debug flags (e.g. `-ggdb3' if using gcc)\n"
+"and don't strip the resulting binaries.\n"
+"You should see locations from the backtrace_symbols(3) function\n"
+"in the form of FILENAME(+OFFSET) or FILENAME(SYMBOL+OFFSET)\n"
+"(e.g. /usr/lib/foo.so(+0xdead) or /usr/lib/foo.so(func+(0xbeef))\n"
+"\n"
+"Any version of addr2line should decode FILENAME(+OFFSET) locations:\n"
+"\n"
+"	addr2line -e FILENAME OFFSET\n"
+"\n"
+"SYMBOL+OFFSET requires addr2line from GNU binutils 2.39+ (Aug 2022):\n"
+"\n"
+"	addr2line -e FILENAME SYMBOL+OFFSET\n", fp);
+
+	FPUTS("\n<a\nhref=\"" URL "\">" URL "</a></pre></body></html>", fp);
 	return h1_200(h1, &html, TYPE_HTML);
 #undef default_min
 }
diff --git a/script/mwrap-perl b/script/mwrap-perl
index 78e71e3..53eaa10 100644
--- a/script/mwrap-perl
+++ b/script/mwrap-perl
@@ -6,6 +6,10 @@ use Devel::Mwrap;
 my ($so) = grep(m!/Mwrap\.so\z!, @DynaLoader::dl_shared_objects);
 defined($so) or die 'Mwrap.so not loaded';
 my $cur = $ENV{LD_PRELOAD};
+if (!@ARGV || ($ARGV[0] // '') =~ /\A(?:-h|--help)\z/) {
+	require Pod::Usage;
+	Pod::Usage::pod2usage(@ARGV ? 0 : 1);
+}
 if (defined $cur) {
 	my @cur = split(/[: \t]+/, $cur);
 	if (!grep(/\A\Q$so\E\z/, @cur)) {
@@ -17,3 +21,77 @@ if (defined $cur) {
 	$ENV{LD_PRELOAD} = $so;
 }
 exec @ARGV;
+__END__
+=head1 NAME
+
+mwrap-perl - run any command under mwrap
+
+=head1 SYNOPSIS
+
+  # to trace a long-running program and access it via $DIRECTORY/$PID.sock:
+  MWRAP=socket_dir:$DIRECTORY mwrap-perl COMMAND
+
+  # to trace a short-lived command and dump its output to a log:
+  MWRAP=dump_path:$FILENAME mwrap-perl COMMAND
+
+=head1 DESCRIPTION
+
+mwrap-perl is a command-line to automatically add Mwrap.so as an
+LD_PRELOAD for any command.  It will resolve malloc-family calls
+to a Perl file and line number, and it can also provide a backtrace
+of native (C/C++) functions for non-Perl programs.
+
+=head1 ENVIRONMENT
+
+C<MWRAP> is the only environment variable read.  It contains multiple
+options delimited by C<,> with names and values delimited by C<:>
+
+=item socket_dir:$DIRECTORY
+
+This launches an embedded HTTP server in each process and binds it
+to C<$DIRECTORY/$PID.sock>.  C<curl --unix-socket $DIRECTORY/$PID.sock>
+or L<mwrap-rproxy(1p)> may be used to access various endpoints in
+the HTTP server.
+
+=item: bt:$DEPTH
+
+The backtrace depth for L<backtrace(3)> in addition to the Perl
+file and line number where C<$DEPTH> is a non-negative number.
+
+The maximum allowed value is 32, though values of 5 or less are
+typically useful.  Increasing this to even 2 or 3 can significantly
+increase the amount of memory mwrap (and liburcu) itself uses.
+
+This is only useful in conjunction with C<socket_dir>
+
+Default: 0
+
+=item dump_path:$FILENAME
+
+Dumps the output
+
+	total_bytes	call_count	location
+
+In the future, dumping to a self-describing CSV will be supported
+
+=back
+
+=head1 CONTACT
+
+Feedback welcome via plain-text mail to L<mailto:mwrap-perl@80x24.org>
+
+Mail archives are hosted at L<https://80x24.org/mwrap-perl/>
+
+=head1 COPYRIGHT
+
+Copyright all contributors L<mailto:mwrap-perl@80x24.org>
+
+License: GPL-2.0+ L<https://www.gnu.org/licenses/gpl-2.0.txt>
+
+Source code is at L<https://80x24.org/mwrap-perl.git/>
+
+=head1 SEE ALSO
+
+L<mwrap-rproxy(1)>, L<Devel::Mwrap(3pm)>
+
+=cut
diff --git a/script/mwrap-rproxy b/script/mwrap-rproxy
index 97cca8e..da5379a 100644
--- a/script/mwrap-rproxy
+++ b/script/mwrap-rproxy
@@ -4,14 +4,17 @@
 # thin wrapper for Devel::Mwrap::Rproxy
 use v5.12; # strict
 eval { require Plack::Runner } or die "Plack not installed: $@\n";
-require Devel::Mwrap::Rproxy;
 use Getopt::Long qw(:config no_ignore_case no_auto_abbrev pass_through);
 my $usage = "$0 --socket-dir=/path/to/socket-dir [PLACKUP_OPTIONS]\n";
-my $socket_dir;
-my $gz = 1;
-GetOptions('socket-dir=s' => \$socket_dir, 'deflate!' => \$gz) or die $usage;
+my %opt = (deflate => 1);
+GetOptions(\%opt, 'socket-dir=s', 'deflate!', 'help|h') or do {
+	require Pod::Usage; Pod::Usage::pod2usage(1);
+};
+if ($opt{help}) { require Pod::Usage; Pod::Usage::pod2usage(0) }
+my $socket_dir = delete $opt{'socket-dir'};
 $socket_dir //= ($ENV{MWRAP} // '') =~ m!\bsocket_dir:([^,]+)! ? $1 : undef;
 $socket_dir // die $usage;
+require Devel::Mwrap::Rproxy;
 my $rproxy = Devel::Mwrap::Rproxy->new($socket_dir);
 my $app = sub { $rproxy->call(@_) };
 my $runner = Plack::Runner->new;
@@ -28,7 +31,78 @@ Inherited socket (fd=3) is non-blocking, making it blocking.
 		$runner->set_options(listen_sock => $s);
 	}
 }
-if ($gz && eval { require Plack::Middleware::Deflater } and !$@) {
+if ($opt{deflate} && eval { require Plack::Middleware::Deflater } and !$@) {
 	$app = Plack::Middleware::Deflater->wrap($app);
 }
 $runner->run($app);
+__END__
+=head1 NAME
+
+mwrap-rproxy - reverse proxy for embedded per-process mwrap httpd
+
+=head1 SYNOPSIS
+
+  # start the long-running COMMAND you wish to trace:
+  MWRAP=socket_dir:$DIRECTORY mwrap-perl COMMAND
+
+  # in a different terminal, point mwrap-proxy to the mwrap-perl socket_dir
+  mwrap-rproxy --socket-dir=$DIRECTORY -l 127.0.0.1:8080
+
+  # open http://127.0.0.1:8080/ in your favorite web browser:
+  w3m http://127.0.0.1:8080/
+
+=head1 DESCRIPTION
+
+B<mwrap-rproxy> is a PSGI reverse proxy to provide access
+via TCP to the native, Unix-socket-only httpd embedded inside
+mwrap core.  It provides a listing of process IDs of each process
+traced via mwrap.
+
+B<mwrap-rproxy> does not have a hard dependency on mwrap-perl itself,
+it exists to provide a convenient interface to programs being
+traced by mwrap-perl.
+
+=head1 OPTIONS
+
+=over 4
+
+=item --socket-dir=DIRECTORY
+
+If unset, it will attempt to parse C<socket_dir:> from the C<MWRAP>
+environment (see L<mwrap-perl(1p)>).
+
+=item --no-deflate
+
+L<Plack::Middleware::Deflater(3pm)> is loaded by default if available.
+Using C<--no-deflate> will save CPU cycles at the expe
+
+=back
+
+Additionally, all options in L<plackup(1p)> are supported.  Notably,
+C<-l>/C<--listen> and C<--path=/prefix> may be useful.
+
+=head1 ENVIRONMENT
+
+mwrap-rproxy supports systemd (and compatible) socket activation via
+C<LISTEN_PID> and C<LISTEN_FDS> variables.  See L<systemd.socket(5)>
+and L<sd_listen_fds(3)>.
+
+=head1 CONTACT
+
+Feedback welcome via plain-text mail to L<mailto:mwrap-perl@80x24.org>
+
+Mail archives are hosted at L<https://80x24.org/mwrap-perl/>
+
+=head1 COPYRIGHT
+
+Copyright all contributors L<mailto:mwrap-perl@80x24.org>
+
+License: GPL-2.0+ L<https://www.gnu.org/licenses/gpl-2.0.txt>
+
+Source code is at L<https://80x24.org/mwrap-perl.git/>
+
+=head1 SEE ALSO
+
+L<mwrap-perl(1p)>
+
+=cut

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-12-16 14:39 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-16 14:39 [PATCH 0/3] fleshing out some things Eric Wong
2022-12-16 14:39 ` [PATCH 1/3] support changing bt_req_depth dynamically Eric Wong
2022-12-16 14:39 ` [PATCH 2/3] support symlink install Eric Wong
2022-12-16 14:39 ` [PATCH 3/3] various documentation updates Eric Wong

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mwrap-perl.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).