diff options
author | Matthew Newhook <matthew@zeroc.com> | 2006-12-22 18:52:53 +0000 |
---|---|---|
committer | Matthew Newhook <matthew@zeroc.com> | 2006-12-22 18:52:53 +0000 |
commit | 84d9f5c369fceccfa16401ed50783ed2ad209559 (patch) | |
tree | 689d30c8707629f1db8155edadb47ce1bce363ad | |
parent | Added autoflushing of batches (diff) | |
download | ice-84d9f5c369fceccfa16401ed50783ed2ad209559.tar.bz2 ice-84d9f5c369fceccfa16401ed50783ed2ad209559.tar.xz ice-84d9f5c369fceccfa16401ed50783ed2ad209559.zip |
http://bugzilla.zeroc.com/bugzilla/show_bug.cgi?id=1391.
38 files changed, 1394 insertions, 328 deletions
diff --git a/cpp/demo/Freeze/bench/Client.cpp b/cpp/demo/Freeze/bench/Client.cpp index e0e70dac728..e0aaab24e2a 100644 --- a/cpp/demo/Freeze/bench/Client.cpp +++ b/cpp/demo/Freeze/bench/Client.cpp @@ -144,6 +144,7 @@ public: TestApp(const string&); virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -717,6 +718,12 @@ typedef IceUtil::Handle<MyFactory> MyFactoryPtr; int TestApp::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + _connection = Freeze::createConnection(communicator(), _envName); cout << "IntIntMap" << endl; @@ -810,6 +817,12 @@ TestApp::run(int argc, char* argv[]) return EXIT_SUCCESS; } +void +TestApp::interruptCallback(int) +{ + exit(EXIT_SUCCESS); +} + int main(int argc, char* argv[]) { diff --git a/cpp/demo/Freeze/library/Client.cpp b/cpp/demo/Freeze/library/Client.cpp index dab9aaa2607..f43eeedf738 100644 --- a/cpp/demo/Freeze/library/Client.cpp +++ b/cpp/demo/Freeze/library/Client.cpp @@ -15,6 +15,7 @@ using namespace std; class LibraryClient : public Ice::Application { virtual int run(int argc, char* argv[]); + virtual void interruptCallback(int); }; int @@ -27,6 +28,30 @@ main(int argc, char* argv[]) int LibraryClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + int runParser(int, char*[], const Ice::CommunicatorPtr&); return runParser(argc, argv, communicator()); } + +void +LibraryClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/Freeze/library/Collocated.cpp b/cpp/demo/Freeze/library/Collocated.cpp index 4283dce2ef8..2d6fceb20e2 100644 --- a/cpp/demo/Freeze/library/Collocated.cpp +++ b/cpp/demo/Freeze/library/Collocated.cpp @@ -24,6 +24,7 @@ public: } virtual int run(int argc, char* argv[]); + virtual void interruptCallback(int); private: @@ -40,6 +41,12 @@ main(int argc, char* argv[]) int LibraryCollocated::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + Ice::PropertiesPtr properties = communicator()->getProperties(); // @@ -84,3 +91,21 @@ LibraryCollocated::run(int argc, char* argv[]) return status; } + +void +LibraryCollocated::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/Freeze/phonebook/Client.cpp b/cpp/demo/Freeze/phonebook/Client.cpp index 625041380a5..2478d5f7429 100644 --- a/cpp/demo/Freeze/phonebook/Client.cpp +++ b/cpp/demo/Freeze/phonebook/Client.cpp @@ -11,9 +11,11 @@ using namespace std; + class PhoneBookClient : public Ice::Application { virtual int run(int argc, char* argv[]); + virtual void interruptCallback(int); }; int @@ -26,6 +28,30 @@ main(int argc, char* argv[]) int PhoneBookClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + int runParser(int, char*[], const Ice::CommunicatorPtr&); return runParser(argc, argv, communicator()); } + +void +PhoneBookClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/Freeze/phonebook/Collocated.cpp b/cpp/demo/Freeze/phonebook/Collocated.cpp index cb213a9da87..e979700f651 100644 --- a/cpp/demo/Freeze/phonebook/Collocated.cpp +++ b/cpp/demo/Freeze/phonebook/Collocated.cpp @@ -24,6 +24,7 @@ public: } virtual int run(int argc, char* argv[]); + virtual void interruptCallback(int); private: @@ -40,6 +41,12 @@ main(int argc, char* argv[]) int PhoneBookCollocated::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + Ice::PropertiesPtr properties = communicator()->getProperties(); // @@ -101,3 +108,21 @@ PhoneBookCollocated::run(int argc, char* argv[]) return status; } + +void +PhoneBookCollocated::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/Glacier2/callback/Client.cpp b/cpp/demo/Glacier2/callback/Client.cpp index 42e32317fe1..54a391b24ef 100644 --- a/cpp/demo/Glacier2/callback/Client.cpp +++ b/cpp/demo/Glacier2/callback/Client.cpp @@ -19,6 +19,7 @@ class CallbackClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); }; int @@ -47,6 +48,12 @@ menu() int CallbackClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter(); if(!defaultRouter) { @@ -208,3 +215,21 @@ CallbackClient::run(int argc, char* argv[]) return EXIT_SUCCESS; } + +void +CallbackClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/Glacier2/chat/Client.cpp b/cpp/demo/Glacier2/chat/Client.cpp index 59cedc50e6b..5c4c8dccb05 100755 --- a/cpp/demo/Glacier2/chat/Client.cpp +++ b/cpp/demo/Glacier2/chat/Client.cpp @@ -93,16 +93,23 @@ public: virtual int run(int argc, char* argv[]) { - Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter(); - if(!defaultRouter) - { - cerr << argv[0] << ": no default router set" << endl; - return EXIT_FAILURE; - } + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); - Glacier2::RouterPrx router = Glacier2::RouterPrx::checkedCast(defaultRouter); { - if(!router) + IceUtil::Mutex::Lock sync(_mutex); + Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter(); + if(!defaultRouter) + { + cerr << argv[0] << ": no default router set" << endl; + return EXIT_FAILURE; + } + + _router = Glacier2::RouterPrx::checkedCast(defaultRouter); + if(!_router) { cerr << argv[0] << ": configured router is not a Glacier2 router" << endl; return EXIT_FAILURE; @@ -126,7 +133,7 @@ public: try { - session = ChatSessionPrx::uncheckedCast(router->createSession(id, pw)); + session = ChatSessionPrx::uncheckedCast(_router->createSession(id, pw)); break; } catch(const Glacier2::PermissionDeniedException& ex) @@ -135,12 +142,15 @@ public: } } - SessionPingThreadPtr ping = new SessionPingThread(session, (long)router->getSessionTimeout() / 2); - ping->start(); + { + IceUtil::Mutex::Lock sync(_mutex); + _ping = new SessionPingThread(session, (long)_router->getSessionTimeout() / 2); + _ping->start(); + } Ice::Identity callbackReceiverIdent; callbackReceiverIdent.name = "callbackReceiver"; - callbackReceiverIdent.category = router->getCategoryForClient(); + callbackReceiverIdent.category = _router->getCategoryForClient(); Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("Chat.Client"); ChatCallbackPrx callback = ChatCallbackPrx::uncheckedCast( @@ -177,9 +187,47 @@ public: } while(cin.good()); + cleanup(); + } + catch(const Ice::Exception& ex) + { + cerr << ex << endl; + cleanup(); + + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } + + virtual void + interruptCallback(int) + { + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); + } + +private: + + void + cleanup() + { + IceUtil::Mutex::Lock sync(_mutex); + if(_router) + { try { - router->destroySession(); + _router->destroySession(); } catch(const Ice::ConnectionLostException&) { @@ -187,25 +235,16 @@ public: // Expected: the router closed the connection. // } + _router = 0; } - catch(const Ice::Exception& ex) + if(_ping) { - cerr << ex << endl; - - ping->destroy(); - ping->getThreadControl().join(); - - return EXIT_FAILURE; + _ping->destroy(); + _ping->getThreadControl().join(); + _ping = 0; } - - ping->destroy(); - ping->getThreadControl().join(); - - return EXIT_SUCCESS; } -private: - void menu() { @@ -223,6 +262,10 @@ private: } return s; } + + IceUtil::Mutex _mutex; + Glacier2::RouterPrx _router; + SessionPingThreadPtr _ping; }; int diff --git a/cpp/demo/Ice/callback/Client.cpp b/cpp/demo/Ice/callback/Client.cpp index 8a6b237b415..0f40c0371a1 100644 --- a/cpp/demo/Ice/callback/Client.cpp +++ b/cpp/demo/Ice/callback/Client.cpp @@ -28,6 +28,7 @@ class CallbackClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -44,6 +45,12 @@ main(int argc, char* argv[]) int CallbackClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + CallbackSenderPrx twoway = CallbackSenderPrx::checkedCast( communicator()->propertyToProxy("Callback.Client.CallbackServer")-> ice_twoway()->ice_timeout(-1)->ice_secure(false)); @@ -169,6 +176,24 @@ CallbackClient::run(int argc, char* argv[]) } void +CallbackClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void CallbackClient::menu() { cout << diff --git a/cpp/demo/Ice/converter/Client.cpp b/cpp/demo/Ice/converter/Client.cpp index 8864838bf69..e833dbc3b48 100644 --- a/cpp/demo/Ice/converter/Client.cpp +++ b/cpp/demo/Ice/converter/Client.cpp @@ -113,7 +113,10 @@ main(int argc, char* argv[]) initData.properties->load("config.client"); communicator1 = Ice::initialize(argc, argv, initData); - communicator2 = Ice::initialize(argc, argv); + Ice::InitializationData initData2; + initData2.properties = Ice::createProperties(); + initData2.properties->load("config.client"); + communicator2 = Ice::initialize(argc, argv, initData2); status = run(argc, argv, communicator1, communicator2); } diff --git a/cpp/demo/Ice/hello/Client.cpp b/cpp/demo/Ice/hello/Client.cpp index 3aca8c3d934..f2de173ada6 100644 --- a/cpp/demo/Ice/hello/Client.cpp +++ b/cpp/demo/Ice/hello/Client.cpp @@ -18,6 +18,7 @@ class HelloClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -34,6 +35,12 @@ main(int argc, char* argv[]) int HelloClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + HelloPrx twoway = HelloPrx::checkedCast( communicator()->propertyToProxy("Hello.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false)); if(!twoway) @@ -189,6 +196,24 @@ HelloClient::run(int argc, char* argv[]) } void +HelloClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void HelloClient::menu() { cout << diff --git a/cpp/demo/Ice/invoke/Client.cpp b/cpp/demo/Ice/invoke/Client.cpp index 3a687a5e29f..0bfe715f5d1 100644 --- a/cpp/demo/Ice/invoke/Client.cpp +++ b/cpp/demo/Ice/invoke/Client.cpp @@ -18,6 +18,7 @@ class InvokeClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -52,6 +53,12 @@ operator<<(ostream& out, Demo::Color c) int InvokeClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + Ice::ObjectPrx obj = communicator()->propertyToProxy("Printer.Proxy"); menu(); @@ -293,6 +300,24 @@ InvokeClient::run(int argc, char* argv[]) } void +InvokeClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void InvokeClient::menu() { cout << diff --git a/cpp/demo/Ice/nested/Client.cpp b/cpp/demo/Ice/nested/Client.cpp index 53d9ae26547..bc10109a1fe 100644 --- a/cpp/demo/Ice/nested/Client.cpp +++ b/cpp/demo/Ice/nested/Client.cpp @@ -13,11 +13,13 @@ using namespace std; using namespace Demo; + class NestedClient : public Ice::Application { public: virtual int run(int, char*[]); + virtual void interruptCallback(int); }; int @@ -30,6 +32,12 @@ main(int argc, char* argv[]) int NestedClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + NestedPrx nested = NestedPrx::checkedCast(communicator()->propertyToProxy("Nested.Client.NestedServer")); if(!nested) { @@ -70,3 +78,27 @@ NestedClient::run(int argc, char* argv[]) return EXIT_SUCCESS; } + +void +NestedClient::interruptCallback(int) +{ +/* + * For this demo we won't destroy the communicator since it has to + * wait for any outstanding invocations to complete which may take + * some time if the nesting level is exceeded. + * + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } +*/ + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/Ice/session/Client.cpp b/cpp/demo/Ice/session/Client.cpp index fc78b4dee0c..e0be25f7d61 100755 --- a/cpp/demo/Ice/session/Client.cpp +++ b/cpp/demo/Ice/session/Client.cpp @@ -72,10 +72,20 @@ class SessionClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: void menu(); + void cleanup(bool); + + // + // The interrupt callback and main can run concurrently with one + // another so shared variables must be mutex protected. + // + IceUtil::Mutex _mutex; + SessionRefreshThreadPtr _refresh; + SessionPrx _session; }; int @@ -88,6 +98,12 @@ main(int argc, char* argv[]) int SessionClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + string name; cout << "Please enter your name ==> "; cin >> name; @@ -104,11 +120,14 @@ SessionClient::run(int argc, char* argv[]) return EXIT_FAILURE; } - SessionPrx session = factory->create(name); - - SessionRefreshThreadPtr refresh = new SessionRefreshThread( - communicator()->getLogger(), IceUtil::Time::seconds(5), session); - refresh->start(); + { + IceUtil::Mutex::Lock sync(_mutex); + _session = factory->create(name); + + _refresh = new SessionRefreshThread( + communicator()->getLogger(), IceUtil::Time::seconds(5), _session); + _refresh->start(); + } vector<HelloPrx> hellos; @@ -144,7 +163,7 @@ SessionClient::run(int argc, char* argv[]) } else if(c == 'c') { - hellos.push_back(session->createHello()); + hellos.push_back(_session->createHello()); cout << "Created hello object " << hellos.size() - 1 << endl; } else if(c == 's') @@ -179,14 +198,7 @@ SessionClient::run(int argc, char* argv[]) // is set to 0 so that if session->destroy() raises an exception // the thread will not be re-terminated and re-joined. // - refresh->terminate(); - refresh->getThreadControl().join(); - refresh = 0; - - if(destroy) - { - session->destroy(); - } + cleanup(destroy); if(shutdown) { factory->shutdown(); @@ -194,14 +206,12 @@ SessionClient::run(int argc, char* argv[]) } catch(...) { - // - // The refresher thread must be terminated in the event of a - // failure. - // - if(refresh) + try + { + cleanup(true); + } + catch(...) { - refresh->terminate(); - refresh->getThreadControl().join(); } throw; } @@ -210,6 +220,50 @@ SessionClient::run(int argc, char* argv[]) } void +SessionClient::interruptCallback(int) +{ + // + // Terminate the refresh thread, destroy the session and then + // destroy the communicator, followed by an exit. We have to call + // exit because main may be blocked in a cin >> s call which + // cannot be interrupted portably. + // + cleanup(true); + + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void +SessionClient::cleanup(bool destroy) +{ + IceUtil::Mutex::Lock sync(_mutex); + if(_refresh) + { + _refresh->terminate(); + _refresh->getThreadControl().join(); + _refresh = 0; + } + + if(destroy && _session) + { + _session->destroy(); + _session = 0; + } +} + +void SessionClient::menu() { cout << diff --git a/cpp/demo/Ice/throughput/Client.cpp b/cpp/demo/Ice/throughput/Client.cpp index 03bfd13aeec..a2c00c008a3 100644 --- a/cpp/demo/Ice/throughput/Client.cpp +++ b/cpp/demo/Ice/throughput/Client.cpp @@ -20,6 +20,7 @@ class ThroughputClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -36,6 +37,12 @@ main(int argc, char* argv[]) int ThroughputClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + Ice::ObjectPrx base = communicator()->propertyToProxy("Throughput.Throughput"); ThroughputPrx throughput = ThroughputPrx::checkedCast(base); if(!throughput) @@ -378,6 +385,24 @@ ThroughputClient::run(int argc, char* argv[]) } void +ThroughputClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void ThroughputClient::menu() { cout << diff --git a/cpp/demo/Ice/value/Client.cpp b/cpp/demo/Ice/value/Client.cpp index a375da519de..de4885f7f79 100644 --- a/cpp/demo/Ice/value/Client.cpp +++ b/cpp/demo/Ice/value/Client.cpp @@ -19,6 +19,7 @@ class ValueClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); }; int @@ -31,6 +32,12 @@ main(int argc, char* argv[]) int ValueClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + Ice::ObjectPrx base = communicator()->propertyToProxy("Value.Initial"); InitialPrx initial = InitialPrx::checkedCast(base); if(!initial) @@ -174,3 +181,21 @@ ValueClient::run(int argc, char* argv[]) return EXIT_SUCCESS; } + +void +ValueClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/IceBox/hello/Client.cpp b/cpp/demo/IceBox/hello/Client.cpp index 17764a6a845..830f24aa7ef 100644 --- a/cpp/demo/IceBox/hello/Client.cpp +++ b/cpp/demo/IceBox/hello/Client.cpp @@ -18,6 +18,7 @@ class HelloClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -50,6 +51,12 @@ HelloClient::menu() int HelloClient::run(int argc, char* argv[]) { + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + HelloPrx twoway = HelloPrx::checkedCast( communicator()->propertyToProxy("Hello.Proxy")->ice_twoway()->ice_timeout(-1)->ice_secure(false)); if(!twoway) @@ -153,3 +160,21 @@ HelloClient::run(int argc, char* argv[]) return EXIT_SUCCESS; } + +void +HelloClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/demo/IceGrid/allocate/Client.cpp b/cpp/demo/IceGrid/allocate/Client.cpp index b4df84f00c9..79b21842dfd 100644 --- a/cpp/demo/IceGrid/allocate/Client.cpp +++ b/cpp/demo/IceGrid/allocate/Client.cpp @@ -57,7 +57,7 @@ public: private: - IceGrid::SessionPrx _session; + const IceGrid::SessionPrx _session; const IceUtil::Time _timeout; bool _destroy; }; @@ -69,11 +69,17 @@ class HelloClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: + void cleanup(); void menu(); string trim(const string&); + + IceUtil::Mutex _mutex; + IceGrid::SessionPrx _session; + SessionKeepAliveThreadPtr _keepAlive; }; int @@ -83,43 +89,25 @@ main(int argc, char* argv[]) return app.main(argc, argv, "config.client"); } -void -HelloClient::menu() -{ - cout << - "usage:\n" - "t: send greeting\n" - "s: shutdown server\n" - "x: exit\n" - "?: help\n"; -} - -string -HelloClient::trim(const string& s) -{ - static const string delims = "\t\r\n "; - string::size_type last = s.find_last_not_of(delims); - if(last != string::npos) - { - return s.substr(s.find_first_not_of(delims), last+1); - } - return s; -} - int HelloClient::run(int argc, char* argv[]) { int status = EXIT_SUCCESS; - IceGrid::RegistryPrx registry = - IceGrid::RegistryPrx::checkedCast(communicator()->stringToProxy("DemoIceGrid/Registry")); + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + + IceGrid::RegistryPrx registry = IceGrid::RegistryPrx::checkedCast( + communicator()->stringToProxy("DemoIceGrid/Registry")); if(!registry) { cerr << argv[0] << ": could not contact registry" << endl; return EXIT_FAILURE; } - IceGrid::SessionPrx session; while(true) { cout << "This demo accepts any user-id / password combination.\n"; @@ -136,7 +124,8 @@ HelloClient::run(int argc, char* argv[]) try { - session = registry->createSession(id, password); + IceUtil::Mutex::Lock sync(_mutex); + _session = registry->createSession(id, password); break; } catch(const IceGrid::PermissionDeniedException& ex) @@ -145,8 +134,11 @@ HelloClient::run(int argc, char* argv[]) } } - SessionKeepAliveThreadPtr keepAlive = new SessionKeepAliveThread(session, registry->getSessionTimeout() / 2); - keepAlive->start(); + { + IceUtil::Mutex::Lock sync(_mutex); + _keepAlive = new SessionKeepAliveThread(_session, registry->getSessionTimeout() / 2); + _keepAlive->start(); + } try { @@ -159,11 +151,11 @@ HelloClient::run(int argc, char* argv[]) HelloPrx hello; try { - hello = HelloPrx::checkedCast(session->allocateObjectById(communicator()->stringToIdentity("hello"))); + hello = HelloPrx::checkedCast(_session->allocateObjectById(communicator()->stringToIdentity("hello"))); } catch(const IceGrid::ObjectNotRegisteredException&) { - hello = HelloPrx::checkedCast(session->allocateObjectByType("::Demo::Hello")); + hello = HelloPrx::checkedCast(_session->allocateObjectByType("::Demo::Hello")); } menu(); @@ -215,14 +207,71 @@ HelloClient::run(int argc, char* argv[]) status = EXIT_FAILURE; } + cleanup(); + return status; +} + +void +HelloClient::interruptCallback(int) +{ + cleanup(); + + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void +HelloClient::cleanup() +{ + IceUtil::Mutex::Lock sync(_mutex); // // Destroy the keepAlive thread and the sesion object otherwise // the session will be kept allocated until the timeout occurs. // Destroying the session will release all allocated objects. // - keepAlive->destroy(); - keepAlive->getThreadControl().join(); - session->destroy(); + if(_keepAlive) + { + _keepAlive->destroy(); + _keepAlive->getThreadControl().join(); + _keepAlive = 0; + } + if(_session) + { + _session->destroy(); + _session = 0; + } +} - return status; +void +HelloClient::menu() +{ + cout << + "usage:\n" + "t: send greeting\n" + "s: shutdown server\n" + "x: exit\n" + "?: help\n"; +} + +string +HelloClient::trim(const string& s) +{ + static const string delims = "\t\r\n "; + string::size_type last = s.find_last_not_of(delims); + if(last != string::npos) + { + return s.substr(s.find_first_not_of(delims), last+1); + } + return s; } diff --git a/cpp/demo/IceGrid/sessionActivation/Client.cpp b/cpp/demo/IceGrid/sessionActivation/Client.cpp index d8fc48e65dc..b4e9f719f53 100644 --- a/cpp/demo/IceGrid/sessionActivation/Client.cpp +++ b/cpp/demo/IceGrid/sessionActivation/Client.cpp @@ -69,11 +69,17 @@ class HelloClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: + void cleanup(); void menu(); string trim(const string&); + + IceUtil::Mutex _mutex; + IceGrid::SessionPrx _session; + SessionKeepAliveThreadPtr _keepAlive; }; int @@ -83,32 +89,17 @@ main(int argc, char* argv[]) return app.main(argc, argv, "config.client"); } -void -HelloClient::menu() -{ - cout << - "usage:\n" - "t: send greeting\n" - "x: exit\n" - "?: help\n"; -} - -string -HelloClient::trim(const string& s) -{ - static const string delims = "\t\r\n "; - string::size_type last = s.find_last_not_of(delims); - if(last != string::npos) - { - return s.substr(s.find_first_not_of(delims), last+1); - } - return s; -} - int HelloClient::run(int argc, char* argv[]) { int status = EXIT_SUCCESS; + + // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + IceGrid::RegistryPrx registry = IceGrid::RegistryPrx::checkedCast(communicator()->stringToProxy("DemoIceGrid/Registry")); if(!registry) @@ -117,7 +108,6 @@ HelloClient::run(int argc, char* argv[]) return EXIT_FAILURE; } - IceGrid::SessionPrx session; while(true) { cout << "This demo accepts any user-id / password combination.\n"; @@ -134,7 +124,8 @@ HelloClient::run(int argc, char* argv[]) try { - session = registry->createSession(id, password); + IceUtil::Mutex::Lock sync(_mutex); + _session = registry->createSession(id, password); break; } catch(const IceGrid::PermissionDeniedException& ex) @@ -143,12 +134,15 @@ HelloClient::run(int argc, char* argv[]) } } - SessionKeepAliveThreadPtr keepAlive = new SessionKeepAliveThread(session, registry->getSessionTimeout() / 2); - keepAlive->start(); + { + IceUtil::Mutex::Lock sync(_mutex); + _keepAlive = new SessionKeepAliveThread(_session, registry->getSessionTimeout() / 2); + _keepAlive->start(); + } try { - HelloPrx hello = HelloPrx::checkedCast(session->allocateObjectById(communicator()->stringToIdentity("hello"))); + HelloPrx hello = HelloPrx::checkedCast(_session->allocateObjectById(communicator()->stringToIdentity("hello"))); menu(); @@ -205,15 +199,72 @@ HelloClient::run(int argc, char* argv[]) status = EXIT_FAILURE; } + cleanup(); + + return status; +} + +void +HelloClient::interruptCallback(int) +{ + cleanup(); + + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} + +void +HelloClient::cleanup() +{ + IceUtil::Mutex::Lock sync(_mutex); // // Destroy the keepAlive thread and the sesion object otherwise // the session will be kept allocated until the timeout occurs. // Destroying the session will release all allocated objects. // - keepAlive->destroy(); - keepAlive->getThreadControl().join(); - session->destroy(); + if(_keepAlive) + { + _keepAlive->destroy(); + _keepAlive->getThreadControl().join(); + _keepAlive = 0; + } + if(_session) + { + _session->destroy(); + _session = 0; + } +} - return status; +void +HelloClient::menu() +{ + cout << + "usage:\n" + "t: send greeting\n" + "x: exit\n" + "?: help\n"; +} + +string +HelloClient::trim(const string& s) +{ + static const string delims = "\t\r\n "; + string::size_type last = s.find_last_not_of(delims); + if(last != string::npos) + { + return s.substr(s.find_first_not_of(delims), last+1); + } + return s; } diff --git a/cpp/demo/IceGrid/simple/Client.cpp b/cpp/demo/IceGrid/simple/Client.cpp index 13259587dfb..bf86e3ee294 100644 --- a/cpp/demo/IceGrid/simple/Client.cpp +++ b/cpp/demo/IceGrid/simple/Client.cpp @@ -19,6 +19,7 @@ class HelloClient : public Ice::Application public: virtual int run(int, char*[]); + virtual void interruptCallback(int); private: @@ -47,6 +48,12 @@ int HelloClient::run(int argc, char* argv[]) { // + // Since this is an interactive demo we want the custom interrupt + // callback to be called when the process is interrupted. + // + userCallbackOnInterrupt(); + + // // First we try to connect to the object with the `hello' // identity. If it's not registered with the registry, we // search for an object with the ::Demo::Hello type. @@ -108,3 +115,20 @@ HelloClient::run(int argc, char* argv[]) return EXIT_SUCCESS; } +void +HelloClient::interruptCallback(int) +{ + try + { + communicator()->destroy(); + } + catch(const IceUtil::Exception& ex) + { + cerr << appName() << ": " << ex << endl; + } + catch(...) + { + cerr << appName() << ": unknown exception" << endl; + } + exit(EXIT_SUCCESS); +} diff --git a/cpp/include/Ice/Application.h b/cpp/include/Ice/Application.h index ca3cd658188..4f2c27300e0 100644 --- a/cpp/include/Ice/Application.h +++ b/cpp/include/Ice/Application.h @@ -38,6 +38,16 @@ public: virtual int run(int, char*[]) = 0; // + // Override this to provide a custom application interrupt + // hook. You must call userCallbackOnInterrupt for this method to + // be called. Note that the interruptCallback can be called + // concurrently with any other thread (including main) in your + // application and thus must take appropriate concurrency + // precautions. + // + virtual void interruptCallback(int); + + // // Return the application name, i.e., argv[0]. // static const char* appName(); @@ -58,6 +68,7 @@ public: static void destroyOnInterrupt(); static void shutdownOnInterrupt(); static void ignoreInterrupt(); + static void userCallbackOnInterrupt(); // // These methods can be used to temporarily block a signal and @@ -81,7 +92,6 @@ public: // static bool interrupted(); - #if defined(__SUNPRO_CC) // // Sun C++ 5.x does not like classes with no data members diff --git a/cpp/src/Ice/Application.cpp b/cpp/src/Ice/Application.cpp index 8bee23ebe60..dfc03f6949c 100644 --- a/cpp/src/Ice/Application.cpp +++ b/cpp/src/Ice/Application.cpp @@ -40,6 +40,7 @@ static CtrlCHandlerCallback _previousCallback = 0; // only the main thread and CtrlCHandler threads are running. // static const char* _appName = 0; +static Application* _application; static CommunicatorPtr _communicator; static CtrlCHandler* _ctrlCHandler = 0; static bool _nohup = false; @@ -62,7 +63,8 @@ const DWORD SIGHUP = CTRL_LOGOFF_EVENT; // CtrlCHandler callbacks. // -static void holdInterruptCallback(int signal) +static void +holdInterruptCallback(int signal) { CtrlCHandlerCallback callback = 0; { @@ -89,7 +91,8 @@ static void holdInterruptCallback(int signal) } } -static void destroyOnInterruptCallback(int signal) +static void +destroyOnInterruptCallback(int signal) { { StaticMutex::Lock lock(_mutex); @@ -151,7 +154,8 @@ static void destroyOnInterruptCallback(int signal) } -static void shutdownOnInterruptCallback(int signal) +static void +shutdownOnInterruptCallback(int signal) { { StaticMutex::Lock lock(_mutex); @@ -171,6 +175,7 @@ static void shutdownOnInterruptCallback(int signal) _interrupted = true; } + assert(_communicator != 0); try { _communicator->shutdown(); @@ -209,6 +214,65 @@ static void shutdownOnInterruptCallback(int signal) } +static void +userCallbackOnInterruptCallback(int signal) +{ + { + StaticMutex::Lock lock(_mutex); + if(_destroyed) + { + // + // Being destroyed by main thread + // + return; + } + if(_nohup && signal == SIGHUP) + { + return; + } + assert(!_callbackInProgress); + _callbackInProgress = true; + _interrupted = true; + } + + assert(_application != 0); + try + { + _application->interruptCallback(signal); + } + catch(const IceUtil::Exception& ex) + { + cerr << _appName << " (while interrupting in response to signal " << signal + << "): " << ex << endl; + } + catch(const std::exception& ex) + { + cerr << _appName << " (while interrupting in response to signal " << signal + << "): std::exception: " << ex.what() << endl; + } + catch(const std::string& msg) + { + cerr << _appName << " (while interrupting in response to signal " << signal + << "): " << msg << endl; + } + catch(const char * msg) + { + cerr << _appName << " (while interrupting in response to signal " << signal + << "): " << msg << endl; + } + catch(...) + { + cerr << _appName << " (while interrupting in response to signal " << signal + << "): unknown exception" << endl; + } + + { + StaticMutex::Lock lock(_mutex); + _callbackInProgress = false; + } + _condVar->signal(); +} + Ice::Application::Application() { @@ -319,6 +383,7 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat _interrupted = false; _appName = argv[0]; + _application = this; _communicator = initialize(argc, argv, initData); _destroyed = false; @@ -327,7 +392,6 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat // _nohup = (_communicator->getProperties()->getPropertyAsInt("Ice.Nohup") > 0); - // // The default is to destroy when a signal is received. // @@ -361,8 +425,9 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat } // - // 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. + // 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. // ignoreInterrupt(); @@ -380,10 +445,12 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat { _destroyed = true; // - // And _communicator != 0, meaning will be destroyed next, - // _destroyed = true also ensures that any remaining callback won't do anything + // And _communicator != 0, meaning will be destroyed + // next, _destroyed = true also ensures that any + // remaining callback won't do anything // } + _application = 0; } if(_communicator != 0) @@ -424,6 +491,11 @@ Ice::Application::main(int argc, char* argv[], const InitializationData& initDat return status; } +void +Ice::Application::interruptCallback(int) +{ +} + const char* Ice::Application::appName() { @@ -438,11 +510,10 @@ Ice::Application::communicator() void Ice::Application::destroyOnInterrupt() -{ +{ // // if _ctrlCHandler == 0, it's really a bug in the caller // - if(_ctrlCHandler != 0) { StaticMutex::Lock lock(_mutex); // we serialize all the interrupt-setting @@ -498,6 +569,25 @@ Ice::Application::ignoreInterrupt() } void +Ice::Application::userCallbackOnInterrupt() +{ + if(_ctrlCHandler != 0) + { + StaticMutex::Lock lock(_mutex); // we serialize all the interrupt-setting + if(_ctrlCHandler->getCallback() == holdInterruptCallback) + { + _released = true; + _ctrlCHandler->setCallback(userCallbackOnInterruptCallback); + _condVar->signal(); + } + else + { + _ctrlCHandler->setCallback(userCallbackOnInterruptCallback); + } + } +} + +void Ice::Application::holdInterrupt() { if(_ctrlCHandler != 0) diff --git a/java/demo/Freeze/library/Client.java b/java/demo/Freeze/library/Client.java index 3105354d443..67b6af17477 100644 --- a/java/demo/Freeze/library/Client.java +++ b/java/demo/Freeze/library/Client.java @@ -9,9 +9,32 @@ public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + return RunParser.runParser(appName(), args, communicator()); } diff --git a/java/demo/Freeze/library/Collocated.java b/java/demo/Freeze/library/Collocated.java index ec6beade155..8cb11e19a00 100644 --- a/java/demo/Freeze/library/Collocated.java +++ b/java/demo/Freeze/library/Collocated.java @@ -9,9 +9,32 @@ class LibraryCollocated extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + Ice.Properties properties = communicator().getProperties(); // diff --git a/java/demo/Freeze/phonebook/Client.java b/java/demo/Freeze/phonebook/Client.java index c4ec8377276..ede5856bcd4 100644 --- a/java/demo/Freeze/phonebook/Client.java +++ b/java/demo/Freeze/phonebook/Client.java @@ -9,9 +9,32 @@ public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + return RunParser.runParser(appName(), args, communicator()); } diff --git a/java/demo/Freeze/phonebook/Collocated.java b/java/demo/Freeze/phonebook/Collocated.java index 825da566780..a02ba0a96f4 100644 --- a/java/demo/Freeze/phonebook/Collocated.java +++ b/java/demo/Freeze/phonebook/Collocated.java @@ -9,9 +9,32 @@ class PhoneBookCollocated extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + Ice.Properties properties = communicator().getProperties(); // diff --git a/java/demo/Glacier2/callback/Client.java b/java/demo/Glacier2/callback/Client.java index b1e90ce021c..b86e111c1cf 100644 --- a/java/demo/Glacier2/callback/Client.java +++ b/java/demo/Glacier2/callback/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private static void menu() { @@ -30,6 +46,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + Ice.RouterPrx defaultRouter = communicator().getDefaultRouter(); if(defaultRouter == null) { diff --git a/java/demo/Ice/callback/Client.java b/java/demo/Ice/callback/Client.java index 35a91f8b6ac..f382f6cbf66 100644 --- a/java/demo/Ice/callback/Client.java +++ b/java/demo/Ice/callback/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private static void menu() { @@ -31,6 +47,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + CallbackSenderPrx twoway = CallbackSenderPrxHelper.checkedCast( communicator().propertyToProxy("Callback.Client.CallbackServer"). ice_twoway().ice_timeout(-1).ice_secure(false)); diff --git a/java/demo/Ice/hello/Client.java b/java/demo/Ice/hello/Client.java index df647df390e..67fd95e2d3e 100644 --- a/java/demo/Ice/hello/Client.java +++ b/java/demo/Ice/hello/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private static void menu() { @@ -33,6 +49,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + HelloPrx twoway = HelloPrxHelper.checkedCast( communicator().propertyToProxy("Hello.Proxy").ice_twoway().ice_timeout(-1).ice_secure(false)); if(twoway == null) @@ -206,3 +229,4 @@ public class Client extends Ice.Application System.exit(status); } } + diff --git a/java/demo/Ice/invoke/Client.java b/java/demo/Ice/invoke/Client.java index 0ba48171d1c..1275ecaad12 100644 --- a/java/demo/Ice/invoke/Client.java +++ b/java/demo/Ice/invoke/Client.java @@ -30,9 +30,32 @@ public class Client extends Ice.Application "?: help\n"); } + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + Ice.ObjectPrx obj = communicator().propertyToProxy("Printer.Proxy"); menu(); diff --git a/java/demo/Ice/nested/Client.java b/java/demo/Ice/nested/Client.java index b16a183b257..60264585c7e 100644 --- a/java/demo/Ice/nested/Client.java +++ b/java/demo/Ice/nested/Client.java @@ -11,10 +11,40 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + /* + * For this demo we won't destroy the communicator since it has to + * wait for any outstanding invocations to complete which may take + * some time if the nesting level is exceeded. + * + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + */ + } + } + public int run(String[] args) { - NestedPrx nested = NestedPrxHelper.checkedCast(communicator().propertyToProxy("Nested.Client.NestedServer")); + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + + NestedPrx nested = NestedPrxHelper.checkedCast( + communicator().propertyToProxy("Nested.Client.NestedServer")); if(nested == null) { System.err.println("invalid proxy"); diff --git a/java/demo/Ice/session/Client.java b/java/demo/Ice/session/Client.java index 5b5a0be67a1..0009a2fefec 100644 --- a/java/demo/Ice/session/Client.java +++ b/java/demo/Ice/session/Client.java @@ -11,6 +11,24 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + System.out.println("Hi"); + cleanup(true); + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + static private class SessionRefreshThread extends Thread { SessionRefreshThread(Ice.Logger logger, long timeout, SessionPrx session) @@ -76,6 +94,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); String name; try @@ -102,15 +127,17 @@ public class Client extends Ice.Application return 1; } - SessionPrx session = factory.create(name); - SessionRefreshThread refresh = new SessionRefreshThread(communicator().getLogger(), 5000, session); - refresh.start(); - + synchronized(this) + { + _session = factory.create(name); + _refresh = new SessionRefreshThread(communicator().getLogger(), 5000, _session); + _refresh.start(); + } + java.util.ArrayList hellos = new java.util.ArrayList(); menu(); - try { boolean destroy = true; @@ -149,7 +176,7 @@ public class Client extends Ice.Application } else if(line.equals("c")) { - hellos.add(session.createHello()); + hellos.add(_session.createHello()); System.out.println("created hello object " + (hellos.size()-1)); } else if(line.equals("s")) @@ -177,26 +204,8 @@ public class Client extends Ice.Application menu(); } } - // - // The refresher thread must be terminated before destroy is - // called, otherwise it might get ObjectNotExistException. refresh - // is set to 0 so that if session->destroy() raises an exception - // the thread will not be re-terminated and re-joined. - // - refresh.terminate(); - try - { - refresh.join(); - } - catch(InterruptedException e) - { - } - refresh = null; - if(destroy) - { - session.destroy(); - } + cleanup(destroy); if(shutdown) { factory.shutdown(); @@ -212,22 +221,39 @@ public class Client extends Ice.Application } finally { - if(refresh != null) - { - refresh.terminate(); - try - { - refresh.join(); - } - catch(InterruptedException e) - { - } - } + cleanup(true); } return 0; } + synchronized private void + cleanup(boolean destroy) + { + // + // The refresher thread must be terminated before destroy is + // called, otherwise it might get ObjectNotExistException. + // + if(_refresh != null) + { + _refresh.terminate(); + try + { + _refresh.join(); + } + catch(InterruptedException e) + { + } + _refresh = null; + } + + if(destroy && _session != null) + { + _session.destroy(); + _session = null; + } + } + public static void main(String[] args) { @@ -235,4 +261,7 @@ public class Client extends Ice.Application int status = app.main("Client", args, "config.client"); System.exit(status); } + + private SessionRefreshThread _refresh = null; + private SessionPrx _session = null; } diff --git a/java/demo/Ice/throughput/Client.java b/java/demo/Ice/throughput/Client.java index 99bfdcef97a..1d926a71b0a 100644 --- a/java/demo/Ice/throughput/Client.java +++ b/java/demo/Ice/throughput/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private static void menu() { @@ -38,6 +54,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + Ice.ObjectPrx base = communicator().propertyToProxy("Throughput.Throughput"); ThroughputPrx throughput = ThroughputPrxHelper.checkedCast(base); if(throughput == null) diff --git a/java/demo/Ice/value/Client.java b/java/demo/Ice/value/Client.java index 3ef39e8a35b..f33166da5fd 100644 --- a/java/demo/Ice/value/Client.java +++ b/java/demo/Ice/value/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private static void readline(java.io.BufferedReader in) { @@ -27,6 +43,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + Ice.ObjectPrx base = communicator().propertyToProxy("Value.Initial"); InitialPrx initial = InitialPrxHelper.checkedCast(base); if(initial == null) diff --git a/java/demo/IceBox/hello/Client.java b/java/demo/IceBox/hello/Client.java index cfa4701dd7c..6a7c1f5156a 100644 --- a/java/demo/IceBox/hello/Client.java +++ b/java/demo/IceBox/hello/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private void menu() { @@ -29,6 +45,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + HelloPrx twoway = HelloPrxHelper.checkedCast( communicator().propertyToProxy("Hello.Proxy").ice_twoway().ice_timeout(-1).ice_secure(false)); if(twoway == null) diff --git a/java/demo/IceGrid/allocate/Client.java b/java/demo/IceGrid/allocate/Client.java index a82004d6763..d8eb2e81b0d 100644 --- a/java/demo/IceGrid/allocate/Client.java +++ b/java/demo/IceGrid/allocate/Client.java @@ -11,6 +11,23 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + cleanup(); + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + static private class SessionKeepAliveThread extends Thread { SessionKeepAliveThread(IceGrid.SessionPrx session, long timeout) @@ -73,6 +90,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + int status = 0; IceGrid.RegistryPrx registry = IceGrid.RegistryPrxHelper.checkedCast(communicator().stringToProxy("DemoIceGrid/Registry")); @@ -83,7 +107,6 @@ public class Client extends Ice.Application } java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); - IceGrid.SessionPrx session; while(true) { System.out.println("This demo accepts any user-id / password combination."); @@ -102,7 +125,10 @@ public class Client extends Ice.Application try { - session = registry.createSession(id, pw); + synchronized(this) + { + _session = registry.createSession(id, pw); + } break; } catch(IceGrid.PermissionDeniedException ex) @@ -116,8 +142,11 @@ public class Client extends Ice.Application } } - SessionKeepAliveThread keepAlive = new SessionKeepAliveThread(session, registry.getSessionTimeout() / 2); - keepAlive.start(); + synchronized(this) + { + _keepAlive = new SessionKeepAliveThread(_session, registry.getSessionTimeout() / 2); + _keepAlive.start(); + } try { @@ -132,11 +161,11 @@ public class Client extends Ice.Application try { hello = HelloPrxHelper.checkedCast( - session.allocateObjectById(communicator().stringToIdentity("hello"))); + _session.allocateObjectById(communicator().stringToIdentity("hello"))); } catch(IceGrid.ObjectNotRegisteredException ex) { - hello = HelloPrxHelper.checkedCast(session.allocateObjectByType("::Demo::Hello")); + hello = HelloPrxHelper.checkedCast(_session.allocateObjectByType("::Demo::Hello")); } menu(); @@ -197,22 +226,36 @@ public class Client extends Ice.Application status = 1; } + cleanup(); + + return status; + } + + synchronized void + cleanup() + { // // Destroy the keepAlive thread and the sesion object otherwise // the session will be kept allocated until the timeout occurs. // Destroying the session will release all allocated objects. // - keepAlive.terminate(); - try + if(_keepAlive != null) { - keepAlive.join(); + _keepAlive.terminate(); + try + { + _keepAlive.join(); + } + catch(InterruptedException e) + { + } + _keepAlive = null; } - catch(InterruptedException e) + if(_session != null) { + _session.destroy(); + _session = null; } - session.destroy(); - - return status; } public static void @@ -222,4 +265,7 @@ public class Client extends Ice.Application int status = app.main("Client", args, "config.client"); System.exit(status); } + + SessionKeepAliveThread _keepAlive; + IceGrid.SessionPrx _session; } diff --git a/java/demo/IceGrid/sessionActivation/Client.java b/java/demo/IceGrid/sessionActivation/Client.java index 7b89d4b16f9..3449068b79a 100644 --- a/java/demo/IceGrid/sessionActivation/Client.java +++ b/java/demo/IceGrid/sessionActivation/Client.java @@ -11,6 +11,23 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + cleanup(); + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + static private class SessionKeepAliveThread extends Thread { SessionKeepAliveThread(IceGrid.SessionPrx session, long timeout) @@ -72,6 +89,13 @@ public class Client extends Ice.Application public int run(String[] args) { + // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + int status = 0; IceGrid.RegistryPrx registry = IceGrid.RegistryPrxHelper.checkedCast(communicator().stringToProxy("DemoIceGrid/Registry")); @@ -82,7 +106,6 @@ public class Client extends Ice.Application } java.io.BufferedReader in = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); - IceGrid.SessionPrx session; while(true) { System.out.println("This demo accepts any user-id / password combination."); @@ -101,7 +124,10 @@ public class Client extends Ice.Application try { - session = registry.createSession(id, pw); + synchronized(this) + { + _session = registry.createSession(id, pw); + } break; } catch(IceGrid.PermissionDeniedException ex) @@ -115,13 +141,16 @@ public class Client extends Ice.Application } } - SessionKeepAliveThread keepAlive = new SessionKeepAliveThread(session, registry.getSessionTimeout() / 2); - keepAlive.start(); + synchronized(this) + { + _keepAlive = new SessionKeepAliveThread(_session, registry.getSessionTimeout() / 2); + _keepAlive.start(); + } try { HelloPrx hello = HelloPrxHelper.checkedCast( - session.allocateObjectById(communicator().stringToIdentity("hello"))); + _session.allocateObjectById(communicator().stringToIdentity("hello"))); menu(); @@ -182,22 +211,36 @@ public class Client extends Ice.Application status = 1; } + cleanup(); + + return status; + } + + synchronized void + cleanup() + { // // Destroy the keepAlive thread and the sesion object otherwise // the session will be kept allocated until the timeout occurs. // Destroying the session will release all allocated objects. // - keepAlive.terminate(); - try + if(_keepAlive != null) { - keepAlive.join(); + _keepAlive.terminate(); + try + { + _keepAlive.join(); + } + catch(InterruptedException e) + { + } + _keepAlive = null; } - catch(InterruptedException e) + if(_session != null) { + _session.destroy(); + _session = null; } - session.destroy(); - - return status; } public static void @@ -207,4 +250,7 @@ public class Client extends Ice.Application int status = app.main("Client", args, "config.client"); System.exit(status); } + + SessionKeepAliveThread _keepAlive; + IceGrid.SessionPrx _session; } diff --git a/java/demo/IceGrid/simple/Client.java b/java/demo/IceGrid/simple/Client.java index 1c9333080ba..d5ae5065837 100644 --- a/java/demo/IceGrid/simple/Client.java +++ b/java/demo/IceGrid/simple/Client.java @@ -11,6 +11,22 @@ import Demo.*; public class Client extends Ice.Application { + class ShutdownHook extends Thread + { + public void + run() + { + try + { + communicator().destroy(); + } + catch(Ice.LocalException ex) + { + ex.printStackTrace(); + } + } + } + private void menu() { @@ -26,6 +42,13 @@ public class Client extends Ice.Application run(String[] args) { // + // Since this is an interactive demo we want to clear the + // Application installed interrupt callback and install our + // own shutdown hook. + // + setInterruptHook(new ShutdownHook()); + + // // First we try to connect to the object with the `hello' // identity. If it's not registered with the registry, we // search for an object with the ::Demo::Hello type. diff --git a/java/src/Ice/Application.java b/java/src/Ice/Application.java index 6735596e912..b27315becef 100644 --- a/java/src/Ice/Application.java +++ b/java/src/Ice/Application.java @@ -135,6 +135,7 @@ public abstract class Application status = 1; } + // This clears any set interrupt. defaultInterrupt(); synchronized(_mutex) @@ -149,6 +150,7 @@ public abstract class Application { } } + if(_destroyed) { _communicator = null; @@ -157,8 +159,9 @@ public abstract class Application { _destroyed = true; // - // And _communicator != null, meaning will be destroyed next, - // _destroyed = true also ensures that any remaining callback won't do anything + // And _communicator != null, meaning will be + // destroyed next, _destroyed = true also ensures that + // any remaining callback won't do anything // } } @@ -186,14 +189,9 @@ public abstract class Application synchronized(_mutex) { - if(_destroyHook != null) - { - _destroyHook.done(); - } - - if(_shutdownHook != null) + if(_appHook != null) { - _shutdownHook.done(); + _appHook.done(); } } @@ -232,43 +230,20 @@ public abstract class Application synchronized(_mutex) { // - // Remove the shutdown hook it's set. + // As soon as the destroy hook ends all the threads are + // terminated. So the destroy hook will join the current + // thread before to end. // - if(_shutdownHook != null) + try { - try - { - Runtime.getRuntime().removeShutdownHook(_shutdownHook); - _shutdownHook.done(); - _shutdownHook = null; - } - catch(java.lang.IllegalStateException ex) - { - // - // Expected if we are in the process of shutting down. - // - } + changeHook(new DestroyHook()); } - - if(_destroyHook == null) + catch(java.lang.IllegalStateException ex) { - // - // As soon as the destroy hook ends all the threads are - // terminated. So the destroy hook will join the current - // thread before to end. - // - _destroyHook = new DestroyHook(); - try - { - Runtime.getRuntime().addShutdownHook(_destroyHook); - } - catch(java.lang.IllegalStateException ex) - { - if(_communicator != null) - { - _communicator.destroy(); - } - } + if(_communicator != null) + { + _communicator.destroy(); + } } } } @@ -279,85 +254,54 @@ public abstract class Application synchronized(_mutex) { // - // Remove the destroy hook if it's set. + // As soon as the shutdown hook ends all the threads are + // terminated. So the shutdown hook will join the current + // thread before to end. // - if(_destroyHook != null) + try { - try - { - Runtime.getRuntime().removeShutdownHook(_destroyHook); - _destroyHook.done(); - _destroyHook = null; - } - catch(java.lang.IllegalStateException ex) - { - // - // Expected if we are in the process of shutting down. - // - } + changeHook(new ShutdownHook()); } - - if(_shutdownHook == null) + catch(java.lang.IllegalStateException ex) { - // - // As soon as the shutdown hook ends all the threads are - // terminated. So the shutdown hook will join the current - // thread before to end. - // - _shutdownHook = new ShutdownHook(); - try - { - Runtime.getRuntime().addShutdownHook(_shutdownHook); - } - catch(java.lang.IllegalStateException ex) - { - if(_communicator != null) - { - _communicator.shutdown(); - } - } + if(_communicator != null) + { + _communicator.shutdown(); + } } } } - + + // + // Install a custom shutdown hook. This hook is registered as a + // shutdown hook and should do whatever is necessary to terminate + // the application. Note that this runs as a shutdown hook so the + // code must obey the same rules as a shutdown hook (specifically + // don't call exit!). The shutdown and destroy shutdown interrupts + // are cleared. This hook is automatically unregistered after + // Application.run() returns. + // public static void - defaultInterrupt() + setInterruptHook(java.lang.Thread newHook) // Pun intended. { - synchronized(_mutex) + try { - if(_shutdownHook != null) - { - try - { - Runtime.getRuntime().removeShutdownHook(_shutdownHook); - _shutdownHook.done(); - _shutdownHook = null; - } - catch(java.lang.IllegalStateException ex) - { - // - // Expected if we are in the process of shutting down. - // - } - } - - if(_destroyHook != null) - { - try - { - Runtime.getRuntime().removeShutdownHook(_destroyHook); - _destroyHook.done(); - _destroyHook = null; - } - catch(java.lang.IllegalStateException ex) - { - // - // Expected if we are in the process of shutting down. - // - } - } + changeHook(new CustomHook(newHook)); + } + catch(java.lang.IllegalStateException ex) + { + // Ignore. } } + + // + // This clears any shutdown hooks including any custom hook. + // + public static void + defaultInterrupt() + { + changeHook(null); + } public static boolean interrupted() @@ -368,6 +312,42 @@ public abstract class Application } } + private static void + changeHook(AppHook newHook) + { + synchronized(_mutex) + { + // + // Remove any existing shutdown hooks. + // + try + { + if(_appHook != null) + { + Runtime.getRuntime().removeShutdownHook(_appHook); + _appHook.done(); + _appHook = null; + } + } + catch(java.lang.IllegalStateException ex) + { + // + // Expected if we are in the process of shutting down. + // + } + + // + // Note that we let the IllegalStateException propogate + // out if necessary. + // + if(newHook != null) + { + Runtime.getRuntime().addShutdownHook(newHook); + _appHook = newHook; + } + } + } + private static boolean setCallbackInProgress(boolean destroy) { @@ -397,13 +377,24 @@ public abstract class Application } } - static class DestroyHook extends Thread + static class AppHook extends Thread { - DestroyHook() + void + done() { - _done = false; + synchronized(_doneMutex) + { + _done = true; + _doneMutex.notify(); + } } + protected boolean _done = false; + protected java.lang.Object _doneMutex = new java.lang.Object(); + } + + static class DestroyHook extends AppHook + { public void run() { @@ -434,28 +425,10 @@ public abstract class Application } } } - - void - done() - { - synchronized(_doneMutex) - { - _done = true; - _doneMutex.notify(); - } - } - - private boolean _done; - private java.lang.Object _doneMutex = new java.lang.Object(); } - static class ShutdownHook extends Thread + static class ShutdownHook extends AppHook { - ShutdownHook() - { - _done = false; - } - public void run() { @@ -486,25 +459,45 @@ public abstract class Application } } } + } - void - done() + // Although this class doesn't actually use any of the AppHook + // done stuff, its more trouble than its worth to add all of the + // code necessary to support another hook member variable and + // support code. + static class CustomHook extends AppHook + { + CustomHook(Thread hook) + { + _hook = hook; + } + + public void + run() { synchronized(_doneMutex) { - _done = true; - _doneMutex.notify(); + if(!setCallbackInProgress(false)) + { + return; + } + + _hook.run(); + + clearCallbackInProgress(); + + // + // Don't bother to join with main, we're done. + // } } - private boolean _done; - private java.lang.Object _doneMutex = new java.lang.Object(); + private Thread _hook; } private static String _appName; private static Communicator _communicator; - private static DestroyHook _destroyHook; - private static ShutdownHook _shutdownHook; + private static AppHook _appHook; private static java.lang.Object _mutex = new java.lang.Object(); private static boolean _callbackInProgress = false; private static boolean _destroyed = false; |