summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2017-03-08 15:47:34 -0800
committerMark Spruiell <mes@zeroc.com>2017-03-08 15:47:34 -0800
commitfc32c2a7805365e7f40ab8a664f94efae35137da (patch)
tree9004df864027bfef52218772e88357e01d9bdf0c /python
parentRefreshed Ice::optional (diff)
downloadice-fc32c2a7805365e7f40ab8a664f94efae35137da.tar.bz2
ice-fc32c2a7805365e7f40ab8a664f94efae35137da.tar.xz
ice-fc32c2a7805365e7f40ab8a664f94efae35137da.zip
- ICE-6845 - More dispatcher fixes for Python
- Deprecated the InitializationData.threadHook member - Added threadStart and threadStop members to InitializationData - InitializationData.batchRequestInterceptor can now be a callable
Diffstat (limited to 'python')
-rw-r--r--python/modules/IcePy/BatchRequestInterceptor.cpp6
-rw-r--r--python/modules/IcePy/Communicator.cpp88
-rw-r--r--python/modules/IcePy/Connection.cpp12
-rw-r--r--python/modules/IcePy/Current.cpp2
-rw-r--r--python/modules/IcePy/Dispatcher.cpp10
-rw-r--r--python/modules/IcePy/ObjectAdapter.cpp2
-rw-r--r--python/modules/IcePy/Operation.cpp31
-rw-r--r--python/modules/IcePy/Properties.cpp3
-rw-r--r--python/modules/IcePy/Proxy.cpp12
-rw-r--r--python/modules/IcePy/Thread.cpp48
-rw-r--r--python/modules/IcePy/Thread.h6
-rw-r--r--python/modules/IcePy/Types.cpp47
-rw-r--r--python/modules/IcePy/Util.cpp46
-rw-r--r--python/modules/IcePy/Util.h7
-rw-r--r--python/python/Ice.py28
-rwxr-xr-xpython/test/Ice/dispatcher/Client.py3
-rwxr-xr-xpython/test/Ice/dispatcher/Dispatcher.py2
-rwxr-xr-xpython/test/Ice/dispatcher/Server.py3
-rw-r--r--python/test/Ice/thread/AllTests.py64
-rw-r--r--python/test/Ice/thread/Client.py37
-rw-r--r--python/test/Ice/thread/Server.py39
-rw-r--r--python/test/Ice/thread/Test.ice45
-rw-r--r--python/test/Ice/thread/TestI.py106
23 files changed, 496 insertions, 151 deletions
diff --git a/python/modules/IcePy/BatchRequestInterceptor.cpp b/python/modules/IcePy/BatchRequestInterceptor.cpp
index 95e7ed1345a..83577944689 100644
--- a/python/modules/IcePy/BatchRequestInterceptor.cpp
+++ b/python/modules/IcePy/BatchRequestInterceptor.cpp
@@ -237,6 +237,12 @@ IcePy::initBatchRequest(PyObject* module)
IcePy::BatchRequestInterceptor::BatchRequestInterceptor(PyObject* interceptor) : _interceptor(interceptor)
{
+ if(!PyCallable_Check(interceptor) && !PyObject_HasAttrString(interceptor, STRCAST("enqueue")))
+ {
+ throw Ice::InitializationException(__FILE__, __LINE__,
+ "batch request interceptor must either be a callable or an object with an 'enqueue' method");
+ }
+
Py_INCREF(interceptor);
}
diff --git a/python/modules/IcePy/Communicator.cpp b/python/modules/IcePy/Communicator.cpp
index 56ffebabc9c..ef6432ebdc5 100644
--- a/python/modules/IcePy/Communicator.cpp
+++ b/python/modules/IcePy/Communicator.cpp
@@ -147,55 +147,55 @@ communicatorInit(CommunicatorObject* self, PyObject* args, PyObject* /*kwds*/)
Ice::InitializationData data;
DispatcherPtr dispatcherWrapper;
- if(initData)
+ try
{
- PyObjectHandle properties = PyObject_GetAttrString(initData, STRCAST("properties"));
- PyObjectHandle logger = PyObject_GetAttrString(initData, STRCAST("logger"));
- PyObjectHandle threadHook = PyObject_GetAttrString(initData, STRCAST("threadHook"));
- PyObjectHandle batchRequestInterceptor = PyObject_GetAttrString(initData, STRCAST("batchRequestInterceptor"));
- PyObjectHandle dispatcher = PyObject_GetAttrString(initData, STRCAST("dispatcher"));
-
- PyErr_Clear(); // PyObject_GetAttrString sets an error on failure.
-
- if(properties.get() && properties.get() != Py_None)
+ if(initData)
{
- //
- // Get the properties implementation.
- //
- PyObjectHandle impl = PyObject_GetAttrString(properties.get(), STRCAST("_impl"));
- assert(impl.get());
- data.properties = getProperties(impl.get());
- }
+ PyObjectHandle properties = getAttr(initData, "properties", false);
+ PyObjectHandle logger = getAttr(initData, "logger", false);
+ PyObjectHandle threadHook = getAttr(initData, "threadHook", false);
+ PyObjectHandle threadStart = getAttr(initData, "threadStart", false);
+ PyObjectHandle threadStop = getAttr(initData, "threadStop", false);
+ PyObjectHandle batchRequestInterceptor = getAttr(initData, "batchRequestInterceptor", false);
+ PyObjectHandle dispatcher = getAttr(initData, "dispatcher", false);
+
+ if(properties.get())
+ {
+ //
+ // Get the properties implementation.
+ //
+ PyObjectHandle impl = getAttr(properties.get(), "_impl", false);
+ assert(impl.get());
+ data.properties = getProperties(impl.get());
+ }
- if(logger.get() && logger.get() != Py_None)
- {
- data.logger = new LoggerWrapper(logger.get());
- }
+ if(logger.get())
+ {
+ data.logger = new LoggerWrapper(logger.get());
+ }
- if(threadHook.get() && threadHook.get() != Py_None)
- {
- data.threadHook = new ThreadHook(threadHook.get());
- }
+ if(threadHook.get() || threadStart.get() || threadStop.get())
+ {
+ data.threadHook = new ThreadHook(threadHook.get(), threadStart.get(), threadStop.get());
+ }
- if(dispatcher.get() && dispatcher.get() != Py_None)
- {
- dispatcherWrapper = new Dispatcher(dispatcher.get());
- data.dispatcher = dispatcherWrapper;
- }
+ if(dispatcher.get())
+ {
+ dispatcherWrapper = new Dispatcher(dispatcher.get());
+ data.dispatcher = dispatcherWrapper;
+ }
- if(batchRequestInterceptor.get() && batchRequestInterceptor.get() != Py_None)
- {
- data.batchRequestInterceptor = new BatchRequestInterceptor(batchRequestInterceptor.get());
+ if(batchRequestInterceptor.get())
+ {
+ data.batchRequestInterceptor = new BatchRequestInterceptor(batchRequestInterceptor.get());
+ }
}
- }
- //
- // We always supply our own implementation of ValueFactoryManager.
- //
- data.valueFactoryManager = new ValueFactoryManager;
+ //
+ // We always supply our own implementation of ValueFactoryManager.
+ //
+ data.valueFactoryManager = new ValueFactoryManager;
- try
- {
if(argList)
{
data.properties = Ice::createProperties(seq, data.properties);
@@ -732,7 +732,7 @@ communicatorFlushBatchRequests(CommunicatorObject* self, PyObject* args)
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(compressBatch, STRCAST("_value"));
+ PyObjectHandle v = getAttr(compressBatch, "_value", false);
assert(v.get());
Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(PyLong_AsLong(v.get()));
@@ -765,7 +765,7 @@ communicatorFlushBatchRequestsAsync(CommunicatorObject* self, PyObject* args, Py
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(compressBatch, STRCAST("_value"));
+ PyObjectHandle v = getAttr(compressBatch, "_value", false);
assert(v.get());
Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(PyLong_AsLong(v.get()));
@@ -834,7 +834,7 @@ communicatorBeginFlushBatchRequests(CommunicatorObject* self, PyObject* args, Py
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(compressBatch, STRCAST("_value"));
+ PyObjectHandle v = getAttr(compressBatch, "_value", false);
assert(v.get());
Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(PyLong_AsLong(v.get()));
@@ -1870,7 +1870,7 @@ IcePy_identityToString(PyObject* /*self*/, PyObject* args)
Ice::ToStringMode toStringMode = Ice::Unicode;
if(mode != Py_None && PyObject_HasAttrString(mode, STRCAST("value")))
{
- PyObjectHandle modeValue = PyObject_GetAttrString(mode, STRCAST("value"));
+ PyObjectHandle modeValue = getAttr(mode, "value", true);
toStringMode = static_cast<Ice::ToStringMode>(PyLong_AsLong(modeValue.get()));
}
diff --git a/python/modules/IcePy/Connection.cpp b/python/modules/IcePy/Connection.cpp
index 2950fc87717..69caaaeacb3 100644
--- a/python/modules/IcePy/Connection.cpp
+++ b/python/modules/IcePy/Connection.cpp
@@ -304,7 +304,7 @@ connectionClose(ConnectionObject* self, PyObject* args)
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(mode, STRCAST("_value"));
+ PyObjectHandle v = getAttr(mode, "_value", true);
assert(v.get());
Ice::ConnectionClose cc = static_cast<Ice::ConnectionClose>(PyLong_AsLong(v.get()));
@@ -427,7 +427,7 @@ connectionFlushBatchRequests(ConnectionObject* self, PyObject* args)
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(compressBatch, STRCAST("_value"));
+ PyObjectHandle v = getAttr(compressBatch, "_value", true);
assert(v.get());
Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(PyLong_AsLong(v.get()));
@@ -460,7 +460,7 @@ connectionFlushBatchRequestsAsync(ConnectionObject* self, PyObject* args, PyObje
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(compressBatch, STRCAST("_value"));
+ PyObjectHandle v = getAttr(compressBatch, "_value", true);
assert(v.get());
Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(PyLong_AsLong(v.get()));
@@ -531,7 +531,7 @@ connectionBeginFlushBatchRequests(ConnectionObject* self, PyObject* args, PyObje
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(compressBatch, STRCAST("_value"));
+ PyObjectHandle v = getAttr(compressBatch, "_value", true);
assert(v.get());
Ice::CompressBatch cb = static_cast<Ice::CompressBatch>(PyLong_AsLong(v.get()));
@@ -833,7 +833,7 @@ connectionSetACM(ConnectionObject* self, PyObject* args)
PyErr_Format(PyExc_TypeError, "value for 'close' argument must be Unset or an enumerator of Ice.ACMClose");
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(c, STRCAST("_value"));
+ PyObjectHandle v = getAttr(c, "_value", true);
assert(v.get());
close = static_cast<Ice::ACMClose>(PyLong_AsLong(v.get()));
}
@@ -846,7 +846,7 @@ connectionSetACM(ConnectionObject* self, PyObject* args)
"value for 'heartbeat' argument must be Unset or an enumerator of Ice.ACMHeartbeat");
return 0;
}
- PyObjectHandle v = PyObject_GetAttrString(h, STRCAST("_value"));
+ PyObjectHandle v = getAttr(h, "_value", true);
assert(v.get());
heartbeat = static_cast<Ice::ACMHeartbeat>(PyLong_AsLong(v.get()));
}
diff --git a/python/modules/IcePy/Current.cpp b/python/modules/IcePy/Current.cpp
index 70cbed0b509..c64c388daf5 100644
--- a/python/modules/IcePy/Current.cpp
+++ b/python/modules/IcePy/Current.cpp
@@ -193,7 +193,7 @@ currentGetter(CurrentObject* self, void* closure)
enumerator = "Idempotent";
break;
}
- self->mode = PyObject_GetAttrString(type, STRCAST(enumerator));
+ self->mode = getAttr(type, enumerator, false);
assert(self->mode);
}
Py_INCREF(self->mode);
diff --git a/python/modules/IcePy/Dispatcher.cpp b/python/modules/IcePy/Dispatcher.cpp
index 70f53e0535c..012d709ef1d 100644
--- a/python/modules/IcePy/Dispatcher.cpp
+++ b/python/modules/IcePy/Dispatcher.cpp
@@ -45,10 +45,9 @@ extern "C"
static PyObject*
dispatcherCallInvoke(DispatcherCallObject* self, PyObject* /*args*/, PyObject* /*kwds*/)
{
- AllowThreads allowThreads; // Release Python's global interpreter lock during blocking calls.
-
try
{
+ AllowThreads allowThreads; // Release Python's global interpreter lock during blocking calls.
(*self->call)->run();
}
catch(const Ice::Exception& ex)
@@ -131,6 +130,11 @@ IcePy::initDispatcher(PyObject* module)
IcePy::Dispatcher::Dispatcher(PyObject* dispatcher) :
_dispatcher(dispatcher)
{
+ if(!PyCallable_Check(dispatcher))
+ {
+ throw Ice::InitializationException(__FILE__, __LINE__, "dispatcher must be a callable");
+ }
+
Py_INCREF(dispatcher);
}
@@ -154,7 +158,7 @@ IcePy::Dispatcher::dispatch(const Ice::DispatcherCallPtr& call, const Ice::Conne
obj->call = new Ice::DispatcherCallPtr(call);
PyObjectHandle c = createConnection(con, _communicator);
- PyObjectHandle tmp = PyObject_CallMethod(_dispatcher.get(), STRCAST("dispatch"), STRCAST("OO"), obj, c.get());
+ PyObjectHandle tmp = PyObject_CallFunction(_dispatcher.get(), STRCAST("OO"), obj, c.get());
Py_DECREF(reinterpret_cast<PyObject*>(obj));
if(!tmp.get())
{
diff --git a/python/modules/IcePy/ObjectAdapter.cpp b/python/modules/IcePy/ObjectAdapter.cpp
index 07877369274..9beb09d1f52 100644
--- a/python/modules/IcePy/ObjectAdapter.cpp
+++ b/python/modules/IcePy/ObjectAdapter.cpp
@@ -1878,7 +1878,7 @@ IcePy::unwrapObjectAdapter(PyObject* obj)
#endif
assert(wrapperType);
assert(PyObject_IsInstance(obj, wrapperType));
- PyObjectHandle impl = PyObject_GetAttrString(obj, STRCAST("_impl"));
+ PyObjectHandle impl = getAttr(obj, "_impl", false);
assert(impl.get());
return getObjectAdapter(impl.get());
}
diff --git a/python/modules/IcePy/Operation.cpp b/python/modules/IcePy/Operation.cpp
index 5db4ab9e41c..1cc2f781099 100644
--- a/python/modules/IcePy/Operation.cpp
+++ b/python/modules/IcePy/Operation.cpp
@@ -700,7 +700,7 @@ doneCallbackInvoke(DoneCallbackObject* self, PyObject* args)
{
assert(self->upcall);
- PyObjectHandle resultMethod = PyObject_GetAttrString(future, STRCAST("result"));
+ PyObjectHandle resultMethod = getAttr(future, "result", false);
assert(resultMethod.get());
PyObjectHandle empty = PyTuple_New(0);
PyObjectHandle result = PyObject_Call(resultMethod.get(), empty.get(), 0);
@@ -1161,14 +1161,14 @@ IcePy::Operation::Operation(const char* n, PyObject* m, PyObject* sm, int amdFla
//
// mode
//
- PyObjectHandle modeValue = PyObject_GetAttrString(m, STRCAST("value"));
+ PyObjectHandle modeValue = getAttr(m, "value", true);
mode = (Ice::OperationMode)static_cast<int>(PyLong_AsLong(modeValue.get()));
assert(!PyErr_Occurred());
//
// sendMode
//
- PyObjectHandle sendModeValue = PyObject_GetAttrString(sm, STRCAST("value"));
+ PyObjectHandle sendModeValue = getAttr(sm, "value", true);
sendMode = (Ice::OperationMode)static_cast<int>(PyLong_AsLong(sendModeValue.get()));
assert(!PyErr_Occurred());
@@ -1187,7 +1187,7 @@ IcePy::Operation::Operation(const char* n, PyObject* m, PyObject* sm, int amdFla
}
else
{
- PyObjectHandle formatValue = PyObject_GetAttrString(fmt, STRCAST("value"));
+ PyObjectHandle formatValue = getAttr(fmt, "value", true);
format = (Ice::FormatType)static_cast<int>(PyLong_AsLong(formatValue.get()));
assert(!PyErr_Occurred());
}
@@ -2863,7 +2863,7 @@ IcePy::SyncBlobjectInvocation::invoke(PyObject* args, PyObject* /* kwds */)
}
#endif
- PyObjectHandle modeValue = PyObject_GetAttrString(mode, STRCAST("value"));
+ PyObjectHandle modeValue = getAttr(mode, "value", true);
Ice::OperationMode sendMode = (Ice::OperationMode)static_cast<int>(PyLong_AsLong(modeValue.get()));
assert(!PyErr_Occurred());
@@ -3028,7 +3028,7 @@ IcePy::AsyncBlobjectInvocation::invoke(PyObject* args, PyObject* kwds)
_op = operation;
- PyObjectHandle modeValue = PyObject_GetAttrString(mode, STRCAST("value"));
+ PyObjectHandle modeValue = getAttr(mode, "value", true);
Ice::OperationMode sendMode = (Ice::OperationMode)static_cast<int>(PyLong_AsLong(modeValue.get()));
assert(!PyErr_Occurred());
@@ -3372,7 +3372,7 @@ IcePy::NewAsyncBlobjectInvocation::handleInvoke(PyObject* args, PyObject* /* kwd
_op = operation;
- PyObjectHandle modeValue = PyObject_GetAttrString(mode, STRCAST("value"));
+ PyObjectHandle modeValue = getAttr(mode, "value", true);
Ice::OperationMode sendMode = (Ice::OperationMode)static_cast<int>(PyLong_AsLong(modeValue.get()));
assert(!PyErr_Occurred());
@@ -3507,7 +3507,7 @@ Upcall::dispatchImpl(PyObject* servant, const string& dispatchName, PyObject* ar
//
// Find the servant method for the operation. Use dispatchName here, not current.operation.
//
- PyObjectHandle servantMethod = PyObject_GetAttrString(servant, const_cast<char*>(dispatchName.c_str()));
+ PyObjectHandle servantMethod = getAttr(servant, dispatchName, false);
if(!servantMethod.get())
{
ostringstream ostr;
@@ -3523,7 +3523,7 @@ Upcall::dispatchImpl(PyObject* servant, const string& dispatchName, PyObject* ar
//
// Get the _iceDispatch method. The _iceDispatch method will invoke the servant method and pass it the arguments.
//
- PyObjectHandle dispatchMethod = PyObject_GetAttrString(servant, STRCAST("_iceDispatch"));
+ PyObjectHandle dispatchMethod = getAttr(servant, "_iceDispatch", false);
if(!dispatchMethod.get())
{
ostringstream ostr;
@@ -3834,7 +3834,7 @@ IcePy::TypedUpcall::exception(PyException& ex)
//
// Get the exception's type.
//
- PyObjectHandle iceType = PyObject_GetAttrString(ex.ex.get(), STRCAST("_ice_type"));
+ PyObjectHandle iceType = getAttr(ex.ex.get(), "_ice_type", false);
assert(iceType.get());
ExceptionInfoPtr info = ExceptionInfoPtr::dynamicCast(getException(iceType.get()));
assert(info);
@@ -4048,7 +4048,7 @@ IcePy::invokeBuiltin(PyObject* proxy, const string& builtin, PyObject* args)
string name = "_op_" + builtin;
PyObject* objectType = lookupType("Ice.Object");
assert(objectType);
- PyObjectHandle obj = PyObject_GetAttrString(objectType, STRCAST(name.c_str()));
+ PyObjectHandle obj = getAttr(objectType, name, false);
assert(obj.get());
OperationPtr op = getOperation(obj.get());
@@ -4065,7 +4065,7 @@ IcePy::invokeBuiltinAsync(PyObject* proxy, const string& builtin, PyObject* args
string name = "_op_" + builtin;
PyObject* objectType = lookupType("Ice.Object");
assert(objectType);
- PyObjectHandle obj = PyObject_GetAttrString(objectType, STRCAST(name.c_str()));
+ PyObjectHandle obj = getAttr(objectType, name, false);
assert(obj.get());
OperationPtr op = getOperation(obj.get());
@@ -4082,7 +4082,7 @@ IcePy::beginBuiltin(PyObject* proxy, const string& builtin, PyObject* args)
string name = "_op_" + builtin;
PyObject* objectType = lookupType("Ice.Object");
assert(objectType);
- PyObjectHandle obj = PyObject_GetAttrString(objectType, STRCAST(name.c_str()));
+ PyObjectHandle obj = getAttr(objectType, name, false);
assert(obj.get());
OperationPtr op = getOperation(obj.get());
@@ -4105,7 +4105,7 @@ IcePy::endBuiltin(PyObject* proxy, const string& builtin, PyObject* args)
string name = "_op_" + builtin;
PyObject* objectType = lookupType("Ice.Object");
assert(objectType);
- PyObjectHandle obj = PyObject_GetAttrString(objectType, STRCAST(name.c_str()));
+ PyObjectHandle obj = getAttr(objectType, name, false);
assert(obj.get());
OperationPtr op = getOperation(obj.get());
@@ -4508,8 +4508,7 @@ IcePy::TypedServantWrapper::ice_invoke_async(const Ice::AMD_Object_ice_invokePtr
// Look for the Operation object in the servant's type.
//
string attrName = "_op_" + current.operation;
- PyObjectHandle h = PyObject_GetAttrString((PyObject*)_servant->ob_type,
- const_cast<char*>(attrName.c_str()));
+ PyObjectHandle h = getAttr((PyObject*)_servant->ob_type, attrName, false);
if(!h.get())
{
PyErr_Clear();
diff --git a/python/modules/IcePy/Properties.cpp b/python/modules/IcePy/Properties.cpp
index dc6481b1a22..bbcca6b179b 100644
--- a/python/modules/IcePy/Properties.cpp
+++ b/python/modules/IcePy/Properties.cpp
@@ -83,7 +83,8 @@ propertiesInit(PropertiesObject* self, PyObject* args, PyObject* /*kwds*/)
assert(propType);
if(PyObject_IsInstance(defaultsObj, propType))
{
- PyObjectHandle impl = PyObject_GetAttrString(defaultsObj, STRCAST("_impl"));
+ PyObjectHandle impl = getAttr(defaultsObj, "_impl", false);
+ assert(impl.get());
defaults = getProperties(impl.get());
}
else if(defaultsObj != Py_None)
diff --git a/python/modules/IcePy/Proxy.cpp b/python/modules/IcePy/Proxy.cpp
index c3fa273fa47..2186cef5bc3 100644
--- a/python/modules/IcePy/Proxy.cpp
+++ b/python/modules/IcePy/Proxy.cpp
@@ -1006,8 +1006,8 @@ proxyIceGetEndpointSelection(ProxyObject* self)
PyObject* cls = lookupType("Ice.EndpointSelectionType");
assert(cls);
- PyObjectHandle rnd = PyObject_GetAttrString(cls, STRCAST("Random"));
- PyObjectHandle ord = PyObject_GetAttrString(cls, STRCAST("Ordered"));
+ PyObjectHandle rnd = getAttr(cls, "Random", false);
+ PyObjectHandle ord = getAttr(cls, "Ordered", false);
assert(rnd.get());
assert(ord.get());
@@ -1051,8 +1051,8 @@ proxyIceEndpointSelection(ProxyObject* self, PyObject* args)
}
Ice::EndpointSelectionType val;
- PyObjectHandle rnd = PyObject_GetAttrString(cls, STRCAST("Random"));
- PyObjectHandle ord = PyObject_GetAttrString(cls, STRCAST("Ordered"));
+ PyObjectHandle rnd = getAttr(cls, "Random", false);
+ PyObjectHandle ord = getAttr(cls, "Ordered", false);
assert(rnd.get());
assert(ord.get());
if(rnd.get() == type)
@@ -2191,7 +2191,7 @@ AMI_Object_ice_flushBatchRequestsI::exception(const Ice::Exception& ex)
}
else
{
- PyObjectHandle method = PyObject_GetAttrString(_callback, STRCAST(methodName.c_str()));
+ PyObjectHandle method = getAttr(_callback, methodName, false);
assert(method.get());
PyObjectHandle exh = convertException(ex);
assert(exh.get());
@@ -2213,7 +2213,7 @@ AMI_Object_ice_flushBatchRequestsI::sent(bool)
const string methodName = "ice_sent";
if(PyObject_HasAttrString(_callback, STRCAST(methodName.c_str())))
{
- PyObjectHandle method = PyObject_GetAttrString(_callback, STRCAST(methodName.c_str()));
+ PyObjectHandle method = getAttr(_callback, methodName, false);
assert(method.get());
PyObjectHandle args = PyTuple_New(0);
PyObjectHandle tmp = PyObject_Call(method.get(), args.get(), 0);
diff --git a/python/modules/IcePy/Thread.cpp b/python/modules/IcePy/Thread.cpp
index 004e209c3d0..06f100200a3 100644
--- a/python/modules/IcePy/Thread.cpp
+++ b/python/modules/IcePy/Thread.cpp
@@ -35,10 +35,12 @@ IcePy::AdoptThread::~AdoptThread()
PyGILState_Release(_state);
}
-IcePy::ThreadHook::ThreadHook(PyObject* threadNotification) :
- _threadNotification(threadNotification)
+IcePy::ThreadHook::ThreadHook(PyObject* threadNotification, PyObject* threadStart, PyObject* threadStop) :
+ _threadNotification(threadNotification), _threadStart(threadStart), _threadStop(threadStop)
{
Py_INCREF(threadNotification);
+ Py_INCREF(threadStart);
+ Py_INCREF(threadStop);
}
void
@@ -46,10 +48,22 @@ IcePy::ThreadHook::start()
{
AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
- PyObjectHandle tmp = PyObject_CallMethod(_threadNotification.get(), STRCAST("start"), 0);
- if(!tmp.get())
+ if(_threadNotification.get())
{
- throwPythonException();
+ PyObjectHandle tmp = PyObject_CallMethod(_threadNotification.get(), STRCAST("start"), 0);
+ if(!tmp.get())
+ {
+ throwPythonException();
+ }
+ }
+ if(_threadStart.get())
+ {
+ PyObjectHandle args = PyTuple_New(0);
+ PyObjectHandle tmp = PyObject_Call(_threadStart.get(), args.get(), 0);
+ if(!tmp.get())
+ {
+ throwPythonException();
+ }
}
}
@@ -58,15 +72,21 @@ IcePy::ThreadHook::stop()
{
AdoptThread adoptThread; // Ensure the current thread is able to call into Python.
- PyObjectHandle tmp = PyObject_CallMethod(_threadNotification.get(), STRCAST("stop"), 0);
- if(!tmp.get())
+ if(_threadNotification.get())
{
- throwPythonException();
+ PyObjectHandle tmp = PyObject_CallMethod(_threadNotification.get(), STRCAST("stop"), 0);
+ if(!tmp.get())
+ {
+ throwPythonException();
+ }
+ }
+ if(_threadStop.get())
+ {
+ PyObjectHandle args = PyTuple_New(0);
+ PyObjectHandle tmp = PyObject_Call(_threadStop.get(), args.get(), 0);
+ if(!tmp.get())
+ {
+ throwPythonException();
+ }
}
-}
-
-PyObject*
-IcePy::ThreadHook::getObject()
-{
- return _threadNotification.get();
}
diff --git a/python/modules/IcePy/Thread.h b/python/modules/IcePy/Thread.h
index 55215522323..5733c4bdce3 100644
--- a/python/modules/IcePy/Thread.h
+++ b/python/modules/IcePy/Thread.h
@@ -58,16 +58,16 @@ class ThreadHook : public Ice::ThreadNotification
{
public:
- ThreadHook(PyObject*);
+ ThreadHook(PyObject*, PyObject*, PyObject*);
virtual void start();
virtual void stop();
- PyObject* getObject();
-
private:
PyObjectHandle _threadNotification;
+ PyObjectHandle _threadStart;
+ PyObjectHandle _threadStop;
};
typedef IceUtil::Handle<ThreadHook> ThreadHookPtr;
diff --git a/python/modules/IcePy/Types.cpp b/python/modules/IcePy/Types.cpp
index f01eaf22ac5..b7183bf02aa 100644
--- a/python/modules/IcePy/Types.cpp
+++ b/python/modules/IcePy/Types.cpp
@@ -507,7 +507,7 @@ IcePy::StreamUtil::getSlicedDataMember(PyObject* obj, ObjectMap* objectMap)
if(PyObject_HasAttrString(obj, STRCAST("_ice_slicedData")))
{
- PyObjectHandle sd = PyObject_GetAttrString(obj, STRCAST("_ice_slicedData"));
+ PyObjectHandle sd = getAttr(obj, "_ice_slicedData", false);
assert(sd.get());
if(sd.get() != Py_None)
@@ -515,7 +515,7 @@ IcePy::StreamUtil::getSlicedDataMember(PyObject* obj, ObjectMap* objectMap)
//
// The "slices" member is a tuple of Ice.SliceInfo objects.
//
- PyObjectHandle sl = PyObject_GetAttrString(sd.get(), STRCAST("slices"));
+ PyObjectHandle sl = getAttr(sd.get(), "slices", false);
assert(sl.get());
assert(PyTuple_Check(sl.get()));
@@ -529,15 +529,15 @@ IcePy::StreamUtil::getSlicedDataMember(PyObject* obj, ObjectMap* objectMap)
Ice::SliceInfoPtr info = new Ice::SliceInfo;
- PyObjectHandle typeId = PyObject_GetAttrString(s.get(), STRCAST("typeId"));
+ PyObjectHandle typeId = getAttr(s.get(), "typeId", false);
assert(typeId.get());
info->typeId = getString(typeId.get());
- PyObjectHandle compactId = PyObject_GetAttrString(s.get(), STRCAST("compactId"));
+ PyObjectHandle compactId = getAttr(s.get(), "compactId", false);
assert(compactId.get());
info->compactId = static_cast<int>(PyLong_AsLong(compactId.get()));
- PyObjectHandle bytes = PyObject_GetAttrString(s.get(), STRCAST("bytes"));
+ PyObjectHandle bytes = getAttr(s.get(), "bytes", false);
assert(bytes.get());
char* str;
Py_ssize_t strsz;
@@ -551,7 +551,7 @@ IcePy::StreamUtil::getSlicedDataMember(PyObject* obj, ObjectMap* objectMap)
vector<Ice::Byte> vtmp(reinterpret_cast<Ice::Byte*>(str), reinterpret_cast<Ice::Byte*>(str + strsz));
info->bytes.swap(vtmp);
- PyObjectHandle instances = PyObject_GetAttrString(s.get(), STRCAST("instances"));
+ PyObjectHandle instances = getAttr(s.get(), "instances", false);
assert(instances.get());
assert(PyTuple_Check(instances.get()));
Py_ssize_t osz = PyTuple_GET_SIZE(instances.get());
@@ -575,11 +575,11 @@ IcePy::StreamUtil::getSlicedDataMember(PyObject* obj, ObjectMap* objectMap)
info->instances.push_back(writer);
}
- PyObjectHandle hasOptionalMembers = PyObject_GetAttrString(s.get(), STRCAST("hasOptionalMembers"));
+ PyObjectHandle hasOptionalMembers = getAttr(s.get(), "hasOptionalMembers", false);
assert(hasOptionalMembers.get());
info->hasOptionalMembers = PyObject_IsTrue(hasOptionalMembers.get()) ? true : false;
- PyObjectHandle isLastSlice = PyObject_GetAttrString(s.get(), STRCAST("isLastSlice"));
+ PyObjectHandle isLastSlice = getAttr(s.get(), "isLastSlice", false);
assert(isLastSlice.get());
info->isLastSlice = PyObject_IsTrue(isLastSlice.get()) ? true : false;
@@ -1380,7 +1380,7 @@ IcePy::StructInfo::marshal(PyObject* p, Ice::OutputStream* os, ObjectMap* object
{
DataMemberPtr member = *q;
char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle attr = PyObject_GetAttrString(p, memberName);
+ PyObjectHandle attr = getAttr(p, member->name, true);
if(!attr.get())
{
PyErr_Format(PyExc_AttributeError, STRCAST("no member `%s' found in %s value"), memberName,
@@ -1453,8 +1453,7 @@ IcePy::StructInfo::print(PyObject* value, IceUtilInternal::Output& out, PrintObj
for(DataMemberList::const_iterator q = members.begin(); q != members.end(); ++q)
{
DataMemberPtr member = *q;
- char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle attr = PyObject_GetAttrString(value, memberName);
+ PyObjectHandle attr = getAttr(value, member->name, true);
out << nl << member->name << " = ";
if(!attr.get())
{
@@ -2922,7 +2921,7 @@ IcePy::ClassInfo::print(PyObject* value, IceUtilInternal::Output& out, PrintObje
}
else
{
- PyObjectHandle iceType = PyObject_GetAttrString(value, STRCAST("_ice_type"));
+ PyObjectHandle iceType = getAttr(value, "_ice_type", false);
ClassInfoPtr info;
if(!iceType.get())
{
@@ -3127,7 +3126,7 @@ IcePy::ValueInfo::print(PyObject* value, IceUtilInternal::Output& out, PrintObje
}
else
{
- PyObjectHandle iceType = PyObject_GetAttrString(value, STRCAST("_ice_type"));
+ PyObjectHandle iceType = getAttr(value, "_ice_type", false);
ValueInfoPtr info;
if(!iceType.get())
{
@@ -3182,8 +3181,7 @@ IcePy::ValueInfo::printMembers(PyObject* value, IceUtilInternal::Output& out, Pr
for(q = members.begin(); q != members.end(); ++q)
{
DataMemberPtr member = *q;
- char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle attr = PyObject_GetAttrString(value, memberName);
+ PyObjectHandle attr = getAttr(value, member->name, true);
out << nl << member->name << " = ";
if(!attr.get())
{
@@ -3198,8 +3196,7 @@ IcePy::ValueInfo::printMembers(PyObject* value, IceUtilInternal::Output& out, Pr
for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q)
{
DataMemberPtr member = *q;
- char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle attr = PyObject_GetAttrString(value, memberName);
+ PyObjectHandle attr = getAttr(value, member->name, true);
out << nl << member->name << " = ";
if(!attr.get())
{
@@ -3358,7 +3355,7 @@ IcePy::ObjectWriter::ObjectWriter(PyObject* object, ObjectMap* objectMap, const
Py_INCREF(_object);
if(!_formal || !_formal->interface)
{
- PyObjectHandle iceType = PyObject_GetAttrString(object, STRCAST("_ice_type"));
+ PyObjectHandle iceType = getAttr(object, "_ice_type", false);
if(!iceType.get())
{
assert(PyErr_Occurred());
@@ -3452,7 +3449,7 @@ IcePy::ObjectWriter::writeMembers(Ice::OutputStream* os, const DataMemberList& m
char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle val = PyObject_GetAttrString(_object, memberName);
+ PyObjectHandle val = getAttr(_object, member->name, true);
if(!val.get())
{
if(member->optional)
@@ -3730,7 +3727,7 @@ IcePy::ExceptionInfo::writeMembers(PyObject* p, Ice::OutputStream* os, const Dat
char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle val = PyObject_GetAttrString(p, memberName);
+ PyObjectHandle val = getAttr(p, member->name, true);
if(!val.get())
{
if(member->optional)
@@ -3836,8 +3833,7 @@ IcePy::ExceptionInfo::printMembers(PyObject* value, IceUtilInternal::Output& out
for(q = members.begin(); q != members.end(); ++q)
{
DataMemberPtr member = *q;
- char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle attr = PyObject_GetAttrString(value, memberName);
+ PyObjectHandle attr = getAttr(value, member->name, true);
out << nl << member->name << " = ";
if(!attr.get() || attr.get() == Unset)
{
@@ -3852,8 +3848,7 @@ IcePy::ExceptionInfo::printMembers(PyObject* value, IceUtilInternal::Output& out
for(q = optionalMembers.begin(); q != optionalMembers.end(); ++q)
{
DataMemberPtr member = *q;
- char* memberName = const_cast<char*>(member->name.c_str());
- PyObjectHandle attr = PyObject_GetAttrString(value, memberName);
+ PyObjectHandle attr = getAttr(value, member->name, true);
out << nl << member->name << " = ";
if(!attr.get())
{
@@ -3878,7 +3873,7 @@ IcePy::ExceptionWriter::ExceptionWriter(const PyObjectHandle& ex, const Exceptio
{
if(!info)
{
- PyObjectHandle iceType = PyObject_GetAttrString(ex.get(), STRCAST("_ice_type"));
+ PyObjectHandle iceType = getAttr(ex.get(), "_ice_type", false);
assert(iceType.get());
_info = ExceptionInfoPtr::dynamicCast(getException(iceType.get()));
assert(_info);
@@ -4725,7 +4720,7 @@ IcePy_stringifyException(PyObject*, PyObject* args)
return 0;
}
- PyObjectHandle iceType = PyObject_GetAttrString(value, STRCAST("_ice_type"));
+ PyObjectHandle iceType = getAttr(value, "_ice_type", false);
assert(iceType.get());
ExceptionInfoPtr info = getException(iceType.get());
assert(info);
diff --git a/python/modules/IcePy/Util.cpp b/python/modules/IcePy/Util.cpp
index d1c92adee65..84da83040f4 100644
--- a/python/modules/IcePy/Util.cpp
+++ b/python/modules/IcePy/Util.cpp
@@ -55,8 +55,8 @@ template<typename T> bool
getVersion(PyObject* p, T& v, const char* type)
{
assert(checkIsInstance(p, type));
- PyObjectHandle major = PyObject_GetAttrString(p, STRCAST("major"));
- PyObjectHandle minor = PyObject_GetAttrString(p, STRCAST("minor"));
+ PyObjectHandle major = getAttr(p, "major", false);
+ PyObjectHandle minor = getAttr(p, "minor", false);
if(major.get())
{
major = PyNumber_Long(major.get());
@@ -208,6 +208,26 @@ IcePy::getStringArg(PyObject* p, const string& arg, string& val)
return true;
}
+PyObject*
+IcePy::getAttr(PyObject* obj, const string& attrib, bool allowNone)
+{
+ PyObject* v = PyObject_GetAttrString(obj, attrib.c_str());
+ if(v == Py_None)
+ {
+ if(!allowNone)
+ {
+ Py_DECREF(v);
+ v = 0;
+ }
+ }
+ else if(!v)
+ {
+ PyErr_Clear(); // PyObject_GetAttrString sets an error on failure.
+ }
+
+ return v;
+}
+
string
IcePy::getFunction()
{
@@ -215,9 +235,9 @@ IcePy::getFunction()
// Get name of current function.
//
PyFrameObject *f = PyThreadState_GET()->frame;
- PyObjectHandle code = PyObject_GetAttrString(reinterpret_cast<PyObject*>(f), STRCAST("f_code"));
+ PyObjectHandle code = getAttr(reinterpret_cast<PyObject*>(f), "f_code", false);
assert(code.get());
- PyObjectHandle func = PyObject_GetAttrString(code.get(), STRCAST("co_name"));
+ PyObjectHandle func = getAttr(code.get(), "co_name", false);
assert(func.get());
return getString(func.get());
}
@@ -394,17 +414,17 @@ IcePy::PyException::raiseLocalException()
catch(Ice::RequestFailedException& e)
{
IcePy::PyObjectHandle member;
- member = PyObject_GetAttrString(ex.get(), STRCAST("id"));
+ member = getAttr(ex.get(), "id", true);
if(member.get() && IcePy::checkIdentity(member.get()))
{
IcePy::getIdentity(member.get(), e.id);
}
- member = PyObject_GetAttrString(ex.get(), STRCAST("facet"));
+ member = getAttr(ex.get(), "facet", true);
if(member.get() && checkString(member.get()))
{
e.facet = getString(member.get());
}
- member = PyObject_GetAttrString(ex.get(), STRCAST("operation"));
+ member = getAttr(ex.get(), "operation", true);
if(member.get() && checkString(member.get()))
{
e.operation = getString(member.get());
@@ -430,7 +450,7 @@ IcePy::PyException::raiseLocalException()
catch(Ice::UnknownException& e)
{
IcePy::PyObjectHandle member;
- member = PyObject_GetAttrString(ex.get(), STRCAST("unknown"));
+ member = getAttr(ex.get(), "unknown", true);
if(member.get() && checkString(member.get()))
{
e.unknown = getString(member.get());
@@ -489,9 +509,9 @@ string
IcePy::PyException::getTypeName()
{
PyObject* cls = reinterpret_cast<PyObject*>(ex.get()->ob_type);
- PyObjectHandle name = PyObject_GetAttrString(cls, "__name__");
+ PyObjectHandle name = getAttr(cls, "__name__", false);
assert(name.get());
- PyObjectHandle mod = PyObject_GetAttrString(cls, "__module__");
+ PyObjectHandle mod = getAttr(cls, "__module__", false);
assert(mod.get());
string result = getString(mod.get());
result += ".";
@@ -970,7 +990,7 @@ IcePy::handleSystemExit(PyObject* ex)
PyObjectHandle code;
if(PyExceptionInstance_Check(ex))
{
- code = PyObject_GetAttrString(ex, STRCAST("code"));
+ code = getAttr(ex, "code", true);
}
else
{
@@ -1042,8 +1062,8 @@ bool
IcePy::getIdentity(PyObject* p, Ice::Identity& ident)
{
assert(checkIdentity(p));
- PyObjectHandle name = PyObject_GetAttrString(p, STRCAST("name"));
- PyObjectHandle category = PyObject_GetAttrString(p, STRCAST("category"));
+ PyObjectHandle name = getAttr(p, "name", true);
+ PyObjectHandle category = getAttr(p, "category", true);
if(name.get())
{
if(!checkString(name.get()))
diff --git a/python/modules/IcePy/Util.h b/python/modules/IcePy/Util.h
index 744a21fa6e2..ecf65dee05b 100644
--- a/python/modules/IcePy/Util.h
+++ b/python/modules/IcePy/Util.h
@@ -110,6 +110,13 @@ inline bool checkString(PyObject* p)
bool getStringArg(PyObject*, const std::string&, std::string&);
//
+// Get an object attribute having the given name. If allowNone is true, a value of Py_None is allowed, otherwise
+// a value of Py_None is treated as if the attribute is undefined (i.e., the function returns nil). The caller
+// must release the reference to the returned object.
+//
+PyObject* getAttr(PyObject*, const std::string&, bool allowNone);
+
+//
// Get the name of the current Python function.
//
std::string getFunction();
diff --git a/python/python/Ice.py b/python/python/Ice.py
index f7f18d96686..aa33ea3ad1a 100644
--- a/python/python/Ice.py
+++ b/python/python/Ice.py
@@ -796,16 +796,6 @@ define the enqueue method.'''
implementation to confirm the batching a this request.'''
pass
-class Dispatcher(object):
- '''Base class for a dispatcher. A subclass must define the dispatch method.'''
-
- def __init__(self):
- pass
-
- def dispatch(call, con):
- '''Invoked when a call needs to be dispatched. Invoke call() from the desired thread.'''
- pass
-
class BatchRequestInterceptor(object):
'''Base class for batch request interceptor. A subclass must
define the enqueue method.'''
@@ -829,18 +819,28 @@ properties: An instance of Ice.Properties. You can use the
logger: An instance of Ice.Logger.
-threadHook: An object that implements ThreadNotification.
+threadStart: A callable that is invoked for each new Ice thread that is started.
+
+threadStop: A callable that is invoked when an Ice thread is stopped.
-dispatcher: An object that implements Dispatcher.
+dispatcher: A callable that is invoked when Ice needs to dispatch an activity. The callable
+ receives two arguments: a callable and an Ice.Connection object. The dispatcher must
+ eventually invoke the callable with no arguments.
-batchRequestInterceptor: An object that implements BatchRequestInterceptor.
+batchRequestInterceptor: A callable that will be invoked when a batch request is queued.
+ The callable receives three arguments: a BatchRequest object, an integer representing
+ the number of requests in the queue, and an integer representing the number of bytes
+ consumed by the requests in the queue. The interceptor must eventually invoke the
+ enqueue method on the BatchRequest object.
valueFactoryManager: An object that implements ValueFactoryManager.
'''
def __init__(self):
self.properties = None
self.logger = None
- self.threadHook = None
+ self.threadHook = None # Deprecated.
+ self.threadStart = None
+ self.threadStop = None
self.dispatcher = None
self.batchRequestInterceptor = None
self.valueFactoryManager = None
diff --git a/python/test/Ice/dispatcher/Client.py b/python/test/Ice/dispatcher/Client.py
index e885ab31545..1047a56e082 100755
--- a/python/test/Ice/dispatcher/Client.py
+++ b/python/test/Ice/dispatcher/Client.py
@@ -37,7 +37,8 @@ try:
#
initData.properties.setProperty("Ice.TCP.SndSize", "50000");
- initData.dispatcher = Dispatcher.Dispatcher()
+ d = Dispatcher.Dispatcher()
+ initData.dispatcher = d.dispatch
with Ice.initialize(sys.argv, initData) as communicator:
status = run(sys.argv, communicator)
diff --git a/python/test/Ice/dispatcher/Dispatcher.py b/python/test/Ice/dispatcher/Dispatcher.py
index 1f4fa4ee1e4..809f7500920 100755
--- a/python/test/Ice/dispatcher/Dispatcher.py
+++ b/python/test/Ice/dispatcher/Dispatcher.py
@@ -14,7 +14,7 @@ def test(b):
if not b:
raise RuntimeError('test assertion failed')
-class Dispatcher(Ice.Dispatcher):
+class Dispatcher:
def __init__(self):
self._calls = []
self._terminated = False
diff --git a/python/test/Ice/dispatcher/Server.py b/python/test/Ice/dispatcher/Server.py
index 59c9438eaa6..f706e6d7783 100755
--- a/python/test/Ice/dispatcher/Server.py
+++ b/python/test/Ice/dispatcher/Server.py
@@ -52,7 +52,8 @@ try:
#
initData.properties.setProperty("Ice.TCP.RcvSize", "50000")
- initData.dispatcher = Dispatcher.Dispatcher()
+ d = Dispatcher.Dispatcher()
+ initData.dispatcher = d.dispatch
with Ice.initialize(sys.argv, initData) as communicator:
status = run(sys.argv, communicator)
diff --git a/python/test/Ice/thread/AllTests.py b/python/test/Ice/thread/AllTests.py
new file mode 100644
index 00000000000..a469d4a7c18
--- /dev/null
+++ b/python/test/Ice/thread/AllTests.py
@@ -0,0 +1,64 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2017 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.
+#
+# **********************************************************************
+
+import Ice, Test, sys, TestI
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+def allTests(communicator):
+
+ ref = "factory:default -p 12010 -t 10000"
+ factory = Test.RemoteCommunicatorFactoryPrx.checkedCast(communicator.stringToProxy(ref))
+
+ sys.stdout.write("testing thread hooks... ")
+ sys.stdout.flush()
+
+ #
+ # Set the maximum size of the server-side thread pool in the new communicator to 5.
+ #
+ props = {}
+ props["Ice.ThreadPool.Server.SizeMax"] = "5"
+ com = factory.createCommunicator(props)
+
+ obj = com.getObject()
+
+ startCount = com.getThreadHookStartCount()
+
+ #
+ # Start 5 async invocations that sleep for a little while to force new threads to be created.
+ #
+ reqs = []
+ for i in range(0, 5):
+ reqs.append(obj.sleepAsync(100))
+ for f in reqs:
+ f.result()
+
+ #
+ # The remote thread hook should detect at least 4 more threads. There could be more for other Ice threads.
+ #
+ test(com.getThreadHookStartCount() - startCount >= 4)
+ test(com.getThreadStartCount() - startCount >= 4)
+
+ #
+ # Destroy the remote communicator to force the destruction of the thread pool.
+ #
+ com.destroy()
+
+ #
+ # Finally, make sure we detected the same number of stops as starts.
+ #
+ test(com.getThreadHookStopCount() == com.getThreadHookStartCount())
+ test(com.getThreadStopCount() == com.getThreadStartCount())
+ test(com.getThreadHookStartCount() == com.getThreadStartCount())
+
+ print("ok")
+
+ factory.shutdown()
diff --git a/python/test/Ice/thread/Client.py b/python/test/Ice/thread/Client.py
new file mode 100644
index 00000000000..65174adc68a
--- /dev/null
+++ b/python/test/Ice/thread/Client.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2017 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.
+#
+# **********************************************************************
+
+import os, sys, traceback
+import Ice
+
+slice_dir = Ice.getSliceDir()
+if not slice_dir:
+ print(sys.argv[0] + ': Slice directory not found.')
+ sys.exit(1)
+
+Ice.loadSlice("'-I" + slice_dir + "' Test.ice")
+import AllTests
+
+def test(b):
+ if not b:
+ raise RuntimeError('test assertion failed')
+
+def run(args, communicator):
+ AllTests.allTests(communicator)
+ return True
+
+try:
+ with Ice.initialize(sys.argv) as communicator:
+ status = run(sys.argv, communicator)
+except:
+ traceback.print_exc()
+ status = False
+
+sys.exit(not status)
diff --git a/python/test/Ice/thread/Server.py b/python/test/Ice/thread/Server.py
new file mode 100644
index 00000000000..adc448c6396
--- /dev/null
+++ b/python/test/Ice/thread/Server.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# **********************************************************************
+#
+# Copyright (c) 2003-2017 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.
+#
+# **********************************************************************
+
+import os, sys, traceback
+import Ice
+
+slice_dir = Ice.getSliceDir()
+if not slice_dir:
+ print(sys.argv[0] + ': Slice directory not found.')
+ sys.exit(1)
+
+Ice.loadSlice("'-I" + slice_dir + "' Test.ice")
+import Test, TestI
+
+def run(args, communicator):
+ communicator.getProperties().setProperty("TestAdapter.Endpoints", "default -p 12010 -t 10000");
+ adapter = communicator.createObjectAdapter("TestAdapter");
+ ident = Ice.stringToIdentity("factory");
+ adapter.add(TestI.RemoteCommunicatorFactoryI(), ident);
+ adapter.activate();
+
+ communicator.waitForShutdown();
+ return True;
+
+try:
+ with Ice.initialize(sys.argv) as communicator:
+ status = run(sys.argv, communicator)
+except:
+ traceback.print_exc()
+ status = False
+
+sys.exit(not status)
diff --git a/python/test/Ice/thread/Test.ice b/python/test/Ice/thread/Test.ice
new file mode 100644
index 00000000000..8e1bb3fda39
--- /dev/null
+++ b/python/test/Ice/thread/Test.ice
@@ -0,0 +1,45 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2017 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.
+//
+// **********************************************************************
+
+#ifndef TEST_ICE
+#define TEST_ICE
+
+#include <Ice/Properties.ice>
+
+module Test
+{
+
+interface TestIntf
+{
+ void sleep(int ms);
+};
+
+interface RemoteCommunicator
+{
+ TestIntf* getObject();
+
+ int getThreadHookStartCount();
+ int getThreadHookStopCount();
+
+ int getThreadStartCount();
+ int getThreadStopCount();
+
+ void destroy();
+};
+
+interface RemoteCommunicatorFactory
+{
+ RemoteCommunicator* createCommunicator(Ice::PropertyDict props);
+
+ void shutdown();
+};
+
+};
+
+#endif
diff --git a/python/test/Ice/thread/TestI.py b/python/test/Ice/thread/TestI.py
new file mode 100644
index 00000000000..5270f46ec64
--- /dev/null
+++ b/python/test/Ice/thread/TestI.py
@@ -0,0 +1,106 @@
+# **********************************************************************
+#
+# Copyright (c) 2003-2017 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.
+#
+# **********************************************************************
+
+import Ice, Test, time, threading
+
+class ThreadHook(Ice.ThreadNotification):
+ def __init__(self):
+ self.threadHookStartCount = 0
+ self.threadHookStopCount = 0
+ self.threadStartCount = 0
+ self.threadStopCount = 0
+ self.cond = threading.Condition()
+
+ def start(self):
+ with self.cond:
+ self.threadHookStartCount += 1
+
+ def stop(self):
+ with self.cond:
+ self.threadHookStopCount += 1
+
+ def threadStart(self):
+ with self.cond:
+ self.threadStartCount += 1
+
+ def threadStop(self):
+ with self.cond:
+ self.threadStopCount += 1
+
+ def getThreadHookStartCount(self):
+ with self.cond:
+ return self.threadHookStartCount
+
+ def getThreadHookStopCount(self):
+ with self.cond:
+ return self.threadHookStopCount
+
+ def getThreadStartCount(self):
+ with self.cond:
+ return self.threadStartCount
+
+ def getThreadStopCount(self):
+ with self.cond:
+ return self.threadStopCount
+
+class TestIntfI(Test._TestIntfDisp):
+ def sleep(self, ms, current = None):
+ time.sleep(ms / 1000.0)
+
+class RemoteCommunicatorI(Test._RemoteCommunicatorDisp):
+ def __init__(self, communicator, hook):
+ self.communicator = communicator
+ self.hook = hook
+ oa = communicator.createObjectAdapterWithEndpoints("", "default")
+ self.obj = Test.TestIntfPrx.uncheckedCast(oa.addWithUUID(TestIntfI()))
+ oa.activate()
+
+ def getObject(self, current = None):
+ return self.obj
+
+ def getThreadHookStartCount(self, current = None):
+ return self.hook.getThreadHookStartCount()
+
+ def getThreadHookStopCount(self, current = None):
+ return self.hook.getThreadHookStopCount()
+
+ def getThreadStartCount(self, current = None):
+ return self.hook.getThreadStartCount()
+
+ def getThreadStopCount(self, current = None):
+ return self.hook.getThreadStopCount()
+
+ def destroy(self, current = None):
+ self.communicator.destroy()
+
+class RemoteCommunicatorFactoryI(Test._RemoteCommunicatorFactoryDisp):
+
+ def createCommunicator(self, props, current = None):
+ #
+ # Prepare the property set using the given properties.
+ #
+ init = Ice.InitializationData()
+ init.properties = Ice.createProperties()
+ for k, v in props.items():
+ init.properties.setProperty(k, v)
+
+ init.threadHook = ThreadHook()
+ init.threadStart = init.threadHook.threadStart
+ init.threadStop = init.threadHook.threadStop
+
+ #
+ # Initialize a new communicator.
+ #
+ communicator = Ice.initialize(init)
+
+ proxy = current.adapter.addWithUUID(RemoteCommunicatorI(communicator, init.threadHook))
+ return Test.RemoteCommunicatorPrx.uncheckedCast(proxy)
+
+ def shutdown(self, current = None):
+ current.adapter.getCommunicator().shutdown()