When there are multiple processes and an interrupt is sent, lisp(openmcl in my case) needs to know which process to interrupt. So when the interrupt is being processed I need to ask emacs for that information before choosing the process to interrupt. What's the proper way to do that?
Also regarding multiple processes: I'm running portable aserve and would like to be able to have errors that occur in the server processes create a slime debugger instance. Is there a way to set that up, given that those processes are not associated with a repl?
Thanks, Alan
Alan Ruttenberg alanralanr@comcast.net writes:
When there are multiple processes and an interrupt is sent, lisp(openmcl in my case) needs to know which process to interrupt. So when the interrupt is being processed I need to ask emacs for that information before choosing the process to interrupt. What's the proper way to do that?
I don't think there is a proper way as of today. The Emacs side has no notion of threads, so is there anything useful it can tell Lisp at all?
How will you interrupt a specific thread in OpenMCL? Do they each have their own OS PID such that you could SIGINT the right one, or is it necessary to do a (interrupt-thread T) sort of call inside Lisp? (I think the first will work in SBCL and the second will be needed in CMUCL).
If the second, a temporary hack could be to have Emacs send e.g. SIGUSR1 and Lisp have a handler that knows to interrupt the Swank request-handler thread, or something..
Also regarding multiple processes: I'm running portable aserve and would like to be able to have errors that occur in the server processes create a slime debugger instance. Is there a way to set that up, given that those processes are not associated with a repl?
We have no reliable way to do this. The unreliable (kinda okay with SERVE-EVENT, probably suicide with threads) is in .emacs:
(setq slime-global-debugger-hook t)
That way *DEBUGGER-HOOK* will be globally bound to contact Emacs, always using the same connection, come-what-may. My previous attempt at multiprocessing support just added locks to this so that only one thread would talk to Emacs at a time.
But hopefully the multiple-session support will fix all this. Today it would be possible for Emacs to connect to multiple Swank servers each run by a different thread in the same Lisp. The trick is just to hack in support for creating these extra connections on-demand (e.g. when a thread hits the debugger). I was planning to hack that up on the weekend if I get time, but you're welcome to beat me to it too :-)
Cheers, Luke
On Jan 8, 2004, at 11:07 AM, Luke Gorrie wrote:
Alan Ruttenberg alanralanr@comcast.net writes:
When there are multiple processes and an interrupt is sent, lisp(openmcl in my case) needs to know which process to interrupt. So when the interrupt is being processed I need to ask emacs for that information before choosing the process to interrupt. What's the proper way to do that?
I don't think there is a proper way as of today. The Emacs side has no notion of threads, so is there anything useful it can tell Lisp at all?
I was thinking that you would interrupt only from a given repl. ccl::*current-process* in a repl gives you a handle on the thread. Could just make the process name or some other identifier a buffer local variable.
How will you interrupt a specific thread in OpenMCL? Do they each have their own OS PID such that you could SIGINT the right one, or is it necessary to do a (interrupt-thread T) sort of call inside Lisp? (I think the first will work in SBCL and the second will be needed in CMUCL).
Openmcl only knows which thread to interrupt through a global variable that is checked during the housekeeping routine that notices that there was an interrupt. In the one repl world I was setting that variable when the connection was being opened.
My thought was that when you run slime-interrupt you record the repl from which it was executed. Then when lisp processes the interrupt instead of looking at it's global it makes a call back to emacs asking for the name of the process associated with the repl from which slime interrupt was called. It's basically another oob event except it needs to get a string response.
If the second, a temporary hack could be to have Emacs send e.g. SIGUSR1 and Lisp have a handler that knows to interrupt the Swank request-handler thread, or something..
Also regarding multiple processes: I'm running portable aserve and would like to be able to have errors that occur in the server processes create a slime debugger instance. Is there a way to set that up, given that those processes are not associated with a repl?
We have no reliable way to do this. The unreliable (kinda okay with SERVE-EVENT, probably suicide with threads) is in .emacs:
(setq slime-global-debugger-hook t)
That way *DEBUGGER-HOOK* will be globally bound to contact Emacs, always using the same connection, come-what-may. My previous attempt at multiprocessing support just added locks to this so that only one thread would talk to Emacs at a time.
But hopefully the multiple-session support will fix all this. Today it would be possible for Emacs to connect to multiple Swank servers each run by a different thread in the same Lisp. The trick is just to hack in support for creating these extra connections on-demand (e.g. when a thread hits the debugger). I was planning to hack that up on the weekend if I get time, but you're welcome to beat me to it too :-)
Cheers, Luke
slime-devel site list slime-devel@common-lisp.net http://common-lisp.net/mailman/listinfo/slime-devel
On Thu, 8 Jan 2004, Alan Ruttenberg wrote:
On Jan 8, 2004, at 11:07 AM, Luke Gorrie wrote:
How will you interrupt a specific thread in OpenMCL? Do they each have their own OS PID such that you could SIGINT the right one, or is it necessary to do a (interrupt-thread T) sort of call inside Lisp? (I think the first will work in SBCL and the second will be needed in CMUCL).
Whether threads have PIDs or not depends on the OS's notion of what a thread is; on Linux they do (and Linux is gradually moving towards the realization that not all PIDs are created equal); on OSX, threads are primitive objects in the Mach kernel.
PROCESS-INTERRUPT in OpenMCL is implemented in terms of pthread_kill() with a distinguished signal number; under Linux, pthread_kill() happens to be implemented in terms of kill() sent to the pthread's PID. However it's implemented, the signal was targeted to a specific thread and the handler for that signal runs on that thread.
Openmcl only knows which thread to interrupt through a global variable that is checked during the housekeeping routine that notices that there was an interrupt. In the one repl world I was setting that variable when the connection was being opened.
SIGINT (from the keyboard or via kill()) is generally delivered to an OS process; when threads are involved, that generally means that the SIGINT handler runs on some arbitrary thread in the process (pretty much any thread that the OS feels like sending it to, as long as the thread doesn't mask SIGINT.) The global variable Alan mentions is used by lisp code that notices a recent SIGINT, so SIGINT is interpreted as an IPC request to the "OS process as a whole" to interrupt what it deems to be the most appropriate thread. (Clearly, the correct implementation of SIGINT is "interrupt the thread that the user thinks it will", and the global variable's just a way of crudlely approximating the right thread.)
Asynchronous signals tend not to carry much information; it's not clear that we could use them to implement IPC requests that asked another OS process to interrupt a specific thread. I'm not sure what kind of IPC mechanisms SWANK/SLIME already provide that might deal with the "OS process as a whole", but the lisp side of it could just involve a thread that listens for IPC requests over a socket that's created when SLIME first starts the lisp OS process. Or something.
(defvar *slime-control-socket* ... "created when SLIME starts the OS process")
(defun slime-control-loop () (loop (multiple-value-bind (request-type request-data) (read-slime-ipc-request *slime-control-socket*) (case request-type (:process-interrupt (ccl:process-interrupt (ccl:find-thread request-data) #'(lambda () ...))) (t (error "This mechanism may be overkill ..."))))))
Gary Byers gb@clozure.com
Hi Gary,
Thanks for the nice description of how threading works.
Asynchronous signals tend not to carry much information; it's not clear that we could use them to implement IPC requests that asked another OS process to interrupt a specific thread. I'm not sure what kind of IPC mechanisms SWANK/SLIME already provide that might deal with the "OS process as a whole", but the lisp side of it could just involve a thread that listens for IPC requests over a socket that's created when SLIME first starts the lisp OS process. Or something.
(defvar *slime-control-socket* ... "created when SLIME starts the OS process")
This seems likely the way to go. With the "socket per thread" plan we already need a control channel so that a Lisp thread hitting the debugger can ask Emacs to open a connection (Emacs can't portably accept incoming ones). Hopefully we can kill two birds with one stone.
It's interesting trying to make sure that designs work with single-threaded, single-threaded+SERVE-EVENT, and multithreaded. In this case I think it's simple and we'll only use a control connection in the multithreaded case.
-Luke