1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/lib/libast/aso/aso.c
Martijn Dekker 807863c29a Update author attributions in all source files
This commit:

1. Updates the COPYRIGHT file with all the contributors to ksh
   93u+m since the reboot, based on the commit history, sorted by
   number of commits in descending order. It also separates the
   authors of backported contributions from direct contributors.

2. Adds missing contributors of source each file to that file's
   copyright header based on that file's commit history.

The script used to maintain this is now up at:
https://github.com/ksh93/ksh/wiki/update-copyright.sh

In addition, the original ast copyright notice is restored to
its EPL 1.0 version -- that is what AT&T Intellectual Property
originally licensed this code under, and we are the ones who
upgraded it to EPL 2.0 (as allowed by EPL 1.0) in 441dcc04.
The history should be accurate.
2022-07-31 00:47:08 +02:00

847 lines
14 KiB
C

/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2012 AT&T Intellectual Property *
* Copyright (c) 2020-2022 Contributors to ksh 93u+m *
* and is licensed under the *
* Eclipse Public License, Version 2.0 *
* *
* A copy of the License is available at *
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html *
* (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* Martijn Dekker <martijn@inlv.org> *
* *
***********************************************************************/
#include "asohdr.h"
#include "FEATURE/aso"
/*
* AST atomic scalar operations
* AT&T Research
*
* cas { 8 16 32 [64] } subset snarfed from the work by
* Adam Edgar and Kiem-Phong Vo 2010-10-10
*
* lock methods and emulations by
* Glenn Fowler 2011-11-11
*
* hopefully stable by 2012-12-12
*/
#if !_PACKAGE_ast
#include <stdio.h>
#define sfsprintf snprintf
#endif
#if defined(_aso_casptr) && (defined(_aso_cas32) || defined(_aso_cas64))
#define ASO_METHOD (&_aso_meth_intrinsic)
#define ASO_LOCKF 0
#else
#define ASO_METHOD (&_aso_meth_signal)
#define ASO_LOCKF _aso_lock_signal
#endif
typedef union
{
uint8_t c[2];
uint16_t i;
} U16_8_t;
typedef union
{
uint8_t c[4];
uint32_t i;
} U32_8_t;
typedef union
{
uint16_t c[2];
uint32_t i;
} U32_16_t;
#ifdef _ast_int8_t
typedef union
{
uint8_t c[8];
uint64_t i;
} U64_8_t;
typedef union
{
uint16_t c[4];
uint64_t i;
} U64_16_t;
typedef union
{
uint32_t c[2];
uint64_t i;
} U64_32_t;
#endif
typedef struct State_s
{
Asometh_t* meth;
Asolock_f lockf;
Asoerror_f errorf;
uintmax_t hung;
unsigned int hung2;
void* data;
pid_t pid;
} State_t;
static unsigned int _aso_data_signal;
static ssize_t
_aso_lock_signal(void* data, ssize_t k, void volatile* p)
{
if (k >= 0)
{
_aso_data_signal--;
return 0;
}
while (_aso_data_signal++)
_aso_data_signal--;
return 1;
}
static Asometh_t _aso_meth_signal = { "signal", ASO_SIGNAL, 0, _aso_lock_signal };
extern Asometh_t _aso_meth_semaphore;
extern Asometh_t _aso_meth_fcntl;
static Asometh_t _aso_meth_intrinsic = { "intrinsic", ASO_INTRINSIC|ASO_PROCESS|ASO_THREAD|ASO_SIGNAL, 0, 0 };
static Asometh_t* method[] =
{
&_aso_meth_signal,
#if defined(_ast_int8_t) && defined(_aso_cas64) || !defined(_ast_int8_t) && defined(_aso_cas32)
&_aso_meth_intrinsic,
#endif
#if _aso_semaphore
&_aso_meth_semaphore,
#endif
#if _aso_fcntl
&_aso_meth_fcntl,
#endif
};
static State_t state =
{
ASO_METHOD, ASO_LOCKF
};
static int
asoerror(int type, const char* format, const char* a, const char* b, long n)
{
char buf[128];
if (b)
sfsprintf(buf, sizeof(buf), format, a, b, n);
else if (a)
sfsprintf(buf, sizeof(buf), format, a, n);
else
sfsprintf(buf, sizeof(buf), format, n);
return state.errorf(type, buf);
}
/*
* if type!=0 return lock method for type with name details
* else if name!=0 return lock method matching <name>[,<details>]
* else return the current lock method
* 0 returned on error
*
* the user visible asometh() calls this function
* it allows, e.g., for -ltaso to provide an asometh() intercept
* that prepends its ASO_THREAD methods ahead of the _asometh() methods
*/
Asometh_t*
_asometh(int type, void* data)
{
size_t n;
int i;
char* e;
Asometh_t* meth;
char* name;
if (type == ASO_NEXT)
{
if (!(meth = (Asometh_t*)data))
return method[0];
for (i = 0; i < elementsof(method) - 1; i++)
if (meth == method[i])
return method[i+1];
return 0;
}
if (type)
{
for (i = 0; i < elementsof(method); i++)
if (method[i]->type & type)
{
method[i]->details = (char*)data;
return method[i];
}
return 0;
}
if (!(name = (char*)data))
return state.meth;
n = (e = strchr(name, ',')) ? (e - name) : strlen(name);
for (i = 0; i < elementsof(method); i++)
if (strncmp(name, method[i]->name, n) == 0)
{
if (e)
method[i]->details = e + 1;
return method[i];
}
return 0;
}
/*
* clean up lock method on exit
*/
static void
asoexit(void)
{
if (state.meth && state.meth->initf && state.data && state.pid == getpid())
{
state.lockf = ASO_METHOD->lockf;
state.meth->initf(state.data, 0);
state.data = 0;
}
}
/*
* initialize lock method
*/
int
asoinit(const char* details, Asometh_t* meth, Asodisc_t* disc)
{
void* data;
if (disc)
{
state.errorf = disc->errorf;
state.hung2 = disc->hung;
state.hung = 1;
state.hung <<= state.hung2;
state.hung--;
}
if (!meth)
return state.pid != 0;
if (!meth->lockf && !(meth->type & ASO_INTRINSIC))
{
if (state.errorf)
asoerror(ASO_EMETHOD, "%s method has no lock function", meth->name, 0, 0);
return -1;
}
state.lockf = ASO_METHOD->lockf;
if (state.meth && state.meth->initf && state.data)
{
state.meth->initf(state.data, 0);
state.data = 0;
}
if (!meth->initf)
data = 0;
else if (!(data = meth->initf(0, details ? details : meth->details)))
{
state.meth = ASO_METHOD;
if (state.errorf)
asoerror(ASO_EMETHOD, "%s method initialization failed -- reverting to the %s method", meth->name, state.meth->name, 0);
return -1;
}
state.meth = meth;
state.data = data;
state.lockf = meth->lockf;
if (!state.pid)
{
state.pid = getpid();
atexit(asoexit);
}
return 0;
}
/*
* loop check for hung spin locks
* and periodic relinquishing of the processor
*/
int
asoloop(uintmax_t rep)
{
if (state.hung && !(rep & state.hung) && state.errorf)
return asoerror(ASO_EHUNG, "spin lock possibly hung after 2^%u attempts", 0, 0, state.hung2);
return (rep & ASO_RELAX) ? 0 : asorelax(1);
}
/*
* error checking state.lockf() call
*/
static ssize_t
lock(void* data, ssize_t k, void volatile* p)
{
ssize_t r;
if ((r = state.lockf(data, k, p)) < 0 && state.errorf)
asoerror(ASO_EMETHOD, "%s method lock failed", state.meth->name, 0, 0);
return r;
}
/*
* sync and return "current" value
*/
uint8_t
asoget8(uint8_t volatile* p)
{
int o;
do
{
o = *p;
} while (asocas8(p, o, o) != o);
return o;
}
uint16_t
asoget16(uint16_t volatile* p)
{
int o;
do
{
o = *p;
} while (asocas16(p, o, o) != o);
return o;
}
uint32_t
asoget32(uint32_t volatile* p)
{
uint32_t o;
do
{
o = *p;
} while (asocas32(p, o, o) != o);
return o;
}
#ifdef _ast_int8_t
uint64_t
asoget64(uint64_t volatile* p)
{
uint64_t o;
do
{
o = *p;
} while (asocas64(p, o, o) != o);
return o;
}
#endif
void*
asogetptr(void volatile* p)
{
void* o;
do
{
o = *(void* volatile*)p;
} while (asocasptr(p, o, o) != o);
return o;
}
/*
* increment and return old value
*/
uint8_t
asoinc8(uint8_t volatile* p)
{
ssize_t k;
int o;
#if defined(_aso_inc8)
if (!state.lockf)
return _aso_inc8(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas8(p, o, o + 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)++;
lock(state.data, k, p);
return o;
}
uint16_t
asoinc16(uint16_t volatile* p)
{
ssize_t k;
int o;
#if defined(_aso_inc16)
if (!state.lockf)
return _aso_inc16(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas16(p, o, o + 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)++;
lock(state.data, k, p);
return o;
}
uint32_t
asoinc32(uint32_t volatile* p)
{
ssize_t k;
int o;
#if defined(_aso_inc32)
if (!state.lockf)
return _aso_inc32(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas32(p, o, o + 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)++;
lock(state.data, k, p);
return o;
}
#ifdef _ast_int8_t
uint64_t
asoinc64(uint64_t volatile* p)
{
ssize_t k;
uint64_t o;
#if defined(_aso_inc64)
if (!state.lockf)
return _aso_inc64(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas64(p, o, o + 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)++;
lock(state.data, k, p);
return o;
}
#endif
/*
* decrement and return old value
*/
uint8_t
asodec8(uint8_t volatile* p)
{
ssize_t k;
int o;
#if defined(_aso_dec8)
if (!state.lockf)
return _aso_dec8(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas8(p, o, o - 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)--;
lock(state.data, k, p);
return o;
}
uint16_t
asodec16(uint16_t volatile* p)
{
ssize_t k;
int o;
#if defined(_aso_dec16)
if (!state.lockf)
return _aso_dec16(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas16(p, o, o - 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)--;
lock(state.data, k, p);
return o;
}
uint32_t
asodec32(uint32_t volatile* p)
{
ssize_t k;
int o;
#if defined(_aso_dec32)
if (!state.lockf)
return _aso_dec32(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas32(p, o, o - 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)--;
lock(state.data, k, p);
return o;
}
#ifdef _ast_int8_t
uint64_t
asodec64(uint64_t volatile* p)
{
ssize_t k;
uint64_t o;
#if defined(_aso_dec64)
if (!state.lockf)
return _aso_dec64(p);
#else
if (!state.lockf)
{
do
{
o = *p;
} while (asocas64(p, o, o - 1) != o);
return o;
}
#endif
k = lock(state.data, 0, p);
o = (*p)--;
lock(state.data, k, p);
return o;
}
#endif
/*
* { 8 16 32 [64] } compare with old, swap with new if same, and return old value
*/
uint8_t
asocas8(uint8_t volatile* p, int o, int n)
{
ssize_t k;
#if defined(_aso_cas8)
if (!state.lockf)
return _aso_cas8(p, o, n);
#elif defined(_aso_cas16)
if (!state.lockf)
{
U16_8_t u;
U16_8_t v;
U16_8_t* a;
int s;
int i;
s = (int)(integralof(p) & (sizeof(u.i) - 1));
a = (U16_8_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
for (;;)
{
u.i = a->i;
u.c[s] = o;
v.i = u.i;
v.c[s] = n;
if (_aso_cas16(&a->i, u.i, v.i) == u.i)
break;
for (i = 0;; i++)
if (i >= elementsof(u.c))
return a->c[s];
else if (i != s && u.c[i] != a->c[i])
break;
}
return o;
}
#elif defined(_aso_cas32)
if (!state.lockf)
{
U32_8_t u;
U32_8_t v;
U32_8_t* a;
int s;
int i;
s = (int)(integralof(p) & (sizeof(u.i) - 1));
a = (U32_8_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
for (;;)
{
u.i = a->i;
u.c[s] = o;
v.i = u.i;
v.c[s] = n;
if (_aso_cas32(&a->i, u.i, v.i) == u.i)
break;
for (i = 0;; i++)
if (i >= elementsof(u.c))
return a->c[s];
else if (i != s && u.c[i] != a->c[i])
break;
}
return o;
}
#elif defined(_aso_cas64)
if (!state.lockf)
{
U64_8_t u;
U64_8_t v;
U64_8_t* a;
int s;
int i;
s = (int)(integralof(p) & (sizeof(u.i) - 1));
a = (U64_8_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
for (;;)
{
u.i = a->i;
u.c[s] = o;
v.i = u.i;
v.c[s] = n;
if (_aso_cas64(&a->i, u.i, v.i) == u.i)
break;
for (i = 0;; i++)
if (i >= elementsof(u.c))
return a->c[s];
else if (i != s && u.c[i] != a->c[i])
break;
}
return o;
}
#endif
k = lock(state.data, 0, p);
if (*p == o)
*p = n;
else
o = *p;
lock(state.data, k, p);
return o;
}
uint16_t
asocas16(uint16_t volatile* p, uint16_t o, uint16_t n)
{
ssize_t k;
#if defined(_aso_cas16)
if (!state.lockf)
return _aso_cas16(p, o, n);
#elif defined(_aso_cas32)
if (!state.lockf)
{
U32_16_t u;
U32_16_t v;
U32_16_t* a;
int s;
int i;
s = (int)(integralof(p) & (sizeof(u.i) - 1)) / 2;
a = (U32_16_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
for (;;)
{
u.i = a->i;
u.c[s] = o;
v.i = u.i;
v.c[s] = n;
if (_aso_cas32(&a->i, u.i, v.i) == u.i)
break;
for (i = 0;; i++)
if (i >= elementsof(u.c))
return a->c[s];
else if (i != s && u.c[i] != a->c[i])
break;
}
return o;
}
#elif defined(_aso_cas64)
if (!state.lockf)
{
U64_16_t u;
U64_16_t v;
U64_16_t* a;
int s;
int i;
s = (int)(integralof(p) & (sizeof(u.i) - 1)) / 2;
a = (U64_16_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
for (;;)
{
u.i = a->i;
u.c[s] = o;
v.i = u.i;
v.c[s] = n;
if (_aso_cas64(&a->i, u.i, v.i) == u.i)
break;
for (i = 0;; i++)
if (i >= elementsof(u.c))
return a->c[s];
else if (i != s && u.c[i] != a->c[i])
break;
}
return o;
}
#endif
k = lock(state.data, 0, p);
if (*p == o)
*p = n;
else
o = *p;
lock(state.data, k, p);
return o;
}
uint32_t
asocas32(uint32_t volatile* p, uint32_t o, uint32_t n)
{
ssize_t k;
#if defined(_aso_cas32)
if (!state.lockf)
return _aso_cas32(p, o, n);
#elif defined(_aso_cas64)
if (!state.lockf)
{
U64_32_t u;
U64_32_t v;
U64_32_t* a;
int s;
int i;
s = (int)(integralof(p) & (sizeof(u.i) - 1)) / 4;
a = (U64_32_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
for (;;)
{
u.i = a->i;
u.c[s] = o;
v.i = u.i;
v.c[s] = n;
if (_aso_cas64(&a->i, u.i, v.i) == u.i)
break;
for (i = 0;; i++)
if (i >= elementsof(u.c))
return a->c[s];
else if (i != s && u.c[i] != a->c[i])
break;
}
return o;
}
#endif
k = lock(state.data, 0, p);
if (*p == o)
*p = n;
else
o = *p;
lock(state.data, k, p);
return o;
}
#ifdef _ast_int8_t
uint64_t
asocas64(uint64_t volatile* p, uint64_t o, uint64_t n)
{
ssize_t k;
#if defined(_aso_cas64)
if (!state.lockf)
return _aso_cas64(p, o, n);
#endif
k = lock(state.data, 0, p);
if (*p == o)
*p = n;
else
o = *p;
lock(state.data, k, p);
return o;
}
#endif
/*
* compare with old, swap with new if same, and return old value
*/
void*
asocasptr(void volatile* p, void* o, void* n)
{
ssize_t k;
#if defined(_aso_casptr)
if (!state.lockf)
return _aso_casptr((void**)p, o, n);
#endif
k = lock(state.data, 0, p);
if (*(void* volatile*)p == o)
*(void* volatile*)p = n;
else
o = *(void* volatile*)p;
lock(state.data, k, p);
return o;
}