Collect ca_client_context operations

Each instance of the caContext class represents a separate CA context,
so each CAChannelProvider creates one and keeps a shared_ptr to it,
making that available to its channels and channel operations. These
also take their own shared_ptr to it as well so the context cannot be
destroyed while it might be needed.

A related caContext Attach object is intended to be short-lived, and
to be allocated on the stack. When created it saves the current CA
context for the thread, replacing it from the caContext given to its
constructor. CA operations will now use the attached context. When the
Attach destructor runs it detaches the thread from the current context
(checking still has the expected value) and re-attaches the thread to
any context that was saved by the constructor.
This commit is contained in:
Andrew Johnson
2020-10-08 00:13:24 -05:00
committed by mdavidsaver
parent 25dde0f4ba
commit f9c40e96cf
8 changed files with 175 additions and 91 deletions

65
src/ca/caContext.cpp Normal file
View File

@@ -0,0 +1,65 @@
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* pvAccessCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include <cadef.h>
#define epicsExportSharedSymbols
#include "caContext.h"
namespace epics {
namespace pvAccess {
namespace ca {
CAContext::CAContext()
{
int result = ca_context_create(ca_enable_preemptive_callback);
if (result != ECA_NORMAL)
throw std::runtime_error("Can't create CA context");
ca_context = ca_current_context();
}
ca_client_context* CAContext::attach()
{
ca_client_context *thread_context = ca_current_context();
if (thread_context != ca_context) {
if (thread_context)
ca_detach_context();
int result = ca_attach_context(ca_context);
if (result != ECA_NORMAL)
throw std::runtime_error("Can't attach to CA context");
}
return thread_context;
}
void CAContext::detach(ca_client_context* restore) \
{
ca_client_context *thread_context = ca_current_context();
if (thread_context != ca_context)
std::cerr << "CA context was changed!" << std::endl;
ca_detach_context();
if (restore) {
int result = ca_attach_context(restore);
if (result != ECA_NORMAL)
std::cerr << "Can't re-attach to CA context" << std::endl;
}
}
CAContext::~CAContext()
{
ca_client_context *thread_context = attach();
ca_context_destroy();
if (thread_context != ca_context) {
int result = ca_attach_context(ca_context);
if (result != ECA_NORMAL)
std::cerr << "Can't re-attach to CA context" << std::endl;
}
}
}}}