summaryrefslogtreecommitdiff
path: root/cpp/test/Ice/gc/Client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/test/Ice/gc/Client.cpp')
-rw-r--r--cpp/test/Ice/gc/Client.cpp689
1 files changed, 689 insertions, 0 deletions
diff --git a/cpp/test/Ice/gc/Client.cpp b/cpp/test/Ice/gc/Client.cpp
new file mode 100644
index 00000000000..42969c0a0e6
--- /dev/null
+++ b/cpp/test/Ice/gc/Client.cpp
@@ -0,0 +1,689 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/Thread.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/MutexPtrLock.h>
+#include <Ice/Ice.h>
+#include <TestCommon.h>
+#include <Test.h>
+#include <fstream>
+
+using namespace std;
+using namespace Test;
+
+namespace
+{
+
+int num = 0;
+::IceUtil::Mutex* numMutex = 0;
+
+class Init
+{
+public:
+
+ Init()
+ {
+ numMutex = new IceUtil::Mutex;
+ }
+
+ ~Init()
+ {
+ delete numMutex;
+ numMutex = 0;
+ }
+};
+
+Init init;
+
+}
+
+static void
+incNum()
+{
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(numMutex);
+ ++num;
+}
+
+static void
+decNum()
+{
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(numMutex);
+ --num;
+}
+
+static int
+getNum()
+{
+ IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(numMutex);
+ return num;
+}
+
+struct N : public C
+{
+ N()
+ {
+ incNum();
+ }
+
+ ~N()
+ {
+ decNum();
+ }
+};
+
+typedef ::IceInternal::Handle<N> NPtr;
+
+struct N2 : public C2
+{
+ N2()
+ {
+ incNum();
+ }
+
+ ~N2()
+ {
+ decNum();
+ }
+};
+
+typedef ::IceInternal::Handle<N2> N2Ptr;
+
+struct NN : public Node
+{
+ NN()
+ {
+ incNum();
+ }
+
+ ~NN()
+ {
+ decNum();
+ }
+};
+
+typedef ::IceInternal::Handle<NN> NNPtr;
+
+struct NL : public Leaf
+{
+ NL()
+ {
+ incNum();
+ }
+
+ ~NL()
+ {
+ decNum();
+ }
+};
+
+typedef ::IceInternal::Handle<NL> NLPtr;
+
+class GarbageProducer : public ::IceUtil::Thread, public ::IceUtil::Monitor< ::IceUtil::Mutex>
+{
+public:
+
+ GarbageProducer()
+ {
+ _stop = false;
+ }
+
+ virtual void run()
+ {
+ ::IceUtil::ThreadControl t = getThreadControl();
+
+ while(true)
+ {
+ {
+ ::IceUtil::Monitor< ::IceUtil::Mutex>::Lock sync(*this);
+ if(_stop)
+ {
+ return;
+ }
+ }
+
+ t.yield();
+
+ {
+ NPtr n = new N;
+ n->left = n;
+ }
+
+ {
+ NPtr n = new N;
+ n->left = n;
+ n->right = n;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n1->right = n2;
+ n2->right = n1;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n1->right = n1;
+ n2->right = n2;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ n1->left = n2;
+ n2->left = n3;
+ n3->left = n1;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ n1->left = n2;
+ n2->left = n3;
+ n3->left = n1;
+ n1->right = n2;
+ n2->right = n3;
+ n3->right = n1;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ n1->left = n2;
+ n2->left = n3;
+ n3->left = n1;
+ n1->right = n3;
+ n2->right = n1;
+ n3->right = n2;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ NPtr n4 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n2->right = n3;
+ n3->left = n4;
+ }
+
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ NPtr n4 = new N;
+ NPtr n5 = new N;
+ NPtr n6 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n2->right = n3;
+ n3->left = n4;
+ n4->right = n5;
+ n5->right = n6;
+ n6->right = n5;
+ }
+ }
+ }
+
+ void stop()
+ {
+ {
+ ::IceUtil::Monitor< ::IceUtil::Mutex>::Lock sync(*this);
+ _stop = true;
+ notify();
+ }
+ getThreadControl().join();
+ }
+
+ void randomWait()
+ {
+ ::IceUtil::Time waitTime = ::IceUtil::Time::milliSeconds(10 + rand() % 50);
+ ::IceUtil::Monitor< ::IceUtil::Mutex>::Lock sync(*this);
+ timedWait(waitTime);
+ }
+
+private:
+
+ bool _stop;
+};
+
+class MyApplication : public Ice::Application
+{
+public:
+
+ MyApplication();
+ virtual int run(int, char* []);
+};
+
+MyApplication::MyApplication()
+ : Ice::Application(Ice::NoSignalHandling)
+{
+}
+
+int
+MyApplication::run(int argc, char* argv[])
+{
+ if(argc < 2 || argc > 3)
+ {
+ cerr << "usage: " << argv[0] << " [testoptions] seedfile [seed]" << endl;
+ return EXIT_FAILURE;
+ }
+
+ cout << "testing single instance... " << flush;
+ {
+ NPtr n = new N;
+ test(getNum() == 1);
+ Ice::collectGarbage();
+ test(getNum() == 1);
+ }
+ test(getNum() == 0);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing single instance cycle... " << flush;
+ {
+ NPtr n = new N;
+ n->left = n;
+ test(getNum() == 1);
+ Ice::collectGarbage();
+ test(getNum() == 1);
+ }
+ test(getNum() == 1);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing single instance cycle with double pointers... " << flush;
+ {
+ NPtr n = new N;
+ n->left = n;
+ n->right = n;
+ test(getNum() == 1);
+ Ice::collectGarbage();
+ test(getNum() == 1);
+ }
+ test(getNum() == 1);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing double instance cycle... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing double instance cycle with double pointers... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n1->right = n2;
+ n2->right = n1;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing double instance cycle with looped pointers... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n1->right = n1;
+ n2->right = n2;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing triple instance cycle... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ n1->left = n2;
+ n2->left = n3;
+ n3->left = n1;
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 3);
+ }
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing triple instance cycle with double pointers... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ n1->left = n2;
+ n2->left = n3;
+ n3->left = n1;
+ n1->right = n2;
+ n2->right = n3;
+ n3->right = n1;
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 3);
+ }
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing triple instance cycle with opposing pointers... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ n1->left = n2;
+ n2->left = n3;
+ n3->left = n1;
+ n1->right = n3;
+ n2->right = n1;
+ n3->right = n2;
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 3);
+ }
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing cycle with trailing instances... " << flush;
+ NPtr n;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ NPtr n4 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n2->right = n3;
+ n3->left = n4;
+ n = n3;
+ test(getNum() == 4);
+ Ice::collectGarbage();
+ test(getNum() == 4);
+ }
+ test(getNum() == 4);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ n = 0;
+ test(getNum() == 0);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing cycle with trailing instances and trailing cycle... " << flush;
+ {
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ NPtr n3 = new N;
+ NPtr n4 = new N;
+ NPtr n5 = new N;
+ NPtr n6 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ n2->right = n3;
+ n3->left = n4;
+ n4->right = n5;
+ n5->right = n6;
+ n6->right = n5;
+ n = n4;
+ test(getNum() == 6);
+ Ice::collectGarbage();
+ test(getNum() == 6);
+ }
+ test(getNum() == 6);
+ Ice::collectGarbage();
+ test(getNum() == 3);
+ n = 0;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing sequence element cycle... " << flush;
+ {
+ CSeq cs;
+ cs.push_back(new N);
+ cs.push_back(new N);
+ cs[0]->left = cs[1];
+ cs[1]->left = cs[0];
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing dictionary element cycle... " << flush;
+ {
+ CDict cd;
+ NPtr n1 = new N;
+ NPtr n2 = new N;
+ n1->left = n2;
+ n2->left = n1;
+ cd[0] = n1;
+ cd[1] = n2;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing sequence of struct cycle... " << flush;
+ {
+ SSeq ss;
+ S s;
+
+ ss.push_back(s);
+ ss.push_back(s);
+ ss[0].theC = new N;
+ ss[1].theC = new N;
+ ss[0].theC->left = ss[1].theC;
+ ss[1].theC->left = ss[0].theC;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing sequence of struct of dictionary cycle... " << flush;
+ {
+ N2Ptr n2 = new N2;
+ S2 s2;
+
+ n2->theS2Seq.push_back(s2);
+ n2->theS2Seq.push_back(s2);
+ n2->theS2Seq[0].theC2Dict[0] = n2;
+ n2->theS2Seq[0].theC2Dict[1] = n2;
+ n2->theS2Seq[1].theC2Dict[0] = n2;
+ n2->theS2Seq[1].theC2Dict[1] = n2;
+ test(getNum() == 1);
+ Ice::collectGarbage();
+ test(getNum() == 1);
+ }
+ Ice::collectGarbage();
+ test(getNum() == 0);
+ cout << "ok" << endl;
+
+ cout << "testing leaf nodes... " << flush;
+
+ {
+ NNPtr nn = new NN;
+ nn->l = new NL;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ Ice::collectGarbage();
+ test(getNum() == 0);
+
+ {
+ NLPtr p;
+ {
+ NNPtr nn = new NN;
+ p = new NL;
+ nn->l = p;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ Ice::collectGarbage();
+ test(getNum() == 1);
+ }
+ test(getNum() == 0);
+
+ {
+ NNPtr nn = new NN;
+ NLPtr nl = new NL;
+ nn->l = nl;
+ nn->n = nn;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+
+ {
+ NNPtr nn1 = new NN;
+ NNPtr nn2 = new NN;
+ NLPtr nl = new NL;
+ nn1->l = nl;
+ nn1->n = nn2;
+ nn2->l = nl;
+ nn2->n = nn1;
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 3);
+ }
+ test(getNum() == 3);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+
+ {
+ NLPtr nl = new NL;
+ test(getNum() == 1);
+ }
+ test(getNum() == 0);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+
+ {
+ NNPtr nn1 = new NN;
+ nn1->n = new NN;
+ test(getNum() == 2);
+ Ice::collectGarbage();
+ test(getNum() == 2);
+ }
+ test(getNum() == 0);
+ Ice::collectGarbage();
+ test(getNum() == 0);
+
+ cout << "ok" << endl;
+
+ cout << "testing for race conditions... " << flush;
+ string seedfile = argv[1];
+ ofstream file(seedfile.c_str());
+ if(!file)
+ {
+ cerr << argv[0] << ": cannot open `" << seedfile << "' for writing" << endl;
+ return EXIT_FAILURE;
+ }
+ ::IceUtil::Time t = ::IceUtil::Time::now();
+ int seed = argc > 2 ? atoi(argv[2]) : static_cast<int>(t.toMilliSeconds());
+ file << seed << "\n";
+ file.close();
+ srand(seed);
+
+ typedef ::IceUtil::Handle<GarbageProducer> GarbageThreadPtr;
+ GarbageThreadPtr garbageThread = new GarbageProducer();
+ garbageThread->start();
+
+ for(int i = 0; i < 50; ++i)
+ {
+ if(interrupted())
+ {
+ break;
+ }
+ garbageThread->randomWait();
+ Ice::collectGarbage();
+ }
+
+ garbageThread->stop();
+ IceUtil::ThreadControl::sleep(IceUtil::Time::seconds(1));
+ Ice::collectGarbage();
+ if(!interrupted())
+ {
+ test(getNum() == 0);
+ cout << "ok" << endl;
+ return EXIT_SUCCESS;
+ }
+ else
+ {
+ return 130; // SIGINT + 128
+ }
+}
+
+int
+main(int argc, char* argv[])
+{
+ MyApplication app;
+ return app.main(argc, argv);
+}