mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
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.
This commit is contained in:
parent
d28913a9e6
commit
9505cd15a6
4 changed files with 82 additions and 123 deletions
|
@ -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,
|
||||
} fmtalloc = {
|
||||
#ifdef PLAN9PORT
|
||||
'u', __flagfmt,
|
||||
ATOMIC_VAR_INIT(27),
|
||||
#else
|
||||
'u', __ifmt,
|
||||
ATOMIC_VAR_INIT(30),
|
||||
#endif
|
||||
'x', __ifmt,
|
||||
0, nil,
|
||||
{
|
||||
{' ', __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->fmt = f;
|
||||
if(p == ep){ /* installing a new format character */
|
||||
fmtalloc.nfmt++;
|
||||
p = &fmtalloc.fmt[i];
|
||||
p->c = c;
|
||||
}
|
||||
p->fmt = f;
|
||||
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;
|
||||
Convfmt *p, *ep;
|
||||
|
||||
/* conflict-free check - common case */
|
||||
__fmtrlock();
|
||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
||||
for(p=fmtalloc.fmt; p<ep; p++)
|
||||
if(p->c == c){
|
||||
__fmtrunlock();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -5,21 +5,11 @@
|
|||
#include "fmtdef.h"
|
||||
|
||||
void
|
||||
__fmtrlock(void)
|
||||
__fmtlock(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
__fmtrunlock(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
__fmtwlock(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
__fmtwunlock(void)
|
||||
__fmtunlock(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue