Skip to content
  • Alan Ruttenberg's avatar
    This commit makes interrupt-thread react quickly. · 9dfc5ad5
    Alan Ruttenberg authored
    What happens on interrupt
    -------------------------
    
    I'm assuming there's both a worker thread(w) and a control thread(c) running.
    
    Running in thread(c)
    
    Call (interrupt-thread thread(w) function args)
    thread(c).interruptThread unpacks the arguments into a list
    It then calls thread(w).interrupt(function, args)
    thread(w).interrupt pushes args and fun on thread(w) thread local variable pending
    it then call java's interrupt() method.
    
    If things are left alone, the java interrupt mechanism will at some
    point throw an InterruptedException when running inside thread(w) various
    lispThread functions catch the InterruptedException and call
    processThreadInterrupts()
    
    processThreadInterrupts() then runs the functions in the thread local
    variable pending.
    
    There's also one check that uses the java interrupt mechanism, a call to
    thread.isInterrupted(). So if thread(w) notices that it's been
    interrupted in this way it will also call processThreadInterrupts().
    
    BUT
    
    Java will only throw the exception when running functions like sleep or
    wait, so the exception won't be handled until one of those methods is
    called within thread(w). The call to isInterrupted() only happens once
    per function call. So if a function is in a loop, it could be a long
    time until the interrupt is handled.
    
    Meanwhile:
    
    Thread(w) is running. The compiler has thoughtfully inserted a check on
    a static variable Lisp.interrupted inside each iteration of a loop. If a
    global Lisp.interrupted get sets to true the compiler inserted code
    calls Lisp.handleInterupts().
    
    BUT
    
    Lisp.interrupted is never set in the normal course of events. There's a
    function to set it, interruptLisp() but no one calls it. interruptLisp
    calls Lisp.setInterrupted() which sets Lisp.interrupted to true.
    
    The change:
    
    We add another static Lisp.threadToInterrupt.
    
    We change setInterrupted() take the boolean but also a thread that you
    want interrupted.  We change handleInterrupts(), which used to call
    break() to check whether the current thread is equal to threadTointerrupt.
    When the current thread is thread(w), it call thread(w).processThreadInterrupts().
    
    Then, we change interruptLisp() to call Lisp.setInterrupted() with the
    thread to be interrupted.
    
    We don't want to have to call interruptLisp separately. So we
    call setInterrupted() directly in thread(c).interruptLisp().
    
    And we win.
    
    In slime, when you hit Control-c, it calls interrupt-thread with the
    function invoking the debugger.  With the change, interrupt-thread gets
    handled promptly and the debugger is called, even if we are in an
    infinite loop.
    9dfc5ad5