Re: Interrupting repl in Slime
Alessio Stalla <[email protected]> Mon, 11 Apr 2022 07:00:51 +0200
| Newsgroups | gmane.editors.j.devel |
|---|---|
| Message-ID | <CAL2Kp+gJCUxgVvnjiUqkfnS7sms2zhJG-LP2-Jqq0Zw7Tr2jog@mail.gmail.com> |
I don't get why ABCL needs a volatile flag where it could just use Thread.interrupted() ( https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupted--). I guess the latter cannot be less efficient than a userland solution like ABCL's. On Mon, 11 Apr 2022 at 04:32, Alan Ruttenberg <[email protected]> wrote: > Ok, I think I cracked it. Check out > https://github.com/armedbear/abcl/pull/482 > Alan > > > On Thu, Apr 7, 2022 at 9:26 PM Alan Ruttenberg <[email protected]> > wrote: > >> >> Some more: This is where the code for checking for interrupt is generated >> (defun maybe-generate-interrupt-check () >> (unless (> *speed* *safety*) >> (let ((label1 (gensym))) >> >> * (emit-getstatic +lisp+ "interrupted" :boolean) (emit 'ifeq label1)* >> (emit-invokestatic +lisp+ "handleInterrupt" nil nil) >> (label label1)))) >> >> I'm thinking, since interrupt-lisp isn't used anyways, modify it to take >> a thread argument. >> In interrupt-lisp, call setInterrupted with that thread. >> In Lisp.java change the type of interrupted and change setInterrupted to >> take a thread argument, setting Lisp.interrupted to it. >> >> Then, in the maybe-generate-interrupt-check don't Lisp.interrupted check >> as boolean, check if eq to current thread. The current thread can be made >> accessible adding (ensure-thread-var-initialized), which puts it into a >> local at the beginning of the function. Access it with (aload *thread*) >> which puts it on the stack. I think this means that the lines underlined >> above get replaced with. >> >> (ensure-thread-var-initialized) >> (emit-getstatic +lisp+ "interrupted" +lisp-thread+) >> (aload *thread*) >> (emit 'if_acmpne label1) >> >> In Lisp.handleInterrupts it's setInterrupted(null) vs >> setInterrrupted(false); >> >> As stated, this mechanism is strictly to enable control-c. >> >> However, maybe we could have it help thread-interrupt respond more >> quickly. in Lisp.handleInterrupts. >> check thread.isInterrupted and call processThreadInterrupts (the thing >> that is done now) otherwise break. >> Have the implementation of thread-interrupt do what it does now and also >> call interrupt-lisp to get it noticed. >> --- >> >> I haven't tried this. Mostly I'm fumbling around trying to get enough >> information to do this. I don't know java byte code except what I learned >> researching this. >> I don't know if there are pitfalls. I don't know why something like this >> wouldn't have been done in the first place. >> >> The only thing I can currently think of is that there could be a race >> condition on setting Lisp.interrupted. >> The consequence of that is that if there were two quick >> thread-interrupts, only one of the threads would >> do the quick response. The other would be processed in the way it >> currently is. >> >> Anyways, comments solicited. >> Alan >> >> >> >> >> >> On Thu, Apr 7, 2022 at 1:21 PM Alan Ruttenberg <[email protected]> >> wrote: >> >>> The functions that ABCL uses in Threads.java are thread.interrupt and >>> thread.isInterrupted. It overrides interrupt and isInterrupted to implement >>> interrupt-thread - by saving away the function the target thread is to be >>> interrupted with. Remember, interrupt-thread isn't executed by the thread >>> to be interrupted, it's called from another thread. The receiving thread >>> handles InterruptedException, which is only called on explicit check of >>> interrupt state or from sleep or wait. >>> >>> Separately, in Lisp.Java there's setInterrupted and handleInterrupt that >>> don't use the java mechanism. Rather setInterrupted sets a static volatile >>> Lisp.interrupted, handleInterrupted clears the variable and calls break. >>> setInterrupted, as I said, is only called from interrupt-lisp. Code >>> generation inserts checks of Lisp.interrupted and calls handleInterrupted >>> if it is set. I have a feeling that this part was done so that frequent >>> interrupt checks could be made without taking the performance hit of a >>> synchronized method call. Remember this check is done inside every loop >>> iteration. The check for Lisp.interrupted is a volatile read, which in most >>> cases is handled in the cache. A write to the volatile invalidates the >>> cache forcing the new value to be read from memory. So much less expensive. >>> >>> It would be useful to know the history of how it came to be that there >>> are two different interrupt mechanisms. >>> >>> >>> >>> On Thu, Apr 7, 2022 at 7:21 AM Alessio Stalla <[email protected]> >>> wrote: >>> >>>> No, I mean >>>> https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#interrupted-- >>>> >>>> The only deprecated methods are suspend, resume and stop. The interrupt >>>> machinery is what developers are supposed to use (at least when not using >>>> some higher-level framework). It's a form of cooperative multitasking, >>>> since a thread can completely ignore the interrupt. However, given we have >>>> control over Lisp threads, we can play nice with that convention, and maybe >>>> offer a without-interrupts special form for performance-critical code where >>>> the developer assumes the responsibility of checking for interrupts in >>>> selected moments. >>>> >>>> On Thu, 7 Apr 2022 at 11:42, Mark Evenson <[email protected]> wrote: >>>> >>>>> >>>>> >>>>> > On Apr 7, 2022, at 08:22, Alessio Stalla <[email protected]> >>>>> wrote: >>>>> > >>>>> > […] Java threads already natively have an interrupt flag. >>>>> >>>>> Presumably, the [Thread.State enumeration] is what you are referring >>>>> to. I have checked that it is present in openjdk{8,11,17}, and not marked >>>>> as deprecated. >>>>> >>>>> [1]: >>>>> https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.State.html >>>>> >>>>> -- >>>>> "A screaming comes across the sky. It has happened before but there >>>>> is nothing >>>>> to compare to it now." >>>>> >>>>> >>>>> >>>>> >>>>> >>>>>