Skip to content

Fix for issue 78 #117

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 38 additions & 14 deletions dyalog_kernel/kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import subprocess
import re
import html
import signal

from collections import deque

Expand Down Expand Up @@ -136,6 +137,34 @@ def out_stream(self, s):
}
self.send_response(self.iopub_socket, 'stream', _content)

def cleanup_dyalog(self):
try:
if DYALOG_HOST == '127.0.0.1':
if self.connected and hasattr(self, 'dyalogTCP'):
self.ride_send(["Exit", {"code": 0}])
if self.dyalog_subprocess:
# Graceful termination
self.dyalog_subprocess.terminate()
try:
self.dyalog_subprocess.wait(timeout=3)
except subprocess.TimeoutExpired:
# Force kill if graceful termination fails
self.dyalog_subprocess.kill()
self.dyalog_subprocess.wait()

if hasattr(self, 'dyalogTCP'):
self.dyalogTCP.close()

self.connected = False

except Exception as e:
debug(f"Error in cleanup_dyalog: {e}")

def signal_handler(self, signum, frame):
debug(f"Received signal {signum}, cleaning up...")
self.cleanup_dyalog()
sys.exit(0)

def dyalog_ride_connect(self):

timeout = time.time() + RIDE_INIT_CONNECT_TIME_OUT
Expand Down Expand Up @@ -196,7 +225,11 @@ def __init__(self, **kwargs):
#from ipykernel import get_connection_file
#s = get_connection_file()
# debug("########## " + str(s))


# Register signal handlers and cleanup
signal.signal(signal.SIGTERM, self.signal_handler)
signal.signal(signal.SIGINT, self.signal_handler)

self._port = DYALOG_PORT
# lets find an available port
# this makes sense only if Dyalog APL and Jupyter executables are on the same host (localhost)
Expand Down Expand Up @@ -229,15 +262,15 @@ def __init__(self, **kwargs):
CloseKey(dyalogKey)
CloseKey(lastKey)
self.dyalog_subprocess = subprocess.Popen([dyalogPath, "RIDE_SPAWNED=1", "DYALOGQUIETUCMDBUILD=1", "Dyalog_LineEditor_Mode=1", 'RIDE_INIT=SERVE::' + str(
self._port).strip(), 'LOG_FILE=nul', "DYALOGJUPYFOLDER=" + os.path.dirname(os.path.abspath(__file__)), "LOAD="+os.path.dirname(os.path.abspath(__file__))+"\\init.aplf"])
self._port).strip(), 'LOG_FILE_INUSE=0', "DYALOGJUPYFOLDER=" + os.path.dirname(os.path.abspath(__file__)), "LOAD="+os.path.dirname(os.path.abspath(__file__))+"\\init.aplf"])
else:
# linux, darwin... etc
dyalog_env = os.environ.copy()
dyalog_env['RIDE_INIT'] = 'SERVE:*:' + str(self._port).strip()
dyalog_env['RIDE_SPAWNED'] = '1'
dyalog_env['DYALOGQUIETUCMDBUILD'] = '1'
dyalog_env['ENABLE_CEF'] = '0'
dyalog_env['LOG_FILE'] = '/dev/null'
dyalog_env['LOG_FILE_INUSE'] = '0'
dyalog_env['DYALOG_LINEEDITOR_MODE'] = '1'
dyalog_env['DYALOGJUPYFOLDER'] = os.path.dirname(os.path.abspath(__file__))
if shutil.which('mapl'):
Expand Down Expand Up @@ -498,14 +531,5 @@ def define_function(self, lines):

def do_shutdown(self, restart):
# shutdown Dyalog executable only if Jupyter kernel has started it.

if DYALOG_HOST == '127.0.0.1':
if self.connected:
self.ride_send(["Exit", {"code": 0}])
# time.sleep(2)
# if self.dyalog_subprocess:
# self.dyalog_subprocess.kill()

self.dyalogTCP.close()
self.connected = False
return {'status': 'ok', 'restart': restart}
self.cleanup_dyalog()
return {'status': 'ok', 'restart': restart}