tlib9: make formatting lock-free again - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 9505cd15a64933bf58ec50548339cf98b1854646
 (DIR) parent d28913a9e6609fef96f5baf6e9f4d5055ede744c
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Tue, 14 Jan 2020 18:03:05 -0500
       
       lib9: make formatting lock-free again
       
       First use of <stdatomic.h>.
       We will see if any supported systems don't have it yet.
       (C11 was so last decade.)
       
       Fixes #338.
       
       Diffstat:
         M src/lib9/fmt/fmt.c                  |     165 ++++++++++++++-----------------
         M src/lib9/fmt/fmtdef.h               |       6 ++----
         M src/lib9/fmt/fmtlock.c              |      14 ++------------
         M src/lib9/fmtlock2.c                 |      22 +++++-----------------
       
       4 files changed, 83 insertions(+), 124 deletions(-)
       ---
 (DIR) diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
       t@@ -1,102 +1,107 @@
        /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
        #include <stdarg.h>
        #include <string.h>
       +#include <stdatomic.h>
        #include "plan9.h"
        #include "fmt.h"
        #include "fmtdef.h"
        
        enum
        {
       -        Maxfmt = 64
       +        Maxfmt = 128
        };
        
        typedef struct Convfmt Convfmt;
        struct Convfmt
        {
                int        c;
       -        volatile        Fmts        fmt;        /* for spin lock in fmtfmt; avoids race due to write order */
       +        Fmts        fmt;
        };
        
        static struct
        {
       -        /* lock by calling __fmtlock, __fmtunlock */
       -        int        nfmt;
       +        /*
       +         * lock updates to fmt by calling __fmtlock, __fmtunlock.
       +         * reads can start at nfmt and work backward without
       +         * further locking. later fmtinstalls take priority over earlier
       +         * ones because of the backwards loop.
       +         * once installed, a format is never overwritten.
       +         */
       +        _Atomic int        nfmt;
                Convfmt        fmt[Maxfmt];
       -} fmtalloc;
       -
       -static Convfmt knownfmt[] = {
       -        ' ',        __flagfmt,
       -        '#',        __flagfmt,
       -        '%',        __percentfmt,
       -        '\'',        __flagfmt,
       -        '+',        __flagfmt,
       -        ',',        __flagfmt,
       -        '-',        __flagfmt,
       -        'C',        __runefmt,        /* Plan 9 addition */
       -        'E',        __efgfmt,
       -#ifndef PLAN9PORT
       -        'F',        __efgfmt,        /* ANSI only */
       -#endif
       -        'G',        __efgfmt,
       -#ifndef PLAN9PORT
       -        'L',        __flagfmt,        /* ANSI only */
       -#endif
       -        'S',        __runesfmt,        /* Plan 9 addition */
       -        'X',        __ifmt,
       -        'b',        __ifmt,                /* Plan 9 addition */
       -        'c',        __charfmt,
       -        'd',        __ifmt,
       -        'e',        __efgfmt,
       -        'f',        __efgfmt,
       -        'g',        __efgfmt,
       -        'h',        __flagfmt,
       -#ifndef PLAN9PORT
       -        'i',        __ifmt,                /* ANSI only */
       -#endif
       -        'l',        __flagfmt,
       -        'n',        __countfmt,
       -        'o',        __ifmt,
       -        'p',        __ifmt,
       -        'r',        __errfmt,
       -        's',        __strfmt,
       -#ifdef PLAN9PORT
       -        'u',        __flagfmt,
       -#else
       -        'u',        __ifmt,
       -#endif
       -        'x',        __ifmt,
       -        0,        nil,
       +} fmtalloc = {
       +        #ifdef PLAN9PORT
       +                ATOMIC_VAR_INIT(27),
       +        #else
       +                ATOMIC_VAR_INIT(30),
       +        #endif
       +        {
       +                {' ',        __flagfmt},
       +                {'#',        __flagfmt},
       +                {'%',        __percentfmt},
       +                {'\'',        __flagfmt},
       +                {'+',        __flagfmt},
       +                {',',        __flagfmt},
       +                {'-',        __flagfmt},
       +                {'C',        __runefmt},        /* Plan 9 addition */
       +                {'E',        __efgfmt},
       +        #ifndef PLAN9PORT
       +                {'F',        __efgfmt},        /* ANSI only */
       +        #endif
       +                {'G',        __efgfmt},
       +        #ifndef PLAN9PORT
       +                {'L',        __flagfmt},        /* ANSI only */
       +        #endif
       +                {'S',        __runesfmt},        /* Plan 9 addition */
       +                {'X',        __ifmt},
       +                {'b',        __ifmt},                /* Plan 9 addition */
       +                {'c',        __charfmt},
       +                {'d',        __ifmt},
       +                {'e',        __efgfmt},
       +                {'f',        __efgfmt},
       +                {'g',        __efgfmt},
       +                {'h',        __flagfmt},
       +        #ifndef PLAN9PORT
       +                {'i',        __ifmt},                /* ANSI only */
       +        #endif
       +                {'l',        __flagfmt},
       +                {'n',        __countfmt},
       +                {'o',        __ifmt},
       +                {'p',        __ifmt},
       +                {'r',        __errfmt},
       +                {'s',        __strfmt},
       +        #ifdef PLAN9PORT
       +                {'u',        __flagfmt},
       +        #else
       +                {'u',        __ifmt},
       +        #endif
       +                {'x',        __ifmt},
       +        }
        };
        
       -
        int        (*fmtdoquote)(int);
        
        /*
       - * __fmtwlock() must be set
       + * __fmtlock() must be set
         */
        static int
        __fmtinstall(int c, Fmts f)
        {
       -        Convfmt *p, *ep;
       +        Convfmt *p;
       +        int i;
        
                if(c<=0 || c>=65536)
                        return -1;
                if(!f)
                        f = __badfmt;
        
       -        ep = &fmtalloc.fmt[fmtalloc.nfmt];
       -        for(p=fmtalloc.fmt; p<ep; p++)
       -                if(p->c == c)
       -                        break;
       -
       -        if(p == &fmtalloc.fmt[Maxfmt])
       +        i = atomic_load(&fmtalloc.nfmt);
       +        if(i == Maxfmt)
                        return -1;
       -
       +        p = &fmtalloc.fmt[i];
       +        p->c = c;
                p->fmt = f;
       -        if(p == ep){        /* installing a new format character */
       -                fmtalloc.nfmt++;
       -                p->c = c;
       -        }
       +        atomic_store(&fmtalloc.nfmt, i+1);
        
                return 0;
        }
       t@@ -106,43 +111,21 @@ fmtinstall(int c, int (*f)(Fmt*))
        {
                int ret;
        
       -        __fmtwlock();
       +        __fmtlock();
                ret = __fmtinstall(c, f);
       -        __fmtwunlock();
       +        __fmtunlock();
                return ret;
        }
        
        static Fmts
        fmtfmt(int c)
        {
       -        Convfmt *p, *ep, *kp;
       -
       -        /* conflict-free check - common case */
       -        __fmtrlock();
       -        ep = &fmtalloc.fmt[fmtalloc.nfmt];
       -        for(p=fmtalloc.fmt; p<ep; p++)
       -                if(p->c == c){
       -                        __fmtrunlock();
       +        Convfmt *p, *ep;
       +
       +        ep = &fmtalloc.fmt[atomic_load(&fmtalloc.nfmt)];
       +        for(p=ep; p-- > fmtalloc.fmt; )
       +                if(p->c == c)
                                return p->fmt;
       -                }
       -        __fmtrunlock();
       -
       -        /* is this a predefined format char? */
       -        for(kp=knownfmt; kp->c; kp++){
       -                if(kp->c == c){
       -                        __fmtwlock();
       -                        /* double-check fmtinstall didn't happen */
       -                        for(p=fmtalloc.fmt; p<ep; p++){
       -                                if(p->c == c){
       -                                        __fmtwunlock();
       -                                        return p->fmt;
       -                                }
       -                        }
       -                        __fmtinstall(kp->c, kp->fmt);
       -                        __fmtwunlock();
       -                        return kp->fmt;
       -                }
       -        }
        
                return __badfmt;
        }
 (DIR) diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
       t@@ -36,10 +36,8 @@ void *       __fmtflush(Fmt *f, void *t, int len);
        int          __fmtpad(Fmt *f, int n);
        double       __fmtpow10(int n);
        int          __fmtrcpy(Fmt *f, const void *vm, int n);
       -void         __fmtrlock(void);
       -void         __fmtrunlock(void);
       -void         __fmtwlock(void);
       -void         __fmtwunlock(void);
       +void         __fmtlock(void);
       +void         __fmtunlock(void);
        int          __ifmt(Fmt *f);
        int          __isInf(double d, int sign);
        int          __isNaN(double d);
 (DIR) diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
       t@@ -5,21 +5,11 @@
        #include "fmtdef.h"
        
        void
       -__fmtrlock(void)
       +__fmtlock(void)
        {
        }
        
        void
       -__fmtrunlock(void)
       -{
       -}
       -
       -void
       -__fmtwlock(void)
       -{
       -}
       -
       -void
       -__fmtwunlock(void)
       +__fmtunlock(void)
        {
        }
 (DIR) diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
       t@@ -1,28 +1,16 @@
        #include <u.h>
        #include <libc.h>
        
       -static RWLock fmtlock;
       +static Lock fmtlock;
        
        void
       -__fmtrlock(void)
       +__fmtlock(void)
        {
       -        rlock(&fmtlock);
       +        lock(&fmtlock);
        }
        
        void
       -__fmtrunlock(void)
       +__fmtunlock(void)
        {
       -        runlock(&fmtlock);
       -}
       -
       -void
       -__fmtwlock(void)
       -{
       -        wlock(&fmtlock);
       -}
       -
       -void
       -__fmtwunlock(void)
       -{
       -        wunlock(&fmtlock);
       +        unlock(&fmtlock);
        }