void ReapThread::add(const ReapablePtr& reapable, int timeout, const Ice::ConnectionPtr& connection) { Lock sync(*this); if(_terminated) { return; } // // NOTE: registering a reapable with a null timeout is allowed. The reapable is reaped // only when the reaper thread is shutdown. // // // 10 seconds is the minimum permissable timeout. // if(timeout > 0 && timeout < 10) { timeout = 10; } ReapableItem item; item.item = reapable; item.connection = connection; item.timeout = timeout == 0 ? IceUtil::Time() : IceUtil::Time::seconds(timeout); _sessions.push_back(item); if(connection) { map<Ice::ConnectionPtr, set<ReapablePtr> >::iterator p = _connections.find(connection); if(p == _connections.end()) { p = _connections.insert(make_pair(connection, set<ReapablePtr>())).first; connection->setCloseCallback(_closeCallback); connection->setHeartbeatCallback(_heartbeatCallback); } p->second.insert(reapable); } if(timeout > 0) { // // If there is a new minimum wake interval then wake the reaping // thread. // if(calcWakeInterval()) { notify(); } // // Since we just added a new session with a non null timeout there // must be a non-zero wakeInterval. // assert(_wakeInterval != IceUtil::Time()); } }
void ReapThread::connectionHeartbeat(const Ice::ConnectionPtr& con) { Lock sync(*this); map<Ice::ConnectionPtr, set<ReapablePtr> >::const_iterator p = _connections.find(con); if(p == _connections.end()) { con->setCloseCallback(0); con->setHeartbeatCallback(0); return; } for(set<ReapablePtr>::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { (*q)->heartbeat(); } }
void SessionHelperI::connected(const Glacier2::RouterPrxPtr& router, const Glacier2::SessionPrxPtr& session) { // // Remote invocation should be done without acquiring a mutex lock. // assert(router); Ice::ConnectionPtr conn = router->ice_getCachedConnection(); string category = router->getCategoryForClient(); Ice::Int acmTimeout = 0; try { acmTimeout = router->getACMTimeout(); } catch(const Ice::OperationNotExistException&) { } if(acmTimeout <= 0) { acmTimeout = static_cast<Ice::Int>(router->getSessionTimeout()); } // // We create the callback object adapter here because createObjectAdapter internally // makes synchronous RPCs to the router. We can't create the OA on-demand when the // client calls objectAdapter() or addWithUUID() because they can be called from the // GUI thread. // if(_useCallbacks) { _adapter = _communicator->createObjectAdapterWithRouter("", router); _adapter->activate(); } bool destroy; { IceUtil::Mutex::Lock sync(_mutex); _router = router; destroy = _destroy; if(!_destroy) { // // Cache the category. // _category = category; // // Assign the session after _destroy is checked. // _session = session; _connected = true; if(acmTimeout > 0) { Ice::ConnectionPtr connection = _router->ice_getCachedConnection(); assert(connection); connection->setACM(acmTimeout, IceUtil::None, Ice::HeartbeatAlways); #ifdef ICE_CPP11_MAPPING connection->setCloseCallback([self = shared_from_this()](Ice::ConnectionPtr) { self->destroy(); }); #else connection->setCloseCallback(ICE_MAKE_SHARED(CloseCallbackI, shared_from_this())); #endif } } } if(destroy) { // // connected() is only called from the ConnectThread so it is ok to // call destroyInternal here. // destroyInternal(new Disconnected(shared_from_this(), _callback)); } else { dispatchCallback(new Connected(_callback, shared_from_this()), conn); } }
bool Glacier2::Application::doMain(Ice::StringSeq& args, const Ice::InitializationData& initData, int& status, int version) { // // Reset internal state variables from Ice.Application. The // remainder are reset at the end of this method. // _callbackInProgress = false; _destroyed = false; _interrupted = false; bool restart = false; bool sessionCreated = false; status = 0; try { _communicator = Ice::initialize(args, initData, version); _router = ICE_UNCHECKED_CAST(Glacier2::RouterPrx, communicator()->getDefaultRouter()); if(!_router) { Error out(getProcessLogger()); out << _appName << ": no glacier2 router configured"; status = 1; } else { // // The default is to destroy when a signal is received. // if(_signalPolicy == ICE_ENUM(SignalPolicy, HandleSignals)) { destroyOnInterrupt(); } // If createSession throws, we're done. try { _session = createSession(); sessionCreated = true; } catch(const Ice::LocalException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; status = 1; } if(sessionCreated) { Ice::Int acmTimeout = 0; try { acmTimeout = _router->getACMTimeout(); } catch(const Ice::OperationNotExistException&) { } if(acmTimeout <= 0) { acmTimeout = static_cast<Ice::Int>(_router->getSessionTimeout()); } if(acmTimeout > 0) { Ice::ConnectionPtr connection = _router->ice_getCachedConnection(); assert(connection); connection->setACM(acmTimeout, IceUtil::None, ICE_ENUM(ACMHeartbeat, HeartbeatAlways)); #ifdef ICE_CPP11_MAPPING connection->setCloseCallback( [this](Ice::ConnectionPtr) { sessionDestroyed(); }); #else connection->setCloseCallback(ICE_MAKE_SHARED(CloseCallbackI, this)); #endif } _category = _router->getCategoryForClient(); IceInternal::ArgVector a(args); status = runWithSession(a.argc, a.argv); } } } // We want to restart on those exceptions which indicate a // break down in communications, but not those exceptions that // indicate a programming logic error (ie: marshal, protocol // failure, etc). catch(const RestartSessionException&) { restart = true; } catch(const Ice::ConnectionRefusedException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; restart = true; } catch(const Ice::ConnectionLostException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; restart = true; } catch(const Ice::UnknownLocalException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; restart = true; } catch(const Ice::RequestFailedException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; restart = true; } catch(const Ice::TimeoutException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; restart = true; } catch(const Ice::LocalException& ex) { Error out(getProcessLogger()); out << _appName << ": " << ex; status = 1; } catch(const std::exception& ex) { Error out(getProcessLogger()); out << _appName << ": std::exception " << ex; status = 1; } catch(const std::string& ex) { Error out(getProcessLogger()); out << _appName << ": c++ exception " << ex; status = 1; } catch(const char* ex) { Error out(getProcessLogger()); out << _appName << ": char* exception " << ex; status = 1; } catch(...) { Error out(getProcessLogger()); out << _appName << ": unknown exception"; status = 1; } // // Don't want any new interrupt and at this point (post-run), // it would not make sense to release a held signal to run // shutdown or destroy. // if(_signalPolicy == ICE_ENUM(SignalPolicy, HandleSignals)) { ignoreInterrupt(); } { IceUtil::Mutex::Lock lock(_mutex); while(_callbackInProgress) { _condVar.wait(lock); } if(_destroyed) { _communicator = 0; } else { _destroyed = true; // // And _communicator != 0, meaning will be destroyed // next, _destroyed = true also ensures that any // remaining callback won't do anything // } _application = 0; } if(sessionCreated && _router) { try { _router->destroySession(); } catch(const Ice::ConnectionLostException&) { // Expected if another thread invoked on an object from the session concurrently. } catch(const Glacier2::SessionNotExistException&) { // This can also occur. } catch(const exception& ex) { // Not expected. Error out(getProcessLogger()); out << "unexpected exception when destroying the session:\n" << ex; } _router = 0; } if(_communicator) { _communicator->destroy(); _communicator = 0; } // // Reset internal state. We cannot reset the Application state // here, since _destroyed must remain true until we re-run // this method. // _adapter = 0; _router = 0; _session = 0; _category.clear(); return restart; }