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 */
|
/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
#include "plan9.h"
|
#include "plan9.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "fmtdef.h"
|
#include "fmtdef.h"
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Maxfmt = 64
|
Maxfmt = 128
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Convfmt Convfmt;
|
typedef struct Convfmt Convfmt;
|
||||||
struct Convfmt
|
struct Convfmt
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
|
Fmts fmt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct
|
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];
|
Convfmt fmt[Maxfmt];
|
||||||
} fmtalloc;
|
} fmtalloc = {
|
||||||
|
#ifdef PLAN9PORT
|
||||||
static Convfmt knownfmt[] = {
|
ATOMIC_VAR_INIT(27),
|
||||||
' ', __flagfmt,
|
#else
|
||||||
'#', __flagfmt,
|
ATOMIC_VAR_INIT(30),
|
||||||
'%', __percentfmt,
|
#endif
|
||||||
'\'', __flagfmt,
|
{
|
||||||
'+', __flagfmt,
|
{' ', __flagfmt},
|
||||||
',', __flagfmt,
|
{'#', __flagfmt},
|
||||||
'-', __flagfmt,
|
{'%', __percentfmt},
|
||||||
'C', __runefmt, /* Plan 9 addition */
|
{'\'', __flagfmt},
|
||||||
'E', __efgfmt,
|
{'+', __flagfmt},
|
||||||
#ifndef PLAN9PORT
|
{',', __flagfmt},
|
||||||
'F', __efgfmt, /* ANSI only */
|
{'-', __flagfmt},
|
||||||
#endif
|
{'C', __runefmt}, /* Plan 9 addition */
|
||||||
'G', __efgfmt,
|
{'E', __efgfmt},
|
||||||
#ifndef PLAN9PORT
|
#ifndef PLAN9PORT
|
||||||
'L', __flagfmt, /* ANSI only */
|
{'F', __efgfmt}, /* ANSI only */
|
||||||
#endif
|
#endif
|
||||||
'S', __runesfmt, /* Plan 9 addition */
|
{'G', __efgfmt},
|
||||||
'X', __ifmt,
|
#ifndef PLAN9PORT
|
||||||
'b', __ifmt, /* Plan 9 addition */
|
{'L', __flagfmt}, /* ANSI only */
|
||||||
'c', __charfmt,
|
#endif
|
||||||
'd', __ifmt,
|
{'S', __runesfmt}, /* Plan 9 addition */
|
||||||
'e', __efgfmt,
|
{'X', __ifmt},
|
||||||
'f', __efgfmt,
|
{'b', __ifmt}, /* Plan 9 addition */
|
||||||
'g', __efgfmt,
|
{'c', __charfmt},
|
||||||
'h', __flagfmt,
|
{'d', __ifmt},
|
||||||
#ifndef PLAN9PORT
|
{'e', __efgfmt},
|
||||||
'i', __ifmt, /* ANSI only */
|
{'f', __efgfmt},
|
||||||
#endif
|
{'g', __efgfmt},
|
||||||
'l', __flagfmt,
|
{'h', __flagfmt},
|
||||||
'n', __countfmt,
|
#ifndef PLAN9PORT
|
||||||
'o', __ifmt,
|
{'i', __ifmt}, /* ANSI only */
|
||||||
'p', __ifmt,
|
#endif
|
||||||
'r', __errfmt,
|
{'l', __flagfmt},
|
||||||
's', __strfmt,
|
{'n', __countfmt},
|
||||||
#ifdef PLAN9PORT
|
{'o', __ifmt},
|
||||||
'u', __flagfmt,
|
{'p', __ifmt},
|
||||||
#else
|
{'r', __errfmt},
|
||||||
'u', __ifmt,
|
{'s', __strfmt},
|
||||||
#endif
|
#ifdef PLAN9PORT
|
||||||
'x', __ifmt,
|
{'u', __flagfmt},
|
||||||
0, nil,
|
#else
|
||||||
|
{'u', __ifmt},
|
||||||
|
#endif
|
||||||
|
{'x', __ifmt},
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int (*fmtdoquote)(int);
|
int (*fmtdoquote)(int);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* __fmtwlock() must be set
|
* __fmtlock() must be set
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
__fmtinstall(int c, Fmts f)
|
__fmtinstall(int c, Fmts f)
|
||||||
{
|
{
|
||||||
Convfmt *p, *ep;
|
Convfmt *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
if(c<=0 || c>=65536)
|
if(c<=0 || c>=65536)
|
||||||
return -1;
|
return -1;
|
||||||
if(!f)
|
if(!f)
|
||||||
f = __badfmt;
|
f = __badfmt;
|
||||||
|
|
||||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
i = atomic_load(&fmtalloc.nfmt);
|
||||||
for(p=fmtalloc.fmt; p<ep; p++)
|
if(i == Maxfmt)
|
||||||
if(p->c == c)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(p == &fmtalloc.fmt[Maxfmt])
|
|
||||||
return -1;
|
return -1;
|
||||||
|
p = &fmtalloc.fmt[i];
|
||||||
|
p->c = c;
|
||||||
p->fmt = f;
|
p->fmt = f;
|
||||||
if(p == ep){ /* installing a new format character */
|
atomic_store(&fmtalloc.nfmt, i+1);
|
||||||
fmtalloc.nfmt++;
|
|
||||||
p->c = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -106,43 +111,21 @@ fmtinstall(int c, int (*f)(Fmt*))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
__fmtwlock();
|
__fmtlock();
|
||||||
ret = __fmtinstall(c, f);
|
ret = __fmtinstall(c, f);
|
||||||
__fmtwunlock();
|
__fmtunlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Fmts
|
static Fmts
|
||||||
fmtfmt(int c)
|
fmtfmt(int c)
|
||||||
{
|
{
|
||||||
Convfmt *p, *ep, *kp;
|
Convfmt *p, *ep;
|
||||||
|
|
||||||
/* conflict-free check - common case */
|
ep = &fmtalloc.fmt[atomic_load(&fmtalloc.nfmt)];
|
||||||
__fmtrlock();
|
for(p=ep; p-- > fmtalloc.fmt; )
|
||||||
ep = &fmtalloc.fmt[fmtalloc.nfmt];
|
if(p->c == c)
|
||||||
for(p=fmtalloc.fmt; p<ep; p++)
|
|
||||||
if(p->c == c){
|
|
||||||
__fmtrunlock();
|
|
||||||
return p->fmt;
|
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;
|
return __badfmt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,8 @@ void * __fmtflush(Fmt *f, void *t, int len);
|
||||||
int __fmtpad(Fmt *f, int n);
|
int __fmtpad(Fmt *f, int n);
|
||||||
double __fmtpow10(int n);
|
double __fmtpow10(int n);
|
||||||
int __fmtrcpy(Fmt *f, const void *vm, int n);
|
int __fmtrcpy(Fmt *f, const void *vm, int n);
|
||||||
void __fmtrlock(void);
|
void __fmtlock(void);
|
||||||
void __fmtrunlock(void);
|
void __fmtunlock(void);
|
||||||
void __fmtwlock(void);
|
|
||||||
void __fmtwunlock(void);
|
|
||||||
int __ifmt(Fmt *f);
|
int __ifmt(Fmt *f);
|
||||||
int __isInf(double d, int sign);
|
int __isInf(double d, int sign);
|
||||||
int __isNaN(double d);
|
int __isNaN(double d);
|
||||||
|
|
|
@ -5,21 +5,11 @@
|
||||||
#include "fmtdef.h"
|
#include "fmtdef.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
__fmtrlock(void)
|
__fmtlock(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
__fmtrunlock(void)
|
__fmtunlock(void)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__fmtwlock(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__fmtwunlock(void)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,16 @@
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
|
|
||||||
static RWLock fmtlock;
|
static Lock fmtlock;
|
||||||
|
|
||||||
void
|
void
|
||||||
__fmtrlock(void)
|
__fmtlock(void)
|
||||||
{
|
{
|
||||||
rlock(&fmtlock);
|
lock(&fmtlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
__fmtrunlock(void)
|
__fmtunlock(void)
|
||||||
{
|
{
|
||||||
runlock(&fmtlock);
|
unlock(&fmtlock);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__fmtwlock(void)
|
|
||||||
{
|
|
||||||
wlock(&fmtlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
__fmtwunlock(void)
|
|
||||||
{
|
|
||||||
wunlock(&fmtlock);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue