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&#39;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&#39;=
t return control to Scheme.=C2=A0 But that can&#39;t be enforced, especiall=
y if it&#39;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=
 &lt;<a href=3D"mailto:[email protected]">[email protected]</a>&gt; 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&gt; 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 &quot;$@&quot;<br>
|#<br>
<br>
;; native busy loops are not interrupted by thread-terminate!<br>
;; =3D&gt; 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 (=
-&gt; (Scm_VM) vmlock))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (set! state (-&gt; (Scm_VM=
) state))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (SCM_INTERNAL_MUTEX_UNLOCK=
 (-&gt; (Scm_VM) vmlock))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (printf &quot;%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&#39;(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 &quot;/proc/self/=
task&quot; :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==--