Ejemplo n.º 1
0
void ProcessVariable::unsubscribe(Guard &guard)
{
    guard.check(__FILE__, __LINE__, mutex);
    // See comments in stop(): this->id is already 0, state==INIT.
    if (isSubscribed(guard))
    {
#ifdef CHECK_EVID
        void *user = peek_evid_userptr(ev_id);
        LOG_ASSERT(user == this);
#endif
        evid _ev_id = ev_id;
        ev_id = 0;
        GuardRelease release(__FILE__, __LINE__, guard);
        {
            Guard ctx_guard(__FILE__, __LINE__, ctx);
            LOG_ASSERT(ctx.isAttached(ctx_guard));
        }
        try
        {
            ca_clear_subscription(_ev_id);
        }
        catch (std::exception &e)
        {
            LOG_MSG("ProcessVariable::unsubscribe(%s): %s\n",
                    getName().c_str(), e.what());
        }
        catch (...)
        {
            LOG_MSG("ProcessVariable::unsubscribe(%s): Unknown Exception\n",
                    getName().c_str());
        }    
    }    
}
Ejemplo n.º 2
0
void ProcessVariable::getValue(Guard &guard)
{
    guard.check(__FILE__, __LINE__, mutex);
    if (state != CONNECTED)
        return; // Can't get
    ++outstanding_gets;
    chid _id = id;
    GuardRelease release(__FILE__, __LINE__, guard); // Unlock while in CAC.
    {
        int status;
        try
        {
            status = ca_array_get_callback(dbr_type, dbr_count,
                                           _id, value_callback, this);
        }
        catch (std::exception &e)
        {
            LOG_MSG("ProcessVariable::getValue(%s): %s\n",
                    getName().c_str(), e.what());
        }
        catch (...)
        {
            LOG_MSG("ProcessVariable::getValue(%s): Unknown Exception\n",
                    getName().c_str());
        }                          
        if (status != ECA_NORMAL)
        {
            LOG_MSG("%s: ca_array_get_callback failed: %s\n",
                    getName().c_str(), ca_message(status));
            return;
        }
        Guard ctx_guard(__FILE__, __LINE__, ctx);
        ctx.requestFlush(ctx_guard);
    }    
}
Ejemplo n.º 3
0
void GroupInfo::addChannel(Guard &group_guard, ArchiveChannel *channel)
{
    group_guard.check(__FILE__, __LINE__, mutex);
    // Is Channel already in group?
    stdList<ArchiveChannel *>::iterator i;
    for (i=channels.begin(); i!=channels.end(); ++i)
        if (*i == channel)
            return;
    channels.push_back(channel);
}
Ejemplo n.º 4
0
// called by ArchiveChannel    
void GroupInfo::decConnected(Guard &group_guard, ArchiveChannel &pv)
{
    group_guard.check(__FILE__, __LINE__, mutex);
    if (num_connected <= 0)
        throw GenericException(__FILE__, __LINE__,
                               "Group %s connect count runs below 0 "
                               "on decrement from '%s'",
                               getName().c_str(), pv.getName().c_str());
     --num_connected;
}
Ejemplo n.º 5
0
// called by ArchiveChannel
void GroupInfo::incConnected(Guard &group_guard, ArchiveChannel &pv)
{
    group_guard.check(__FILE__, __LINE__, mutex);
    ++num_connected;
    if (num_connected > channels.size())
        throw GenericException(__FILE__, __LINE__,
                               "Group %s connect count is %zu out of %zu "
                               "on increment from '%s'",
                               getName().c_str(),
                               (size_t)num_connected,
                               (size_t)channels.size(),
                               pv.getName().c_str());    
}
Ejemplo n.º 6
0
// called by ArchiveChannel
void GroupInfo::disable(Guard &group_guard,
                        ArchiveChannel *cause, const epicsTime &when)
{
    group_guard.check(__FILE__, __LINE__, mutex);
    LOG_MSG("'%s' disables group '%s'\n",
            cause->getName().c_str(), getName().c_str());
    ++disable_count;
    if (disable_count != 1) // Was already disabled?
        return;
    // Disable all channels in this group
    stdList<ArchiveChannel *>::iterator ci;
    for (ci = channels.begin(); ci != channels.end(); ++ci)
    {
        ArchiveChannel *c = *ci;
        Guard guard(__FILE__, __LINE__, *c);
        c->disable(guard, when);
    }
}
Ejemplo n.º 7
0
void ProcessVariable::stop(Guard &guard)
{
#   ifdef DEBUG_PV
    printf("stop ProcessVariable(%s)\n", getName().c_str());
#   endif
    guard.check(__FILE__, __LINE__, mutex);
    LOG_ASSERT(isRunning(guard));
    // We'll unlock in unsubscribe(), and then for the ca_clear_channel.
    // At those times, an ongoing connection could invoke the connection_handler,
    // control_callback or subscribe.
    // Setting all indicators back to INIT state will cause those to bail.
    chid _id = id;
    id = 0;
    bool was_connected = (state == CONNECTED);
    state = INIT;
    outstanding_gets = 0;
    unsubscribe(guard);
    // Unlock around CA lib. calls to prevent deadlocks.
    {
        GuardRelease release(__FILE__, __LINE__, guard);
        {   // If we were subscribed, this was already checked in unsubscribe()...
            Guard ctx_guard(__FILE__, __LINE__, ctx);
            LOG_ASSERT(ctx.isAttached(ctx_guard));
        }
        try
        {
            ca_clear_channel(_id);
        }
        catch (std::exception &e)
        {
            LOG_MSG("ProcessVariable::stop(%s): %s\n",
                    getName().c_str(), e.what());
        }
        catch (...)
        {
            LOG_MSG("ProcessVariable::stop(%s): Unknown Exception\n",
                    getName().c_str());
        }
        // If there are listeners, tell them that we are disconnected.
        if (was_connected)
            firePvDisconnected();
    }
}
Ejemplo n.º 8
0
void ProcessVariable::start(Guard &guard)
{
    guard.check(__FILE__, __LINE__, mutex);
#   ifdef DEBUG_PV
    printf("start ProcessVariable(%s)\n", getName().c_str());
#   endif
    LOG_ASSERT(! isRunning(guard));
    LOG_ASSERT(state == INIT);
    state = DISCONNECTED;
    // Unlock around CA lib. calls to prevent deadlocks in callbacks.
    int status;
    chid _id;
    {
        GuardRelease release(__FILE__, __LINE__, guard);
        {
            try
            {
       	        status = ca_create_channel(getName().c_str(),
                                           connection_handler,
                                           this, CA_PRIORITY_ARCHIVE, &_id);
            }
            catch (std::exception &e)
            {
                LOG_MSG("ProcessVariable::start(%s): %s\n",
                        getName().c_str(), e.what());
            }
            catch (...)
            {
                LOG_MSG("ProcessVariable::start(%s): Unknown Exception\n",
                        getName().c_str());
            }                          
            Guard ctx_guard(__FILE__, __LINE__, ctx);
            ctx.requestFlush(ctx_guard);
        }
    }
    id = _id;
    if (status != ECA_NORMAL)
        LOG_MSG("'%s': ca_create_channel failed, status %s\n",
                getName().c_str(), ca_message(status));
}
Ejemplo n.º 9
0
// called by ArchiveChannel
void GroupInfo::enable(Guard &group_guard,
                       ArchiveChannel *cause, const epicsTime &when)
{
    group_guard.check(__FILE__, __LINE__, mutex);
    LOG_MSG("'%s' enables group '%s'\n",
            cause->getName().c_str(), getName().c_str());
    if (disable_count <= 0)
    {
        LOG_MSG("Group %s is not disabled, ERROR!\n", getName().c_str());
        return;
    }
    --disable_count;
    if (disable_count > 0) // Still disabled?
        return;
    // Enable all channels in this group
    stdList<ArchiveChannel *>::iterator ci;
    for (ci = channels.begin(); ci != channels.end(); ++ci)
    {
        ArchiveChannel *c = *ci;
        Guard guard(__FILE__, __LINE__, *c);
        c->enable(guard, when);
    }
}
Ejemplo n.º 10
0
ProcessVariable::State ProcessVariable::getState(Guard &guard) const
{
    guard.check(__FILE__, __LINE__, mutex);
    return state;
}
Ejemplo n.º 11
0
void ProcessVariable::subscribe(Guard &guard)
{
    guard.check(__FILE__, __LINE__, mutex);
    if (dbr_type == 0)
        throw GenericException(__FILE__, __LINE__,
                               "Cannot subscribe to %s, never connected",
                               getName().c_str());
    // Prevent multiple subscriptions
    if (isSubscribed(guard))
        return;
    // While we were unlocked, a disconnect or stop() could have happend,
    // in which case we need to bail out.
    if (id == 0 || state != CONNECTED)
    {
        LOG_MSG("'%s': Skipped subscription, state %s, id 0x%lu.\n",
                getName().c_str(),  getStateStr(guard), (unsigned long) id);
        return;
    }
    chid     _id    = id;
    evid     _ev_id = 0;
    DbrType  _type  = dbr_type;
    DbrCount _count = dbr_count;
    {   // Release around CA call??
        // --  GuardRelease release(__FILE__, __LINE__, guard);
        // Right now, could a stop() and ca_clear_channel(id) happen,
        // so that ca_create_subscription() uses an invalid id?
        //
        // Task A, CAC client:
        // control_callback, pvConnected, subscribe
        //
        // Task B, Engine or HTTPD:
        // stop, clear_channel
        //
        // LockTest.cpp indicates that the clear_channel() will wait
        // for the CAC library to leabe the control_callback.
        // So even though we unlock the ProcessVariable and somebody
        // could invoke stop() and set id=0, we have the copied _id,
        // and the ca_clear_channel(id) won't happen until we leave
        // the control_callback.
        // This of course only handles the use case of the engine
        // where subscribe is invoked from control_callback & pvConnected.
        // to be on the safe side, we keep the guard and prevent a stop(),
        // until we find a deadlock that forces us to reconsider....
        {
            int status;
            try
            {
                status = ca_create_subscription(_type, _count, _id,
                                                DBE_LOG | DBE_ALARM,
                                                value_callback, this, &_ev_id);
            }
            catch (std::exception &e)
            {
                LOG_MSG("ProcessVariable::subscribe(%s): %s\n",
                        getName().c_str(), e.what());
            }
            catch (...)
            {
                LOG_MSG("ProcessVariable::subscribe(%s): Unknown Exception\n",
                        getName().c_str());
            } 
            if (status != ECA_NORMAL)
            {
                LOG_MSG("%s: ca_create_subscription failed: %s\n",
                        getName().c_str(), ca_message(status));
                return;
            }
            Guard ctx_guard(__FILE__, __LINE__, ctx);
            ctx.requestFlush(ctx_guard);
        }
    }
    ev_id = _ev_id;
    LOG_ASSERT(ev_id != 0);
#ifdef CHECK_EVID
    void *user = peek_evid_userptr(ev_id);
    LOG_ASSERT(user == this);
#endif
}
Ejemplo n.º 12
0
bool ProcessVariable::isRunning(Guard &guard)
{
    guard.check(__FILE__, __LINE__, mutex);
    return id != 0;
}