aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2020-01-14 18:03:05 -0500
committerRuss Cox <rsc@swtch.com>2020-01-14 18:04:00 -0500
commit9505cd15a64933bf58ec50548339cf98b1854646 (patch)
treee3f519f753b124a27780470cf483f9f4a550a9d9 /src
parentd28913a9e6609fef96f5baf6e9f4d5055ede744c (diff)
downloadplan9port-9505cd15a64933bf58ec50548339cf98b1854646.tar.gz
plan9port-9505cd15a64933bf58ec50548339cf98b1854646.tar.bz2
plan9port-9505cd15a64933bf58ec50548339cf98b1854646.zip
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 (limited to 'src')
-rw-r--r--src/lib9/fmt/fmt.c165
-rw-r--r--src/lib9/fmt/fmtdef.h6
-rw-r--r--src/lib9/fmt/fmtlock.c14
-rw-r--r--src/lib9/fmtlock2.c22
4 files changed, 83 insertions, 124 deletions
diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
index 9c3f45d3..a86482c3 100644
--- a/src/lib9/fmt/fmt.c
+++ b/src/lib9/fmt/fmt.c
@@ -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;
}
@@ -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;
}
diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
index d547184d..2bafd36d 100644
--- a/src/lib9/fmt/fmtdef.h
+++ b/src/lib9/fmt/fmtdef.h
@@ -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);
diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
index eb9cd845..cabe05f4 100644
--- a/src/lib9/fmt/fmtlock.c
+++ b/src/lib9/fmt/fmtlock.c
@@ -5,21 +5,11 @@
#include "fmtdef.h"
void
-__fmtrlock(void)
+__fmtlock(void)
{
}
void
-__fmtrunlock(void)
-{
-}
-
-void
-__fmtwlock(void)
-{
-}
-
-void
-__fmtwunlock(void)
+__fmtunlock(void)
{
}
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
index b755daa3..d711e6d4 100644
--- a/src/lib9/fmtlock2.c
+++ b/src/lib9/fmtlock2.c
@@ -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);
}