ca provider destruction fixed

resolves #53
This commit is contained in:
Matej Sekoranja
2016-06-14 22:34:14 +02:00
parent ce6ea1e51d
commit 3a73cb687b
4 changed files with 51 additions and 8 deletions

View File

@@ -251,7 +251,8 @@ CAChannel::CAChannel(std::string const & _channelName,
channelRequester(_channelRequester),
channelID(0),
channelType(0),
elementCount(0)
elementCount(0),
destroyed(false)
{
PVACCESS_REFCOUNT_MONITOR_CONSTRUCT(caChannel);
}
@@ -265,6 +266,8 @@ void CAChannel::activate(short priority)
&channelID);
if (result == ECA_NORMAL)
{
channelProvider->registerChannel(shared_from_this());
// TODO be sure that ca_connection_handler is not called before this call
EXCEPTION_GUARD(channelRequester->channelCreated(Status::Ok, shared_from_this()));
}
@@ -278,6 +281,19 @@ void CAChannel::activate(short priority)
CAChannel::~CAChannel()
{
PVACCESS_REFCOUNT_MONITOR_DESTRUCT(caChannel);
Lock lock(requestsMutex);
{
if (destroyed)
return;
destroyed = true;
}
channelProvider->unregisterChannel(this);
/* Clear CA Channel */
threadAttach();
ca_clear_channel(channelID);
}
@@ -454,19 +470,24 @@ void CAChannel::printInfo(std::ostream& out)
void CAChannel::destroy()
{
threadAttach();
Lock lock(requestsMutex);
{
if (destroyed)
return;
destroyed = true;
while (!requests.empty())
{
ChannelRequest::shared_pointer request = requests.rbegin()->second.lock();
ChannelRequest::shared_pointer request = requests.begin()->second.lock();
if (request)
request->destroy();
}
}
channelProvider->unregisterChannel(shared_from_this());
/* Clear CA Channel */
threadAttach();
ca_clear_channel(channelID);
}

View File

@@ -25,13 +25,15 @@ using namespace epics::pvAccess::ca;
std::string CAChannelProvider::PROVIDER_NAME = "ca";
CAChannelProvider::CAChannelProvider() : current_context(0)
CAChannelProvider::CAChannelProvider() : current_context(0), destroyed(false)
{
initialize();
}
CAChannelProvider::~CAChannelProvider()
{
// call destroy() to destroy CA context
destroy();
}
std::string CAChannelProvider::getProviderName()
@@ -107,11 +109,17 @@ void CAChannelProvider::destroy()
{
Lock lock(channelsMutex);
{
if (destroyed)
return;
destroyed = true;
while (!channels.empty())
{
Channel::shared_pointer channel = channels.rbegin()->second.lock();
Channel::shared_pointer channel = channels.begin()->second.lock();
if (channel)
channel->destroy();
else
channels.erase(channels.begin());
}
}
@@ -136,6 +144,12 @@ void CAChannelProvider::unregisterChannel(Channel::shared_pointer const & channe
channels.erase(channel.get());
}
void CAChannelProvider::unregisterChannel(Channel* pchannel)
{
Lock lock(channelsMutex);
channels.erase(pchannel);
}
void CAChannelProvider::initialize()
{
/* Create Channel Access */

View File

@@ -112,9 +112,12 @@ private:
epics::pvData::Mutex requestsMutex;
// TODO std::unordered_map
// void* is not the nicest thing, but there is no fast weak_ptr==
// void* is not the nicest thing, but there is no fast weak_ptr::operator==
typedef std::map<void*, ChannelRequest::weak_pointer> RequestsList;
RequestsList requests;
// synced on requestsMutex
bool destroyed;
};

View File

@@ -23,6 +23,7 @@ class epicsShareClass CAChannelProvider :
public std::tr1::enable_shared_from_this<CAChannelProvider>
{
public:
POINTER_DEFINITIONS(CAChannelProvider);
static std::string PROVIDER_NAME;
@@ -63,6 +64,7 @@ public:
void registerChannel(Channel::shared_pointer const & channel);
void unregisterChannel(Channel::shared_pointer const & channel);
void unregisterChannel(Channel* pchannel);
private:
@@ -72,9 +74,12 @@ private:
epics::pvData::Mutex channelsMutex;
// TODO std::unordered_map
// void* is not the nicest thing, but there is no fast weak_ptr==
// void* is not the nicest thing, but there is no fast weak_ptr::operator==
typedef std::map<void*, Channel::weak_pointer> ChannelList;
ChannelList channels;
// synced on channelsMutex
bool destroyed;
};