Fix IPyKernel restarting

This commit is contained in:
Florian Märkl 2018-02-23 17:42:54 +01:00 committed by xarkes
parent 06dffde0fe
commit b45314fd19
6 changed files with 49 additions and 8 deletions

View File

@ -3,6 +3,7 @@ import logging
import threading import threading
import signal import signal
import cutter_internal import cutter_internal
import zmq
from ipykernel.kernelapp import IPKernelApp from ipykernel.kernelapp import IPKernelApp
from ipykernel.ipkernel import IPythonKernel from ipykernel.ipkernel import IPythonKernel
@ -28,6 +29,16 @@ class IPyKernelInterfaceKernel:
else: else:
return 0 return 0
def cleanup(self):
self._app.heartbeat.context.destroy()
self._thread.join()
self._app.heartbeat.join()
self._app.iopub_thread.stop()
self._app.kernel.shell.history_manager.save_thread.stop()
zmq.Context.instance().destroy()
# successful if only the main thread remains
return len(threading.enumerate()) == 1
class CutterIPythonKernel(IPythonKernel): class CutterIPythonKernel(IPythonKernel):
def __init__(self, **kwargs): def __init__(self, **kwargs):

View File

@ -156,3 +156,29 @@ NestedIPyKernel *JupyterConnection::getNestedIPyKernel(long id)
} }
return *it; return *it;
} }
QVariant JupyterConnection::pollNestedIPyKernel(long id)
{
auto it = kernels.find(id);
if(it == kernels.end())
{
return QVariant(0);
}
NestedIPyKernel *kernel = *it;
QVariant v = kernel->poll();
if(!v.isNull())
{
// if poll of kernel returns anything but None, it has already quit and should be cleaned up
PyThreadState *subinterpreterState = kernel->getThreadState();
delete kernel;
kernels.erase(it);
PyThreadState *parentThreadState = PyThreadState_Swap(subinterpreterState);
Py_EndInterpreter(subinterpreterState);
PyThreadState_Swap(parentThreadState);
}
return v;
}

View File

@ -26,6 +26,7 @@ public:
long startNestedIPyKernel(const QStringList &argv); long startNestedIPyKernel(const QStringList &argv);
NestedIPyKernel *getNestedIPyKernel(long id); NestedIPyKernel *getNestedIPyKernel(long id);
QVariant pollNestedIPyKernel(long id);
signals: signals:
void urlReceived(const QString &url); void urlReceived(const QString &url);

View File

@ -62,6 +62,13 @@ NestedIPyKernel::NestedIPyKernel(PyObject *cutterIPykernelModule, const QStringL
NestedIPyKernel::~NestedIPyKernel() NestedIPyKernel::~NestedIPyKernel()
{ {
auto parentThreadState = PyThreadState_Swap(threadState);
auto ret = PyObject_CallMethod(kernel, "cleanup", nullptr);
if (!ret)
{
PyErr_Print();
}
PyThreadState_Swap(parentThreadState);
} }
void NestedIPyKernel::sendSignal(long signum) void NestedIPyKernel::sendSignal(long signum)

View File

@ -20,6 +20,8 @@ public:
void sendSignal(long signum); void sendSignal(long signum);
QVariant poll(); QVariant poll();
PyThreadState *getThreadState() { return threadState; }
private: private:
NestedIPyKernel(PyObject *cutterIPykernelModule, const QStringList &argv); NestedIPyKernel(PyObject *cutterIPykernelModule, const QStringList &argv);

View File

@ -110,13 +110,7 @@ PyObject *api_internal_kernel_interface_poll(PyObject *, PyObject *args)
return nullptr; return nullptr;
} }
NestedIPyKernel *kernel = Jupyter()->getNestedIPyKernel(id); QVariant v = Jupyter()->pollNestedIPyKernel(id);
if(!kernel)
{
return PyLong_FromLong(0);
}
QVariant v = kernel->poll();
bool ok; bool ok;
auto ret = static_cast<long>(v.toLongLong(&ok)); auto ret = static_cast<long>(v.toLongLong(&ok));
if(ok) if(ok)