mwrap (Perl version) user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: mwrap-perl@80x24.org
Subject: [PATCH 15/19] httpd: pause forking thread on resource limitations
Date: Thu, 15 Dec 2022 20:52:51 +0000	[thread overview]
Message-ID: <20221215205255.27840-16-e@80x24.org> (raw)
In-Reply-To: <20221215205255.27840-1-e@80x24.org>

We shouldn't abort the program due to resource limitations.
Instead, the least intrusive course of action is probably to
sleep and wait for other threads in the process to do cleanup
work.
---
 mwrap_httpd.h | 70 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 42 insertions(+), 28 deletions(-)

diff --git a/mwrap_httpd.h b/mwrap_httpd.h
index fc096c0..4864e72 100644
--- a/mwrap_httpd.h
+++ b/mwrap_httpd.h
@@ -79,7 +79,8 @@ struct mw_h1 { /* each HTTP/1.x client (heap) */
 
 struct mw_h1d { /* the daemon + listener, a singleton */
 	int lfd;
-	unsigned alive;
+	uint8_t alive; /* set by parent */
+	uint8_t running; /* cleared by child */
 	struct cds_list_head conn; /* <=> mw_h1.nd */
 	/* use open_memstream + fwrite to implement a growing pollfd array */
 	struct mw_fbuf pb; /* pollfd vector */
@@ -996,8 +997,7 @@ static struct pollfd *poll_detach(struct mw_h1d *h1d, nfds_t *nfds)
 
 static void non_fatal_pause(const char *fail_fn)
 {
-	fprintf(stderr,
-"%s: %m (non-fatal, pausing mwrap-httpd thread)\n", fail_fn);
+	fprintf(stderr, "%s: %m (non-fatal, pausing mwrap-httpd)\n", fail_fn);
 	poll(NULL, 0, 1000);
 }
 
@@ -1037,13 +1037,19 @@ static void h1d_event_step(struct mw_h1d *h1d)
 			case EPERM:
 				fail_fn = "accept4";
 				break;
-			/* hope other cleanup work gets done: */
+			/*
+			 * EINVAL, EBADF, ENOTSOCK, EOPNOTSUPP are all fatal
+			 * bugs.  The last 3 would be wayward closes in the
+			 * application being traced
+			 */
 			default:
-				fprintf(stderr, "accept4: %m (fatal)\n");
+				fprintf(stderr,
+					"accept4: %m (fatal in mwrap-httpd)\n");
 				abort();
 			}
 		}
 	}
+	/* hope other cleanup work gets done by other threads: */
 	non_fatal_pause(fail_fn);
 }
 
@@ -1094,12 +1100,6 @@ static int h1d_init(struct mw_h1d *h1d, const char *menv)
 	memcpy(h1d->pid_str, p, h1d->pid_len);
 	if (unlink(sa.un.sun_path) < 0 && errno != ENOENT)
 		return fprintf(stderr, "unlink(%s): %m\n", sa.un.sun_path);
-	/*
-	 * lfd may be >=0 if h1d_stop_join failed in parent and we're now
-	 * running in a forked child
-	 */
-	if (h1d->lfd >= 0)
-		(void)close(h1d->lfd);
 	h1d->lfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
 	if (h1d->lfd < 0)
 		return fprintf(stderr, "socket: %m\n");
@@ -1112,6 +1112,7 @@ static int h1d_init(struct mw_h1d *h1d, const char *menv)
 		goto close_fail;
 	}
 	h1d->alive = 1; /* runs in parent, before pthread_create */
+	h1d->running = 1;
 	CDS_INIT_LIST_HEAD(&h1d->conn);
 	return 0;
 close_fail:
@@ -1145,8 +1146,8 @@ static void *h1d_run(void *x) /* pthread_create cb */
 	locating = 1; /* don't report our own memory use */
 
 	for (; uatomic_read(&h1d->alive); ) {
-		if (poll_add(h1d, h1d->lfd, POLLIN))
-			exit(EXIT_FAILURE);
+		while (poll_add(h1d, h1d->lfd, POLLIN))
+			non_fatal_pause("poll_add(lfd)");
 		cds_list_for_each_entry_safe(h1, nxt, &h1d->conn, nd)
 			if (poll_add(h1d, h1->fd, h1->events))
 				h1_close(h1);
@@ -1155,13 +1156,14 @@ static void *h1d_run(void *x) /* pthread_create cb */
 
 		if (rc < 0) {
 			switch (errno) {
-			case EINTR: break;
+			case EINTR: break; /* shouldn't happen, actually */
 			case ENOMEM: /* may be common */
 			case EINVAL: /* RLIMIT_NOFILE hit */
 				non_fatal_pause("poll");
 				break; /* to forloop where rc<0 */
-			default:
-				fprintf(stderr, "poll: %m (fatal)\n");
+			default: /* EFAULT is a fatal bug */
+				fprintf(stderr,
+					"poll: %m (fatal in mwrap-httpd)\n");
 				abort();
 			}
 		} else {
@@ -1181,6 +1183,7 @@ static void *h1d_run(void *x) /* pthread_create cb */
 			}
 		}
 	}
+	uatomic_set(&h1d->running, 0);
 	free(poll_detach(h1d, &nfds));
 	cds_list_for_each_entry_safe(h1, nxt, &h1d->conn, nd)
 		h1_close(h1);
@@ -1210,27 +1213,34 @@ static void h1d_stop_join(struct mw_h1d *h1d)
 	socklen_t len = (socklen_t)sizeof(sa);
 	int e, sfd;
 	void *ret;
-#define ERR ": %m (can't stop mwrap-httpd before fork)\n"
+#define ERR ": (stopping mwrap-httpd before fork): "
 
 	mwrap_assert(uatomic_read(&h1d->alive) == 0);
-	if (getsockname(h1d->lfd, &sa.any, &len) < 0) {
-		fprintf(stderr, "getsockname"ERR);
-		return;
+	while (getsockname(h1d->lfd, &sa.any, &len) < 0) {
+		non_fatal_pause("getsockname"ERR);
+		if (!uatomic_read(&h1d->running))
+			goto join_thread;
 	}
-	sfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
-	if (sfd < 0) {
-		fprintf(stderr, "socket"ERR);
-		return;
+retry_socket:
+	while ((sfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) < 0) {
+		non_fatal_pause("socket"ERR);
+		if (!uatomic_read(&h1d->running))
+			goto join_thread;
 	}
 	if (connect(sfd, &sa.any, len) < 0) {
-		fprintf(stderr, "connect"ERR);
+		int e = errno;
 		close(sfd);
-		return;
+		errno = e;
+		non_fatal_pause("connect"ERR);
+		if (!uatomic_read(&h1d->running))
+			goto join_thread;
+		goto retry_socket;
 	}
 #undef ERR
 	(void)close(sfd);
+join_thread:
 	e = pthread_join(h1d->tid, &ret);
-	if (e) {
+	if (e) { /* EDEADLK, EINVAL, ESRCH are all fatal bugs */
 		fprintf(stderr, "BUG? pthread_join: %s\n", strerror(e));
 		abort();
 	}
@@ -1248,8 +1258,12 @@ static void h1d_start(void) /* may be called as pthread_atfork child cb */
 {
 	if (mwrap_env && !h1d_init(&g_h1d, mwrap_env) && g_h1d.alive) {
 		int rc = pthread_create(&g_h1d.tid, NULL, h1d_run, &g_h1d);
-		if (rc) /* non-fatal */
+		if (rc) { /* non-fatal */
 			fprintf(stderr, "pthread_create: %s\n", strerror(rc));
+			(void)close(g_h1d.lfd);
+			g_h1d.lfd = -1;
+			g_h1d.alive = 0;
+		}
 	}
 }
 

  parent reply	other threads:[~2022-12-15 20:52 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-15 20:52 [PATCH 00/19] another round of httpd improvements Eric Wong
2022-12-15 20:52 ` [PATCH 01/19] mwrap_httpd: show current bytes consistently Eric Wong
2022-12-15 20:52 ` [PATCH 02/19] introduce AUTO_FREE macro to simplify cleanup Eric Wong
2022-12-15 20:52 ` [PATCH 03/19] httpd: rework httpd to use auto-free for memstream Eric Wong
2022-12-15 20:52 ` [PATCH 04/19] httpd: avoid newline if not using bt: >= 1 Eric Wong
2022-12-15 20:52 ` [PATCH 05/19] mwrap_httpd: flesh out /$PID/ and /$PID/trim endpoints Eric Wong
2022-12-15 20:52 ` [PATCH 06/19] mwrap_httpd: add info about src_file and src_loc stats Eric Wong
2022-12-15 20:52 ` [PATCH 07/19] use uatomic_inc where appropriate Eric Wong
2022-12-15 20:52 ` [PATCH 08/19] httpd: drop unnecessary AND ops from base-64 Eric Wong
2022-12-15 20:52 ` [PATCH 09/19] mymalloc: add notes on the malloc implementation Eric Wong
2022-12-15 20:52 ` [PATCH 10/19] rproxy: link to mwrap_httpd /$PID/ root without each, too Eric Wong
2022-12-15 20:52 ` [PATCH 11/19] httpd: shrink `mean_life' field to `double' Eric Wong
2022-12-15 20:52 ` [PATCH 12/19] httpd: support CSV output Eric Wong
2022-12-15 20:52 ` [PATCH 13/19] rproxy: enable deflater by default Eric Wong
2022-12-15 20:52 ` [PATCH 14/19] mwrap_httpd: do not abort on fork if out-of-resources Eric Wong
2022-12-15 20:52 ` Eric Wong [this message]
2022-12-15 20:52 ` [PATCH 16/19] rename mwrap_httpd.h to httpd.h Eric Wong
2022-12-15 20:52 ` [PATCH 17/19] httpd: describe simple and naive buffering scheme Eric Wong
2022-12-15 20:52 ` [PATCH 18/19] httpd: drop TODO item for pipelining Eric Wong
2022-12-15 20:52 ` [PATCH 19/19] avoid -Warray-bounds warning, avoid stack overallocation Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221215205255.27840-16-e@80x24.org \
    --to=e@80x24.org \
    --cc=mwrap-perl@80x24.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).