From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <9front-bounces@9front.inri.net> X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI autolearn=ham autolearn_force=no version=3.4.4 Received: from 9front.inri.net (9front.inri.net [168.235.81.73]) by inbox.vuxu.org (Postfix) with ESMTP id 2991B247F7 for ; Sat, 11 May 2024 23:28:56 +0200 (CEST) Received: from mail.posixcafe.org ([45.76.19.58]) by 9front; Sat May 11 17:26:17 -0400 2024 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=posixcafe.org; s=20200506; t=1715462765; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=FEUleM7ushtDgne4h8XKgbQj1UYL0VYxrIipIBCFuFI=; b=o2d1h/Fwjm+0iWCm9S70LrIpcaETNiWwp1bLn1vU7klemmw/4/OMwCaAyL8mAd19ZuCPVM qAx9tN49YqjYmCyBiudwTT/AYAkkEXU4hzdYOmPaNEikrmpjUshbN+ka6ui7rRd56sA60w oVfEE6oQ/NoLdiSqTOk7A3faWX4Fc5M= Received: from [192.168.168.200] ( [207.45.82.38]) by mail.posixcafe.org (OpenSMTPD) with ESMTPSA id eb2f604d (TLSv1.3:TLS_AES_256_GCM_SHA384:256:NO) for <9front@9front.org>; Sat, 11 May 2024 16:26:04 -0500 (CDT) Message-ID: Date: Sat, 11 May 2024 16:26:13 -0500 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US To: 9front@9front.org From: Jacob Moody Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: mobile immutable TOR NoSQL CMS generator Subject: [9front] [PATH] error()/waserror() for userspace Reply-To: 9front@9front.org Precedence: bulk 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 +#include + +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 +#include + +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 +#include +#include + +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 +#include +#include +#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 +#include +#include +#include + +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 @@ +