threadOnce further reduce boilerplate
also latch failure
This commit is contained in:
+2
-5
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user