Re: Alarm signal and recv system call

Matthew Fluet <[email protected]> Thu, 15 Nov 2018 21:14:07 -0500
Newsgroups gmane.comp.lang.ml.mlton.user
Message-ID <CAMrhFL7ObKCQLZ0Hbcoe0uj=QmJ+hc74ZyegCHuOHY6T3DZRcg@mail.gmail.com>
--===============7506386836349485545==
Content-Type: multipart/alternative; boundary="000000000000837ea9057abeb9a9"

--000000000000837ea9057abeb9a9
Content-Type: text/plain; charset="UTF-8"

On Thu, Nov 15, 2018 at 6:43 PM Henry Cejtin <[email protected]> wrote:

> The  behavior I see when I set MLton.Signal.restart to false is not that
> OS.SysError is raised, but that the program immediately exits (with exit
> status 1).
>
> Here is the code.
>
> ======
> val () = MLton.Signal.restart := false
> fun sh () = let val () = print "Got signaled\n"
>             in OS.Process.exit OS.Process.failure
>             end
> val _ = MLton.Signal.setHandler
>            (Posix.Signal.int,
>             MLton.Signal.Handler.simple sh)
> val _ = print "Waiting:\n"
> val msg = (case TextIO.inputLine TextIO.stdIn of
>              NONE => "*** EOF ***"
>            | SOME msg => msg)
>           handle e => (print ("inputLine raised "
>                                  ^ exnName e
>                                  ^ ", with message "
>                                  ^ exnMessage e
>                                  ^ "\n");
>                        raise Fail "Deadly raise from inputLine")
> val _ = print ("Got " ^ msg ^ "\n")
> ======
>
> When  run,  if  I hit control-C after seeing the Waiting: prompt it just
> exists.  I would have expected to the print in the handle to be run.
>

Here's the behavior I see with your program:

[matthew@shadow tmp]$ mlton
MLton 20180207
[matthew@shadow tmp]$ mlton z.sml
[matthew@shadow tmp]$ ./z
Waiting:
^CGot signaled
That's what I would expect from your program.  Your signal handler performs
`OS.Process.exit OS.Process.failure`, so it never returns from the signal
handler to the "restart or raise" wrapper around the system call: "If a
system call is interrupted by a signal, then the signal handler will run
before the call is restarted or OS.SysError is raised; that is, before the
Signal.restart check." (http://mlton.org/MLtonSignal)


> On a rather  unrelated  note,  is  there  any  way  to  prepend  (as  in
> MLton.Thread.prepend)    to    a    MLton.Runnable.t   (instead   of   a
> MLton.Thread.t?  I.e., can I insert some code to be run in  the  handler
> context of a runnable?
>

No.  A MLton.Thread.Runnable.t is really just the suspended stack, possibly
suspended at any (GC safe) point by a signal.  I don't think there is any
good way to run "new" code on that stack, although the parasitic threads
that Suresh and Lukasz implemented seems to have done something like that.


> I  can  definitely  imagine that this may have been forbidden because it
> would cause the control flow analysis to violate assumptions.
>

Right (or, one would need to assume that any exception could be thrown from
any point).

The connection is that if one could do that, it would be a way to insert
> the raising of an exception in the signal handler.

Perhaps that would be a bad idea anyway?
>

I don't know if it is a bad idea, but it isn't one that MLton currently
supports.

-Matthew



> On Thu, Nov 15, 2018 at 3:58 PM Matthew Fluet <[email protected]>
> wrote:
> >
> > In addition to Henry's comments, there is a little more to the story.
> It is true that at the libc level, an interrupted system call will
> typically return immediately with -1 and errno set to EINTR.  MLton's
> implementation of the Basis Library chooses to restart most such libc
> functions.  However, this is configurable via `val MLton.Signal.restart :
> bool ref`.  See the "Interruptible System Calls" section of
> http://mlton.org/MLtonSignal.  The default (of restarting system calls)
> makes sense for some uses of signals (e.g., profiling or asking a
> long-running program to save state in response to a periodic signal).
> Also, in the context of high-level operations, performing something like
> BinIO.output with a very large output vector could result in multiple
> system calls (as buffers are filled), so it may be almost impossible to
> handle the OS.SysError exception and resume so that no output is lost.
> >
> > On Thu, Nov 15, 2018 at 11:32 AM Henry Cejtin <[email protected]>
> wrote:
> >>
> >> You  have  to  remember  that  MLton  signal  handlers  are running in a
> >> separate thread.  It gets passed the thread  that  was  interrupted  and
> >> returns  the  thread to run when the handler is finished.  The result of
> >> Handler.simple returns the thread it was called with, and hence restarts
> >> the interrupted thread.
> >>
> >> If  you  want the Socket.recvVec (or whatever) to be `aborted', then you
> >> can't use Handler.simple to make the handler.  Instead you have to  have
> >> some  other  thread to resume, or, if you want the program to terminate,
> >> you have to terminate it in the handler.  You can do  the  latter  with,
> >> for example, OS.Process.exit.
> >>
> >> Doing this, your sample program would look like this:
> >>
> >>     fun h = let val () = print "Alarm sig\n"
> >>             in OS.Process.exit OS.Process.failure
> >>             end
> >>     val () = MLton.Signal.setHandler (Posix.Signal.arm,
> >>                                       MLton.Signal.Handler.simple h)
> >>     val () = Posix.Process.Alarm (Time.fromSeconds (Int.toLarge 3))
> >>     val r = Socket.recvVec (socket, 1024)
> >>     val () = print "Done\n"
> >> On Thu, Nov 15, 2018 at 5:54 AM Kostirya <[email protected]> wrote:
> >> >
> >> > I was surprised to find that Alarm signal do not abort recvVec
> function.
> >> > How is this possible?
> >> > I thought recv was always aborted on signal.
> >> >
> >> >
> >> > I use for test:
> >> >
> >> > val _ = MLton.Signal.setHandler(Posix.Signal.alrm,
> >> > MLton.Signal.Handler.simple (fn _ => print "Alarm sig\n"))
> >> > val _ = Posix.Process.alarm (Time.fromSeconds (Int.toLarge 3))
> >> > val r = Socket.recvVec (socket, 1024)
> >> > val _ = print "Done\n"
> >> >
> >> > --
> >> > You received this message because you are subscribed to the Google
> Groups "MLton-user" group.
> >> > To unsubscribe from this group and stop receiving emails from it,
> send an email to [email protected].
> >> >
> >> >
> >> >
> >> > _______________________________________________
> >> > MLton-user mailing list
> >> > [email protected]; [email protected]
> >> > https://lists.sourceforge.net/lists/listinfo/mlton-user
> >>
> >> --
> >> You received this message because you are subscribed to the Google
> Groups "MLton-user" group.
> >> To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected].
> >>
> >>
> >>
> >> _______________________________________________
> >> MLton-user mailing list
> >> [email protected]; [email protected]
> >> https://lists.sourceforge.net/lists/listinfo/mlton-user
> >
> > --
> > You received this message because you are subscribed to the Google
> Groups "MLton-user" group.
> > To unsubscribe from this group and stop receiving emails from it, send
> an email to [email protected].
> > _______________________________________________
> > MLton-user mailing list
> > [email protected]; [email protected]
> > https://lists.sourceforge.net/lists/listinfo/mlton-user
>
> --
> You received this message because you are subscribed to the Google Groups
> "MLton-user" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
>
>
>
> _______________________________________________
> MLton-user mailing list
> [email protected]; [email protected]
> https://lists.sourceforge.net/lists/listinfo/mlton-user
>

-- 
You received this message because you are subscribed to the Google Groups "MLton-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].

--000000000000837ea9057abeb9a9
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div cl=
ass=3D"gmail_default" style=3D"font-family:&quot;courier new&quot;,monospac=
e;font-size:large"><span style=3D"font-family:Arial,Helvetica,sans-serif;fo=
nt-size:small">On Thu, Nov 15, 2018 at 6:43 PM Henry Cejtin &lt;<a href=3D"=
mailto:[email protected]">[email protected]</a>&gt; wrote:</span>=
<br></div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);paddin=
g-left:1ex">The=C2=A0 behavior I see when I set MLton.Signal.restart to fal=
se is not that<br>
OS.SysError is raised, but that the program immediately exits (with exit<br=
>
status 1).<br>
<br>
Here is the code.<br>
<br>
=3D=3D=3D=3D=3D=3D<br>
val () =3D MLton.Signal.restart :=3D false<br>
fun sh () =3D let val () =3D print &quot;Got signaled\n&quot;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 in OS.Process.exit OS.Process.fai=
lure<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 end<br>
val _ =3D MLton.Signal.setHandler<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(<a href=3D"http://Posix.Signal.in=
t" rel=3D"noreferrer" target=3D"_blank">Posix.Signal.int</a>,<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MLton.Signal.Handler.simple sh)<b=
r>
val _ =3D print &quot;Waiting:\n&quot;<br>
val msg =3D (case TextIO.inputLine TextIO.stdIn of<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0NONE =3D&gt; &quot;*** EOF =
***&quot;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| SOME msg =3D&gt; msg)<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 handle e =3D&gt; (print (&quot;inputLine=
 raised &quot;<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^ exnName e<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^ &quot;, with message &quot;<=
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^ exnMessage e<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^ &quot;\n&quot;);<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0raise Fail &quot;Deadly raise from inputLine&quot;)<br>
val _ =3D print (&quot;Got &quot; ^ msg ^ &quot;\n&quot;)<br>
=3D=3D=3D=3D=3D=3D<br>
<br>
When=C2=A0 run,=C2=A0 if=C2=A0 I hit control-C after seeing the Waiting: pr=
ompt it just<br>
exists.=C2=A0 I would have expected to the print in the handle to be run.<b=
r></blockquote><div><br></div><div><div class=3D"gmail_default" style=3D"fo=
nt-family:&quot;courier new&quot;,monospace;font-size:large">Here&#39;s the=
 behavior I see with your program:</div><div class=3D"gmail_default" style=
=3D"font-family:&quot;courier new&quot;,monospace;font-size:large"><br></di=
v><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&quot;=
,monospace;font-size:large">[matthew@shadow tmp]$ mlton</div><div class=3D"=
gmail_default" style=3D"font-family:&quot;courier new&quot;,monospace;font-=
size:large">MLton 20180207</div><div class=3D"gmail_default" style=3D"font-=
family:&quot;courier new&quot;,monospace;font-size:large">[matthew@shadow t=
mp]$ mlton z.sml</div><div class=3D"gmail_default" style=3D"font-family:&qu=
ot;courier new&quot;,monospace;font-size:large">[matthew@shadow tmp]$ ./z</=
div><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&quo=
t;,monospace;font-size:large">Waiting:</div><div class=3D"gmail_default" st=
yle=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">^CGot=
 signaled</div><div class=3D"gmail_default" style=3D"font-family:&quot;cour=
ier new&quot;,monospace;font-size:large"></div><div class=3D"gmail_default"=
 style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large">Th=
at&#39;s what I would expect from your program.=C2=A0 Your signal handler p=
erforms `OS.Process.exit OS.Process.failure`, so it never returns from the =
signal handler to the &quot;restart or raise&quot; wrapper around the syste=
m call: &quot;If a system call is interrupted by a signal, then the signal =
handler will run before the call is restarted or OS.SysError is raised; tha=
t is, before the Signal.restart check.&quot; (<a href=3D"http://mlton.org/M=
LtonSignal">http://mlton.org/MLtonSignal</a>)</div></div><div>=C2=A0</div><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex">
On a rather=C2=A0 unrelated=C2=A0 note,=C2=A0 is=C2=A0 there=C2=A0 any=C2=
=A0 way=C2=A0 to=C2=A0 prepend=C2=A0 (as=C2=A0 in<br>
MLton.Thread.prepend)=C2=A0 =C2=A0 to=C2=A0 =C2=A0 a=C2=A0 =C2=A0 MLton.Run=
nable.t=C2=A0 =C2=A0(instead=C2=A0 =C2=A0of=C2=A0 =C2=A0a<br>
MLton.Thread.t?=C2=A0 I.e., can I insert some code to be run in=C2=A0 the=
=C2=A0 handler<br>
context of a runnable?<br></blockquote><div><br></div><div><div class=3D"gm=
ail_default" style=3D"font-family:&quot;courier new&quot;,monospace;font-si=
ze:large">No.=C2=A0 A MLton.Thread.Runnable.t is really just the suspended =
stack, possibly suspended at any (GC safe) point by a signal.=C2=A0 I don&#=
39;t think there is any good way to run &quot;new&quot; code on that stack,=
 although the parasitic threads that Suresh and Lukasz implemented seems to=
 have done something like that.</div></div><div>=C2=A0</div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex">
I=C2=A0 can=C2=A0 definitely=C2=A0 imagine that this may have been forbidde=
n because it<br>
would cause the control flow analysis to violate assumptions.<br></blockquo=
te><div><br></div><div><div class=3D"gmail_default" style=3D"font-family:&q=
uot;courier new&quot;,monospace;font-size:large">Right (or, one would need =
to assume that any exception could be thrown from any point).</div></div><d=
iv><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px =
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The connection is that if one could do that, it would be a way to insert<br=
>
the raising of an exception in the signal handler.</blockquote><blockquote =
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px sol=
id rgb(204,204,204);padding-left:1ex">
Perhaps that would be a bad idea anyway?<br></blockquote><div><br></div><di=
v><div class=3D"gmail_default" style=3D"font-family:&quot;courier new&quot;=
,monospace;font-size:large">I don&#39;t know if it is a bad idea, but it is=
n&#39;t one that MLton currently supports.</div><div class=3D"gmail_default=
" style=3D"font-family:&quot;courier new&quot;,monospace;font-size:large"><=
br></div><div class=3D"gmail_default" style=3D"font-family:&quot;courier ne=
w&quot;,monospace;font-size:large">-Matthew</div><br></div><div>=C2=A0</div=
><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border=
-left:1px solid rgb(204,204,204);padding-left:1ex">
On Thu, Nov 15, 2018 at 3:58 PM Matthew Fluet &lt;<a href=3D"mailto:matthew=
[email protected]" target=3D"_blank">[email protected]</a>&gt; wrote:<=
br>
&gt;<br>
&gt; In addition to Henry&#39;s comments, there is a little more to the sto=
ry.=C2=A0 It is true that at the libc level, an interrupted system call wil=
l typically return immediately with -1 and errno set to EINTR.=C2=A0 MLton&=
#39;s implementation of the Basis Library chooses to restart most such libc=
 functions.=C2=A0 However, this is configurable via `val MLton.Signal.resta=
rt : bool ref`.=C2=A0 See the &quot;Interruptible System Calls&quot; sectio=
n of <a href=3D"http://mlton.org/MLtonSignal" rel=3D"noreferrer" target=3D"=
_blank">http://mlton.org/MLtonSignal</a>.=C2=A0 The default (of restarting =
system calls) makes sense for some uses of signals (e.g., profiling or aski=
ng a long-running program to save state in response to a periodic signal).=
=C2=A0 Also, in the context of high-level operations, performing something =
like BinIO.output with a very large output vector could result in multiple =
system calls (as buffers are filled), so it may be almost impossible to han=
dle the OS.SysError exception and resume so that no output is lost.<br>
&gt;<br>
&gt; On Thu, Nov 15, 2018 at 11:32 AM Henry Cejtin &lt;<a href=3D"mailto:he=
[email protected]" target=3D"_blank">[email protected]</a>&gt; wrot=
e:<br>
&gt;&gt;<br>
&gt;&gt; You=C2=A0 have=C2=A0 to=C2=A0 remember=C2=A0 that=C2=A0 MLton=C2=
=A0 signal=C2=A0 handlers=C2=A0 are running in a<br>
&gt;&gt; separate thread.=C2=A0 It gets passed the thread=C2=A0 that=C2=A0 =
was=C2=A0 interrupted=C2=A0 and<br>
&gt;&gt; returns=C2=A0 the=C2=A0 thread to run when the handler is finished=
.=C2=A0 The result of<br>
&gt;&gt; Handler.simple returns the thread it was called with, and hence re=
starts<br>
&gt;&gt; the interrupted thread.<br>
&gt;&gt;<br>
&gt;&gt; If=C2=A0 you=C2=A0 want the Socket.recvVec (or whatever) to be `ab=
orted&#39;, then you<br>
&gt;&gt; can&#39;t use Handler.simple to make the handler.=C2=A0 Instead yo=
u have to=C2=A0 have<br>
&gt;&gt; some=C2=A0 other=C2=A0 thread to resume, or, if you want the progr=
am to terminate,<br>
&gt;&gt; you have to terminate it in the handler.=C2=A0 You can do=C2=A0 th=
e=C2=A0 latter=C2=A0 with,<br>
&gt;&gt; for example, OS.Process.exit.<br>
&gt;&gt;<br>
&gt;&gt; Doing this, your sample program would look like this:<br>
&gt;&gt;<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0fun h =3D let val () =3D print &quot;Alarm sig\=
n&quot;<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0in OS.Process.exit =
OS.Process.failure<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0end<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0val () =3D MLton.Signal.setHandler (Posix.Signa=
l.arm,<br>
&gt;&gt;=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=A0ML=
ton.Signal.Handler.simple h)<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0val () =3D Posix.Process.Alarm (Time.fromSecond=
s (Int.toLarge 3))<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0val r =3D Socket.recvVec (socket, 1024)<br>
&gt;&gt;=C2=A0 =C2=A0 =C2=A0val () =3D print &quot;Done\n&quot;<br>
&gt;&gt; On Thu, Nov 15, 2018 at 5:54 AM Kostirya &lt;<a href=3D"mailto:kos=
[email protected]" target=3D"_blank">[email protected]</a>&gt; wrote:<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I was surprised to find that Alarm signal do not abort recvVe=
c function.<br>
&gt;&gt; &gt; How is this possible?<br>
&gt;&gt; &gt; I thought recv was always aborted on signal.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I use for test:<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; val _ =3D MLton.Signal.setHandler(Posix.Signal.alrm,<br>
&gt;&gt; &gt; MLton.Signal.Handler.simple (fn _ =3D&gt; print &quot;Alarm s=
ig\n&quot;))<br>
&gt;&gt; &gt; val _ =3D Posix.Process.alarm (Time.fromSeconds (Int.toLarge =
3))<br>
&gt;&gt; &gt; val r =3D Socket.recvVec (socket, 1024)<br>
&gt;&gt; &gt; val _ =3D print &quot;Done\n&quot;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; --<br>
&gt;&gt; &gt; You received this message because you are subscribed to the G=
oogle Groups &quot;MLton-user&quot; group.<br>
&gt;&gt; &gt; To unsubscribe from this group and stop receiving emails from=
 it, send an email to <a href=3D"mailto:mlton-user%[email protected]"=
 target=3D"_blank">[email protected]</a>.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; _______________________________________________<br>
&gt;&gt; &gt; MLton-user mailing list<br>
&gt;&gt; &gt; <a href=3D"mailto:[email protected]" target=3D=
"_blank">[email protected]</a>; <a href=3D"mailto:mlton-user=
@mlton.org" target=3D"_blank">[email protected]</a><br>
&gt;&gt; &gt; <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton=
-user" rel=3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/l=
ists/listinfo/mlton-user</a><br>
&gt;&gt;<br>
&gt;&gt; --<br>
&gt;&gt; You received this message because you are subscribed to the Google=
 Groups &quot;MLton-user&quot; group.<br>
&gt;&gt; To unsubscribe from this group and stop receiving emails from it, =
send an email to <a href=3D"mailto:mlton-user%[email protected]" targ=
et=3D"_blank">[email protected]</a>.<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; _______________________________________________<br>
&gt;&gt; MLton-user mailing list<br>
&gt;&gt; <a href=3D"mailto:[email protected]" target=3D"_bla=
nk">[email protected]</a>; <a href=3D"mailto:mlton-user@mlto=
n.org" target=3D"_blank">[email protected]</a><br>
&gt;&gt; <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-user=
" rel=3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/=
listinfo/mlton-user</a><br>
&gt;<br>
&gt; --<br>
&gt; You received this message because you are subscribed to the Google Gro=
ups &quot;MLton-user&quot; group.<br>
&gt; To unsubscribe from this group and stop receiving emails from it, send=
 an email to <a href=3D"mailto:mlton-user%[email protected]" target=
=3D"_blank">[email protected]</a>.<br>
&gt; _______________________________________________<br>
&gt; MLton-user mailing list<br>
&gt; <a href=3D"mailto:[email protected]" target=3D"_blank">=
[email protected]</a>; <a href=3D"mailto:[email protected]=
g" target=3D"_blank">[email protected]</a><br>
&gt; <a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-user" re=
l=3D"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/list=
info/mlton-user</a><br>
<br>
-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;MLton-user&quot; group.<br>
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:mlton-user%[email protected]" target=3D"_bl=
ank">[email protected]</a>.<br>
<br>
<br>
<br>
_______________________________________________<br>
MLton-user mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">MLton=
[email protected]</a>; <a href=3D"mailto:[email protected]" ta=
rget=3D"_blank">[email protected]</a><br>
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-user" rel=3D"=
noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo/=
mlton-user</a><br>
</blockquote></div></div></div></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;MLton-user&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:[email protected]">mlton-user+unsu=
[email protected]</a>.<br />

--000000000000837ea9057abeb9a9--


--===============7506386836349485545==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline


--===============7506386836349485545==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
MLton-user mailing list
[email protected]; [email protected]
https://lists.sourceforge.net/lists/listinfo/mlton-user

--===============7506386836349485545==--