Re: [MLton] Multithreading issue when using FFI with C/C++

Matthew Fluet <[email protected]> Wed, 9 Mar 2022 10:00:09 -0500
Newsgroups gmane.comp.lang.ml.mlton.devel
Message-ID <CAMrhFL7EN8jaTfAFSPMY6JeuhEZ-Tn9vFGp_s=eDe404Rf_X5Q@mail.gmail.com>
--===============5206239793893434773==
Content-Type: multipart/alternative; boundary="0000000000003a2eb705d9ca5bba"

--0000000000003a2eb705d9ca5bba
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

This would be the expected behavior, because neither the MLton runtime nor
the MLton compiled mutator code is thread safe.  The `libtest_open(argc,
argv)` initializes the (shared) heap and runtime system, which has a
significant amount of shared global state.  Each (parallel) invocation of
`ffi_func` will be accessing and mutating that shared state, leading to
undefined behavior.
You could protect the invocations of `ffi_func` with a global lock on the
C++ side, but that would only be beneficial if there are very few
concurrent invocations of `ffi_func`.  If you are hoping to obtain some
parallel speedup with a significant portion of the computation being done
on the SML-side, then I'm afraid that MLton will not suffice for this
purpose.  You might check out the MaPLe project (https://github.com/MPLLang=
),
which is a Parallel ML based on MLton.  Though, I do not believe that it
supports exporting SML functions to C/C++.


On Tue, Mar 8, 2022 at 9:25 PM Weiqi Sun <[email protected]> wrote:

> Hi,
>
> I have some sml code that I want to export to C or C++ using the mlton FF=
I
> feature. However, I encountered an issue when calling the exported sml
> function from C/C++ in a multithreading environment. I simplified the iss=
ue
> as the following:
>
> I export a dummy sml function called ffi_func that always returns an
> integer 1 in =E2=80=9Clibtest.sml=E2=80=9D:
>
> val f =3D _export "ffi_func": (unit -> int) -> unit;
> val _ =3D f(fn () =3D> 1);
>
> Then I compiled it to an archive named libtest.a and export a header file
> test_ffi.h using the following command:
>
> mlton -default-ann 'allowFFI true' -export-header test_ffi.h -format arch=
ive -libname libtest libtest.sml
>
> With the compiled archive, I can call the ffi_func function in C code
> =E2=80=9Cmain.c=E2=80=9D. But when I call it inside threading, it throws =
a segmentation
> fault.
>
> #include <stdio.h>
> #include <pthread.h>
> #include "test_ffi.h"
>
> void* callOut(void *thread_id) {
>     int *myid =3D (int *)thread_id;
>     for (int i =3D 0; i < 100; ++i) {
>         int rc =3D ffi_func();
>         printf("call out: %d - %d - %d\n", *myid, i, rc);
>     }
>     return NULL;
> }
>
> void multiRun(int n) {
>     printf("num thread: %d\n", n);
>
>     pthread_t thread[n];
>     int thread_num[n];
>     for (int i =3D 0; i < n; ++i) {
>         thread_num[i] =3D i;
>         pthread_create(&thread[i], NULL, callOut, (void *)&thread_num[i])=
;
>     }
>
>     for (int i =3D 0; i < n; ++i) {
>         pthread_join(thread[i], NULL);
>     }
> }
>
> int main(int argc, const char** argv) {
>     libtest_open(argc, argv);
>
>     int n =3D *argv[1] - '0';
>     multiRun(n);
>
>     libtest_close();
> }
>
> The code is compiled by:
>
> gcc -o test_c main.c -L. -ltest -lpthread
>
> If I run test_c with only one thread, it works well. But if I use more
> than one thread, I got segmentation fault. And different runs give
> different error messages. For example, by running ./test_c 3 multiple
> times, I could get the following error messages
>
> unhandled exception: Option
> MLton bug: Mlton.Exit.halt
> Please send a bug report to [email protected]
> Thread.atomicSwitch didn't set r.
>
> zsh: segmentation fault ./test_c 3
>
> Or
>
> unhandled exception: Fail8
> Thread.atomicSwitch didn't set r.
> MLton bug: MLton.Exit.halt
> Please send a bug report to [email protected].
>
> zsh: bus error ./test_c 3
>
> I tested this with both MLton 20201002 and MLton 20210117 and they give
> the same errors. And this problem appears on both Mac and Linux.
>
> Any advice will be appreciated.
>
> Thanks,
> Weiqi
>
> --
> You received this message because you are subscribed to the Google Groups
> "MLton" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> _______________________________________________
> MLton-devel mailing list
> [email protected]; [email protected]
> https://lists.sourceforge.net/lists/listinfo/mlton-devel
>

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

<div dir=3D"ltr"><div class=3D"gmail_default" style=3D"font-family:arial,sa=
ns-serif;font-size:large">This would be the expected behavior, because neit=
her the MLton runtime nor the MLton compiled mutator code is thread safe.=
=C2=A0 The `libtest_open(argc, argv)` initializes the (shared) heap and run=
time system, which has a significant amount of shared global state.=C2=A0 E=
ach (parallel) invocation of `ffi_func` will be accessing and mutating that=
 shared state, leading to undefined behavior.</div><div class=3D"gmail_defa=
ult" style=3D"font-family:arial,sans-serif;font-size:large">You could prote=
ct the invocations of `ffi_func` with a global lock on the C++ side, but th=
at would only be beneficial if there are very few concurrent invocations of=
 `ffi_func`.=C2=A0 If you are hoping to obtain some parallel speedup with a=
 significant portion of the computation being done on the SML-side, then I&=
#39;m afraid that MLton will not suffice for this purpose.=C2=A0 You might =
check out the MaPLe project (<a href=3D"https://github.com/MPLLang">https:/=
/github.com/MPLLang</a>), which is a Parallel ML based on MLton.=C2=A0 Thou=
gh, I do not believe that it supports exporting SML functions to C/C++.</di=
v><div class=3D"gmail_default" style=3D"font-family:arial,sans-serif;font-s=
ize:large"><br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" =
class=3D"gmail_attr">On Tue, Mar 8, 2022 at 9:25 PM Weiqi Sun &lt;<a href=
=3D"mailto:[email protected]">[email protected]</a>&gt; wrote:<br></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"><div dir=3D"ltr"><div><p s=
tyle=3D"margin:0px 0px 1.2em">Hi,</p><p style=3D"margin:0px 0px 1.2em">I ha=
ve some sml code that I want to export to C or C++ using the mlton FFI feat=
ure. However, I encountered an issue when calling the exported sml function=
 from C/C++ in a multithreading environment. I simplified the issue as the =
following:</p>
<p style=3D"margin:0px 0px 1.2em">I export a dummy sml function called <cod=
e style=3D"font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monosp=
ace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px sol=
id rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;dis=
play:inline">ffi_func</code> that always returns an integer <code style=3D"=
font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:=
0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,=
234,234);background-color:rgb(248,248,248);border-radius:3px;display:inline=
">1</code> in =E2=80=9Clibtest.sml=E2=80=9D:</p>
<pre style=3D"font-family:Consolas,Inconsolata,Courier,monospace;font-size:=
1em;line-height:1.2em;margin:1.2em 0px"><code style=3D"font-size:0.85em;fon=
t-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;backgroun=
d-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3=
px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block">val=
 f =3D _export &quot;ffi_func&quot;: (unit -&gt; int) -&gt; unit;
val _ =3D f(fn () =3D&gt; 1);
</code></pre><p style=3D"margin:0px 0px 1.2em">Then I compiled it to an arc=
hive named <code style=3D"font-size:0.85em;font-family:Consolas,Inconsolata=
,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap=
;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);border=
-radius:3px;display:inline">libtest.a</code> and export a header file <code=
 style=3D"font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospa=
ce;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px soli=
d rgb(234,234,234);background-color:rgb(248,248,248);border-radius:3px;disp=
lay:inline">test_ffi.h</code> using the following command:</p>
<pre style=3D"font-family:Consolas,Inconsolata,Courier,monospace;font-size:=
1em;line-height:1.2em;margin:1.2em 0px"><code style=3D"font-size:0.85em;fon=
t-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;backgroun=
d-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3=
px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block">mlt=
on -default-ann &#39;allowFFI true&#39; -export-header test_ffi.h -format a=
rchive -libname libtest libtest.sml
</code></pre><p style=3D"margin:0px 0px 1.2em">With the compiled archive, I=
 can call the <code style=3D"font-size:0.85em;font-family:Consolas,Inconsol=
ata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-w=
rap;border:1px solid rgb(234,234,234);background-color:rgb(248,248,248);bor=
der-radius:3px;display:inline">ffi_func</code> function in C code =E2=80=9C=
main.c=E2=80=9D. But when I call it inside threading, it throws a segmentat=
ion fault.</p>
<pre style=3D"font-family:Consolas,Inconsolata,Courier,monospace;font-size:=
1em;line-height:1.2em;margin:1.2em 0px"><code style=3D"font-size:0.85em;fon=
t-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;backgroun=
d-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3=
px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block">#in=
clude &lt;stdio.h&gt;
#include &lt;pthread.h&gt;
#include &quot;test_ffi.h&quot;

void* callOut(void *thread_id) {
    int *myid =3D (int *)thread_id;
    for (int i =3D 0; i &lt; 100; ++i) {
        int rc =3D ffi_func();
        printf(&quot;call out: %d - %d - %d\n&quot;, *myid, i, rc);
    }
    return NULL;
}

void multiRun(int n) {
    printf(&quot;num thread: %d\n&quot;, n);

    pthread_t thread[n];
    int thread_num[n];
    for (int i =3D 0; i &lt; n; ++i) {
        thread_num[i] =3D i;
        pthread_create(&amp;thread[i], NULL, callOut, (void *)&amp;thread_n=
um[i]);
    }

    for (int i =3D 0; i &lt; n; ++i) {
        pthread_join(thread[i], NULL);
    }
}

int main(int argc, const char** argv) {
    libtest_open(argc, argv);

    int n =3D *argv[1] - &#39;0&#39;;
    multiRun(n);

    libtest_close();
}
</code></pre><p style=3D"margin:0px 0px 1.2em">The code is compiled by:</p>
<pre style=3D"font-family:Consolas,Inconsolata,Courier,monospace;font-size:=
1em;line-height:1.2em;margin:1.2em 0px"><code style=3D"font-size:0.85em;fon=
t-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;backgroun=
d-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3=
px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block">gcc=
 -o test_c main.c -L. -ltest -lpthread
</code></pre><p style=3D"margin:0px 0px 1.2em">If I run <code style=3D"font=
-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px =
0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,=
234);background-color:rgb(248,248,248);border-radius:3px;display:inline">te=
st_c</code> with only one thread, it works well. But if I use more than one=
 thread, I got segmentation fault. And different runs give different error =
messages. For example, by running <code style=3D"font-size:0.85em;font-fami=
ly:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3=
em;white-space:pre-wrap;border:1px solid rgb(234,234,234);background-color:=
rgb(248,248,248);border-radius:3px;display:inline">./test_c 3</code> multip=
le times, I could get the following error messages</p>
<pre style=3D"font-family:Consolas,Inconsolata,Courier,monospace;font-size:=
1em;line-height:1.2em;margin:1.2em 0px"><code style=3D"font-size:0.85em;fon=
t-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;backgroun=
d-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3=
px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block">unh=
andled exception: Option
MLton bug: Mlton.Exit.halt
Please send a bug report to <a href=3D"mailto:[email protected]" target=3D"_b=
lank">[email protected]</a>
Thread.atomicSwitch didn&#39;t set r.

zsh: segmentation fault ./test_c 3
</code></pre><p style=3D"margin:0px 0px 1.2em">Or</p>
<pre style=3D"font-family:Consolas,Inconsolata,Courier,monospace;font-size:=
1em;line-height:1.2em;margin:1.2em 0px"><code style=3D"font-size:0.85em;fon=
t-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;backgroun=
d-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-radius:3=
px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block">unh=
andled exception: Fail8
Thread.atomicSwitch didn&#39;t set r.
MLton bug: MLton.Exit.halt
Please send a bug report to <a href=3D"mailto:[email protected]" target=3D"_b=
lank">[email protected]</a>.

zsh: bus error ./test_c 3
</code></pre><p style=3D"margin:0px 0px 1.2em">I tested this with both MLto=
n 20201002 and MLton 20210117 and they give the same errors. And this probl=
em appears on both Mac and Linux.</p>
<p style=3D"margin:0px 0px 1.2em">Any advice will be appreciated.</p>
<p style=3D"margin:0px 0px 1.2em">Thanks,<br>Weiqi</p>
<div title=3D"MDH:PGRpdiBpZD0iZ21haWwtOjE5aiIgY2xhc3M9ImdtYWlsLUFyIGdtYWlsL=
UF1IGdtYWlsLUFvIj48
ZGl2IGlkPSJnbWFpbC06MTlmIiBjbGFzcz0iZ21haWwtQW0gZ21haWwtQWwgZWRpdGFibGUgZ21=
h
aWwtTFctYXZmIGdtYWlsLXRTLXRXIGdtYWlsLXRTLXRZIiBhcmlhLWxhYmVsPSJNZXNzYWdlIEJ=
v
ZHkiIHJvbGU9InRleHRib3giIGFyaWEtbXVsdGlsaW5lPSJ0cnVlIiB0YWJpbmRleD0iMSIgc3R=
5
bGU9ImRpcmVjdGlvbjogbHRyOyBtaW4taGVpZ2h0OiAzMzZweDsiPjxkaXYgaWQ9ImdtYWlsLTp=
4
cCIgY2xhc3M9ImdtYWlsLUFyIGdtYWlsLUF1IGdtYWlsLUFvIj48ZGl2IGlkPSJnbWFpbC06eHQ=
i
IGNsYXNzPSJnbWFpbC1BbSBnbWFpbC1BbCBlZGl0YWJsZSBnbWFpbC1MVy1hdmYgZ21haWwtdFM=
t
dFcgZ21haWwtdFMtdFkiIGFyaWEtbGFiZWw9Ik1lc3NhZ2UgQm9keSIgYXJpYS1tdWx0aWxpbmU=
9
InRydWUiIHRhYmluZGV4PSIxIiBzdHlsZT0iZGlyZWN0aW9uOiBsdHI7IG1pbi1oZWlnaHQ6IDM=
z
NnB4OyI+SGksPGRpdj48YnI+PC9kaXY+PGRpdj5JIGhhdmUgc29tZSA8c3BhbiB6ZXVtNGMxND0=
i
UFJfMV8wIiBkYXRhLWRkbndhYj0iUFJfMV8wIiBhcmlhLWludmFsaWQ9ImdyYW1tYXIiIGNsYXN=
z
PSJMbSBuZyI+c21sPC9zcGFuPiBjb2RlIHRoYXQgSSB3YW50IHRvIGV4cG9ydCB0byBDIG9yIEM=
r
KyB1c2luZyB0aGUgbWx0b24gRkZJIGZlYXR1cmUuIEhvd2V2ZXIsIEkgZW5jb3VudGVyZWQmbmJ=
z
cDthbiBpc3N1ZSB3aGVuIGNhbGxpbmcgdGhlIGV4cG9ydGVkIHNtbCBmdW5jdGlvbiBmcm9tIEM=
v
QysrIDxzcGFuIHpldW00YzE0PSJQUl8yXzAiIGRhdGEtZGRud2FiPSJQUl8yXzAiIGFyaWEtaW5=
2
YWxpZD0iZ3JhbW1hciIgY2xhc3M9IkxtIG5nIj5pbiBtdWx0aXRocmVhZGluZzwvc3Bhbj4gZW5=
2
aXJvbm1lbnQuIEkgc2ltcGxpZmllZCZuYnNwO3RoZSBpc3N1ZSBhcyB0aGUgZm9sbG93aW5nOjw=
v
ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+SSBleHBvcnQgYSBkdW1teSBzbWwgZnVuY3Rpb24gY2F=
s
bGVkIGBmZmlfZnVuY2AgdGhhdCBhbHdheSByZXR1cm4gYW4gaW50ZWdlciBgMWAgaW4gImxpYnR=
l
c3Quc21sIjo8L2Rpdj48ZGl2PmBgYDwvZGl2PjxkaXY+dmFsIGYgPSBfZXhwb3J0ICJmZmlfZnV=
u
YyI6ICh1bml0IC0mZ3Q7IGludCkgLSZndDsgdW5pdDs8L2Rpdj48ZGl2PnZhbCBfID0gZihmbiA=
o
KSA9Jmd0OyAxKTs8L2Rpdj48ZGl2PmBgYDwvZGl2PjxkaXY+VGhlbiBJIGNvbXBpbGVkIGl0IHR=
v
IGFuIGFyY2hpdmUgbmFtZWQgYGxpYnRlc3QuYWAgYW5kIGV4cG9ydCBhIGhlYWRlciBmaWxlIGB=
0
ZXN0X2ZmaS5oYCB1c2luZyB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6PC9kaXY+PGRpdj5gYGA8L2R=
p
dj48ZGl2Pm1sdG9uIC1kZWZhdWx0LWFubiAnYWxsb3dGRkkgdHJ1ZScgLWV4cG9ydC1oZWFkZXI=
g
dGVzdF9mZmkuaCAtZm9ybWF0IGFyY2hpdmUgLWxpYm5hbWUgbGlidGVzdCBsaWJ0ZXN0LnNtbDw=
v
ZGl2PjxkaXY+YGBgPC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5XaXRoIHRoZSBjb21waWxlZCB=
h
cmNoaXZlLCBJIGNhbiBjYWxsIHRoZSBgZmZpX2Z1bmNgIGZ1bmN0aW9uIGluIEMgY29kZSAibWF=
p
bi5jIi4gQnV0IHdoZW4gSSA8c3BhbiB6ZXVtNGMxND0iUFJfMzJfMCIgZGF0YS1kZG53YWI9IlB=
S
XzMyXzAiIGFyaWEtaW52YWxpZD0iZ3JhbW1hciIgY2xhc3M9IkxtIG5nIj5jYWxsaW5nPC9zcGF=
u
PiBpdCBpbnNpZGUgdGhyZWFkaW5nLCBpdCA8c3BhbiB6ZXVtNGMxND0iUFJfMzNfMCIgZGF0YS1=
k
ZG53YWI9IlBSXzMzXzAiIGFyaWEtaW52YWxpZD0iZ3JhbW1hciIgY2xhc3M9IkxtIG5nIj50aHJ=
v
d3Mgc2VnbWVudGF0aW9uPC9zcGFuPiBmYXVsdC48L2Rpdj48ZGl2PmBgYDwvZGl2PjxkaXY+I2l=
u
Y2x1ZGUgJmx0O3N0ZGlvLmgmZ3Q7PC9kaXY+PGRpdj4jaW5jbHVkZSAmbHQ7cHRocmVhZC5oJmd=
0
OzwvZGl2PjxkaXY+I2luY2x1ZGUgInRlc3RfZmZpLmgiPC9kaXY+PGRpdj48YnI+PC9kaXY+PGR=
p
dj52b2lkKiBjYWxsT3V0KHZvaWQgKnRocmVhZF9pZCkgezwvZGl2PjxkaXY+Jm5ic3A7ICZuYnN=
w
OyBpbnQgKm15aWQgPSAoaW50ICopdGhyZWFkX2lkOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyB=
m
b3IgKGludCBpID0gMDsgaSAmbHQ7IDEwMDsmbmJzcDsrK2kpIHs8L2Rpdj48ZGl2PiZuYnNwOyA=
m
bmJzcDsgJm5ic3A7ICZuYnNwOyBpbnQgcmMgPSBmZmlfZnVuYygpOzwvZGl2PjxkaXY+Jm5ic3A=
7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHByaW50ZigiY2FsbCBvdXQ6ICVkIC0gJWQgLSAlZFxuIiw=
g
Km15aWQsIGksIHJjKTs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgfTwvZGl2PjxkaXY+Jm5ic3A=
7
ICZuYnNwOyByZXR1cm4gTlVMTDs8L2Rpdj48ZGl2Pn08L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl=
2
PnZvaWQgbXVsdGlSdW4oaW50IG4pIHs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgcHJpbnRmKCJ=
u
dW0gdGhyZWFkOiAlZFxuIiwgbik7PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj4mbmJzcDsgJm5=
i
c3A7IHB0aHJlYWRfdCB0aHJlYWRbbl07PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IGludCB0aHJ=
l
YWRfbnVtW25dOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBmb3IgKGludCBpID0gMDsgaSAmbHQ=
7
IG47Jm5ic3A7KytpKSB7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgdGh=
y
ZWFkX251bVtpXSA9IGk7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgcHR=
o
cmVhZF9jcmVhdGUoPHNwYW4gemV1bTRjMTQ9IlBSXzVfMCIgZGF0YS1kZG53YWI9IlBSXzVfMCI=
g
YXJpYS1pbnZhbGlkPSJzcGVsbGluZyIgY2xhc3M9IkxJIG5nIj4mYW1wO3RocmVhZDwvc3Bhbj5=
b
aV0sIE5VTEwsIGNhbGxPdXQsICh2b2lkICopJmFtcDt0aHJlYWRfbnVtW2ldKTs8L2Rpdj48ZGl=
2
PiZuYnNwOyAmbmJzcDsgfTwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyB=
m
b3IgKGludCBpID0gMDsgaSAmbHQ7IG47Jm5ic3A7KytpKSB7PC9kaXY+PGRpdj4mbmJzcDsgJm5=
i
c3A7ICZuYnNwOyAmbmJzcDsgcHRocmVhZF9qb2luKHRocmVhZFtpXSwgTlVMTCk7PC9kaXY+PGR=
p
dj4mbmJzcDsgJm5ic3A7IH08L2Rpdj48ZGl2Pn08L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2Pml=
u
dCBtYWluKGludCBhcmdjLCBjb25zdCBjaGFyKiogYXJndikgezwvZGl2PjxkaXY+Jm5ic3A7ICZ=
u
YnNwOyBsaWJ0ZXN0X29wZW4oYXJnYywgYXJndik7PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj4=
m
bmJzcDsgJm5ic3A7IGludCBuID0gKmFyZ3ZbMV0gLSAnMCc7PC9kaXY+PGRpdj4mbmJzcDsgJm5=
i
c3A7IG11bHRpUnVuKG4pOzwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyB=
s
aWJ0ZXN0X2Nsb3NlKCk7PC9kaXY+PGRpdj59PC9kaXY+PGRpdj5gYGA8L2Rpdj48ZGl2Pjxicj4=
8
L2Rpdj48ZGl2PlRoZSBjb2RlIGlzIGNvbXBpbGVkIGJ5Ojxicj5gYGA8L2Rpdj48ZGl2PmdjYyA=
t
byB0ZXN0X2MgbWFpbi5jIC1MLiAtPHNwYW4gemV1bTRjMTQ9IlBSXzZfMCIgZGF0YS1kZG53YWI=
9
IlBSXzZfMCIgYXJpYS1pbnZhbGlkPSJzcGVsbGluZyIgY2xhc3M9IkxJIG5nIj5sdGVzdDwvc3B=
h
bj4mbmJzcDstbHB0aHJlYWQ8L2Rpdj48ZGl2PmBgYDwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY=
+
SWYgSSBydW4gYHRlc3RfY2Agd2l0aCBvbmx5IG9uZSB0aHJlYWQsIGl0IHdvcmtzIHdlbGwuIEJ=
1
dCBpZiBJIHVzZSBtb3JlIHRoYW4gb25lIHRocmVhZCwgSSA8c3BhbiB6ZXVtNGMxND0iUFJfN18=
w
IiBkYXRhLWRkbndhYj0iUFJfN18wIiBhcmlhLWludmFsaWQ9ImdyYW1tYXIiIGNsYXNzPSJMbSB=
u
ZyI+Z290PC9zcGFuPiBzZWdtZW50YXRpb24gZmF1bHQuIEFuZCBkaWZmZXJlbnQgcnVucyBnaXZ=
l
IGRpZmZlcmVudCBlcnJvciBtZXNzYWdlcy4gRm9yIGV4YW1wbGUsIGJ5IHJ1bm5pbmcgYC4vdGV=
z
dF9jIDNgIG11bHRpcGxlIHRpbWVzLCBJIGNvdWxkIGdldCB0aGUgZm9sbG93aW5nIGVycm9yIG1=
l
c3NhZ2VzPC9kaXY+PGRpdj5gYGA8L2Rpdj48ZGl2PnVuaGFuZGxlZCBleGNlcHRpb246IE9wdGl=
v
bjwvZGl2PjxkaXY+TUx0b24gYnVnOiA8c3BhbiB6ZXVtNGMxND0iUFJfOF8wIiBkYXRhLWRkbnd=
h
Yj0iUFJfOF8wIiBhcmlhLWludmFsaWQ9InNwZWxsaW5nIiBjbGFzcz0iTEkgbmciPk1sdG9uLkV=
4
aXQuaGFsdDwvc3Bhbj48L2Rpdj48ZGl2PlBsZWFzZSBzZW5kIGEgYnVnIHJlcG9ydCB0byBNTHR=
v
bkBtbHRvbi5vcmc8L2Rpdj48ZGl2PlRocmVhZC5hdG9taWNTd2l0Y2ggZGlkbid0IHNldCByLjw=
v
ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+enNoOiBzZWdtZW50YXRpb24gZmF1bHQgLi90ZXN0X2M=
g
MzwvZGl2PjxkaXY+YGBgPC9kaXY+PGRpdj5PcjwvZGl2PjxkaXY+YGBgPC9kaXY+PGRpdj51bmh=
h
bmRsZWQgZXhjZXB0aW9uOiBGYWlsODwvZGl2PjxkaXY+VGhyZWFkLmF0b21pY1N3aXRjaCBkaWR=
u
J3Qgc2V0IHIuPC9kaXY+PGRpdj5NTHRvbiBidWc6IE1MdG9uLkV4aXQuaGFsdDwvZGl2PjxkaXY=
+
UGxlYXNlIHNlbmQgYSBidWcgcmVwb3J0IHRvIE1MdG9uQG1sdG9uLm9yZy48L2Rpdj48ZGl2Pjx=
i
cj48L2Rpdj48ZGl2PnpzaDogYnVzIGVycm9yIC4vdGVzdF9jIDM8L2Rpdj48ZGl2PmBgYDwvZGl=
2
PjxkaXY+PGJyPjwvZGl2PjxkaXY+SSB0ZXN0ZWQgdGhpcyB3aXRoIGJvdGggTUx0b24mbmJzcDs=
y
MDIwMTAwMiBhbmQgTUx0b24gMjAyMTAxMTcgYW5kIHRoZXkgZ2l2ZSB0aGUgc2FtZSBlcnJvcnM=
u
IEFuZCB0aGlzIHByb2JsZW0gYXBwZWFycyBvbiBib3RoIE1hYyBhbmQgTGludXguPC9kaXY+PGR=
p
dj48YnI+PC9kaXY+PGRpdj5BbnkgYWR2aWNlIHdpbGwgYmUgYXBwcmVjaWF0ZWQuPC9kaXY+PGR=
p
dj48YnI+PC9kaXY+PGRpdj5UaGFua3MsPC9kaXY+PGRpdj5XZWlxaTwvZGl2PjwvZGl2PjwvZGl=
2
PjwvZGl2PjwvZGl2Pg=3D=3D" style=3D"height:0px;width:0px;max-height:0px;max-=
width:0px;overflow:hidden;font-size:0em;padding:0px;margin:0px"></div></div=
></div>

<p></p>

-- <br>
You received this message because you are subscribed to the Google Groups &=
quot;MLton&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]" target=3D"_blank">ml=
[email protected]</a>.<br>
_______________________________________________<br>
MLton-devel mailing list<br>
<a href=3D"mailto:[email protected]" target=3D"_blank">MLto=
[email protected]</a>; <a href=3D"mailto:[email protected]"=
 target=3D"_blank">[email protected]</a><br>
<a href=3D"https://lists.sourceforge.net/lists/listinfo/mlton-devel" rel=3D=
"noreferrer" target=3D"_blank">https://lists.sourceforge.net/lists/listinfo=
/mlton-devel</a><br>
</blockquote></div>

--0000000000003a2eb705d9ca5bba--


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


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

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

--===============5206239793893434773==--