9front - general discussion about 9front
 help / color / mirror / Atom feed
From: Jacob Moody <moody@posixcafe.org>
To: 9front@9front.org
Subject: [9front] [PATH] error()/waserror() for userspace
Date: Sat, 11 May 2024 16:26:13 -0500	[thread overview]
Message-ID: <dc77bc7f-ff64-4afb-bb24-82621f7f30ec@posixcafe.org> (raw)

Hello,

Through some discussions I've been thinking about how to perhaps do better
process-local variables then our current privalloc(), I've been toying with
this idea for a while and think I've come up with a decent alternative.

This patch implements two new segments that a process can attach to
that have convenient properties. "Private" segments are zero'd on
rfork, no matter the RFMEM flag. "Stack" segments are exactly what
they sound like, they have the same semantics as the stack segment,
so they are always Copy-On-Write no matter the RFMEM flag.

What I have here is an error()/waserror() that uses these segments
to implement itself. It also has a libthread implementation so it
may be used transparently. This is to provide some idea of how this
type of interface can be used.

I am not entirely sure that this is the correct interface for code
like this so I welcome feedback. If this is an interface that we
like I can then start to work on the man pages and use of this
for other bits of code.


Thanks,
moody

diff 025a2d172ebfe36bc0da32f5712dd250916c73f1 uncommitted
--- /dev/null
+++ b/sys/include/error.h
@@ -1,0 +1,7 @@
+_Noreturn void	error(char*, ...);
+_Noreturn void	nexterror(void);
+void		poperror(void);
+jmp_buf*	pusherrlab(void);
+
+#define waserror() (setjmp(*pusherrlab()))
+#pragma	varargck	argpos	error	1
--- a/sys/include/libc.h
+++ b/sys/include/libc.h
@@ -116,6 +116,11 @@
 extern	void*	malloctopoolblock(void*);

 /*
+ * privmalloc
+ */
+extern	void*	privmalloc(ulong);
+
+/*
  * print routines
  */
 typedef struct Fmt	Fmt;
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -143,7 +143,7 @@
 };

 /* Segment type from portdat.h */
-static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", "Sticky" };
+static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", "Sticky", "Private" };

 /*
  * Qids are, in path:
--- a/sys/src/9/port/devswap.c
+++ b/sys/src/9/port/devswap.c
@@ -202,6 +202,7 @@
 				case SG_BSS:
 				case SG_STACK:
 				case SG_SHARED:
+				case SG_PRIVATE:
 					pageout(p, s);
 					break;
 				}
@@ -302,6 +303,7 @@
 	case SG_BSS:
 	case SG_STACK:
 	case SG_SHARED:
+	case SG_PRIVATE:
 		if(ioptr >= conf.nswppo)
 			break;

--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -172,6 +172,7 @@
 	case SG_BSS:
 	case SG_SHARED:			/* Zero fill on demand */
 	case SG_STACK:
+	case SG_PRIVATE:
 		if(*pg == nil) {
 			new = newpage(1, &s, addr);
 			if(s == nil)
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -372,15 +372,16 @@
 /* Segment types */
 enum
 {
-	SG_TYPE		= 07,		/* Mask type of segment */
-	SG_TEXT		= 00,
-	SG_DATA		= 01,
-	SG_BSS		= 02,
-	SG_STACK	= 03,
-	SG_SHARED	= 04,
-	SG_PHYSICAL	= 05,
-	SG_FIXED	= 06,
-	SG_STICKY	= 07,
+	SG_TYPE		= 0xf,		/* Mask type of segment */
+	SG_TEXT		= 0,
+	SG_DATA		= 1,
+	SG_BSS		= 2,
+	SG_STACK	= 3,
+	SG_SHARED	= 4,
+	SG_PHYSICAL	= 5,
+	SG_FIXED	= 6,
+	SG_STICKY	= 7,
+	SG_PRIVATE	= 8,

 	SG_RONLY	= 0040,		/* Segment is read only */
 	SG_CEXEC	= 0100,		/* Detach at exec */
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -9,9 +9,11 @@
  * Attachable segment types
  */
 static Physseg physseg[10] = {
-	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE	},
-	{ SG_BSS,	"memory",	0,	SEGMAXSIZE	},
-	{ 0,		0,		0,	0		},
+	{ SG_SHARED,		"shared",	0,	SEGMAXSIZE	},
+	{ SG_BSS,		"memory",	0,	SEGMAXSIZE	},
+	{ SG_STACK|SG_CEXEC,	"stack",	0,	SEGMAXSIZE	},
+	{ SG_PRIVATE|SG_CEXEC,	"private",	0,	SEGMAXSIZE	},
+	{ 0,			0,		0,	0		},
 };

 static Lock physseglock;
@@ -169,6 +171,10 @@
 	case SG_STICKY:
 		goto sameseg;

+	case SG_PRIVATE:
+		n = newseg(s->type, s->base, s->size);
+		goto nocopy;
+
 	case SG_STACK:
 		n = newseg(s->type, s->base, s->size);
 		break;
@@ -203,6 +209,7 @@
 			n->map[i] = ptecpy(pte);

 	n->flushme = s->flushme;
+nocopy:
 	if(s->ref > 1)
 		procflushseg(s);
 	qunlock(s);
--- /dev/null
+++ b/sys/src/libc/port/err.c
@@ -1,0 +1,64 @@
+#include <u.h>
+#include <libc.h>
+
+typedef struct Errlab Errlab;
+struct Errlab {
+	int n;
+	jmp_buf s[32];
+};
+
+static Errlab*
+errorchk(void)
+{
+	static Errlab *e = nil;
+	static Lock l = {0};
+
+	if(e == nil){
+		lock(&l);
+		if(e == nil)
+			e = privmalloc(sizeof(Errlab));
+		unlock(&l);
+	}
+	return e;
+}
+
+_Noreturn void
+nexterror(void)
+{
+	Errlab *e;
+
+	e = errorchk();
+	if(e->n <= 0)
+		abort();
+	longjmp(e->s[--e->n], 1);
+}
+
+_Noreturn void
+error(char *fmt, ...)
+{
+	va_list arg;
+	char buf[ERRMAX];
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+ERRMAX, fmt, arg);
+	va_end(arg);
+	errstr(buf, ERRMAX);
+
+	nexterror();
+}
+
+void
+poperror(void)
+{
+	if(--errorchk()->n < 0)
+		abort();
+}
+
+jmp_buf*
+pusherrlab(void)
+{
+	Errlab *e;
+
+	e = errorchk();
+	return e->s + e->n++;
+}
--- a/sys/src/libc/port/mkfile
+++ b/sys/src/libc/port/mkfile
@@ -23,6 +23,7 @@
 	cycles.c\
 	date.c\
 	encodefmt.c\
+	err.c\
 	execl.c\
 	exits.c\
 	exp.c\
@@ -57,6 +58,7 @@
 	pool.c\
 	pow.c\
 	pow10.c\
+	privmalloc.c\
 	profile.c\
 	qsort.c\
 	quote.c\
--- /dev/null
+++ b/sys/src/libc/port/privmalloc.c
@@ -1,0 +1,30 @@
+#include <u.h>
+#include <libc.h>
+
+enum {
+	Maxsize = 1024*1024,
+};
+
+static Lock alloc;
+static uchar *segstart, *segpos, *segend;
+
+void*
+privmalloc(ulong n)
+{
+	void *p;
+
+	lock(&alloc);
+	if(segstart == nil){
+		segstart = segpos = segattach(0, "private", 0, Maxsize);
+		if(segstart == nil)
+			abort();
+		segend = segstart + Maxsize;
+	}
+	if(segpos + n < segend){
+		p = segpos;
+		segpos += n;
+	} else
+		p = nil;
+	unlock(&alloc);
+	return p;
+}
--- /dev/null
+++ b/sys/src/libc/test/err.c
@@ -1,0 +1,67 @@
+#include <u.h>
+#include <libc.h>
+#include <error.h>
+
+int n;
+
+void
+singleproc(void)
+{
+	n = 0;
+
+	if(waserror()){
+		if(n != 2)
+			sysfatal("missed label");
+		return;
+	}
+
+	if(waserror()){
+		n++;
+		nexterror();
+	}
+
+	n++;
+	error("blah");
+}
+
+int n2;
+Lock l;
+
+void
+multiproc(void)
+{
+
+	if(waserror()){
+		if(n2 != 1)
+			sysfatal("missed multiproc label");
+		waitpid();
+		return;
+	}
+	/*
+	 * Have the child add a new error label first
+	 * and check that it hasn't impacted the parents
+	 * error stack.
+	 */
+	lock(&l);
+	switch(rfork(RFMEM|RFPROC)){
+	case -1:
+		sysfatal("fork fail: %r");
+	default:
+		lock(&l);
+		n2++;
+		error("blah");
+	case 0:
+		if(waserror())
+			exits(nil);
+		unlock(&l);
+		error("blah");
+	}
+}
+
+void
+main(int, char**)
+{
+	singleproc();
+	multiproc();
+	exits(nil);
+}
--- a/sys/src/libc/test/mkfile
+++ b/sys/src/libc/test/mkfile
@@ -2,6 +2,7 @@

 TEST=\
 	date\
+	err\
 	pow\
 	runebreak\
 	runenorm\
--- /dev/null
+++ b/sys/src/libthread/err.c
@@ -1,0 +1,51 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "threadimpl.h"
+
+static Errlab*
+errorchk(void)
+{
+	return &_threadgetproc()->thread->errlab;
+}
+
+_Noreturn void
+nexterror(void)
+{
+	Errlab *e;
+
+	e = errorchk();
+	if(e->n <= 0)
+		abort();
+	longjmp(e->s[--e->n], 1);
+}
+
+_Noreturn void
+error(char *fmt, ...)
+{
+	va_list arg;
+	char buf[ERRMAX];
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+ERRMAX, fmt, arg);
+	va_end(arg);
+	errstr(buf, ERRMAX);
+
+	nexterror();
+}
+
+void
+poperror(void)
+{
+	if(--errorchk()->n < 0)
+		abort();
+}
+
+jmp_buf*
+pusherrlab(void)
+{
+	Errlab *e;
+
+	e = errorchk();
+	return e->s + e->n++;
+}
--- a/sys/src/libthread/mkfile
+++ b/sys/src/libthread/mkfile
@@ -8,6 +8,7 @@
 	chanprint.$O\
 	create.$O\
 	debug.$O\
+	err.$O\
 	exec.$O\
 	exit.$O\
 	id.$O\
--- /dev/null
+++ b/sys/src/libthread/test/err.c
@@ -1,0 +1,67 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <error.h>
+
+static int b;
+
+void
+threadb(void*)
+{
+	if(waserror()){
+		if(b != 2)
+			sysfatal("missed label");
+		threadexits(nil);
+	}
+
+	if(waserror()){
+		b++;
+		nexterror();
+	}
+
+	b++;
+	error("blah");
+}
+
+static int a;
+
+void
+threada(void*)
+{
+	if(waserror()){
+		if(a != 2)
+			sysfatal("missed label");
+		threadexits(nil);
+	}
+
+	if(waserror()){
+		a++;
+		nexterror();
+	}
+
+	a++;
+	error("blah");
+}
+
+static int n;
+
+void
+threadmain(int, char**)
+{
+	n = 0;
+	if(waserror()){
+		if(n != 2)
+			sysfatal("missed label");
+		exits(nil);
+	}
+
+	if(waserror()){
+		n++;
+		nexterror();
+	}
+
+	threadcreate(threada, nil, 1024);
+	threadcreate(threadb, nil, 1024);
+	n++;
+	error("fail");
+}
--- /dev/null
+++ b/sys/src/libthread/test/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TEST=\
+	err\
+
+</sys/src/cmd/mktest
--- a/sys/src/libthread/threadimpl.h
+++ b/sys/src/libthread/threadimpl.h
@@ -26,6 +26,7 @@
 typedef struct Execargs	Execargs;
 typedef struct Proc		Proc;
 typedef struct Iocall	Iocall;
+typedef struct Errlab	Errlab;

 /* must match list in sched.c */
 typedef enum
@@ -62,6 +63,11 @@
 	Thread	**tail;
 };

+struct Errlab {
+	int n;
+	jmp_buf s[32];
+};
+
 struct Thread
 {
 	Lock		lock;		/* protects thread data structure */
@@ -90,6 +96,7 @@
 	Chanstate	chan;		/* which channel operation is current */
 	Alt		*alt;		/* pointer to current alt structure (debugging) */

+	Errlab		errlab;		/* waserror()/error() jmp labels */
 	void*		udata;		/* User per-thread data pointer */
 };



             reply	other threads:[~2024-05-11 21:28 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-11 21:26 Jacob Moody [this message]
2024-05-12 14:47 ` cinap_lenrek

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=dc77bc7f-ff64-4afb-bb24-82621f7f30ec@posixcafe.org \
    --to=moody@posixcafe.org \
    --cc=9front@9front.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.
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 NNTP newsgroup(s).