evhelper external/internal
This commit is contained in:
+51
-16
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user