How to tell (in C++) when an adapter is deactivated

mefostermefoster Member Mary Ellen FosterOrganization: Heriot-Watt University, EdinburghProject: ECHOES learning environment ✭✭✭
I'm integrating an Ice server with an external event loop. Here's the pseudocode for my main loop (actually in the run method of an Ice::Application subclass):
Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter ("talker");
Ice::Identity id = communicator()->stringToIdentity ("talker");
TalkerI talkerI = new TalkerI();
adapter->add (talkerI, id);

while (adapter is not deactivated) {
    // Process external events, with timeout
}

If I wanted, I could run my main event loop in a separate thread, waitForShutdown() in my main method, and set a flag to break the event loop that way. For the moment, though, I'm running the loop on the main thread as described above, and it's working pretty well, with one biggish hack.

The problem is, there seems to be no neat way of finding out whether an adapter has been deactivated. There is a private "checkForDeactivation()" method in ObjectAdapterI.cpp that throws an exception if the adapter is deactivated, but that can't be called externally. What I'm doing right now is the following (inside a while(true) loop):
try {
    adapter->getCommunicator();
} catch (const Ice::ObjectAdapterDeactivateException&) {
    break;
}

Is there a neater way to do this? Is there any possibility that checkForDeactivation() could be made public? Or am I just going about things backwards (entirely possible!)?

Thanks,

MEF

Comments

  • bernardbernard Jupiter, FLAdministrators, ZeroC Staff Bernard NormierOrganization: ZeroC, Inc.Project: Ice ZeroC Staff
    Hi Mary,

    Ice has no checkForDeactivation() or tryWaitForDeactivate(): you can only wait synchronously for such event.

    However, I don't see why that's an issue. After all, you control when your adapter is deactivated either explicitely or indirectly through a communicator shutdown. You can easily insert an "adapter going down" notification wherever your application calls communicator->shutdown(), communicator->destroy() or adapter->deactivate().

    Cheers,
    Bernard
  • mefostermefoster Member Mary Ellen FosterOrganization: Heriot-Watt University, EdinburghProject: ECHOES learning environment ✭✭✭
    Heh ... returning to this thread two months later. :) Sorry about that, got sidetracked into other stuff.

    The reason I can't just piggyback on communicator->shutdown() and similar methods is that this server is started and stopped through IceGrid, so I never explicitly call those methods myself internally. So what I'd basically like to do is run my loop until I'm disconnected from outside, and as I said, the only way I've found to detect "I'm disconnected from outside" is the hacky try-catch method I described above.

    There's no possibility that "checkForDeactivation()" could be made public? It would make things neater ... but at least I've got my workaround now, so it's not a big deal.

    MEF
  • michimichi Member Michi HenningOrganization: Triodia TechnologiesProject: I have a passing interest in Ice :-) ✭✭✭
    mefoster wrote:
    [...] the only way I've found to detect "I'm disconnected from outside" is the hacky try-catch method I described above.

    There's no possibility that "checkForDeactivation()" could be made public.

    I'm not sure that would help. If we were to make checkForDeactivation() public, what would that achieve? Suppose, in your loop, you call checkForDeactivation(), which returns false. Then, when you attempt to use the adapter, you might still get an exception because, in between the test and the attempt to use the adapter, it might have been deactivated.

    I guess your problem is that you simply want to terminate the loop once the adapter is deactivated, but you don't need to actually use the adapter in the body of the loop?

    Cheers,

    Michi.
  • mefostermefoster Member Mary Ellen FosterOrganization: Heriot-Watt University, EdinburghProject: ECHOES learning environment ✭✭✭
    michi wrote:
    I guess your problem is that you simply want to terminate the loop once the adapter is deactivated, but you don't need to actually use the adapter in the body of the loop?

    Yes, that's exactly it. The loop is just a standard GUI event loop, and I want to make sure that it gets terminated when the adapter gets disconnected. Is there any other way to accomplish this? Maybe adding some sort of shutdown hook?

    MEF
  • bernardbernard Jupiter, FLAdministrators, ZeroC Staff Bernard NormierOrganization: ZeroC, Inc.Project: Ice ZeroC Staff
    Another possibility would be to register a "dummy" servant locator with your OA.

    Ice will call deactivate() on this servant locator (that you implement) when the OA is deactivated.

    Cheers,
    Bernard
  • mefostermefoster Member Mary Ellen FosterOrganization: Heriot-Watt University, EdinburghProject: ECHOES learning environment ✭✭✭
    Another possibility would be to register a "dummy" servant locator with your OA.

    Ice will call deactivate() on this servant locator (that you implement) when the OA is deactivated.

    I finally tried this. It doesn't seem to do what I want; the deactivate() doesn't seem to get called until the point where I'm actually exiting, not when I stop the server through IceGrid.

    Here's some code to make it clearer; this is an excerpt from the run() method of an Ice::Application:
        jast::common::DummyServantLocator *sl = new jast::common::DummyServantLocator();
    	
        TalkerI *talkerI = new TalkerI( talkerDML );
        adapter->add(talkerI, id);
        adapter->addServantLocator (sl, "");
        adapter->activate();
        
        while (!(sl->isDone())) {
            try {
                adapter->getCommunicator();
        	} catch (const Ice::ObjectAdapterDeactivatedException&) {
                cerr << "Deactivated!!" << endl;
                break;
            }
            // Call the external event loop
            talkerDML->vRun(Poll_e, 100);
        }
    	
        cerr << "Talker server exiting!" << endl;
        return EXIT_SUCCESS;
    

    Here's a bit of DummyServantLocator:
    void jast::common::DummyServantLocator::deactivate (const std::string& category) {
    	std::cerr << "Dummy servant locator deactivated!" << std::endl;
    	deactivated = true;
    }
    
    bool jast::common::DummyServantLocator::isDone() {
    	return deactivated;
    }
    

    If I don't put in the try-catch, the loop never breaks at all when I stop the server through IceGrid. If I do put it in, the sequence of outputs printed when I stop through IceGrid is:
    Deactivated!!
    Talker server exiting!
    Dummy servant locator deactivated!

    Of course, there may be threading issues or something going on, but it looks to me like this means ServantLocator.deactivate() doesn't get called until after I return from run(). Would it help if I stopped using Ice::Application?

    Thanks for your help,

    MEF
  • benoitbenoit Rennes, FranceAdministrators, ZeroC Staff Benoit FoucherOrganization: ZeroC, Inc.Project: Ice ZeroC Staff
    Hi,

    You're right -- the dummy servant locator approach won't work because the servant locator isn't deactivated when the communicator shutdown or the adapter deactivation is initiated (either with Ice::Communicator::shutdown() or Ice::ObjectAdapter::deactivate()). Servant locators are deactivated when the communicator is destroyed or by the thread that calls waitForDeactivate() on the object adapter.

    Right now, to solve your poblem, I think the simplest would be to start a separate thread that just calls the communicator waitForShutdown() method. When waitForShutdown() returns, the thread would set a flag and terminate. Your event loop in the main thread would check for this flag.

    We have been discussing the addition of a method to check the state of the adapter, this will most likely be added in future Ice releases!

    Cheers,
    Benoit.
  • mefostermefoster Member Mary Ellen FosterOrganization: Heriot-Watt University, EdinburghProject: ECHOES learning environment ✭✭✭
    benoit wrote:
    Right now, to solve your poblem, I think the simplest would be to start a separate thread that just calls the communicator waitForShutdown() method. When waitForShutdown() returns, the thread would set a flag and terminate. Your event loop in the main thread would check for this flag.

    Thanks, that works well. I think that was what I had originally tried, but then I decided to see if I could avoid threads. But it does seem to be the most elegant solution.

    MEF
Sign In or Register to comment.