threadOnce further reduce boilerplate

also latch failure
This commit is contained in:
Michael Davidsaver
2023-09-04 16:17:25 +02:00
parent 59164a63f7
commit d7e49605cc
10 changed files with 76 additions and 59 deletions
+2 -5
View File
@@ -23,7 +23,7 @@ static
IOCGroupConfig* configInstance;
static
void onceConfigInstance(void*)
void onceConfigInstance()
{
try {
configInstance = new IOCGroupConfig;
@@ -32,12 +32,9 @@ void onceConfigInstance(void*)
}
}
static
epicsThreadOnceId onceConfig = EPICS_THREAD_ONCE_INIT;
IOCGroupConfig& IOCGroupConfig::instance()
{
epicsThreadOnce(&onceConfig, &onceConfigInstance, nullptr);
threadOnce<&onceConfigInstance>();
return *configInstance;
}
+6 -10
View File
@@ -56,9 +56,7 @@ struct pvxServer_t {
server::Server srv;
} *pvxServer;
epicsThreadOnceId pvxServerID = EPICS_THREAD_ONCE_INIT;
void pvxServerInit(void*) {
void pvxServerInit() {
pvxServer = new pvxServer_t();
}
} // namespace
@@ -69,7 +67,7 @@ void pvxServerInit(void*) {
* @return the pvxs server instance
*/
server::Server server() {
threadOnce(&pvxServerID, &pvxServerInit);
threadOnce<&pvxServerInit>();
Guard (pvxServer->lock);
if(pvxServer->srv)
return pvxServer->srv;
@@ -84,7 +82,7 @@ void initialisePvxsServer() {
Config conf = ::pvxs::impl::inUnitTest() ? Config::isolated() : Config::from_env();
Server newsrv(conf);
threadOnce(&pvxServerID, &pvxServerInit);
threadOnce<&pvxServerInit>();
Guard G(pvxServer->lock);
if(pvxServer->srv)
throw std::logic_error(SB()<<__func__<<" found existing server?!?");
@@ -182,14 +180,12 @@ struct RefTrack {
std::map<std::string, size_t> refs;
} *refTrack;
epicsThreadOnceId refSavedOnce = EPICS_THREAD_ONCE_INIT;
void refSavedInit(void *) {
void refSavedInit() {
refTrack = new RefTrack();
}
void pvxrefsave() {
epicsThreadOnce(&refSavedOnce, &refSavedInit, nullptr);
threadOnce<&refSavedInit>();
epicsGuard<epicsMutex> G(refTrack->lock);
refTrack->refs = instanceSnapshot();
}
@@ -198,7 +194,7 @@ void pvxrefdiff() {
auto cur(instanceSnapshot());
std::map<std::string, int64_t> diff;
epicsThreadOnce(&refSavedOnce, &refSavedInit, nullptr);
threadOnce<&refSavedInit>();
{
epicsGuard<epicsMutex> G(refTrack->lock);
+4 -9
View File
@@ -52,10 +52,7 @@ VFunctor0::~VFunctor0() {}
}
static
epicsThreadOnceId evthread_once = EPICS_THREAD_ONCE_INIT;
static
void evthread_init(void* unused)
void evthread_init()
{
#if defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED)
evthread_use_windows_threads();
@@ -147,7 +144,7 @@ struct evbase::Pvt final : public epicsThreadRunable
epicsThreadGetStackSize(epicsThreadStackBig),
prio)
{
threadOnce(&evthread_once, &evthread_init, nullptr);
threadOnce<&evthread_init>();
worker.start();
start_sync.wait();
@@ -699,19 +696,17 @@ bool evsocket::init_canIPv6() noexcept
# define getMonotonic getCurrent
#endif
static epicsThreadOnceId mapOnce = EPICS_THREAD_ONCE_INIT;
static IfaceMap* theinstance;
static
void mapInit(void*)
void mapInit()
{
theinstance = new IfaceMap();
}
IfaceMap& IfaceMap::instance()
{
threadOnce(&mapOnce, &mapInit);
threadOnce<&mapInit>();
assert(theinstance);
return *theinstance;
}
+6 -8
View File
@@ -247,7 +247,7 @@ struct logger_gbl_t {
}
} *logger_gbl;
void logger_prepare(void *unused)
void logger_prepare()
{
logger_gbl = new logger_gbl_t;
@@ -260,8 +260,6 @@ void logger_prepare(void *unused)
}
}
epicsThreadOnceId logger_once = EPICS_THREAD_ONCE_INIT;
} // namespace
Level logger::init()
@@ -274,7 +272,7 @@ Level logger::init()
if(this->lvl.compare_exchange_strong(lvl, Level::Warn)) {
// logger now has default config of Level::Err
// we will fully initialize
threadOnce(&logger_once, &logger_prepare, nullptr);
threadOnce<&logger_prepare>();
assert(logger_gbl);
Guard G(logger_gbl->lock);
@@ -326,7 +324,7 @@ void xerrlogHexPrintf(const void *buf, size_t buflen)
void logger_level_set(const char *name, int lvl)
{
threadOnce(&logger_once, &logger_prepare, nullptr);
threadOnce<&logger_prepare>();
assert(logger_gbl);
Guard G(logger_gbl->lock);
@@ -335,7 +333,7 @@ void logger_level_set(const char *name, int lvl)
void logger_level_clear()
{
threadOnce(&logger_once, &logger_prepare, nullptr);
threadOnce<&logger_prepare>();
assert(logger_gbl);
Guard G(logger_gbl->lock);
@@ -348,7 +346,7 @@ void logger_config_env()
if(!env || !*env)
return;
threadOnce(&logger_once, &logger_prepare, nullptr);
threadOnce<&logger_prepare>();
Guard G(logger_gbl->lock);
@@ -397,7 +395,7 @@ namespace pvxs {namespace impl {
void logger_shutdown()
{
threadOnce(&logger_once, &logger_prepare, nullptr);
threadOnce<&logger_prepare>();
errlogFlush();
+2 -5
View File
@@ -38,10 +38,7 @@ static
LPFN_WSARECVMSG WSARecvMsg;
static
epicsThreadOnceId oseOnce = EPICS_THREAD_ONCE_INIT;
static
void oseDoOnce(void*)
void oseDoOnce()
{
evsocket dummy(AF_INET, SOCK_DGRAM, 0);
GUID guid = WSAID_WSARECVMSG;
@@ -64,7 +61,7 @@ void oseDoOnce(void*)
void osiSockAttachExt()
{
osiSockAttach();
epicsThreadOnce(&oseOnce, &oseDoOnce, nullptr);
threadOnce<&oseDoOnce>();
}
void evsocket::enable_SO_RXQ_OVFL() const {}
+2 -5
View File
@@ -38,10 +38,7 @@ DEFINE_LOGGER(log, "pvxs.util");
DEFINE_LOGGER(logiface, "pvxs.iface");
static
epicsThreadOnceId oseOnce = EPICS_THREAD_ONCE_INIT;
static
void oseDoOnce(void*)
void oseDoOnce()
{
evsocket::canIPv6 = evsocket::init_canIPv6();
#ifdef __linux__
@@ -54,7 +51,7 @@ void oseDoOnce(void*)
void osiSockAttachExt() {
osiSockAttach();
epicsThreadOnce(&oseOnce, &oseDoOnce, nullptr);
threadOnce<&oseDoOnce>();
}
void evsocket::enable_SO_RXQ_OVFL() const
+2 -4
View File
@@ -519,17 +519,15 @@ evbase& UDPManager::loop()
}
namespace {
epicsThreadOnceId collector_once = EPICS_THREAD_ONCE_INIT;
void collector_init(void *unused)
void collector_init()
{
(void)unused;
udp_gbl = new udp_gbl_t;
}
} // namespace
UDPManager UDPManager::instance(bool share)
{
threadOnce(&collector_once, &collector_init, nullptr);
threadOnce<&collector_init>();
assert(udp_gbl);
Guard G(udp_gbl->lock);
+13 -11
View File
@@ -77,13 +77,12 @@ unsigned long version_abi_int()
}
namespace {
epicsThreadOnceId ICountOnce = EPICS_THREAD_ONCE_INIT;
struct ICountGbl_t {
RWLock lock;
std::map<std::string, std::atomic<size_t>*> counters;
} *ICountGbl;
void ICountInit(void*)
void ICountInit()
{
ICountGbl = new ICountGbl_t;
}
@@ -92,7 +91,7 @@ void ICountInit(void*)
void registerICount(const char *name, std::atomic<size_t>& Cnt)
{
epicsThreadOnce(&ICountOnce, &ICountInit, nullptr);
threadOnce<&ICountInit>();
auto& gbl = *ICountGbl;
try {
auto L(gbl.lock.lockWriter());
@@ -110,7 +109,7 @@ std::map<std::string, size_t> instanceSnapshot()
std::map<std::string, size_t> ret;
{
epicsThreadOnce(&ICountOnce, &ICountInit, nullptr);
threadOnce<&ICountInit>();
auto& gbl = *ICountGbl;
auto L(gbl.lock.lockReader());
for(auto& pair : gbl.counters) {
@@ -729,28 +728,31 @@ void compat_make_socket_nonblocking(SOCKET sock)
namespace pvxs {namespace impl {
struct onceArgs {
EPICSTHREADFUNC fn;
void *arg;
threadOnceInfo *info;
std::exception_ptr err;
};
static
void onceWrapper(void *raw)
void onceWrapper(void *raw) noexcept
{
auto args = static_cast<onceArgs*>(raw);
try {
args->fn(args->arg);
args->info->fn();
args->info->ok = true;
}catch(...){
args->err = std::current_exception();
args->info->ok = false;
}
}
void threadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC fn, void *arg)
void threadOnce_(threadOnceInfo *info)
{
onceArgs args{fn, arg};
epicsThreadOnce(id, &onceWrapper, &args);
onceArgs args{info};
epicsThreadOnce(&info->id, &onceWrapper, &args);
if(args.err)
std::rethrow_exception(args.err);
if(!info->ok)
throw std::logic_error("threadOnce() : Previous failure");
}
template<>
+17 -1
View File
@@ -29,6 +29,7 @@
#include <event2/util.h>
#include <compilerDependencies.h>
#include <epicsThread.h>
#include <pvxs/version.h>
#include <pvxs/util.h>
@@ -90,8 +91,23 @@ void strDiff(std::ostream& out,
const char *lhs,
const char *rhs);
struct threadOnceInfo {
epicsThreadOnceId id = EPICS_THREAD_ONCE_INIT;
void (* const fn)();
bool ok = false;
explicit constexpr threadOnceInfo(void (*fn)()) :fn(fn) {}
};
PVXS_API
void threadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC fn, void *arg=nullptr);
void threadOnce_(threadOnceInfo *info) ;
template<void (*onceFn)()>
void threadOnce() noexcept {
// global name qualified by onceFn address.
// effectively replicated for each onceFn
static threadOnceInfo info{onceFn};
threadOnce_(&info);
}
namespace idetail {
template <typename I>
+22 -1
View File
@@ -267,11 +267,31 @@ void testStrDiff()
"+ \" yyy\"\n");
}
size_t onceCount[2];
template<size_t I>
void onceInc() {
onceCount[I]++;
}
void testOnce()
{
testShow()<<__func__;
threadOnce<onceInc<0>>();
threadOnce<onceInc<1>>();
threadOnce<onceInc<0>>();
threadOnce<onceInc<1>>();
testEq(onceCount[0], 1u);
testEq(onceCount[1], 1u);
}
} // namespace
MAIN(testutil)
{
testPlan(33);
testPlan(35);
testTrue(version_abi_check())<<" 0x"<<std::hex<<PVXS_VERSION<<" ~= 0x"<<std::hex<<PVXS_ABI_VERSION;
testServerGUID();
testFill();
@@ -280,5 +300,6 @@ MAIN(testutil)
testAccount();
testTestEq();
testStrDiff();
testOnce();
return testDone();
}