This commit is contained in:
mrkraimer
2018-05-03 08:30:06 -04:00
32 changed files with 707 additions and 694 deletions

View File

@@ -1,8 +1,33 @@
/** @page pvarelease_notes Release Notes
Release 6.0.0 (UNRELEASED)
Release 6.1.0 (UNRELEASED)
==========================
- Deprecations
- pv/namedLockPattern.h
- Removals
- Remove deprecated methods configure(), flush(), and poll() from ChannelProvider.
- Remove RPCClient::sendRequest()
- Remove RPCService::destroy() and dispose()
- Typedefs GUID, Service
- Fixes
- pvAccessLog() add EPICS_PRINTF_STYLE()
- ioc: shutdown PVA server via epicsAtExit()
- fix 'pva' provider registration during static linking
- Various fixes related to shared_ptr loop breaking.
- Several *NULL bugs.
- PVA client context: avoid lock order violations
- Changes
- pvac::Monitor - shallow copy into Monitor::root
- pvget -m shows time and alarm if available (thanks to Andrew Starritt)
- Additions
- pvput to NTEnum via. string now supported
- pvac::* add valid() method and boolean cast shorthand. Also reset() and operator<<(ostream, ...)
- Add pvac::ClientProvider::named()
Release 6.0.0 (Dec 2017)
========================
- Incompatible changes
- Requires pvDataCPP >=7.0.0 due to headers moved from pvDataCPP into this module: requester.h, destoryable.h, and monitor.h
- Major changes to shared_ptr ownership rules for epics::pvAccess::ChannelProvider and

View File

@@ -36,8 +36,6 @@ using namespace epics::pvAccess;
enum PrintMode { ValueOnlyMode, StructureMode, TerseMode };
PrintMode mode = ValueOnlyMode;
char fieldSeparator = ' ';
bool columnMajor = false;
bool transpose = false;
@@ -242,7 +240,7 @@ void formatTable(std::ostream& o,
{
for (size_t i = 0; i < numColumns; i++)
{
if (separator == ' ')
if (fieldSeparator == ' ')
{
int width = std::max(labels[i].size()+padding, maxColumnLength);
o << std::setw(width) << std::right;
@@ -250,7 +248,7 @@ void formatTable(std::ostream& o,
}
else if (i > 0)
{
o << separator;
o << fieldSeparator;
}
o << labels[i];
@@ -263,7 +261,7 @@ void formatTable(std::ostream& o,
{
for (size_t i = 0; i < numColumns; i++)
{
if (separator == ' ' && (showHeader || numColumns > 1))
if (fieldSeparator == ' ' && (showHeader || numColumns > 1))
{
int width = std::max(labels[i].size()+padding, maxColumnLength);
o << setw(width) << std::right;
@@ -271,7 +269,7 @@ void formatTable(std::ostream& o,
}
else if (i > 0)
{
o << separator;
o << fieldSeparator;
}
PVScalarArrayPtr array = columnData[i];
@@ -297,7 +295,7 @@ void formatTable(std::ostream& o,
{
if (showHeader && labels.size())
{
if (separator == ' ')
if (fieldSeparator == ' ')
{
o << std::setw(maxLabelColumnLength) << std::left;
}
@@ -306,12 +304,12 @@ void formatTable(std::ostream& o,
for (size_t r = 0; r < maxValues; r++)
{
if (separator == ' ' && (showHeader || numColumns > 1))
if (fieldSeparator == ' ' && (showHeader || numColumns > 1))
{
o << std::setw(maxColumnLength) << std::right;
}
else if (showHeader || r > 0)
o << separator;
o << fieldSeparator;
PVScalarArrayPtr array = columnData[i];
if (array.get() && r < array->getLength())
@@ -433,10 +431,10 @@ void formatNTMatrix(std::ostream& o, PVStructurePtr const & pvStruct)
{
for (int32 c = 0; c < cols; c++)
{
if (separator == ' ' && cols > 1)
if (fieldSeparator == ' ' && cols > 1)
o << std::setw(maxColumnLength) << std::right;
else if (c > 0)
o << separator;
o << fieldSeparator;
if (columnMajor)
value->dumpValue(o, r + c * rows);
@@ -459,10 +457,10 @@ void formatNTMatrix(std::ostream& o, PVStructurePtr const & pvStruct)
{
for (int32 r = 0; r < rows; r++)
{
if (separator == ' ' && rows > 1)
if (fieldSeparator == ' ' && rows > 1)
o << std::setw(maxColumnLength) << std::right;
else if (r > 0)
o << separator;
o << fieldSeparator;
if (columnMajor)
value->dumpValue(o, ix++);
@@ -540,7 +538,7 @@ void formatNTNameValue(std::ostream& o, PVStructurePtr const & pvStruct)
{
for (size_t i = 0; i < numColumns; i++)
{
if (separator == ' ')
if (fieldSeparator == ' ')
{
int width = std::max(nameData[i].size()+padding, maxColumnLength);
o << std::setw(width) << std::right;
@@ -548,7 +546,7 @@ void formatNTNameValue(std::ostream& o, PVStructurePtr const & pvStruct)
}
else if (i > 0)
{
o << separator;
o << fieldSeparator;
}
o << nameData[i];
@@ -559,7 +557,7 @@ void formatNTNameValue(std::ostream& o, PVStructurePtr const & pvStruct)
// then values
for (size_t i = 0; i < numColumns; i++)
{
if (separator == ' ' && showHeader)
if (fieldSeparator == ' ' && showHeader)
{
int width = std::max(nameData[i].size()+padding, maxColumnLength);
o << std::setw(width) << std::right;
@@ -567,7 +565,7 @@ void formatNTNameValue(std::ostream& o, PVStructurePtr const & pvStruct)
}
else if (i > 0)
{
o << separator;
o << fieldSeparator;
}
array->dumpValue(o, i);
}
@@ -586,20 +584,20 @@ void formatNTNameValue(std::ostream& o, PVStructurePtr const & pvStruct)
{
if (showHeader)
{
if (separator == ' ')
if (fieldSeparator == ' ')
{
o << std::setw(maxLabelColumnLength) << std::left;
}
o << nameData[i];
}
if (separator == ' ' && showHeader)
if (fieldSeparator == ' ' && showHeader)
{
o << std::setw(maxColumnLength) << std::right;
}
else if (showHeader)
{
o << separator;
o << fieldSeparator;
}
array->dumpValue(o, i);
@@ -899,7 +897,7 @@ void printValue(std::string const & channelName, PVStructure::shared_pointer con
if (forceTerseWithName)
{
if (!channelName.empty())
std::cout << channelName << separator;
std::cout << channelName << fieldSeparator;
terseStructure(std::cout, pv) << std::endl;
}
else if (mode == ValueOnlyMode)
@@ -1044,7 +1042,7 @@ void usage (void)
" -p <provider>: Set default provider name, default is '%s'\n"
" -q: Quiet mode, print only error messages\n"
" -d: Enable debug output\n"
" -F <ofs>: Use <ofs> as an alternate output field separator\n"
" -F <ofs>: Use <ofs> as an alternate output field fieldSeparator\n"
" -f <input file>: Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin\n"
" -c: Wait for clean shutdown and report used instance count (for expert users)\n"
" enum format:\n"
@@ -1416,7 +1414,7 @@ int main (int argc, char *argv[])
dumpStructure = true;
break;
case 'i': /* T-types format mode */
formatTTypes(false);
formatTTypesFlag = false;
break;
case 't': /* Terse mode */
mode = TerseMode;
@@ -1478,7 +1476,7 @@ int main (int argc, char *argv[])
break;
}
case 'n':
setEnumPrintMode(NumberEnum);
enumMode = NumberEnum;
break;
case '?':
fprintf(stderr,
@@ -1525,8 +1523,7 @@ int main (int argc, char *argv[])
SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError);
std::cout << std::boolalpha;
terseSeparator(fieldSeparator);
terseArrayCount(false);
arrayCountFlag = false;
bool allOK = true;

View File

@@ -48,8 +48,6 @@ string defaultProvider("pva");
enum PrintMode { ValueOnlyMode, StructureMode, TerseMode };
PrintMode mode = ValueOnlyMode;
char fieldSeparator = ' ';
void usage (void)
{
fprintf (stderr, "\nUsage: pvget [options] <PV name>...\n\n"
@@ -305,14 +303,7 @@ struct MonitorRequesterImpl : public MonitorRequester, public Tracker
}
else
{
if (fieldSeparator == ' ' && value->getField()->getType() == scalar)
std::cout << std::setw(30) << std::left << m_channelName;
else
std::cout << m_channelName;
std::cout << fieldSeparator;
terse(std::cout, value) << '\n';
printMonitoredValue (value, element);
}
}
}
@@ -344,6 +335,35 @@ struct MonitorRequesterImpl : public MonitorRequester, public Tracker
std::cerr << "unlisten" << m_channelName << '\n';
done();
}
private:
// For value type scalar or scalarArray when mode is ValueOnlyMode
void printMonitoredValue (PVField::shared_pointer value, MonitorElement* element)
{
PVStructure::shared_pointer timeStamp(element->pvStructurePtr->getSubField<PVStructure>("timeStamp"));
PVStructure::shared_pointer alarm(element->pvStructurePtr->getSubField<PVStructure>("alarm"));
if (fieldSeparator == ' ' && value->getField()->getType() == scalar)
std::cout << std::setw(30) << std::left;
std::cout << m_channelName << fieldSeparator;
if (timeStamp)
terseStructure(std::cout, timeStamp) << " ";
terse(std::cout, value) << " ";
if (alarm)
{
PVScalar::shared_pointer pvSeverity(alarm->getSubField<PVScalar>("severity"));
bool inAlarm = !pvSeverity ? false : (pvSeverity->getAs<uint32>()!=0);
if (inAlarm)
terseStructure(std::cout, alarm);
}
std::cout<< '\n';
}
};
} // namespace
@@ -405,7 +425,7 @@ int main (int argc, char *argv[])
mode = TerseMode;
break;
case 'i': /* T-types format mode */
formatTTypes(false);
formatTTypesFlag = false;
break;
case 'm': /* Monitor mode */
monitor = true;
@@ -446,7 +466,7 @@ int main (int argc, char *argv[])
break;
}
case 'n':
setEnumPrintMode(NumberEnum);
enumMode = NumberEnum;
break;
case '?':
fprintf(stderr,
@@ -509,7 +529,6 @@ int main (int argc, char *argv[])
SET_LOG_LEVEL(debugFlag ? logLevelDebug : logLevelError);
std::cout << std::boolalpha;
terseSeparator(fieldSeparator);
// ================ Connect channels and start operations
@@ -565,8 +584,6 @@ int main (int argc, char *argv[])
std::cerr<<"Provider "<<uri.protocol<<" can't create channel \""<<pvs[n]<<"\"\n";
return 1;
}
if(!channel)
continue;
chan_cache[pvs[n]] = channel;
} else {
channel = it->second;

View File

@@ -490,7 +490,6 @@ int main (int argc, char *argv[])
int opt; /* getopt() current option */
bool debug = false;
double timeOut = DEFAULT_TIMEOUT;
// char fieldSeparator = ' ';
bool printInfo = false;
/*

View File

@@ -51,8 +51,6 @@ const string noAddress;
enum PrintMode { ValueOnlyMode, StructureMode, TerseMode };
PrintMode mode = ValueOnlyMode;
char fieldSeparator = ' ';
bool debug = false;
void usage (bool details=false)
@@ -609,8 +607,6 @@ int main (int argc, char *argv[])
SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError);
std::cout << std::boolalpha;
terseSeparator(fieldSeparator);
setEnumPrintMode(enumMode);
epics::pvAccess::ca::CAClientFactory::start();

View File

@@ -43,35 +43,14 @@ std::ostream& operator<<(std::ostream& o, const dump_stack_only_on_debug& d)
return o;
}
char separator = ' ';
void terseSeparator(char c)
{
separator = c;
}
char fieldSeparator = ' ';
char arrayCountFlag = true;
void terseArrayCount(bool flag)
{
arrayCountFlag = flag;
}
EnumMode enumMode = AutoEnum;
void setEnumPrintMode(EnumMode mode)
{
enumMode = mode;
}
bool formatTTypesFlag = true;
void formatTTypes(bool flag)
{
formatTTypesFlag = flag;
}
bool printUserTagFlag = true;
void printUserTag(bool flag)
{
printUserTagFlag = flag;
}
std::ostream& terse(std::ostream& o, PVField::const_shared_pointer const & pv)
{
@@ -149,7 +128,7 @@ std::ostream& printTimeT(std::ostream& o, epics::pvData::PVStructure::const_shar
epicsTimeToStrftime(timeText, sizeof(timeText), "%Y-%m-%dT%H:%M:%S.%03f", &epicsTS);
o << timeText;
if (printUserTagFlag && tagf)
o << separator << tagf->getAs<int32>();
o << fieldSeparator << tagf->getAs<int32>();
return o;
}
@@ -192,14 +171,14 @@ std::ostream& printAlarmT(std::ostream& o, epics::pvData::PVStructure::const_sha
o << v;
else
o << severityNames[v];
o << separator;
o << fieldSeparator;
v = pvStatus->get();
if (v < 0 || v > 7)
o << v;
else
o << statusNames[v];
o << separator;
o << fieldSeparator;
if (pvMessage->get().empty())
o << "<no message>";
else
@@ -266,7 +245,7 @@ std::ostream& terseStructure(std::ostream& o, PVStructure::const_shared_pointer
if (first)
first = false;
else
o << separator;
o << fieldSeparator;
terse(o, fieldsData[i]);
}
@@ -294,7 +273,7 @@ std::ostream& terseScalarArray(std::ostream& o, const PVScalarArray::const_share
o << '0';
return o;
}
o << length << separator;
o << length << fieldSeparator;
}
bool first = true;
@@ -302,7 +281,7 @@ std::ostream& terseScalarArray(std::ostream& o, const PVScalarArray::const_share
if (first)
first = false;
else
o << separator;
o << fieldSeparator;
pvArray->dumpValue(o, i);
}
@@ -325,7 +304,7 @@ std::ostream& terseStructureArray(std::ostream& o, PVStructureArray::const_share
o << '0';
return o;
}
o << length << separator;
o << length << fieldSeparator;
}
PVStructureArray::const_svector data = pvArray->view();
@@ -334,7 +313,7 @@ std::ostream& terseStructureArray(std::ostream& o, PVStructureArray::const_share
if (first)
first = false;
else
o << separator;
o << fieldSeparator;
terseStructure(o, data[i]);
}
@@ -351,7 +330,7 @@ std::ostream& terseUnionArray(std::ostream& o, PVUnionArray::const_shared_pointe
o << '0';
return o;
}
o << length << separator;
o << length << fieldSeparator;
}
PVUnionArray::const_svector data = pvArray->view();
@@ -360,7 +339,7 @@ std::ostream& terseUnionArray(std::ostream& o, PVUnionArray::const_shared_pointe
if (first)
first = false;
else
o << separator;
o << fieldSeparator;
terseUnion(o, data[i]);
}

View File

@@ -7,8 +7,6 @@ void convertStructure(std::string* buffer, epics::pvData::PVStructure *data, int
void convertArray(std::string*, epics::pvData::PVScalarArray * pv, int notFirst);
void convertStructureArray(std::string*, epics::pvData::PVStructureArray * pvdata, int notFirst);
void terseSeparator(char c);
void terseArrayCount(bool flag);
std::ostream& terse(std::ostream& o, epics::pvData::PVField::const_shared_pointer const & pv);
std::ostream& terseUnion(std::ostream& o, epics::pvData::PVUnion::const_shared_pointer const & pvUnion);
std::ostream& terseStructure(std::ostream& o, const epics::pvData::PVStructure::const_shared_pointer &pvStructure);
@@ -17,14 +15,10 @@ std::ostream& terseStructureArray(std::ostream& o, epics::pvData::PVStructureArr
std::ostream& terseUnionArray(std::ostream& o, epics::pvData::PVUnionArray::const_shared_pointer const & pvArray);
enum EnumMode { AutoEnum, NumberEnum, StringEnum };
void setEnumPrintMode(EnumMode mode);
void formatTTypes(bool flag);
bool isTType(epics::pvData::PVStructure::const_shared_pointer const & pvStructure);
bool formatTType(std::ostream& o, const epics::pvData::PVStructure::const_shared_pointer &pvStructure);
void printUserTag(bool flag);
std::ostream& printEnumT(std::ostream& o, epics::pvData::PVStructure const & pvEnumT);
std::ostream& printEnumT(std::ostream& o, epics::pvData::PVStructure::const_shared_pointer const & pvEnumT);
std::ostream& printTimeT(std::ostream& o, epics::pvData::PVStructure::const_shared_pointer const & pvTimeT);

View File

@@ -3,6 +3,8 @@
* found in the file LICENSE that is included with the distribution
*/
#include <typeinfo>
#include <epicsMutex.h>
#include <epicsGuard.h>
#include <epicsEvent.h>
@@ -197,6 +199,17 @@ void ClientChannel::removeConnectListener(ConnectCallback* cb)
}
}
void ClientChannel::show(std::ostream& strm) const
{
if(impl) {
strm<<typeid(*impl->channel.get()).name()<<" : ";
impl->channel->printInfo(strm);
} else {
strm<<"NULL Channel";
}
}
static
void register_reftrack()
{
@@ -266,6 +279,12 @@ ClientProvider::ClientProvider(const std::tr1::shared_ptr<epics::pvAccess::Chann
ClientProvider::~ClientProvider() {}
std::string
ClientProvider::name() const
{
return impl->provider->getProviderName();
}
ClientChannel
ClientProvider::connect(const std::string& name,
const ClientChannel::Options& conf)
@@ -305,6 +324,43 @@ void ClientProvider::disconnect()
impl->channels.clear();
}
::std::ostream& operator<<(::std::ostream& strm, const Operation& op)
{
if(op.impl) {
op.impl->show(strm);
} else {
strm << "Operation()";
}
return strm;
}
::std::ostream& operator<<(::std::ostream& strm, const ClientChannel& op)
{
if(op.impl) {
strm << "ClientChannel("
<< typeid(*op.impl->channel.get()).name()<<", "
"\"" << op.impl->channel->getChannelName() <<"\", "
"\"" << op.impl->channel->getProvider()->getProviderName() <<"\", "
"connected="<<(op.impl->channel->isConnected()?"true":"false")
<<"\")";
} else {
strm << "ClientChannel()";
}
return strm;
}
::std::ostream& operator<<(::std::ostream& strm, const ClientProvider& op)
{
if(op.impl) {
strm << "ClientProvider("
<< typeid(*op.impl->provider.get()).name()<<", "
"\""<<op.impl->provider->getProviderName()<<"\")";
} else {
strm << "ClientProvider()";
}
return strm;
}
namespace detail {
void registerRefTrack()

View File

@@ -177,6 +177,13 @@ struct GetPutter : public pva::ChannelPutRequester,
callEvent(G, status.isSuccess()? pvac::GetEvent::Success : pvac::GetEvent::Fail);
}
virtual void show(std::ostream &strm) const
{
strm << "Operation(Get/Put"
"\"" << name() <<"\""
")";
}
};
size_t GetPutter::num_instances;

View File

@@ -248,6 +248,20 @@ ClientChannel::monitor(MonitorCallback *cb,
return Monitor(ret);
}
::std::ostream& operator<<(::std::ostream& strm, const Monitor& op)
{
if(op.impl) {
strm << "Monitor("
"\"" << op.impl->chan->getChannelName() <<"\", "
"\"" << op.impl->chan->getProvider()->getProviderName() <<"\", "
"connected="<<(op.impl->chan->isConnected()?"true":"false")
<<"\")";
} else {
strm << "Monitor()";
}
return strm;
}
namespace detail {
void registerRefTrackMonitor()

View File

@@ -140,6 +140,13 @@ struct RPCer : public pva::ChannelRPCRequester,
callEvent(G, status.isSuccess()? pvac::GetEvent::Success : pvac::GetEvent::Fail);
}
virtual void show(std::ostream &strm) const
{
strm << "Operation(RPC"
"\"" << name() <<"\""
")";
}
};
size_t RPCer::num_instances;

View File

@@ -5,6 +5,7 @@
#ifndef PVATESTCLIENT_H
#define PVATESTCLIENT_H
#include <ostream>
#include <stdexcept>
#include <list>
@@ -53,6 +54,7 @@ struct epicsShareClass Operation
virtual ~Impl() {}
virtual std::string name() const =0;
virtual void cancel() =0;
virtual void show(std::ostream&) const =0;
};
Operation() {}
@@ -64,7 +66,21 @@ struct epicsShareClass Operation
//! Does not wait for remote confirmation.
void cancel();
bool valid() const { return !!impl; }
#if __cplusplus>=201103L
explicit operator bool() const { return valid(); }
#else
private:
typedef bool (Operation::*bool_type)() const;
public:
operator bool_type() const { return valid() ? &Operation::valid : 0; }
#endif
void reset() { impl.reset(); }
protected:
friend epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const Operation& op);
std::tr1::shared_ptr<Impl> impl;
};
@@ -133,8 +149,22 @@ struct epicsShareClass Monitor
epics::pvData::BitSet changed,
overrun;
bool valid() const { return !!impl; }
#if __cplusplus>=201103L
explicit operator bool() const { return valid(); }
#else
private:
typedef bool (Monitor::*bool_type)() const;
public:
operator bool_type() const { return valid() ? &Monitor::valid : 0; }
#endif
void reset() { impl.reset(); }
private:
std::tr1::shared_ptr<Impl> impl;
friend epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const Monitor& op);
friend struct MonitorSync;
};
@@ -220,6 +250,7 @@ private:
std::tr1::shared_ptr<Impl> impl;
friend class ClientProvider;
friend void detail::registerRefTrack();
friend epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const ClientChannel& op);
ClientChannel(const std::tr1::shared_ptr<Impl>& i) :impl(i) {}
public:
@@ -247,6 +278,19 @@ public:
//! Channel name or an empty string
std::string name() const;
bool valid() const { return !!impl; }
#if __cplusplus>=201103L
explicit operator bool() const { return valid(); }
#else
private:
typedef bool (ClientChannel::*bool_type)() const;
public:
operator bool_type() const { return valid() ? &ClientChannel::valid : 0; }
#endif
void reset() { impl.reset(); }
//! callback for get() and rpc()
struct GetCallback {
virtual ~GetCallback() {}
@@ -358,6 +402,7 @@ public:
//! Remove from list of listeners
void removeConnectListener(ConnectCallback*);
void show(std::ostream& strm) const;
private:
std::tr1::shared_ptr<epics::pvAccess::Channel> getChannel();
};
@@ -421,6 +466,7 @@ class epicsShareClass ClientProvider
struct Impl;
std::tr1::shared_ptr<Impl> impl;
friend void detail::registerRefTrack();
friend epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const ClientProvider& op);
public:
/** Use named provider.
@@ -435,6 +481,8 @@ public:
explicit ClientProvider(const std::tr1::shared_ptr<epics::pvAccess::ChannelProvider>& provider);
~ClientProvider();
std::string name() const;
/** Get a new Channel
*
* Does not block.
@@ -450,6 +498,19 @@ public:
//! Clear channel cache
void disconnect();
bool valid() const { return !!impl; }
#if __cplusplus>=201103L
explicit operator bool() const { return valid(); }
#else
private:
typedef bool (ClientProvider::*bool_type)() const;
public:
operator bool_type() const { return valid() ? &ClientProvider::valid : 0; }
#endif
void reset() { impl.reset(); }
};
@@ -460,6 +521,11 @@ ClientChannel::put(const epics::pvData::PVStructure::const_shared_pointer& pvReq
return detail::PutBuilder(*this, pvRequest);
}
epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const Operation& op);
epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const Monitor& op);
epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const ClientChannel& op);
epicsShareFunc ::std::ostream& operator<<(::std::ostream& strm, const ClientProvider& op);
//! @}
}//namespace pvac

View File

@@ -24,6 +24,7 @@
#include "pv/codec.h"
#include <pv/serverContextImpl.h>
#include <pv/serverChannelImpl.h>
#include <pv/blockingUDP.h>
using namespace epics::pvData;
using std::string;
@@ -173,6 +174,7 @@ void providerRegInit(void*)
registerRefCounter("ServerChannel", &ServerChannel::num_instances);
registerRefCounter("Transport (ABC)", &Transport::num_instances);
registerRefCounter("BlockingTCPTransportCodec", &detail::BlockingTCPTransportCodec::num_instances);
registerRefCounter("BlockingUDPTransport", &BlockingUDPTransport::num_instances);
registerRefCounter("ChannelProvider (ABC)", &ChannelProvider::num_instances);
registerRefCounter("Channel (ABC)", &Channel::num_instances);
registerRefCounter("ChannelRequester (ABC)", &ChannelRequester::num_instances);

View File

@@ -9,7 +9,7 @@ pvAccess_SRCS += blockingUDPTransport.cpp
pvAccess_SRCS += blockingUDPConnector.cpp
pvAccess_SRCS += beaconHandler.cpp
pvAccess_SRCS += blockingTCPConnector.cpp
pvAccess_SRCS += simpleChannelSearchManagerImpl.cpp
pvAccess_SRCS += channelSearchManager.cpp
pvAccess_SRCS += abstractResponseHandler.cpp
pvAccess_SRCS += blockingTCPAcceptor.cpp
pvAccess_SRCS += transportRegistry.cpp

View File

@@ -17,6 +17,7 @@
#include <pv/lock.h>
#include <pv/byteBuffer.h>
#include <pv/reftrack.h>
#define epicsExportSharedSymbols
#include <pv/blockingUDP.h>
@@ -42,6 +43,8 @@ inline int sendto(int s, const char *buf, size_t len, int flags, const struct so
// reserve some space for CMD_ORIGIN_TAG message
#define RECEIVE_BUFFER_PRE_RESERVE (PVA_MESSAGE_HEADER_SIZE + 16)
size_t BlockingUDPTransport::num_instances;
BlockingUDPTransport::BlockingUDPTransport(bool serverFlag,
ResponseHandler::shared_pointer const & responseHandler, SOCKET channel,
osiSockAddr& bindAddress,
@@ -79,9 +82,12 @@ BlockingUDPTransport::BlockingUDPTransport(bool serverFlag,
sockAddrToDottedIP(&_remoteAddress.sa, strBuffer, sizeof(strBuffer));
_remoteName = strBuffer;
}
REFTRACE_INCREMENT(num_instances);
}
BlockingUDPTransport::~BlockingUDPTransport() {
REFTRACE_DECREMENT(num_instances);
close(true); // close the socket and stop the thread.
}

View File

@@ -11,7 +11,7 @@
#include <pv/timeStamp.h>
#define epicsExportSharedSymbols
#include <pv/simpleChannelSearchManagerImpl.h>
#include <pv/channelSearchManager.h>
#include <pv/pvaConstants.h>
#include <pv/blockingUDP.h>
#include <pv/serializeHelper.h>
@@ -20,28 +20,55 @@
using namespace std;
using namespace epics::pvData;
namespace {
namespace pva = epics::pvAccess;
class MockTransportSendControl: public pva::TransportSendControl
{
public:
void endMessage() {}
void flush(bool /*lastMessageCompleted*/) {}
void setRecipient(const osiSockAddr& /*sendTo*/) {}
void startMessage(epics::pvData::int8 /*command*/, std::size_t /*ensureCapacity*/, epics::pvData::int32 /*payloadSize*/) {}
void ensureBuffer(std::size_t /*size*/) {}
void alignBuffer(std::size_t /*alignment*/) {}
void flushSerializeBuffer() {}
void cachedSerialize(const std::tr1::shared_ptr<const epics::pvData::Field>& field, epics::pvData::ByteBuffer* buffer)
{
// no cache
field->serialize(buffer, this);
}
virtual bool directSerialize(epics::pvData::ByteBuffer* /*existingBuffer*/, const char* /*toSerialize*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/)
{
return false;
}
};
}// namespace
namespace epics {
namespace pvAccess {
const int SimpleChannelSearchManagerImpl::DATA_COUNT_POSITION = PVA_MESSAGE_HEADER_SIZE + 4+1+3+16+2+1+4;
const int SimpleChannelSearchManagerImpl::CAST_POSITION = PVA_MESSAGE_HEADER_SIZE + 4;
const int SimpleChannelSearchManagerImpl::PAYLOAD_POSITION = 4;
const int ChannelSearchManager::DATA_COUNT_POSITION = PVA_MESSAGE_HEADER_SIZE + 4+1+3+16+2+1+4;
const int ChannelSearchManager::CAST_POSITION = PVA_MESSAGE_HEADER_SIZE + 4;
const int ChannelSearchManager::PAYLOAD_POSITION = 4;
// 225ms +/- 25ms random
const double SimpleChannelSearchManagerImpl::ATOMIC_PERIOD = 0.225;
const int SimpleChannelSearchManagerImpl::PERIOD_JITTER_MS = 25;
const double ChannelSearchManager::ATOMIC_PERIOD = 0.225;
const int ChannelSearchManager::PERIOD_JITTER_MS = 25;
const int SimpleChannelSearchManagerImpl::DEFAULT_USER_VALUE = 1;
const int SimpleChannelSearchManagerImpl::BOOST_VALUE = 1;
const int ChannelSearchManager::DEFAULT_USER_VALUE = 1;
const int ChannelSearchManager::BOOST_VALUE = 1;
// must be power of two (so that search is done)
const int SimpleChannelSearchManagerImpl::MAX_COUNT_VALUE = 1 << 8;
const int SimpleChannelSearchManagerImpl::MAX_FALLBACK_COUNT_VALUE = (1 << 7) + 1;
const int ChannelSearchManager::MAX_COUNT_VALUE = 1 << 8;
const int ChannelSearchManager::MAX_FALLBACK_COUNT_VALUE = (1 << 7) + 1;
const int SimpleChannelSearchManagerImpl::MAX_FRAMES_AT_ONCE = 10;
const int SimpleChannelSearchManagerImpl::DELAY_BETWEEN_FRAMES_MS = 50;
const int ChannelSearchManager::MAX_FRAMES_AT_ONCE = 10;
const int ChannelSearchManager::DELAY_BETWEEN_FRAMES_MS = 50;
SimpleChannelSearchManagerImpl::SimpleChannelSearchManagerImpl(Context::shared_pointer const & context) :
ChannelSearchManager::ChannelSearchManager(Context::shared_pointer const & context) :
m_context(context),
m_responseAddress(), // initialized in activate()
m_canceled(),
@@ -49,7 +76,6 @@ SimpleChannelSearchManagerImpl::SimpleChannelSearchManagerImpl(Context::shared_p
m_sendBuffer(MAX_UDP_UNFRAGMENTED_SEND),
m_channels(),
m_lastTimeSent(),
m_mockTransportSendControl(),
m_channelMutex(),
m_userValueMutex(),
m_mutex()
@@ -58,7 +84,7 @@ SimpleChannelSearchManagerImpl::SimpleChannelSearchManagerImpl(Context::shared_p
srand ( time(NULL) );
}
void SimpleChannelSearchManagerImpl::activate()
void ChannelSearchManager::activate()
{
m_responseAddress = Context::shared_pointer(m_context)->getSearchTransport()->getRemoteAddress();
@@ -73,15 +99,15 @@ void SimpleChannelSearchManagerImpl::activate()
context->getTimer()->schedulePeriodic(shared_from_this(), period, period);
}
SimpleChannelSearchManagerImpl::~SimpleChannelSearchManagerImpl()
ChannelSearchManager::~ChannelSearchManager()
{
Lock guard(m_mutex);
if (!m_canceled.get()) {
LOG(logLevelWarn, "Logic error: SimpleChannelSearchManagerImpl destroyed w/o cancel()");
LOG(logLevelWarn, "Logic error: ChannelSearchManager destroyed w/o cancel()");
}
}
void SimpleChannelSearchManagerImpl::cancel()
void ChannelSearchManager::cancel()
{
Lock guard(m_mutex);
@@ -94,13 +120,13 @@ void SimpleChannelSearchManagerImpl::cancel()
context->getTimer()->cancel(shared_from_this());
}
int32_t SimpleChannelSearchManagerImpl::registeredCount()
int32_t ChannelSearchManager::registeredCount()
{
Lock guard(m_channelMutex);
return static_cast<int32_t>(m_channels.size());
}
void SimpleChannelSearchManagerImpl::registerSearchInstance(SearchInstance::shared_pointer const & channel, bool penalize)
void ChannelSearchManager::registerSearchInstance(SearchInstance::shared_pointer const & channel, bool penalize)
{
if (m_canceled.get())
return;
@@ -122,16 +148,14 @@ void SimpleChannelSearchManagerImpl::registerSearchInstance(SearchInstance::shar
callback();
}
void SimpleChannelSearchManagerImpl::unregisterSearchInstance(SearchInstance::shared_pointer const & channel)
void ChannelSearchManager::unregisterSearchInstance(SearchInstance::shared_pointer const & channel)
{
Lock guard(m_channelMutex);
pvAccessID id = channel->getSearchInstanceID();
m_channels_t::iterator channelsIter = m_channels.find(id);
if(channelsIter != m_channels.end())
m_channels.erase(id);
m_channels.erase(id);
}
void SimpleChannelSearchManagerImpl::searchResponse(const ServerGUID & guid, pvAccessID cid, int32_t /*seqNo*/, int8_t minorRevision, osiSockAddr* serverAddress)
void ChannelSearchManager::searchResponse(const ServerGUID & guid, pvAccessID cid, int32_t /*seqNo*/, int8_t minorRevision, osiSockAddr* serverAddress)
{
Lock guard(m_channelMutex);
m_channels_t::iterator channelsIter = m_channels.find(cid);
@@ -162,13 +186,13 @@ void SimpleChannelSearchManagerImpl::searchResponse(const ServerGUID & guid, pvA
}
}
void SimpleChannelSearchManagerImpl::newServerDetected()
void ChannelSearchManager::newServerDetected()
{
boost();
callback();
}
void SimpleChannelSearchManagerImpl::initializeSendBuffer()
void ChannelSearchManager::initializeSendBuffer()
{
// for now OK, since it is only set here
m_sequenceNumber++;
@@ -197,12 +221,13 @@ void SimpleChannelSearchManagerImpl::initializeSendBuffer()
// TODO now only TCP is supported
// note: this affects DATA_COUNT_POSITION
m_sendBuffer.putByte((int8_t)1);
// TODO "tcp" constant
SerializeHelper::serializeString("tcp", &m_sendBuffer, &m_mockTransportSendControl);
MockTransportSendControl control;
SerializeHelper::serializeString("tcp", &m_sendBuffer, &control);
m_sendBuffer.putShort((int16_t)0); // count
}
void SimpleChannelSearchManagerImpl::flushSendBuffer()
void ChannelSearchManager::flushSendBuffer()
{
Lock guard(m_mutex);
@@ -219,7 +244,7 @@ void SimpleChannelSearchManagerImpl::flushSendBuffer()
}
bool SimpleChannelSearchManagerImpl::generateSearchRequestMessage(SearchInstance::shared_pointer const & channel,
bool ChannelSearchManager::generateSearchRequestMessage(SearchInstance::shared_pointer const & channel,
ByteBuffer* requestMessage, TransportSendControl* control)
{
epics::pvData::int16 dataCount = requestMessage->getShort(DATA_COUNT_POSITION);
@@ -231,7 +256,7 @@ bool SimpleChannelSearchManagerImpl::generateSearchRequestMessage(SearchInstance
return false;
*/
const std::string name = channel->getSearchInstanceName();
const std::string& name(channel->getSearchInstanceName());
// not nice...
const int addedPayloadSize = sizeof(int32)/sizeof(int8) + (1 + sizeof(int32)/sizeof(int8) + name.length());
if(((int)requestMessage->getRemaining()) < addedPayloadSize)
@@ -245,17 +270,19 @@ bool SimpleChannelSearchManagerImpl::generateSearchRequestMessage(SearchInstance
return true;
}
bool SimpleChannelSearchManagerImpl::generateSearchRequestMessage(SearchInstance::shared_pointer const & channel,
bool ChannelSearchManager::generateSearchRequestMessage(SearchInstance::shared_pointer const & channel,
bool allowNewFrame, bool flush)
{
MockTransportSendControl control;
Lock guard(m_mutex);
bool success = generateSearchRequestMessage(channel, &m_sendBuffer, &m_mockTransportSendControl);
bool success = generateSearchRequestMessage(channel, &m_sendBuffer, &control);
// buffer full, flush
if(!success)
{
flushSendBuffer();
if(allowNewFrame)
generateSearchRequestMessage(channel, &m_sendBuffer, &m_mockTransportSendControl);
generateSearchRequestMessage(channel, &m_sendBuffer, &control);
if (flush)
flushSendBuffer();
return true;
@@ -267,7 +294,7 @@ bool SimpleChannelSearchManagerImpl::generateSearchRequestMessage(SearchInstance
return flush;
}
void SimpleChannelSearchManagerImpl::boost()
void ChannelSearchManager::boost()
{
Lock guard(m_channelMutex);
Lock guard2(m_userValueMutex);
@@ -281,7 +308,7 @@ void SimpleChannelSearchManagerImpl::boost()
}
}
void SimpleChannelSearchManagerImpl::callback()
void ChannelSearchManager::callback()
{
// high-frequency beacon anomaly trigger guard
{
@@ -346,12 +373,12 @@ void SimpleChannelSearchManagerImpl::callback()
flushSendBuffer();
}
bool SimpleChannelSearchManagerImpl::isPowerOfTwo(int32_t x)
bool ChannelSearchManager::isPowerOfTwo(int32_t x)
{
return ((x > 0) && (x & (x - 1)) == 0);
}
void SimpleChannelSearchManagerImpl::timerStopped()
void ChannelSearchManager::timerStopped()
{
}

View File

@@ -1040,14 +1040,11 @@ void BlockingTCPTransportCodec::close() {
// wakeup processSendQueue
// clean resources (close socket)
internalClose(true);
internalClose();
// Break sender from queue wait
BreakTransport::shared_pointer B(new BreakTransport);
enqueueSendRequest(B);
// post close
internalPostClose(true);
}
}
@@ -1058,9 +1055,42 @@ void BlockingTCPTransportCodec::waitJoin()
_readThread.exitWait();
}
void BlockingTCPTransportCodec::internalClose(bool /*force*/)
void BlockingTCPTransportCodec::internalClose()
{
this->internalDestroy();
{
epicsSocketSystemCallInterruptMechanismQueryInfo info =
epicsSocketSystemCallInterruptMechanismQuery ();
switch ( info )
{
case esscimqi_socketCloseRequired:
epicsSocketDestroy ( _channel );
break;
case esscimqi_socketBothShutdownRequired:
{
/*int status =*/ ::shutdown ( _channel, SHUT_RDWR );
/*
if ( status ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
LOG(logLevelDebug,
"TCP socket to %s failed to shutdown: %s.",
inetAddressToString(_socketAddress).c_str(), sockErrBuf);
}
*/
epicsSocketDestroy ( _channel );
}
break;
case esscimqi_socketSigAlarmRequired:
// not supported anymore anyway
default:
epicsSocketDestroy(_channel);
}
}
Transport::shared_pointer thisSharedPtr = this->shared_from_this();
_context->getTransportRegistry()->remove(thisSharedPtr);
// TODO sync
if (_securitySession)
@@ -1096,13 +1126,23 @@ void BlockingTCPTransportCodec::start() {
void BlockingTCPTransportCodec::receiveThread()
{
Transport::shared_pointer ptr = this->shared_from_this();
/* This innocuous ref. is an important hack.
* The code behind Transport::close() will cause
* channels and operations to drop references
* to this transport. This ref. keeps it from
* being destroyed way down the call stack, from
* which it is apparently not possible to return
* safely. Rather than try to untangle this
* knot, just keep this ref...
*/
Transport::shared_pointer ptr(this->shared_from_this());
while (this->isOpen())
{
try {
this->processRead();
} catch (std::exception &e) {
PRINT_EXCEPTION(e);
LOG(logLevelError,
"an exception caught while in receiveThread at %s:%d: %s",
__FILE__, __LINE__, e.what());
@@ -1112,14 +1152,13 @@ void BlockingTCPTransportCodec::receiveThread()
__FILE__, __LINE__);
}
}
this->_shutdownEvent.signal();
}
void BlockingTCPTransportCodec::sendThread()
{
Transport::shared_pointer ptr = this->shared_from_this();
// cf. the comment in receiveThread()
Transport::shared_pointer ptr(this->shared_from_this());
this->setSenderThread();
@@ -1130,6 +1169,7 @@ void BlockingTCPTransportCodec::sendThread()
} catch (connection_closed_exception &cce) {
// noop
} catch (std::exception &e) {
PRINT_EXCEPTION(e);
LOG(logLevelWarn,
"an exception caught while in sendThread at %s:%d: %s",
__FILE__, __LINE__, e.what());
@@ -1204,47 +1244,6 @@ BlockingTCPTransportCodec::BlockingTCPTransportCodec(bool serverFlag, const Cont
}
// must be called only once, when there will be no operation on socket (e.g. just before tx/rx thread exists)
void BlockingTCPTransportCodec::internalDestroy() {
if(_channel != INVALID_SOCKET) {
epicsSocketSystemCallInterruptMechanismQueryInfo info =
epicsSocketSystemCallInterruptMechanismQuery ();
switch ( info )
{
case esscimqi_socketCloseRequired:
epicsSocketDestroy ( _channel );
break;
case esscimqi_socketBothShutdownRequired:
{
/*int status =*/ ::shutdown ( _channel, SHUT_RDWR );
/*
if ( status ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
LOG(logLevelDebug,
"TCP socket to %s failed to shutdown: %s.",
inetAddressToString(_socketAddress).c_str(), sockErrBuf);
}
*/
epicsSocketDestroy ( _channel );
}
break;
case esscimqi_socketSigAlarmRequired:
// not supported anymore anyway
default:
epicsSocketDestroy(_channel);
}
_channel = INVALID_SOCKET; //TODO: mutex to guard _channel
}
Transport::shared_pointer thisSharedPtr = this->shared_from_this();
_context->getTransportRegistry()->remove(thisSharedPtr);
}
void BlockingTCPTransportCodec::invalidDataStreamHandler() {
close();
@@ -1529,12 +1528,11 @@ void BlockingServerTCPTransportCodec::send(ByteBuffer* buffer,
buffer->putShort(0x7FFF);
// list of authNZ plugin names
map<string, SecurityPlugin::shared_pointer>& securityPlugins = _context->getSecurityPlugins();
const Context::securityPlugins_t& securityPlugins = _context->getSecurityPlugins();
vector<string> validSPNames;
validSPNames.reserve(securityPlugins.size());
for (map<string, SecurityPlugin::shared_pointer>::const_iterator iter =
securityPlugins.begin();
for (Context::securityPlugins_t::const_iterator iter(securityPlugins.begin());
iter != securityPlugins.end(); iter++)
{
SecurityPlugin::shared_pointer securityPlugin = iter->second;
@@ -1593,9 +1591,9 @@ void BlockingServerTCPTransportCodec::destroyAllChannels() {
it->second->destroy();
}
void BlockingServerTCPTransportCodec::internalClose(bool force) {
void BlockingServerTCPTransportCodec::internalClose() {
Transport::shared_pointer thisSharedPtr = shared_from_this();
BlockingTCPTransportCodec::internalClose(force);
BlockingTCPTransportCodec::internalClose();
destroyAllChannels();
}
@@ -1627,8 +1625,7 @@ void BlockingServerTCPTransportCodec::authNZInitialize(const std::string& securi
// check if plug-in name is valid
SecurityPlugin::shared_pointer securityPlugin;
map<string, SecurityPlugin::shared_pointer>::iterator spIter =
_context->getSecurityPlugins().find(securityPluginName);
Context::securityPlugins_t::const_iterator spIter(_context->getSecurityPlugins().find(securityPluginName));
if (spIter != _context->getSecurityPlugins().end())
securityPlugin = spIter->second;
if (!securityPlugin)
@@ -1779,24 +1776,15 @@ bool BlockingClientTCPTransportCodec::acquire(ClientChannelImpl::shared_pointer
}
// _mutex is held when this method is called
void BlockingClientTCPTransportCodec::internalClose(bool forced) {
BlockingTCPTransportCodec::internalClose(forced);
void BlockingClientTCPTransportCodec::internalClose() {
BlockingTCPTransportCodec::internalClose();
TimerCallbackPtr tcb = std::tr1::dynamic_pointer_cast<TimerCallback>(shared_from_this());
_context->getTimer()->cancel(tcb);
}
void BlockingClientTCPTransportCodec::internalPostClose(bool forced) {
BlockingTCPTransportCodec::internalPostClose(forced);
// _owners cannot change when transport is closed
closedNotifyClients();
}
/**
* Notifies clients about disconnect.
*/
void BlockingClientTCPTransportCodec::closedNotifyClients() {
// Notifies clients about disconnect.
// check if still acquired
size_t refs = _owners.size();
@@ -1937,13 +1925,12 @@ void BlockingClientTCPTransportCodec::authNZInitialize(const std::vector<std::st
{
if (!offeredSecurityPlugins.empty())
{
map<string, SecurityPlugin::shared_pointer>& availableSecurityPlugins =
_context->getSecurityPlugins();
const Context::securityPlugins_t& availableSecurityPlugins(_context->getSecurityPlugins());
for (vector<string>::const_iterator offeredSP = offeredSecurityPlugins.begin();
offeredSP != offeredSecurityPlugins.end(); offeredSP++)
{
map<string, SecurityPlugin::shared_pointer>::iterator spi = availableSecurityPlugins.find(*offeredSP);
Context::securityPlugins_t::const_iterator spi(availableSecurityPlugins.find(*offeredSP));
if (spi != availableSecurityPlugins.end())
{
SecurityPlugin::shared_pointer securityPlugin = spi->second;

View File

@@ -49,6 +49,8 @@ class BlockingUDPTransport : public epics::pvData::NoDefaultMethods,
public:
POINTER_DEFINITIONS(BlockingUDPTransport);
static size_t num_instances;
private:
std::tr1::weak_ptr<BlockingUDPTransport> internal_this;
friend class BlockingUDPConnector;

View File

@@ -20,6 +20,7 @@
#endif
#include <pv/pvaDefs.h>
#include <pv/remote.h>
namespace epics {
namespace pvAccess {
@@ -31,11 +32,11 @@ public:
/**
* Destructor
*/
virtual ~SearchInstance() {};
virtual ~SearchInstance() {}
virtual pvAccessID getSearchInstanceID() = 0;
virtual std::string getSearchInstanceName() = 0;
virtual const std::string& getSearchInstanceName() = 0;
virtual int32_t& getUserValue() = 0;
@@ -49,34 +50,34 @@ public:
virtual void searchResponse(const ServerGUID & guid, int8_t minorRevision, osiSockAddr* serverAddress) = 0;
};
class ChannelSearchManager {
class ChannelSearchManager :
public epics::pvData::TimerCallback,
public std::tr1::enable_shared_from_this<ChannelSearchManager>
{
public:
POINTER_DEFINITIONS(ChannelSearchManager);
virtual ~ChannelSearchManager();
/**
* Destructor
* Cancel.
*/
virtual ~ChannelSearchManager() {};
void cancel();
/**
* Get number of registered channels.
* @return number of registered channels.
*/
virtual int32_t registeredCount() = 0;
int32_t registeredCount();
/**
* Register channel.
* @param channel
* @param channel to register.
*/
virtual void registerSearchInstance(SearchInstance::shared_pointer const & channel, bool penalize = false) = 0;
void registerSearchInstance(SearchInstance::shared_pointer const & channel, bool penalize = false);
/**
* Unregister channel.
* @param channel
* @param channel to unregister.
*/
virtual void unregisterSearchInstance(SearchInstance::shared_pointer const & channel) = 0;
void unregisterSearchInstance(SearchInstance::shared_pointer const & channel);
/**
* Search response from server (channel found).
* @param guid server GUID.
@@ -85,19 +86,105 @@ public:
* @param minorRevision server minor PVA revision.
* @param serverAddress server address.
*/
virtual void searchResponse(const ServerGUID & guid, pvAccessID cid, int32_t seqNo, int8_t minorRevision, osiSockAddr* serverAddress) = 0;
void searchResponse(const ServerGUID & guid, pvAccessID cid, int32_t seqNo, int8_t minorRevision, osiSockAddr* serverAddress);
/**
* New server detected.
* Boost searching of all channels.
*/
virtual void newServerDetected() = 0;
void newServerDetected();
/// Timer callback.
virtual void callback() OVERRIDE FINAL;
/// Timer stooped callback.
virtual void timerStopped() OVERRIDE FINAL;
/**
* Cancel.
* Private constructor.
* @param context
*/
virtual void cancel() = 0;
ChannelSearchManager(Context::shared_pointer const & context);
void activate();
private:
bool generateSearchRequestMessage(SearchInstance::shared_pointer const & channel, bool allowNewFrame, bool flush);
static bool generateSearchRequestMessage(SearchInstance::shared_pointer const & channel,
epics::pvData::ByteBuffer* byteBuffer, TransportSendControl* control);
void boost();
void initializeSendBuffer();
void flushSendBuffer();
static bool isPowerOfTwo(int32_t x);
/**
* Context.
*/
Context::weak_pointer m_context;
/**
* Response address.
*/
osiSockAddr m_responseAddress;
/**
* Canceled flag.
*/
AtomicBoolean m_canceled;
/**
* Search (datagram) sequence number.
*/
int32_t m_sequenceNumber;
/**
* Send byte buffer (frame)
*/
epics::pvData::ByteBuffer m_sendBuffer;
/**
* Set of registered channels.
*/
typedef std::map<pvAccessID,SearchInstance::weak_pointer> m_channels_t;
m_channels_t m_channels;
/**
* Time of last frame send.
*/
int64_t m_lastTimeSent;
/**
* This instance mutex.
*/
epics::pvData::Mutex m_channelMutex;
/**
* User value lock.
*/
epics::pvData::Mutex m_userValueMutex;
/**
* m_channels mutex.
*/
epics::pvData::Mutex m_mutex;
static const int DATA_COUNT_POSITION;
static const int CAST_POSITION;
static const int PAYLOAD_POSITION;
static const double ATOMIC_PERIOD;
static const int PERIOD_JITTER_MS;
static const int DEFAULT_USER_VALUE;
static const int BOOST_VALUE;
static const int MAX_COUNT_VALUE;
static const int MAX_FALLBACK_COUNT_VALUE;
static const int MAX_FRAMES_AT_ONCE;
static const int DELAY_BETWEEN_FRAMES_MS;
};
}

View File

@@ -338,9 +338,6 @@ public:
return std::string("tcp");
}
void internalDestroy();
virtual void processControlMessage() OVERRIDE FINAL {
if (_command == 2)
{
@@ -452,25 +449,16 @@ protected:
virtual void sendBufferFull(int tries) OVERRIDE FINAL;
/**
* Called to any resources just before closing transport
* @param[in] force flag indicating if forced (e.g. forced
* disconnect) is required
* Called from close(). after start of shutdown (isOpen()==false)
* but before worker thread shutdown.
*/
virtual void internalClose(bool force);
/**
* Called to any resources just after closing transport and without any locks held on transport
* @param[in] force flag indicating if forced (e.g. forced
* disconnect) is required
*/
virtual void internalPostClose(bool force) {}
virtual void internalClose();
private:
AtomicValue<bool> _isOpen;
epics::pvData::Thread _readThread, _sendThread;
epics::pvData::Event _shutdownEvent;
const SOCKET _channel;
protected:
SOCKET _channel;
osiSockAddr _socketAddress;
std::string _socketName;
protected:
@@ -589,7 +577,7 @@ public:
protected:
void destroyAllChannels();
virtual void internalClose(bool force) OVERRIDE FINAL;
virtual void internalClose() OVERRIDE FINAL;
private:
@@ -689,8 +677,7 @@ public:
protected:
virtual void internalClose(bool force) OVERRIDE FINAL;
virtual void internalPostClose(bool force) OVERRIDE FINAL;
virtual void internalClose() OVERRIDE FINAL;
private:

View File

@@ -317,11 +317,12 @@ public:
virtual Configuration::const_shared_pointer getConfiguration() = 0;
typedef std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > securityPlugins_t;
/**
* Get map of available security plug-ins.
* @return the map of available security plug-ins
*/
virtual std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getSecurityPlugins() = 0;
virtual const securityPlugins_t& getSecurityPlugins() = 0;
///

View File

@@ -188,6 +188,8 @@ public:
* @param remoteAddress
* @return a new session.
* @throws SecurityException
*
* @warning a Ref. loop is created if the SecuritySession stores a pointer to 'control'
*/
// authentication must be done immediately when connection is established (timeout 3seconds),
// later on authentication process can be repeated
@@ -423,12 +425,14 @@ public:
return thisInstance;
}
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getClientSecurityPlugins()
typedef std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > securityPlugins_t;
securityPlugins_t& getClientSecurityPlugins()
{
return m_clientSecurityPlugins;
}
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getServerSecurityPlugins()
securityPlugins_t& getServerSecurityPlugins()
{
return m_serverSecurityPlugins;
}
@@ -448,8 +452,8 @@ public:
private:
SecurityPluginRegistry();
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > m_clientSecurityPlugins;
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> > m_serverSecurityPlugins;
securityPlugins_t m_clientSecurityPlugins;
securityPlugins_t m_serverSecurityPlugins;
};
}

View File

@@ -1,204 +0,0 @@
/**
* 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.
*/
#ifndef SIMPLECHANNELSEARCHMANAGERIMPL_H
#define SIMPLECHANNELSEARCHMANAGERIMPL_H
#ifdef epicsExportSharedSymbols
# define simpleChannelSearchManagerEpicsExportSharedSymbols
# undef epicsExportSharedSymbols
#endif
#include <pv/lock.h>
#include <pv/byteBuffer.h>
#include <pv/timer.h>
#ifdef simpleChannelSearchManagerEpicsExportSharedSymbols
# define epicsExportSharedSymbols
# undef simpleChannelSearchManagerEpicsExportSharedSymbols
#endif
#include <pv/channelSearchManager.h>
#include <pv/remote.h>
namespace epics {
namespace pvAccess {
class MockTransportSendControl: public TransportSendControl
{
public:
void endMessage() {}
void flush(bool /*lastMessageCompleted*/) {}
void setRecipient(const osiSockAddr& /*sendTo*/) {}
void startMessage(epics::pvData::int8 /*command*/, std::size_t /*ensureCapacity*/, epics::pvData::int32 /*payloadSize*/) {}
void ensureBuffer(std::size_t /*size*/) {}
void alignBuffer(std::size_t /*alignment*/) {}
void flushSerializeBuffer() {}
void cachedSerialize(const std::tr1::shared_ptr<const epics::pvData::Field>& field, epics::pvData::ByteBuffer* buffer)
{
// no cache
field->serialize(buffer, this);
}
virtual bool directSerialize(epics::pvData::ByteBuffer* /*existingBuffer*/, const char* /*toSerialize*/,
std::size_t /*elementCount*/, std::size_t /*elementSize*/)
{
return false;
}
};
class SimpleChannelSearchManagerImpl :
public ChannelSearchManager,
public epics::pvData::TimerCallback,
public std::tr1::enable_shared_from_this<SimpleChannelSearchManagerImpl>
{
public:
POINTER_DEFINITIONS(SimpleChannelSearchManagerImpl);
/**
* Constructor.
* @param context
*/
virtual ~SimpleChannelSearchManagerImpl();
/**
* Cancel.
*/
void cancel();
/**
* Get number of registered channels.
* @return number of registered channels.
*/
int32_t registeredCount();
/**
* Register channel.
* @param channel to register.
*/
void registerSearchInstance(SearchInstance::shared_pointer const & channel, bool penalize = false);
/**
* Unregister channel.
* @param channel to unregister.
*/
void unregisterSearchInstance(SearchInstance::shared_pointer const & channel);
/**
* Search response from server (channel found).
* @param guid server GUID.
* @param cid client channel ID.
* @param seqNo search sequence number.
* @param minorRevision server minor PVA revision.
* @param serverAddress server address.
*/
void searchResponse(const ServerGUID & guid, pvAccessID cid, int32_t seqNo, int8_t minorRevision, osiSockAddr* serverAddress);
/**
* New server detected.
* Boost searching of all channels.
*/
void newServerDetected();
/// Timer callback.
void callback();
/// Timer stooped callback.
void timerStopped();
/**
* Private constructor.
* @param context
*/
SimpleChannelSearchManagerImpl(Context::shared_pointer const & context);
void activate();
private:
bool generateSearchRequestMessage(SearchInstance::shared_pointer const & channel, bool allowNewFrame, bool flush);
static bool generateSearchRequestMessage(SearchInstance::shared_pointer const & channel,
epics::pvData::ByteBuffer* byteBuffer, TransportSendControl* control);
void boost();
void initializeSendBuffer();
void flushSendBuffer();
static bool isPowerOfTwo(int32_t x);
/**
* Context.
*/
Context::weak_pointer m_context;
/**
* Response address.
*/
osiSockAddr m_responseAddress;
/**
* Canceled flag.
*/
AtomicBoolean m_canceled;
/**
* Search (datagram) sequence number.
*/
int32_t m_sequenceNumber;
/**
* Send byte buffer (frame)
*/
epics::pvData::ByteBuffer m_sendBuffer;
/**
* Set of registered channels.
*/
typedef std::map<pvAccessID,SearchInstance::weak_pointer> m_channels_t;
m_channels_t m_channels;
/**
* Time of last frame send.
*/
int64_t m_lastTimeSent;
/**
* Mock transport send control
*/
MockTransportSendControl m_mockTransportSendControl;
/**
* This instance mutex.
*/
epics::pvData::Mutex m_channelMutex;
/**
* User value lock.
*/
epics::pvData::Mutex m_userValueMutex;
/**
* m_channels mutex.
*/
epics::pvData::Mutex m_mutex;
static const int DATA_COUNT_POSITION;
static const int CAST_POSITION;
static const int PAYLOAD_POSITION;
static const double ATOMIC_PERIOD;
static const int PERIOD_JITTER_MS;
static const int DEFAULT_USER_VALUE;
static const int BOOST_VALUE;
static const int MAX_COUNT_VALUE;
static const int MAX_FALLBACK_COUNT_VALUE;
static const int MAX_FRAMES_AT_ONCE;
static const int DELAY_BETWEEN_FRAMES_MS;
};
}
}
#endif /* SIMPLECHANNELSEARCHMANAGERIMPL_H */

View File

@@ -11,6 +11,8 @@
#include <stdexcept>
#include <osiSock.h>
#include <epicsGuard.h>
#include <pv/lock.h>
#include <pv/timer.h>
#include <pv/bitSetUtil.h>
@@ -28,7 +30,7 @@
#include <pv/codec.h>
#include <pv/channelSearchManager.h>
#include <pv/serializationHelper.h>
#include <pv/simpleChannelSearchManagerImpl.h>
#include <pv/channelSearchManager.h>
#include <pv/clientContextImpl.h>
#include <pv/configuration.h>
#include <pv/beaconHandler.h>
@@ -915,6 +917,7 @@ public:
}
}
// TODO: m_structure and m_bitSet guarded by m_structureMutex? (as below)
if (!(*m_structure->getStructure() == *pvPutStructure->getStructure()))
{
EXCEPTION_GUARD3(m_callback, cb, cb->putDone(invalidPutStructureStatus, thisPtr));
@@ -933,10 +936,11 @@ public:
}
try {
lock();
*m_bitSet = *pvPutBitSet;
m_structure->copyUnchecked(*pvPutStructure, *m_bitSet);
unlock();
{
epicsGuard<ChannelPutImpl> G(*this);
*m_bitSet = *pvPutBitSet;
m_structure->copyUnchecked(*pvPutStructure, *m_bitSet);
}
m_channel->checkAndGetTransport()->enqueueSendRequest(internal_from_this<ChannelPutImpl>());
} catch (std::runtime_error &rte) {
abortRequest();
@@ -1182,10 +1186,11 @@ public:
}
try {
lock();
*m_putDataBitSet = *bitSet;
m_putData->copyUnchecked(*pvPutStructure, *m_putDataBitSet);
unlock();
{
epicsGuard<ChannelPutGetImpl> G(*this);
*m_putDataBitSet = *bitSet;
m_putData->copyUnchecked(*pvPutStructure, *m_putDataBitSet);
}
m_channel->checkAndGetTransport()->enqueueSendRequest(internal_from_this<ChannelPutGetImpl>());
} catch (std::runtime_error &rte) {
abortRequest();
@@ -1420,9 +1425,10 @@ public:
}
try {
m_structureMutex.lock();
m_structure = pvArgument;
m_structureMutex.unlock();
{
epicsGuard<epicsMutex> G(m_structureMutex);
m_structure = pvArgument;
}
m_channel->checkAndGetTransport()->enqueueSendRequest(internal_from_this<ChannelRPCImpl>());
} catch (std::runtime_error &rte) {
@@ -1844,9 +1850,6 @@ private:
MonitorElement::shared_pointer m_overrunElement;
bool m_overrunInProgress;
MonitorElement::shared_pointer m_nullMonitorElement;
PVStructure::shared_pointer m_up2datePVStructure;
int32 m_releasedCount;
@@ -1872,7 +1875,6 @@ public:
m_monitorQueue(),
m_callback(callback), m_mutex(),
m_bitSet1(), m_bitSet2(), m_overrunInProgress(false),
m_nullMonitorElement(),
m_releasedCount(0),
m_reportQueueStateInProgress(false),
m_channel(channel), m_ioid(ioid),
@@ -2007,10 +2009,10 @@ public:
guard.unlock();
EXCEPTION_GUARD3(m_callback, cb, cb->unlisten(shared_from_this()));
}
return m_nullMonitorElement;
return MonitorElement::shared_pointer();
}
MonitorElement::shared_pointer retVal = m_monitorQueue.front();
MonitorElement::shared_pointer retVal(m_monitorQueue.front());
m_monitorQueue.pop();
return retVal;
}
@@ -2055,14 +2057,18 @@ public:
if (sendAck)
{
guard.unlock();
try
{
m_channel->checkAndGetTransport()->enqueueSendRequest(shared_from_this());
} catch (std::runtime_error&) {
// assume wrong connection state from checkAndGetTransport()
guard.lock();
m_reportQueueStateInProgress = false;
} catch (std::exception& e) {
LOG(logLevelWarn, "Ignore exception during MonitorStrategyQueue::release: %s", e.what());
guard.lock();
m_reportQueueStateInProgress = false;
}
}
@@ -2387,12 +2393,19 @@ public:
if (!startRequest(QOS_PROCESS | QOS_GET))
return BaseRequestImpl::otherRequestPendingStatus;
bool restore = m_started;
m_started = true;
guard.unlock();
try
{
m_channel->checkAndGetTransport()->enqueueSendRequest(internal_from_this<ChannelMonitorImpl>());
m_started = true;
return Status::Ok;
} catch (std::runtime_error &rte) {
guard.lock();
m_started = restore;
abortRequest();
return BaseRequestImpl::channelNotConnected;
}
@@ -2413,12 +2426,19 @@ public:
if (!startRequest(QOS_PROCESS))
return BaseRequestImpl::otherRequestPendingStatus;
bool restore = m_started;
m_started = false;
guard.unlock();
try
{
m_channel->checkAndGetTransport()->enqueueSendRequest(internal_from_this<ChannelMonitorImpl>());
m_started = false;
return Status::Ok;
} catch (std::runtime_error &rte) {
guard.lock();
m_started = restore;
abortRequest();
return BaseRequestImpl::channelNotConnected;
}
@@ -2446,7 +2466,7 @@ public:
class AbstractClientResponseHandler : public ResponseHandler {
protected:
ClientContextImpl::weak_pointer _context;
const ClientContextImpl::weak_pointer _context;
public:
AbstractClientResponseHandler(ClientContextImpl::shared_pointer const & context, string const & description) :
ResponseHandler(context.get(), description), _context(ClientContextImpl::weak_pointer(context)) {
@@ -3285,7 +3305,44 @@ private:
virtual void destroy() OVERRIDE FINAL
{
destroy(false);
// Hack. Prevent Transport from being dtor'd while m_channelMutex is held
Transport::shared_pointer old_transport;
{
Lock guard(m_channelMutex);
if (m_connectionState == DESTROYED)
return;
REFTRACE_DECREMENT(num_active);
old_transport = m_transport;
m_getfield.reset();
// stop searching...
shared_pointer thisChannelPointer = internal_from_this();
m_context->getChannelSearchManager()->unregisterSearchInstance(thisChannelPointer);
disconnectPendingIO(true);
if (m_connectionState == CONNECTED)
{
disconnect(false, true);
}
else if (m_transport)
{
// unresponsive state, do not forget to release transport
m_transport->release(getID());
m_transport.reset();
}
setConnectionState(DESTROYED);
// unregister
m_context->unregisterChannel(thisChannelPointer);
}
// should be called without any lock hold
reportChannelStateChange();
}
virtual string getRequesterName() OVERRIDE FINAL
@@ -3355,7 +3412,7 @@ public:
return m_channelID;
}
virtual string getSearchInstanceName() OVERRIDE FINAL {
virtual const string& getSearchInstanceName() OVERRIDE FINAL {
return m_name;
}
@@ -3388,7 +3445,11 @@ public:
void disconnect() {
{
// Hack. Prevent Transport from being dtor'd while m_channelMutex is held
Transport::shared_pointer old_transport;
Lock guard(m_channelMutex);
old_transport = m_transport;
// if not destroyed...
if (m_connectionState == DESTROYED)
throw std::runtime_error("Channel destroyed.");
@@ -3400,42 +3461,6 @@ public:
reportChannelStateChange();
}
/**
* Create a channel, i.e. submit create channel request to the server.
* This method is called after search is complete.
* @param transport
*/
void createChannel(Transport::shared_pointer const & transport)
{
Lock guard(m_channelMutex);
// do not allow duplicate creation to the same transport
if (!m_allowCreation)
return;
m_allowCreation = false;
// check existing transport
if (m_transport.get() && m_transport.get() != transport.get())
{
disconnectPendingIO(false);
m_transport->release(getID());
}
else if (m_transport.get() == transport.get())
{
// request to sent create request to same transport, ignore
// this happens when server is slower (processing search requests) than client generating it
return;
}
m_transport = transport;
m_transport->enqueueSendRequest(internal_from_this());
}
virtual void cancel() {
// noop
}
virtual void timeout() {
createChannelFailed();
}
@@ -3445,15 +3470,14 @@ public:
*/
virtual void createChannelFailed() OVERRIDE FINAL
{
// Hack. Prevent Transport from being dtor'd while m_channelMutex is held
Transport::shared_pointer old_transport;
Lock guard(m_channelMutex);
cancel();
// release transport if active
if (m_transport)
{
m_transport->release(getID());
m_transport.reset();
old_transport.swap(m_transport);
}
// ... and search again, with penalty
@@ -3476,7 +3500,6 @@ public:
if (m_connectionState == DESTROYED)
{
// end connection request
cancel();
return;
}
@@ -3496,71 +3519,6 @@ public:
LOG(logLevelError, "connectionCompleted() %d '%s' unhandled exception: %s\n", sid, m_name.c_str(), e.what());
// noop
}
// NOTE: always call cancel
// end connection request
cancel();
}
// should be called without any lock hold
reportChannelStateChange();
}
/**
* @param force force destruction regardless of reference count (not used now)
*/
void destroy(bool force) {
{
Lock guard(m_channelMutex);
if (m_connectionState == DESTROYED)
return;
//throw std::runtime_error("Channel already destroyed.");
}
REFTRACE_DECREMENT(num_active);
destroyChannel(force);
}
/**
* Actual destroy method, to be called <code>CAJContext</code>.
* @param force force destruction regardless of reference count
* @throws PVAException
* @throws std::runtime_error
* @throws IOException
*/
void destroyChannel(bool /*force*/) OVERRIDE FINAL {
{
Lock guard(m_channelMutex);
if (m_connectionState == DESTROYED)
throw std::runtime_error("Channel already destroyed.");
m_getfield.reset();
// stop searching...
shared_pointer thisChannelPointer = internal_from_this();
m_context->getChannelSearchManager()->unregisterSearchInstance(thisChannelPointer);
cancel();
disconnectPendingIO(true);
if (m_connectionState == CONNECTED)
{
disconnect(false, true);
}
else if (m_transport)
{
// unresponsive state, do not forget to release transport
m_transport->release(getID());
m_transport.reset();
}
setConnectionState(DESTROYED);
// unregister
m_context->unregisterChannel(thisChannelPointer);
}
// should be called without any lock hold
@@ -3584,7 +3542,6 @@ public:
if (!initiateSearch) {
// stop searching...
m_context->getChannelSearchManager()->unregisterSearchInstance(internal_from_this());
cancel();
}
setConnectionState(DISCONNECTED);
@@ -3660,9 +3617,12 @@ public:
}
virtual void searchResponse(const ServerGUID & guid, int8 minorRevision, osiSockAddr* serverAddress) OVERRIDE FINAL {
// Hack. Prevent Transport from being dtor'd while m_channelMutex is held
Transport::shared_pointer old_transport;
Lock guard(m_channelMutex);
Transport::shared_pointer transport = m_transport;
if (transport.get())
Transport::shared_pointer transport(m_transport);
if (transport)
{
// GUID check case: same server listening on different NIF
@@ -3679,7 +3639,7 @@ public:
// NOTE: this creates a new or acquires an existing transport (implies increases usage count)
transport = m_context->getTransport(internal_from_this(), serverAddress, minorRevision, m_priority);
if (!transport.get())
if (!transport)
{
createChannelFailed();
return;
@@ -3690,7 +3650,34 @@ public:
std::copy(guid.value, guid.value + 12, m_guid.value);
// create channel
createChannel(transport);
{
Lock guard(m_channelMutex);
// do not allow duplicate creation to the same transport
if (!m_allowCreation)
return;
m_allowCreation = false;
// check existing transport
if (m_transport && m_transport.get() != transport.get())
{
disconnectPendingIO(false);
m_transport->release(getID());
}
else if (m_transport.get() == transport.get())
{
// request to sent create request to same transport, ignore
// this happens when server is slower (processing search requests) than client generating it
return;
}
// rotate: transport -> m_transport -> old_transport ->
old_transport.swap(m_transport);
m_transport.swap(transport);
m_transport->enqueueSendRequest(internal_from_this());
}
}
virtual void transportClosed() OVERRIDE FINAL {
@@ -4109,7 +4096,40 @@ public:
m_contextState = CONTEXT_DESTROYED;
}
internalDestroy();
//
// cleanup
//
m_timer->close();
m_channelSearchManager->cancel();
// this will also close all PVA transports
destroyAllChannels();
// stop UDPs
for (BlockingUDPTransportVector::const_iterator iter = m_udpTransports.begin();
iter != m_udpTransports.end(); iter++)
(*iter)->close();
m_udpTransports.clear();
// stop UDPs
if (m_searchTransport)
m_searchTransport->close();
// wait for all transports to cleanly exit
int tries = 40;
epics::pvData::int32 transportCount;
while ((transportCount = m_transportRegistry.size()) && tries--)
epicsThreadSleep(0.025);
{
Lock guard(m_beaconMapMutex);
m_beaconHandlers.clear();
}
if (transportCount)
LOG(logLevelDebug, "PVA client context destroyed with %u transport(s) active.", (unsigned)transportCount);
}
virtual ~InternalClientContextImpl()
@@ -4152,7 +4172,7 @@ private:
// stores many weak_ptr
m_responseHandler.reset(new ClientResponseHandler(thisPointer));
m_channelSearchManager.reset(new SimpleChannelSearchManagerImpl(thisPointer));
m_channelSearchManager.reset(new ChannelSearchManager(thisPointer));
// preinitialize security plugins
SecurityPluginRegistry::instance();
@@ -4188,40 +4208,6 @@ private:
// TODO what if initialization failed!!!
}
void internalDestroy() {
//
// cleanup
//
// this will also close all PVA transports
destroyAllChannels();
// stop UDPs
for (BlockingUDPTransportVector::const_iterator iter = m_udpTransports.begin();
iter != m_udpTransports.end(); iter++)
(*iter)->close();
m_udpTransports.clear();
// stop UDPs
if (m_searchTransport)
m_searchTransport->close();
// wait for all transports to cleanly exit
int tries = 40;
epics::pvData::int32 transportCount;
while ((transportCount = m_transportRegistry.size()) && tries--)
epicsThreadSleep(0.025);
{
Lock guard(m_beaconMapMutex);
m_beaconHandlers.clear();
}
if (transportCount)
LOG(logLevelDebug, "PVA client context destroyed with %u transport(s) active.", (unsigned)transportCount);
}
void destroyAllChannels() {
Lock guard(m_cidMapMutex);
@@ -4472,7 +4458,7 @@ private:
}
}
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getSecurityPlugins() OVERRIDE FINAL
const securityPlugins_t& getSecurityPlugins() OVERRIDE FINAL
{
return SecurityPluginRegistry::instance().getClientSecurityPlugins();
}
@@ -4586,7 +4572,7 @@ private:
* Channel search manager.
* Manages UDP search requests.
*/
SimpleChannelSearchManagerImpl::shared_pointer m_channelSearchManager;
ChannelSearchManager::shared_pointer m_channelSearchManager;
/**
* Beacon handler map.

View File

@@ -41,7 +41,6 @@ public:
POINTER_DEFINITIONS(ClientChannelImpl);
virtual pvAccessID getChannelID() = 0;
virtual void destroyChannel(bool force) = 0;
virtual void connectionCompleted(pvAccessID sid/*, rights*/) = 0;
virtual void createChannelFailed() = 0;
virtual ClientContextImpl* getContext() = 0;

View File

@@ -109,12 +109,16 @@ void BeaconEmitter::timerStopped()
void BeaconEmitter::destroy()
{
_timer->cancel(shared_from_this());
Timer::shared_pointer timer(_timer.lock());
if(timer)
timer->cancel(shared_from_this());
}
void BeaconEmitter::start()
{
_timer->scheduleAfterDelay(shared_from_this(), 0.0);
Timer::shared_pointer timer(_timer.lock());
if(timer)
timer->scheduleAfterDelay(shared_from_this(), 0.0);
}
void BeaconEmitter::reschedule()
@@ -122,7 +126,9 @@ void BeaconEmitter::reschedule()
const double period = (_beaconSequenceID >= _beaconCountLimit) ? _slowBeaconPeriod : _fastBeaconPeriod;
if (period > 0)
{
_timer->scheduleAfterDelay(shared_from_this(), period);
Timer::shared_pointer timer(_timer.lock());
if(timer)
timer->scheduleAfterDelay(shared_from_this(), period);
}
}

View File

@@ -13,40 +13,19 @@ using namespace epics::pvData;
namespace epics {
namespace pvAccess {
DefaultBeaconServerStatusProvider::DefaultBeaconServerStatusProvider(ServerContext::shared_pointer const & context): _context(context)
{
initialize();
}
DefaultBeaconServerStatusProvider::DefaultBeaconServerStatusProvider(ServerContext::shared_pointer const & context)
:_status(getPVDataCreate()->createPVStructure(getFieldCreate()->createFieldBuilder()
->add("connections", pvInt)
->add("connections", pvInt)
->add("allocatedMemory", pvLong)
->add("freeMemory", pvLong)
->add("threads", pvInt)
->add("deadlocks", pvInt)
->add("averageSystemLoad", pvDouble)
->createStructure()))
{}
DefaultBeaconServerStatusProvider::~DefaultBeaconServerStatusProvider()
{
}
void DefaultBeaconServerStatusProvider::initialize()
{
FieldCreatePtr fieldCreate = getFieldCreate();
StringArray fieldNames;
fieldNames.resize(6);
fieldNames[0] = "connections";
fieldNames[1] = "allocatedMemory";
fieldNames[2] = "freeMemory";
fieldNames[3] = "threads";
fieldNames[4] = "deadlocks";
fieldNames[5] = "averageSystemLoad";
FieldConstPtrArray fields;
fields.resize(6);
// TODO hierarchy can be used...
fields[0] = fieldCreate->createScalar(pvInt);
fields[1] = fieldCreate->createScalar(pvLong);
fields[2] = fieldCreate->createScalar(pvLong);
fields[3] = fieldCreate->createScalar(pvInt);
fields[4] = fieldCreate->createScalar(pvInt);
fields[5] = fieldCreate->createScalar(pvDouble);
_status = getPVDataCreate()->createPVStructure(fieldCreate->createStructure(fieldNames, fields));
}
DefaultBeaconServerStatusProvider::~DefaultBeaconServerStatusProvider() {}
PVField::shared_pointer DefaultBeaconServerStatusProvider::getServerStatusData()
{

View File

@@ -95,7 +95,7 @@ private:
/**
* Protocol.
*/
std::string _protocol;
const std::string _protocol;
/**
* Transport.
@@ -110,22 +110,22 @@ private:
/**
* Server GUID.
*/
ServerGUID _guid;
const ServerGUID _guid;
/**
* Fast (at startup) beacon period (in sec).
*/
double _fastBeaconPeriod;
const double _fastBeaconPeriod;
/**
* Slow (after beaconCountLimit is reached) beacon period (in sec).
*/
double _slowBeaconPeriod;
const double _slowBeaconPeriod;
/**
* Limit on number of beacons issued.
*/
epics::pvData::int16 _beaconCountLimit;
const epics::pvData::int16 _beaconCountLimit;
/**
* Server address.
@@ -135,17 +135,18 @@ private:
/**
* Server port.
*/
epics::pvData::int32 _serverPort;
const epics::pvData::int32 _serverPort;
/**
* Server status provider implementation (optional).
*/
BeaconServerStatusProvider::shared_pointer _serverStatusProvider;
/**
* Timer.
/** Timer is referenced by server context, which also references us.
* We will also be queuing ourselves, and be referenced by Timer.
* So keep only a weak ref to Timer to avoid possible ref. loop.
*/
epics::pvData::Timer::shared_pointer _timer;
epics::pvData::Timer::weak_pointer _timer;
};
}

View File

@@ -63,17 +63,8 @@ public:
virtual epics::pvData::PVField::shared_pointer getServerStatusData();
private:
/**
* Initialize
*/
void initialize();
private:
epics::pvData::PVStructure::shared_pointer _status;
std::tr1::shared_ptr<ServerContext> _context;
//ServerContext::shared_pointer _context;
};
}

View File

@@ -51,7 +51,7 @@ public:
Transport::shared_pointer getSearchTransport() OVERRIDE FINAL;
Configuration::const_shared_pointer getConfiguration() OVERRIDE FINAL;
TransportRegistry* getTransportRegistry() OVERRIDE FINAL;
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& getSecurityPlugins() OVERRIDE FINAL;
const securityPlugins_t& getSecurityPlugins() OVERRIDE FINAL;
virtual void newServerDetected() OVERRIDE FINAL;
@@ -259,11 +259,6 @@ private:
*/
void loadConfiguration();
/**
* Destroy all transports.
*/
void destroyAllTransports();
Configuration::const_shared_pointer configuration;
epicsTimeStamp _startTime;

View File

@@ -39,7 +39,7 @@ ServerContextImpl::ServerContextImpl():
_broadcastPort(PVA_BROADCAST_PORT),
_serverPort(PVA_SERVER_PORT),
_receiveBufferSize(MAX_TCP_RECV),
_timer(new Timer("pvAccess-server timer", lowerPriority)),
_timer(new Timer("PVAS timers", lowerPriority)),
_beaconEmitter(),
_acceptor(),
_transportRegistry(),
@@ -307,6 +307,12 @@ void ServerContextImpl::run(uint32 seconds)
void ServerContextImpl::shutdown()
{
if(!_timer)
return; // already shutdown
// abort pending timers and prevent new timers from starting
_timer->close();
// stop responding to search requests
for (BlockingUDPTransportVector::const_iterator iter = _udpTransports.begin();
iter != _udpTransports.end(); iter++)
@@ -346,7 +352,7 @@ void ServerContextImpl::shutdown()
}
// this will also destroy all channels
destroyAllTransports();
_transportRegistry.clear();
// drop timer queue
LEAK_CHECK(_timer, "_timer")
@@ -360,12 +366,6 @@ void ServerContextImpl::shutdown()
_runEvent.signal();
}
void ServerContextImpl::destroyAllTransports()
{
// now clear all (release)
_transportRegistry.clear();
}
void ServerContext::printInfo(int lvl)
{
printInfo(cout, lvl);
@@ -540,7 +540,7 @@ epicsTimeStamp& ServerContextImpl::getStartTime()
}
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& ServerContextImpl::getSecurityPlugins()
const Context::securityPlugins_t& ServerContextImpl::getSecurityPlugins()
{
return SecurityPluginRegistry::instance().getServerSecurityPlugins();
}

View File

@@ -628,9 +628,9 @@ void ChannelAccessIFTest::test_channelGetIntProcessInternal(Channel::shared_poin
pvTimeStamp.get(timeStamp);
double deltaT = TimeStamp::diff(timeStamp, previousTimestamp);
testOk((previousValue +1)/*%11*/ == value->get(), "%s: testing the counter value change",
testMethodName.c_str());
testOk(deltaT > 0.9 && deltaT < 2.0,
testOk((previousValue +1) == value->get(), "%s: testing the counter value change %d == %d",
testMethodName.c_str(), previousValue +1, (int)value->get());
testOk(deltaT > 0.1 && deltaT < 20.0,
"%s: timestamp change was %g", testMethodName.c_str(), deltaT);
}
@@ -1608,9 +1608,9 @@ void ChannelAccessIFTest::test_channelPutGetIntProcess() {
//cout << "Testing1:" << testValue << " == " << getValuePtr->get() << endl;
//cout << "Testing2:" << timeStamp.getSecondsPastEpoch() << ">" << previousTimestampSec << endl;
testOk( testValue == getValuePtr->get(), "%s: testing the counter value change",
CURRENT_FUNCTION);
testOk(deltaT > 0.9 && deltaT < 2.0,
testOk( testValue == getValuePtr->get(), "%s: testing the counter value change %d == %d",
CURRENT_FUNCTION, testValue, (int)getValuePtr->get());
testOk(deltaT > 0.1 && deltaT < 20.0,
"%s: timestamp change is %g", CURRENT_FUNCTION, deltaT);
}