This commit is contained in:
Michael Davidsaver
2017-06-20 15:33:36 +02:00
parent 61312b2a65
commit 9a9896042a
5 changed files with 135 additions and 7 deletions

View File

@ -20,8 +20,10 @@ digraph clientowner {
ChannelArray;
ChannelArrayRequester [shape=box];
Channel -> ChannelProvider [color=green, style=dashed];
ChannelProvider -> Channel [color=green, style=dashed];
# Operation -> Requester strong ref
Channel -> ChannelProvider [color=red, style=dashed];
Channel -> ChannelRequester [color=red, style=dashed];
ChannelGet -> ChannelGetRequester [color=red, style=dashed];
ChannelPut -> ChannelPutRequester [color=red, style=dashed];

View File

@ -8,3 +8,12 @@ and again each time a channel becomes Connected.
@include getme.cpp
*/
/**
@page examples_monitorme Client Monitor Example
This example demonstrates a client which sets up a persistent Monitor operation.
@include monitorme.cpp
*/

View File

@ -4,10 +4,12 @@
@mainpage pvAccess C++ docs
The epics::pvAccess namespace.
See pv/pvAccess.h
See pv/pvAccess.h header.
@code
#include <pv/configuration.h>
#include <pv/pvAccess.h>
#include <pv/clientFactory.h>
@endcode
See the @ref providers page.
@ -15,6 +17,7 @@ See the @ref providers page.
Examples
- @ref examples_getme
- @ref examples_monitorme
*/

View File

@ -48,6 +48,30 @@ is called when a Channel becomes (dis)connected.
A "Requester" sub-class must be provided when each "Operation" is created.
This Requester then becomes bound to the Operation.
@subsubsection provider_roles_requester_locking
Operations methods may call requester methods, and vis versa.
The following rules must be followed to avoid deadlocks.
- No locks must be held when Requester methods are called.
- Locks may be held when Operation methods are called.
These rules place the burdon of avoiding deadlocks on the ChannelProvider implementation (Server role).
Clients must still be aware when Operation methods can call Requester methods recursivly,
and consider this when locking.
For example, the following call stack may legitimetly occur for a ChannelProvider
to for a Get which accesses locally stored data.
- Channel::createChannelGet()
- ChannelGetRequester::channelGetConnect()
- ChannelGet::get()
- ChannelGetRequester::getDone()
Thus care should be taken when calling ChannelGet::get() from within ChannelGetRequester::getDone()
to avoid infinite recursion.
@subsection providers_ownership shared_ptr<> and Ownership
"Operations" and "Requesters" are always handled via std::tr1::shared_ptr.
@ -153,6 +177,11 @@ which is uniquely owned by the caller (see @ref providers_ownership_unique).
As such, the caller must keep a reference to to the Channel or it will be destroyed.
This may be done explicitly, or implicitly by storing a reference to an Operation.
@note The returned Channel does *not* hold a strong reference for the ChannelProvider
from which it was created.
User code *must* keep a reference to the provider as long as Channels are in use.
All Channels are automatically closed when their provider is destroyed.
A Channel can be created at any time, and shall succeed as long as
the provided name and address are syntactically valid, and the priority is in the valid range.
@ -202,22 +231,99 @@ When the underlying Channel becomes disconnected or is destroyed,
then the channelDisconnect() method of each Requester is called (eg.
see epics::pvAccess::ChannelBaseRequester::channelDisconnect()
).
All operations are implicitly cancelled/stopped before channelDisconnect() is called.
@subsubsection providers_client_operations_lifetime Operation Lifetime and (dis)connection
An Operation can be created at any time regardless of whether a Channel is connected or not.
An Operation will remain associated with a Channel through (re)connection and disconnection.
@subsubsection providers_client_operations_exec Executing an Operation
After an Operation becomes ready/connected an additional step is necessary to request data.
- epics::pvAccess::ChannelGet::get()
- epics::pvAccess::ChannelPut::get()
- epics::pvAccess::ChannelPut::put()
- epics::pvAccess::ChannelRPC::request()
- epics::pvAccess::ChannelPutGet::putGet()
- epics::pvAccess::ChannelPutGet::getPut()
- epics::pvAccess::ChannelPutGet::getGet()
- epics::pvAccess::ChannelProcess::process()
- epics::pvAccess::ChannelArray::putArray()
- epics::pvAccess::ChannelArray::getArray()
- epics::pvAccess::ChannelArray::getLength()
- epics::pvAccess::ChannelArray::setLength()
Once one of these methods is called to execute an operation,
none may be again until the corresponding completion callback is called,
or the operation is cancel()ed (or epics::pvAccess::Monitor::stop() ).
- epics::pvAccess::ChannelGetRequester::getDone()
- epics::pvAccess::ChannelPutRequester::getDone()
- epics::pvAccess::ChannelPutRequester::putDone()
- epics::pvAccess::ChannelRPCRequester::requestDone()
- epics::pvAccess::ChannelPutGetRequester::putGetDone()
- epics::pvAccess::ChannelPutGetRequester::getPutDone()
- epics::pvAccess::ChannelPutGetRequester::getGetDone()
- epics::pvAccess::ChannelProcessRequester::processDone()
- epics::pvAccess::ChannelArrayRequester::putArrayDone()
- epics::pvAccess::ChannelArrayRequester::getArrayDone()
- epics::pvAccess::ChannelArrayRequester::getLengthDone()
- epics::pvAccess::ChannelArrayRequester::setLengthDone()
@subsubsection providers_client_operations_monitor Monitor Operation
epics::pvAccess::Monitor operations are handled differently than others as
more than one subscription update may be delivered after start() is called.
During or after epics::pvAccess::MonitorRequester::monitorConnect()
it is necessary to call epics::pvAccess::Monitor::start()
to begin receiving subscription updates.
The epics::pvAccess::Monitor::poll() and epics::pvAccess::Monitor::release()
methods access a FIFO queue of subscription updates which have been received.
The epics::pvAccess::MonitorRequester::monitorEvent() method is called
when this FIFO becomes not empty.
@note The pvAccess::MonitorRequester::monitorEvent() is called from a server internal thread
which may be shared with other operations.
In order to avoid delaying other channels/operations
it is recommended to use monitorEvent() as notification for a client
specific worker thread where poll() and release() are called.
epics::pvAccess::MonitorRequester::unlisten() is called to indicate a subscription
has reached a definite end without an error.
Not all subscription sources will use this.
@warning It is critical that any non-NULL MonitorElement returned by poll()
must be passed to release().
Failure to do this will result in a resource leak and possibly stall
the monitor.
See epics::pvAccess::Monitor::Stats::noutstanding
epics::pvAccess::Monitor::getStats() can help diagnose problems related
to the Monitor FIFO.
See epics::pvAccess::Monitor::Stats.
@subsection provides_client_ownership Client Ownership
Implicit ownership in classes outside the control of client code.
@dotfile client_ownership.dot Client implicit relationships
- Channel hold strong refs. of ChannelProvider and ChannelRequester
- Channel holds weak ref. to ChannelProvider
- ChannelProvider holds weak ref. to Channel
- Channel holds strong ref. to ChannelRequester
- Channel holds weak refs to all Operations
- Operation holds strong refs to the corresponding Requester, and Channel
@subsection provides_client_examples Client Examples
- @ref examples_getme
- @ref examples_monitorme
@section providers_server Server Role
*/