mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
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.
847 lines
14 KiB
C
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;
|
|
}
|