Re: native busy loop and thread-terminate!
Shiro Kawai <[email protected]> Mon, 27 Jan 2025 22:25:49 -1000
| Newsgroups | gmane.lisp.scheme.gauche |
|---|---|
| Message-ID | <CALN0JNH4-=P+McfNZ49VWj=HUPZj7n0m9nxpH-6d1KcMGS3UeQ@mail.gmail.com> |
--===============6726048499164378765== Content-Type: multipart/alternative; boundary="0000000000005e15e1062cbff12f" --0000000000005e15e1062cbff12f Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Aah, right. On Unix-based systems, thread-terminate! uses a signal to tell the target to terminate. It can't be intercepted by Scheme-level, but it is still queued by the receiving side, and only becomes effective when the thread calls Scm_SigCheck()---usually from the VM loop. I think the supposed way is that C extension code needs to invoke Scm_SigCheck() occasionally if it doesn't return control to Scheme. But that can't be enforced, especially if it's in the third party code. We can employ a similar handling mechanism like typing ^C several times to force gosh quit. That is, thread-terminate! resends thread termination signal after a short wait, and if the receiving side gets multiple termination signal queued, it terminates the thread then. On Mon, Jan 27, 2025 at 7:26=E2=80=AFAM Jens Thiele <[email protected]> wrote: > Hi, > > It looks like native busy loops are not interrupted by thread-terminate! > =3D> they have to cooperate. > > A first test below. Does that make sense? Is it ok to use > SCM_INTERNAL_MUTEX_LOCK/SCM_INTERNAL_MUTEX_UNLOCK/SCM_INTERNAL_THREAD_EXI= T > ? > > #!/bin/sh > #| -*- mode: scheme; coding: utf-8; -*- > exec gosh -I. -- $0 "$@" > |# > > ;; native busy loops are not interrupted by thread-terminate! > ;; =3D> they have to cooperate > > (use gauche.threads) > (use file.util) > (use runtime-compile) > > (compile-and-load > `((inline-stub > (define-cproc busy-loop () > (let* ((i::int 0)) > (while (1) > ;; you would do some calculations here > (inc! i) > ;; poll whether we have to terminate > ;; otherwise we keep running on thread-terminate! below > (when (not (% i 100000)) > (let* ((state::int 0)) > (SCM_INTERNAL_MUTEX_LOCK (-> (Scm_VM) vmlock)) > (set! state (-> (Scm_VM) state)) > (SCM_INTERNAL_MUTEX_UNLOCK (-> (Scm_VM) vmlock)) > (printf "%d %d %d\n" i state SCM_VM_TERMINATED) > (when (=3D=3D state SCM_VM_TERMINATED) > (SCM_INTERNAL_THREAD_EXIT))))))))) > '(busy-loop)) > > ;; todo: linux specific > (define (num-threads) > (guard (e > [else > +nan.0]) > (length (directory-list "/proc/self/task" :children? #t)))) > > (define (main args) > #?=3D(num-threads) > (let1 t (thread-start! (make-thread (lambda() > (busy-loop)))) > (sys-sleep 1) > #?=3D(num-threads) > (thread-terminate! t) > #?=3D(num-threads) > (guard (e [else #?=3De]) > (thread-join! t))) > #?=3D(num-threads) > (sys-sleep 1) > #?=3D(num-threads) > (sys-sleep 10) > 0) > > > _______________________________________________ > Gauche-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/gauche-devel > --0000000000005e15e1062cbff12f Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">Aah, right. On Unix-based systems, thread-terminate! uses = a signal to tell the target to terminate.=C2=A0 It can't be intercepted= by Scheme-level, but it is still queued by the=C2=A0receiving side, and on= ly becomes effective when the thread calls Scm_SigCheck()---usually from th= e VM loop.<div><div><br></div><div>I think the supposed way is that C exten= sion=C2=A0code needs to invoke Scm_SigCheck() occasionally if it doesn'= t return control to Scheme.=C2=A0 But that can't be enforced, especiall= y if it's in the third party code.</div><div><br></div><div>We can empl= oy a similar handling mechanism like typing ^C several times to force gosh = quit.=C2=A0 That is, thread-terminate! resends thread termination signal af= ter a short wait, and if the receiving side gets multiple termination=C2=A0= signal queued, it terminates the thread=C2=A0then.</div><div><br></div><div= ><br></div><div><br></div><div><br></div><div><br><div><br></div></div></di= v></div><br><div class=3D"gmail_quote gmail_quote_container"><div dir=3D"lt= r" class=3D"gmail_attr">On Mon, Jan 27, 2025 at 7:26=E2=80=AFAM Jens Thiele= <<a href=3D"mailto:[email protected]">[email protected]</a>> wrote:<br></d= iv><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bord= er-left:1px solid rgb(204,204,204);padding-left:1ex">Hi,<br> <br> It looks like native busy loops are not interrupted by thread-terminate!<br= > =3D> they have to cooperate.<br> <br> A first test below. Does that make sense? Is it ok to use<br> SCM_INTERNAL_MUTEX_LOCK/SCM_INTERNAL_MUTEX_UNLOCK/SCM_INTERNAL_THREAD_EXIT<= br> ?<br> <br> #!/bin/sh<br> #| -*- mode: scheme; coding: utf-8; -*-<br> exec gosh -I. -- $0 "$@"<br> |#<br> <br> ;; native busy loops are not interrupted by thread-terminate!<br> ;; =3D> they have to cooperate<br> <br> (use gauche.threads)<br> (use file.util)<br> (use runtime-compile)<br> <br> (compile-and-load<br> =C2=A0`((inline-stub<br> =C2=A0 =C2=A0 (define-cproc busy-loop ()<br> =C2=A0 =C2=A0 =C2=A0 (let* ((i::int 0))<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 (while (1)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; you would do some calculations here<b= r> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (inc! i)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; poll whether we have to terminate<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ;; otherwise we keep running on thread-t= erminate! below<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (not (% i 100000))<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let* ((state::int 0))<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (SCM_INTERNAL_MUTEX_LOCK (= -> (Scm_VM) vmlock))<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (set! state (-> (Scm_VM= ) state))<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (SCM_INTERNAL_MUTEX_UNLOCK= (-> (Scm_VM) vmlock))<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (printf "%d %d %d\n&q= uot; i state SCM_VM_TERMINATED)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (=3D=3D state SCM_VM= _TERMINATED)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (SCM_INTERNAL_THREA= D_EXIT)))))))))<br> =C2=A0'(busy-loop))<br> <br> ;; todo: linux specific<br> (define (num-threads)<br> =C2=A0 (guard (e<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 [else<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0+nan.0])<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(length (directory-list "/proc/self/= task" :children? #t))))<br> <br> (define (main args)<br> =C2=A0 #?=3D(num-threads)<br> =C2=A0 (let1 t (thread-start! (make-thread (lambda()<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (busy-lo= op))))<br> =C2=A0 =C2=A0 (sys-sleep 1)<br> =C2=A0 =C2=A0 #?=3D(num-threads)<br> =C2=A0 =C2=A0 (thread-terminate! t)<br> =C2=A0 =C2=A0 #?=3D(num-threads)<br> =C2=A0 =C2=A0 (guard (e [else #?=3De])<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(thread-join! t)))<br> =C2=A0 #?=3D(num-threads)<br> =C2=A0 (sys-sleep 1)<br> =C2=A0 #?=3D(num-threads)<br> =C2=A0 (sys-sleep 10)<br> =C2=A0 0)<br> <br> <br> _______________________________________________<br> Gauche-devel mailing list<br> <a href=3D"mailto:[email protected]" target=3D"_blank">Gau= [email protected]</a><br> <a href=3D"https://lists.sourceforge.net/lists/listinfo/gauche-devel" rel= =3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listi= nfo/gauche-devel</a><br> </blockquote></div> --0000000000005e15e1062cbff12f-- --===============6726048499164378765== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline --===============6726048499164378765== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Gauche-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/gauche-devel --===============6726048499164378765==--