Skip to content

Commit

Permalink
Make more threadsafe by using Queue. Also add a few binaries that wer…
Browse files Browse the repository at this point in the history
…e causing windows to fail without. Should fix #32
  • Loading branch information
quinnj committed Feb 27, 2014
1 parent 9ad0cec commit ef521ef
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 22 deletions.
13 changes: 4 additions & 9 deletions IJulia.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os, time, sublime, sublime_plugin
from . import KernelManager
from . import Kernel

SETTINGS_FILE = 'Sublime-IJulia.sublime-settings'

Expand Down Expand Up @@ -50,9 +50,9 @@ def remove_ijulia_view(self, view):
class IJuliaView(object):
def start_kernel(self):
print("Starting IJulia backend...")
self.kernel = KernelManager.KernelManager(self.id,self.cmd,self)
self.kernel = Kernel.Kernel(self.id,self.cmd,self)
self.kernel.start()
self.kernel.execute("Base.banner()")
self.kernel.queue.put_nowait("Base.banner()")

def __init__(self, view, id, cmd):
self.id = id
Expand Down Expand Up @@ -178,18 +178,13 @@ def enter(self, edit):
v.sel().add(sublime.Region(v.size()))
v.run_command("i_julia_insert_text", {"pos": v.sel()[0].begin(), "text": '\n'})
command = self.user_input
#v.run_command("insert", {"characters": '\n'})
self._output_end += len(command)
self.stdout_pos = self._output_end
manager.cmdhist.insert(0,command[:-1])
manager.cmdhist = list(self.unique(manager.cmdhist))
self.cmdstate = -1
self.command = command
self.execute()
self.kernel.queue.put_nowait(command)

def execute(self):
self.kernel.execute(self.command)

def stdout_output(self, data):
data = data.replace('\r\n','\n')
self._view.run_command("i_julia_insert_text",
Expand Down
51 changes: 38 additions & 13 deletions KernelManager.py → Kernel.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import os, subprocess, threading, time, json
import os, subprocess, threading, time, json, sys, queue
from ctypes import *
from subprocess import Popen
debug = 0
Expand All @@ -11,13 +11,19 @@ def plugin_loaded():
global zmq
if not debug:
settings = sublime.load_settings(SETTINGS_FILE)
cmd = os.path.expanduser(settings.get(sublime.platform())["zmq_shared_library"])
if os.path.exists(cmd):
zmq = cdll.LoadLibrary(cmd)
elif os.path.exists(cmd.replace("/v0.3","")):
zmq = cdll.LoadLibrary(cmd.replace("/v0.3",""))
plat = sublime.platform()
cmd = settings.get(plat)
if plat == "windows":
p = os.path.dirname(__file__) + '/windeps/'
print(p)
os.environ['PATH'] = p + ';' + os.environ['PATH']
zmq_lib = os.path.expanduser(cmd["zmq_shared_library"])
if os.path.exists(zmq_lib):
zmq = cdll.LoadLibrary(zmq_lib)
elif os.path.exists(zmq_lib.replace("/v0.3","")):
zmq = cdll.LoadLibrary(zmq_lib.replace("/v0.3",""))
else:
sublime.error_message("ZMQ Shared Library not found at %s" % cmd)
sublime.error_message("ZMQ Shared Library not found at %s" % zmq_lib)
else:
zmq = cdll.LoadLibrary('C:/Users/karbarcca/.julia/v0.3/ZMQ/deps/usr/lib/libzmq.dll')
#Return types
Expand All @@ -28,11 +34,13 @@ def plugin_loaded():
zmq.zmq_connect.restype = c_int
zmq.zmq_close.restype = c_int
zmq.zmq_send.restype = c_int
zmq.zmq_msg_init.restype = c_int
zmq.zmq_msg_recv.restype = c_int
zmq.zmq_msg_size.restype = c_size_t
zmq.zmq_msg_close.restype = c_int
zmq.zmq_strerror.restype = c_char_p
zmq.zmq_msg_init.restype = c_int
zmq.zmq_errno.restype = c_int
zmq.zmq_ctx_destroy.restype = c_int
#Argtypes
zmq.zmq_socket.argtypes = [c_void_p, c_int]
zmq.zmq_setsockopt.argtypes = [c_void_p, c_int, c_void_p, c_size_t]
Expand All @@ -43,6 +51,8 @@ def plugin_loaded():
zmq.zmq_msg_recv.argtypes = [POINTER(_Message), c_void_p, c_int]
zmq.zmq_msg_data.argtypes = [POINTER(_Message)]
zmq.zmq_msg_size.argtypes = [POINTER(_Message)]
zmq.zmq_msg_close.argtypes = [POINTER(_Message)]
zmq.zmq_ctx_destroy.argtypes = [c_void_p]

def zmq_error():
err = zmq.zmq_errno()
Expand Down Expand Up @@ -77,7 +87,6 @@ def zmq_profile(filename, id):
class _Message(Structure):
_fields_ = [("_", c_ubyte * 32)]

#MSG_NULL =
class Message(object):
def __init__(self):
self.msg = _Message()
Expand All @@ -103,6 +112,9 @@ def __init__(self):
self.ptr = zmq.zmq_ctx_new()
self.sockets = []

def close(self):
zmq.zmq_ctx_destroy(self.ptr)

class Socket(object):
def __init__(self, context, sock_type):
self.ptr = zmq.zmq_socket(context.ptr, sock_type)
Expand Down Expand Up @@ -150,6 +162,7 @@ def recv_msg_bytes(self):
zmq.zmq_msg_recv(byref(m.msg),self.ptr,NOBLOCK)
data = zmq.zmq_msg_data(byref(m.msg))
length = zmq.zmq_msg_size(byref(m.msg))
zmq.zmq_msg_close(byref(m.msg))
return data[:length]
else:
return ''
Expand All @@ -160,6 +173,7 @@ def recv_msg(self):
zmq.zmq_msg_recv(byref(m.msg),self.ptr,NOBLOCK)
data = zmq.zmq_msg_data(byref(m.msg))
length = zmq.zmq_msg_size(byref(m.msg))
zmq.zmq_msg_close(byref(m.msg))
return data[:length].decode()
else:
return ''
Expand Down Expand Up @@ -198,13 +212,16 @@ def recv_block(self):
m = Msg(idents, json.loads(header), json.loads(content), json.loads(parent_header), json.loads(metadata))
return m

class KernelManager(threading.Thread):
class Kernel(threading.Thread):
def __init__(self, id, cmd, jv):
super(KernelManager, self).__init__()
super(Kernel, self).__init__()
self.id = id
e = os.path.expanduser
ju = e(cmd['julia'])
iju = e(cmd['ijulia_kernel'])
if 'julia_type' in cmd and 'binary' in cmd['julia_type']:
p = os.path.dirname(cmd['julia'])
os.environ['PATH'] += p
if not os.path.exists(iju):
if not os.path.exists(iju.replace("/v0.3","")):
sublime.error_message("IJulia kernel.jl file not found at %s" % iju)
Expand Down Expand Up @@ -232,9 +249,11 @@ def __init__(self, id, cmd, jv):
self.shell.connect(ip + str(profile['shell_port']))
self.sub = Socket(self.context, SUB)
self.sub.connect(ip + str(profile['iopub_port']))
self.queue = queue.Queue()
self.jv = jv
self.startup = 1
self.liveness = 5
self.idle = True
self.handlers = {'': self.emp_h,
'pyin': self.pyin_h,
'pyout': self.pyout_h,
Expand Down Expand Up @@ -335,7 +354,6 @@ def emp_h(self):
self.kernel.poll()
if self.kernel.returncode != None:
return 0
#sublime.error_message('IJulia Kernel failed to start. Check your "julia_command" value in the Sublime-IJulia package settings or through the custom command interface. Otherwise, please open an issue to troubleshoot: https://github.com/karbarcca/Sublime-IJulia/issues?state=open')
return 1
elif response or r:
return 1
Expand Down Expand Up @@ -371,8 +389,10 @@ def status_h(self):
if status == 'idle':
self.jv.in_output()
self.jv._view.set_status("kernel","")
self.idle = True
else:
self.jv._view.set_status("kernel","IJulia kernel is working...")
self.idle = False
return 1

def display_data_h(self):
Expand All @@ -382,7 +402,11 @@ def display_data_h(self):

def run(self):
l = self.liveness
q = self.queue
while True:
if self.idle and not q.empty():
code = q.get_nowait()
self.execute(code)
self.shell.recv_msg()
m = self.sub.recv_msg()
r = self.handlers.get(m, self.pyin_h)()
Expand All @@ -394,8 +418,9 @@ def run(self):
if l == 0:
print("Kernel died, closing sockets....")
self.heartbeat.close()
self.sub.close()
self.shell.close()
self.sub.close()
print("Sockets closed...")
self.jv.on_close()
self.context.close()
break
Binary file added windeps/libgcc_s_seh-1.dll
Binary file not shown.
Binary file added windeps/libstdc++-6.dll
Binary file not shown.

0 comments on commit ef521ef

Please sign in to comment.