evhelper external/internal

This commit is contained in:
Michael Davidsaver
2020-12-30 07:42:35 -08:00
parent 8eac7c9941
commit bd6fb00dd5
3 changed files with 98 additions and 26 deletions
+51 -16
View File
@@ -105,6 +105,8 @@ struct evbase::Pvt : public epicsThreadRunable
{
SockAttach attach;
std::weak_ptr<Pvt> internal_self;
struct Work {
std::function<void()> fn;
std::exception_ptr *result;
@@ -140,10 +142,7 @@ struct evbase::Pvt : public epicsThreadRunable
}
}
virtual ~Pvt()
{
join();
}
virtual ~Pvt() {}
void join()
{
@@ -238,12 +237,28 @@ struct evbase::Pvt : public epicsThreadRunable
};
evbase::evbase(const std::string &name, unsigned prio)
:pvt(new Pvt(name, prio))
,base(pvt->base.get())
{}
{
auto internal(std::make_shared<Pvt>(name, prio));
internal->internal_self = internal;
pvt.reset(internal.get(), [internal](Pvt*) mutable {
auto temp(std::move(internal));
temp->join();
});
base = pvt->base.get();
}
evbase::~evbase() {}
evbase evbase::internal() const
{
evbase ret;
ret.pvt = decltype(pvt)(pvt->internal_self);
ret.base = base;
return ret;
}
void evbase::join() const
{
pvt->join();
@@ -254,13 +269,16 @@ void evbase::sync() const
call([](){});
}
void evbase::dispatch(std::function<void()>&& fn) const
bool evbase::_dispatch(std::function<void()>&& fn, bool dothrow) const
{
bool empty;
{
Guard G(pvt->lock);
if(!pvt->running)
throw std::logic_error("Worker stopped");
if(!pvt->running) {
if(dothrow)
throw std::logic_error("Worker stopped");
return false;
}
empty = pvt->actions.empty();
pvt->actions.emplace_back(std::move(fn), nullptr, nullptr);
}
@@ -268,13 +286,15 @@ void evbase::dispatch(std::function<void()>&& fn) const
timeval now{};
if(empty && event_add(pvt->dowork.get(), &now))
throw std::runtime_error("Unable to wakeup dispatch()");
return true;
}
void evbase::call(std::function<void()>&& fn) const
bool evbase::_call(std::function<void()>&& fn, bool dothrow) const
{
if(pvt->worker.isCurrentThread()) {
fn();
return;
return true;
}
static ThreadEvent done;
@@ -283,8 +303,11 @@ void evbase::call(std::function<void()>&& fn) const
bool empty;
{
Guard G(pvt->lock);
if(!pvt->running)
throw std::logic_error("Worker stopped");
if(!pvt->running) {
if(dothrow)
throw std::logic_error("Worker stopped");
return false;
}
empty = pvt->actions.empty();
pvt->actions.emplace_back(std::move(fn), &result, done.get());
}
@@ -297,6 +320,7 @@ void evbase::call(std::function<void()>&& fn) const
Guard G(pvt->lock);
if(result)
std::rethrow_exception(result);
return true;
}
void evbase::assertInLoop() const
@@ -309,9 +333,20 @@ void evbase::assertInLoop() const
}
}
bool evbase::inLoop() const
bool evbase::assertInRunningLoop() const
{
return pvt->worker.isCurrentThread();
if(pvt->worker.isCurrentThread())
return true;
Guard G(pvt->lock);
if(!pvt->running)
return false;
char name[32];
pvt->worker.getName(name, sizeof(name));
log_exc_printf(logerr, "Not in running evbase worker: \"%s\" != \"%s\"\n",
name, epicsThread::getNameSelf());
throw std::logic_error("Not in running evbase worker");
}
evsocket::evsocket(evutil_socket_t sock)
+35 -6
View File
@@ -61,22 +61,51 @@ struct owned_ptr : public std::unique_ptr<T>
struct PVXS_API evbase {
evbase() = default;
evbase(const evbase&) = default;
evbase(evbase&&) = default;
explicit evbase(const std::string& name, unsigned prio=0);
~evbase();
evbase internal() const;
void join() const;
void sync() const;
// queue request to execute in event loop. return immediately.
void dispatch(std::function<void()>&& fn) const;
private:
bool _dispatch(std::function<void()>&& fn, bool dothrow) const;
bool _call(std::function<void()>&& fn, bool dothrow) const;
public:
// queue request to execute in event loop. return after executed.
void call(std::function<void()>&& fn) const;
inline
void call(std::function<void()>&& fn) const {
_call(std::move(fn), true);
}
inline
bool tryCall(std::function<void()>&& fn) const {
return _call(std::move(fn), false);
}
// queue request to execute in event loop. return immediately.
inline
void dispatch(std::function<void()>&& fn) const {
_dispatch(std::move(fn), true);
}
inline
bool tryDispatch(std::function<void()>&& fn) const {
return _dispatch(std::move(fn), false);
}
bool tryInvoke(bool docall, std::function<void()>&& fn) const {
if(docall)
return tryCall(std::move(fn));
else
return tryDispatch(std::move(fn));
}
void assertInLoop() const;
bool inLoop() const;
//! Caller must be on the worker, or the worker must be stopped.
//! @returns true if working is running.
bool assertInRunningLoop() const;
inline void reset() { pvt.reset(); }
+12 -4
View File
@@ -29,15 +29,13 @@ void test_call()
auto snap = instanceSnapshot();
testEq(snap["evbase"], 1u);
testOk1(!base.inLoop());
{
bool called = false;
base.call([&called, &base]() {
testDiag("in loop 1");
called = true;
testOk1(!!base.inLoop());
base.assertInLoop();
testTrue(base.assertInRunningLoop());
});
testOk1(called==true);
}
@@ -65,6 +63,16 @@ void test_call()
testFail("Caught wrong exception : %s \"%s\"", typeid(e).name(), e.what());
}
auto internal(base.internal());
base = evbase();
// loop stopped
testFalse(internal.assertInRunningLoop());
testThrows<std::logic_error>([&internal]() {
internal.call([]() {});
});
testFalse(internal.tryCall([](){}));
}
void test_fill_evbuf()
@@ -116,7 +124,7 @@ void test_fill_evbuf()
MAIN(testev)
{
SockAttach attach;
testPlan(15);
testPlan(17);
testSetup();
test_call();
test_fill_evbuf();